@mochabug/adapt-web 1.0.1-rc.14 → 1.0.1-rc.16

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/README.md CHANGED
@@ -436,6 +436,16 @@ All three approaches compose — use `theme` for colors, CSS variables for fine-
436
436
  | `--mb-adapt-cap-spinner-thickness` | `3px` | |
437
437
  | `--mb-adapt-cap-font` | `inherit` | |
438
438
 
439
+ ### Z-index / stacking
440
+
441
+ | Variable | Default | Description |
442
+ |---|---|---|
443
+ | `--mb-adapt-z-base` | `0` | Base z-index offset — added to all internal z-index values |
444
+
445
+ Set `--mb-adapt-z-base` to shift all internal z-index values. Useful when embedding inside modals or drawers that have their own stacking context. Example: `--mb-adapt-z-base: 10000` lifts all layers by 10000.
446
+
447
+ Internal stacking order from low to high: separators (1), resize handles (10), minimized tabs (100), floating panels (100000+), status/cap (200000), confirm dialog (300000), drop targets (999998), drag ghost (999999). All values are offset by `--mb-adapt-z-base`.
448
+
439
449
  </details>
440
450
 
441
451
  ---
package/dist/README.md CHANGED
@@ -6,7 +6,7 @@ Embed Adapt automations in any website.
6
6
  npm install @mochabug/adapt-web
7
7
  ```
8
8
 
9
- **CDN base:** `https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/`
9
+ **CDN base:** `https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/`
10
10
 
11
11
  | Bundle | File | Includes |
12
12
  |--------|------|----------|
@@ -20,8 +20,8 @@ npm install @mochabug/adapt-web
20
20
  Bundles merge into a single `MbAdapt` global, so you can combine them. For example, headless + Cap for automations that need proof-of-work but no UI:
21
21
 
22
22
  ```html
23
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-core.min.js"></script>
24
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.cap.min.js"></script>
23
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-core.min.js"></script>
24
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.cap.min.js"></script>
25
25
  <script>
26
26
  // MbAdapt has exports from both scripts
27
27
  var client = MbAdapt.createAdaptClient(
@@ -43,12 +43,12 @@ Preload the script and load the stylesheet in `<head>` to eliminate flash of uns
43
43
 
44
44
  ```html
45
45
  <head>
46
- <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.min.js" as="script">
47
- <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/styles.css">
46
+ <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.min.js" as="script">
47
+ <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/styles.css">
48
48
  </head>
49
49
  <body>
50
50
  <adapt-automation automation-id="YOUR_ID" requires-challenge style="height: 600px"></adapt-automation>
51
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.min.js"></script>
51
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.min.js"></script>
52
52
  </body>
53
53
  ```
54
54
 
@@ -56,12 +56,12 @@ No challenges? Use the core bundle and drop `requires-challenge`:
56
56
 
57
57
  ```html
58
58
  <head>
59
- <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.core.min.js" as="script">
60
- <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/styles.css">
59
+ <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.core.min.js" as="script">
60
+ <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/styles.css">
61
61
  </head>
62
62
  <body>
63
63
  <adapt-automation automation-id="YOUR_ID" style="height: 600px"></adapt-automation>
64
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.core.min.js"></script>
64
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.core.min.js"></script>
65
65
  </body>
66
66
  ```
67
67
 
@@ -71,14 +71,14 @@ Just the element and script. CSS is auto-injected at runtime.
71
71
 
72
72
  ```html
73
73
  <adapt-automation automation-id="YOUR_ID" requires-challenge style="height: 600px"></adapt-automation>
74
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.min.js"></script>
74
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.min.js"></script>
75
75
  ```
76
76
 
77
77
  Without challenges:
78
78
 
79
79
  ```html
80
80
  <adapt-automation automation-id="YOUR_ID" style="height: 600px"></adapt-automation>
81
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.core.min.js"></script>
81
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.core.min.js"></script>
82
82
  ```
83
83
 
84
84
  ### ESM
@@ -160,12 +160,12 @@ Requires a `client` JS property — set it after the element is in the DOM.
160
160
 
161
161
  ```html
162
162
  <head>
163
- <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.cap.min.js" as="script">
164
- <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/styles.css">
163
+ <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.cap.min.js" as="script">
164
+ <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/styles.css">
165
165
  </head>
166
166
  <body>
167
167
  <adapt-cap automation-id="YOUR_ID"></adapt-cap>
168
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.cap.min.js"></script>
168
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.cap.min.js"></script>
169
169
  <script>
170
170
  var el = document.querySelector('adapt-cap');
171
171
  el.client = MbAdapt.createConnectClient({ id: 'YOUR_ID' });
@@ -180,7 +180,7 @@ Requires a `client` JS property — set it after the element is in the DOM.
180
180
 
181
181
  ```html
182
182
  <adapt-cap automation-id="YOUR_ID"></adapt-cap>
183
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/adapt-web.cap.min.js"></script>
183
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/adapt-web.cap.min.js"></script>
184
184
  <script>
185
185
  var el = document.querySelector('adapt-cap');
186
186
  el.client = MbAdapt.createConnectClient({ id: 'YOUR_ID' });
@@ -436,6 +436,16 @@ All three approaches compose — use `theme` for colors, CSS variables for fine-
436
436
  | `--mb-adapt-cap-spinner-thickness` | `3px` | |
437
437
  | `--mb-adapt-cap-font` | `inherit` | |
438
438
 
439
+ ### Z-index / stacking
440
+
441
+ | Variable | Default | Description |
442
+ |---|---|---|
443
+ | `--mb-adapt-z-base` | `0` | Base z-index offset — added to all internal z-index values |
444
+
445
+ Set `--mb-adapt-z-base` to shift all internal z-index values. Useful when embedding inside modals or drawers that have their own stacking context. Example: `--mb-adapt-z-base: 10000` lifts all layers by 10000.
446
+
447
+ Internal stacking order from low to high: separators (1), resize handles (10), minimized tabs (100), floating panels (100000+), status/cap (200000), confirm dialog (300000), drop targets (999998), drag ghost (999999). All values are offset by `--mb-adapt-z-base`.
448
+
439
449
  </details>
440
450
 
441
451
  ---
@@ -1 +1 @@
1
- typeof window<"u"&&!window.CAP_CUSTOM_WASM_URL&&(window.CAP_CUSTOM_WASM_URL=new URL("https://cdn.mochabug.com/adapt/web/1.0.1-rc.14/cap_wasm.js",window.location.href).href);import{timestampDate}from"@bufbuild/protobuf/wkt";let currentClient=null,currentAutomationId=null;const verificationTokens=new Map;async function createChallenge(client,id){const response=await client.createChallenge({id});return{count:response.count,size:response.size,difficulty:response.difficulty,expires:response.expires?timestampDate(response.expires):new Date,token:response.token,verificationToken:response.verificationToken}}async function redeemChallenge(client,id,verificationToken,solutions){const response=await client.redeemChallenge({id,verificationToken,solutions});return{token:response.token,expires:response.expires?timestampDate(response.expires):new Date}}typeof window<"u"&&(window.CAP_CUSTOM_FETCH=async(url,options)=>{const urlStr=url.toString();if(urlStr.endsWith("/challenge")){if(!currentClient||!currentAutomationId)return new Response(JSON.stringify({error:"Cap adapter not initialized"}),{status:500,headers:{"Content-Type":"application/json"}});try{const challengeInfo=await createChallenge(currentClient,currentAutomationId);return verificationTokens.set(currentAutomationId,challengeInfo.verificationToken),new Response(JSON.stringify({challenge:{c:challengeInfo.count,s:challengeInfo.size,d:challengeInfo.difficulty},token:challengeInfo.token,expires:challengeInfo.expires.toISOString()}),{status:200,headers:{"Content-Type":"application/json"}})}catch(error){return new Response(JSON.stringify({error:String(error)}),{status:500,headers:{"Content-Type":"application/json"}})}}if(urlStr.endsWith("/redeem")){if(!currentClient||!currentAutomationId)return new Response(JSON.stringify({error:"Cap adapter not initialized"}),{status:500,headers:{"Content-Type":"application/json"}});const verificationToken=verificationTokens.get(currentAutomationId);if(!verificationToken)return new Response(JSON.stringify({error:"No verification token found - challenge must be created first"}),{status:400,headers:{"Content-Type":"application/json"}});try{const solutions=((options?.body?JSON.parse(options.body):{}).solutions||[]).map(s=>BigInt(s)),redeemed=await redeemChallenge(currentClient,currentAutomationId,verificationToken,solutions);return verificationTokens.delete(currentAutomationId),new Response(JSON.stringify({success:!0,token:redeemed.token,expires:redeemed.expires.toISOString()}),{status:200,headers:{"Content-Type":"application/json"}})}catch(error){return new Response(JSON.stringify({error:String(error)}),{status:500,headers:{"Content-Type":"application/json"}})}}return fetch(url,options)});function setupCapAdapter(client,automationId){currentClient=client,currentAutomationId=automationId}function cleanupCapAdapter(){currentAutomationId&&verificationTokens.delete(currentAutomationId),currentClient=null,currentAutomationId=null}export{cleanupCapAdapter,createChallenge,redeemChallenge,setupCapAdapter};
1
+ typeof window<"u"&&!window.CAP_CUSTOM_WASM_URL&&(window.CAP_CUSTOM_WASM_URL=new URL("https://cdn.mochabug.com/adapt/web/1.0.1-rc.16/cap_wasm.js",window.location.href).href);import{timestampDate}from"@bufbuild/protobuf/wkt";let currentClient=null,currentAutomationId=null;const verificationTokens=new Map;async function createChallenge(client,id){const response=await client.createChallenge({id});return{count:response.count,size:response.size,difficulty:response.difficulty,expires:response.expires?timestampDate(response.expires):new Date,token:response.token,verificationToken:response.verificationToken}}async function redeemChallenge(client,id,verificationToken,solutions){const response=await client.redeemChallenge({id,verificationToken,solutions});return{token:response.token,expires:response.expires?timestampDate(response.expires):new Date}}typeof window<"u"&&(window.CAP_CUSTOM_FETCH=async(url,options)=>{const urlStr=url.toString();if(urlStr.endsWith("/challenge")){if(!currentClient||!currentAutomationId)return new Response(JSON.stringify({error:"Cap adapter not initialized"}),{status:500,headers:{"Content-Type":"application/json"}});try{const challengeInfo=await createChallenge(currentClient,currentAutomationId);return verificationTokens.set(currentAutomationId,challengeInfo.verificationToken),new Response(JSON.stringify({challenge:{c:challengeInfo.count,s:challengeInfo.size,d:challengeInfo.difficulty},token:challengeInfo.token,expires:challengeInfo.expires.toISOString()}),{status:200,headers:{"Content-Type":"application/json"}})}catch(error){return new Response(JSON.stringify({error:String(error)}),{status:500,headers:{"Content-Type":"application/json"}})}}if(urlStr.endsWith("/redeem")){if(!currentClient||!currentAutomationId)return new Response(JSON.stringify({error:"Cap adapter not initialized"}),{status:500,headers:{"Content-Type":"application/json"}});const verificationToken=verificationTokens.get(currentAutomationId);if(!verificationToken)return new Response(JSON.stringify({error:"No verification token found - challenge must be created first"}),{status:400,headers:{"Content-Type":"application/json"}});try{const solutions=((options?.body?JSON.parse(options.body):{}).solutions||[]).map(s=>BigInt(s)),redeemed=await redeemChallenge(currentClient,currentAutomationId,verificationToken,solutions);return verificationTokens.delete(currentAutomationId),new Response(JSON.stringify({success:!0,token:redeemed.token,expires:redeemed.expires.toISOString()}),{status:200,headers:{"Content-Type":"application/json"}})}catch(error){return new Response(JSON.stringify({error:String(error)}),{status:500,headers:{"Content-Type":"application/json"}})}}return fetch(url,options)});function setupCapAdapter(client,automationId){currentClient=client,currentAutomationId=automationId}function cleanupCapAdapter(){currentAutomationId&&verificationTokens.delete(currentAutomationId),currentClient=null,currentAutomationId=null}export{cleanupCapAdapter,createChallenge,redeemChallenge,setupCapAdapter};
@@ -31,6 +31,7 @@ const PANEL_MANAGER_CSS=`/* ====================================================
31
31
  --_status-text: var(--mb-adapt-status-text, #374151);
32
32
  --_drag-ghost-shadow: var(--mb-adapt-drag-ghost-shadow, 0 4px 12px rgba(0, 0, 0, 0.15));
33
33
  --_border-radius: var(--mb-adapt-border-radius, 8px);
34
+ --_z-base: var(--mb-adapt-z-base, 0);
34
35
  --mb-adapt-responsive-breakpoint: 768;
35
36
  --mb-adapt-responsive-hysteresis: 40;
36
37
 
@@ -165,7 +166,7 @@ const PANEL_MANAGER_CSS=`/* ====================================================
165
166
  background: var(--_fork-separator);
166
167
  transition: background 0.15s;
167
168
  position: relative;
168
- z-index: 1;
169
+ z-index: calc(1 + var(--_z-base));
169
170
  touch-action: none;
170
171
  }
171
172
 
@@ -203,7 +204,7 @@ const PANEL_MANAGER_CSS=`/* ====================================================
203
204
 
204
205
  .mb-group-tabs {
205
206
  display: flex;
206
- align-items: center;
207
+ align-items: stretch;
207
208
  overflow-x: auto;
208
209
  overflow-y: hidden;
209
210
  flex: 0 1 auto;
@@ -349,7 +350,7 @@ const PANEL_MANAGER_CSS=`/* ====================================================
349
350
  /* \u2500\u2500 Floating overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
350
351
  .mb-floating-overlay {
351
352
  position: fixed;
352
- z-index: 100000;
353
+ z-index: calc(100000 + var(--_z-base));
353
354
  box-shadow: var(--_floating-shadow);
354
355
  border: var(--_floating-border);
355
356
  backdrop-filter: var(--_floating-backdrop);
@@ -400,7 +401,7 @@ const PANEL_MANAGER_CSS=`/* ====================================================
400
401
  /* \u2500\u2500 Resize handles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
401
402
  .mb-resize-handle {
402
403
  position: absolute;
403
- z-index: 10;
404
+ z-index: calc(10 + var(--_z-base));
404
405
  touch-action: none;
405
406
  }
406
407
 
@@ -442,7 +443,7 @@ const PANEL_MANAGER_CSS=`/* ====================================================
442
443
  display: flex;
443
444
  align-items: center;
444
445
  justify-content: center;
445
- z-index: 200000;
446
+ z-index: calc(200000 + var(--_z-base));
446
447
  background: transparent;
447
448
  pointer-events: none;
448
449
  }
@@ -515,7 +516,7 @@ const PANEL_MANAGER_CSS=`/* ====================================================
515
516
  flex-direction: row;
516
517
  align-items: center;
517
518
  justify-content: center;
518
- z-index: 300000;
519
+ z-index: calc(300000 + var(--_z-base));
519
520
  background: rgba(0, 0, 0, 0.4);
520
521
  height: auto;
521
522
  min-height: 0;
@@ -592,7 +593,7 @@ const PANEL_MANAGER_CSS=`/* ====================================================
592
593
  align-items: center;
593
594
  justify-content: center;
594
595
  pointer-events: none;
595
- z-index: 200000;
596
+ z-index: calc(200000 + var(--_z-base));
596
597
  }
597
598
 
598
599
  .mb-adapt-cap > * {
@@ -664,7 +665,7 @@ cap-widget::part(attribution) {
664
665
  display: none;
665
666
  height: var(--_toolbar-height);
666
667
  flex-shrink: 0;
667
- z-index: 100;
668
+ z-index: calc(100 + var(--_z-base));
668
669
  align-items: stretch;
669
670
  background: var(--_fork-tab-bg);
670
671
  border-bottom: 1px solid var(--_fork-separator);
@@ -737,7 +738,7 @@ cap-widget::part(attribution) {
737
738
  .mb-drag-ghost {
738
739
  position: fixed;
739
740
  pointer-events: none;
740
- z-index: 999999;
741
+ z-index: calc(999999 + var(--_z-base));
741
742
  padding: 4px 10px;
742
743
  background: var(--_fork-tab-bg);
743
744
  color: var(--_fork-tab-color);
@@ -767,7 +768,7 @@ cap-widget::part(attribution) {
767
768
  .mb-drop-overlay {
768
769
  position: fixed;
769
770
  pointer-events: none;
770
- z-index: 999998;
771
+ z-index: calc(999998 + var(--_z-base));
771
772
  display: none;
772
773
  box-sizing: border-box;
773
774
  border-radius: 6px;
@@ -1 +1 @@
1
- import{SVG_POPOUT,SVG_WINDOW}from"./panel-setup.js";let iframeDragDepth=0;function disableIframePointEvents(){return iframeDragDepth++,document.documentElement.classList.add("mb-dragging"),{release(){--iframeDragDepth<=0&&(iframeDragDepth=0,document.documentElement.classList.remove("mb-dragging"))}}}class Panel{constructor(id,element,title){this.group=null;this.id=id,this.element=element,this.title=title||id,this.wrapper=document.createElement("div"),this.wrapper.className="mb-panel",this.wrapper.dataset.panelId=id,this.wrapper.dataset.active="false",this.wrapper.appendChild(element)}}let groupIdCounter=0;class PanelGroup{constructor(id){this._panels=[];this._activePanel=null;this._headerHidden=!1;this._locked=!1;this._onTabClose=null;this._onTabPointerDown=null;this._onTabPopOut=null;this._location="grid";this._onLocationChangedCb=null;this._isInFloatingSplit=!1;this._onSplitStateChangedCb=null;this._dragConstraint="any";this._dockingBlocked=!1;this._dialogDockingBlocked=!1;this._onPanelCountChangedCb=null;this._onActivePanelChangedCb=null;this.id=id||`group-${++groupIdCounter}`,this.element=document.createElement("div"),this.element.className="mb-group",this.element.dataset.groupId=this.id,this.headerElement=document.createElement("div"),this.headerElement.className="mb-group-header",this.headerPrefix=document.createElement("div"),this.headerPrefix.className="mb-group-header-prefix",this.tabsElement=document.createElement("div"),this.tabsElement.className="mb-group-tabs",this.headerVoid=document.createElement("div"),this.headerVoid.className="mb-group-header-void",this.headerActions=document.createElement("div"),this.headerActions.className="mb-group-header-actions",this.headerElement.appendChild(this.headerPrefix),this.headerElement.appendChild(this.tabsElement),this.headerElement.appendChild(this.headerVoid),this.headerElement.appendChild(this.headerActions),this.contentElement=document.createElement("div"),this.contentElement.className="mb-group-content",this.element.appendChild(this.headerElement),this.element.appendChild(this.contentElement)}get panels(){return this._panels}get activePanel(){return this._activePanel}get size(){return this._panels.length}get locked(){return this._locked}set locked(value){this._locked=value}setHeaderHidden(hidden){this._headerHidden=hidden,this.headerElement.style.display=hidden?"none":""}get headerHidden(){return this._headerHidden}setHeaderActions(element){this.headerActions.innerHTML="",this.headerActions.appendChild(element)}setHeaderPrefix(element){this.headerPrefix.innerHTML="",this.headerPrefix.appendChild(element)}onTabClose(cb){this._onTabClose=cb}onTabPointerDown(cb){this._onTabPointerDown=cb}get location(){return this._location}set location(value){this._location!==value&&(this._location=value,this._onLocationChangedCb?.(value))}onLocationChanged(cb){this._onLocationChangedCb=cb}fireLocationChanged(){this._onLocationChangedCb?.(this._location)}get isInFloatingSplit(){return this._isInFloatingSplit}set isInFloatingSplit(value){this._isInFloatingSplit!==value&&(this._isInFloatingSplit=value,this._onSplitStateChangedCb?.(value))}onSplitStateChanged(cb){this._onSplitStateChangedCb=cb}onTabPopOut(cb){this._onTabPopOut=cb}get dragConstraint(){return this._dragConstraint}set dragConstraint(v){this._dragConstraint=v}get dockingBlocked(){return this._dockingBlocked}set dockingBlocked(v){this._dockingBlocked=v}get dialogDockingBlocked(){return this._dialogDockingBlocked}set dialogDockingBlocked(v){this._dialogDockingBlocked=v}onPanelCountChanged(cb){this._onPanelCountChangedCb=cb}onActivePanelChanged(cb){this._onActivePanelChangedCb=cb}addPanel(panel){if(this._panels.some(p=>p.id===panel.id))return;panel.group=this,this._panels.push(panel),this.contentElement.appendChild(panel.wrapper);const tab=this.createTab(panel);this.tabsElement.appendChild(tab),this.activatePanel(panel.id),this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length)}removePanel(panelId){const idx=this._panels.findIndex(p=>p.id===panelId);if(idx===-1)return null;const panel=this._panels[idx];if(this._panels.splice(idx,1),panel.wrapper.remove(),this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`)?.remove(),panel.group=null,this._activePanel===panel&&(this._activePanel=null,this._panels.length>0)){const newActive=this._panels[Math.min(idx,this._panels.length-1)];newActive&&this.activatePanel(newActive.id)}return this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length),panel}detachPanel(panelId){const idx=this._panels.findIndex(p=>p.id===panelId);if(idx===-1)return null;const panel=this._panels[idx];if(this._panels.splice(idx,1),this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`)?.remove(),panel.group=null,this._activePanel===panel&&(this._activePanel=null,this._panels.length>0)){const newActive=this._panels[Math.min(idx,this._panels.length-1)];newActive&&this.activatePanel(newActive.id)}return this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length),panel}activatePanel(panelId){const panel=this._panels.find(p=>p.id===panelId);if(!panel)return;this._activePanel=panel;for(const p of this._panels)p.wrapper.dataset.active=p===panel?"true":"false";const tabs=this.tabsElement.querySelectorAll(".mb-tab");for(const tab of tabs){const isActive=tab.dataset.tabId===panelId;tab.dataset.active=isActive?"true":"false"}this._onActivePanelChangedCb?.(panelId)}reorderPanel(panelId,dropX){const panelIdx=this._panels.findIndex(p=>p.id===panelId);if(panelIdx===-1)return;const panel=this._panels[panelIdx],tabs=Array.from(this.tabsElement.querySelectorAll(".mb-tab"));let targetIdx=this._panels.length;for(let i=0;i<tabs.length;i++){const rect=tabs[i].getBoundingClientRect();if(dropX<rect.left+rect.width/2){targetIdx=i;break}}if(targetIdx===panelIdx||targetIdx===panelIdx+1)return;this._panels.splice(panelIdx,1);const insertAt=panelIdx<targetIdx?targetIdx-1:targetIdx;this._panels.splice(insertAt,0,panel);const tabEl=this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`);if(tabEl){const refTab=this.tabsElement.querySelectorAll(".mb-tab")[insertAt];refTab&&refTab!==tabEl?this.tabsElement.insertBefore(tabEl,refTab):this.tabsElement.appendChild(tabEl)}}createTab(panel){const tab=document.createElement("div");tab.className="mb-tab",tab.dataset.tabId=panel.id,tab.dataset.active="false";const label=document.createElement("span");label.className="mb-tab-label",label.innerHTML=SVG_WINDOW,label.title=panel.title,tab.appendChild(label);const actions=document.createElement("div");actions.className="mb-tab-actions";const popOutBtn=document.createElement("button");popOutBtn.className="mb-tab-popout",popOutBtn.title="Pop out",popOutBtn.innerHTML=SVG_POPOUT,popOutBtn.addEventListener("click",e=>{e.stopPropagation(),this._onTabPopOut?.(panel.id)}),actions.appendChild(popOutBtn);const closeBtn=document.createElement("button");return closeBtn.className="mb-tab-close",closeBtn.title="Close",closeBtn.innerHTML='<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><line x1="4" y1="4" x2="12" y2="12"/><line x1="12" y1="4" x2="4" y2="12"/></svg>',closeBtn.addEventListener("click",e=>{e.stopPropagation(),this._onTabClose?.(panel.id)}),actions.appendChild(closeBtn),tab.appendChild(actions),tab.addEventListener("pointerdown",e=>{e.target.closest(".mb-tab-close")||e.target.closest(".mb-tab-popout")||e.button===0&&(e.preventDefault(),this._onTabPointerDown?.(panel.id,e))}),tab}dispose(){this._panels=[],this._activePanel=null,this.element.remove()}}let zIndexCounter=1e5;class FloatingOverlay{constructor(group,opts,parentElement,insertBefore){this.internalLayout=null;this.toolbarElement=null;this.savedBounds=null;this._isMaximized=!1;this._onDragEnd=null;this._onDragMove=null;this.group=group,this.bounds={...opts},this.element=document.createElement("div"),this.element.className="mb-floating-overlay",this.element.dataset.groupId=group.id,this.applyBounds();const directions=["n","s","e","w","ne","nw","se","sw"];for(const dir of directions){const handle=document.createElement("div");handle.className=`mb-resize-handle mb-resize-${dir}`,handle.addEventListener("pointerdown",e=>this.onResizeStart(e,dir)),this.element.appendChild(handle)}this.element.addEventListener("pointerdown",()=>this.bringToFront(),!0),group.headerVoid.addEventListener("pointerdown",e=>this.onDragStart(e)),group.headerVoid.style.cursor="grab";const parent=parentElement??document.body;insertBefore?parent.insertBefore(this.element,insertBefore):parent.appendChild(this.element),this.element.appendChild(group.element),this.bringToFront()}get isMaximized(){return this._isMaximized}set onDragEnd(cb){this._onDragEnd=cb}set onDragMove(cb){this._onDragMove=cb}bringToFront(){zIndexCounter+=2,this.element.style.zIndex=String(zIndexCounter)}maximize(){this._isMaximized||(this.savedBounds={...this.bounds},this._isMaximized=!0,this.element.style.inset="0",this.element.style.width="auto",this.element.style.height="auto",this.element.classList.add("mb-floating-maximized"))}restore(){!this._isMaximized||!this.savedBounds||(this._isMaximized=!1,this.bounds={...this.savedBounds},this.savedBounds=null,this.element.classList.remove("mb-floating-maximized"),this.element.style.inset="",this.applyBounds())}hide(){this.element.style.display="none"}show(){this.element.style.display=""}dispose(){this.internalLayout&&(this.internalLayout.dispose(),this.internalLayout=null),this.removeToolbar(),this.element.remove()}getBounds(){return{...this.bounds}}setBounds(partial){if(this._isMaximized)return;const pad=10;partial.width!==void 0&&(this.bounds.width=Math.min(partial.width,window.innerWidth-this.bounds.x-pad)),partial.height!==void 0&&(this.bounds.height=Math.min(partial.height,window.innerHeight-this.bounds.y-pad)),this.applyBounds()}setFullBounds(bounds){if(this._isMaximized)return;const vw=window.innerWidth,vh=window.innerHeight,pad=10,minVisible=100;this.bounds={width:Math.max(minVisible,Math.min(bounds.width,vw-pad)),height:Math.max(minVisible,Math.min(bounds.height,vh-pad)),x:Math.max(0,Math.min(bounds.x,vw-minVisible)),y:Math.max(0,Math.min(bounds.y,vh-minVisible))},this.applyBounds()}applyBounds(){this.element.style.position="fixed",this.element.style.left=`${this.bounds.x}px`,this.element.style.top=`${this.bounds.y}px`,this.element.style.width=`${this.bounds.width}px`,this.element.style.height=`${this.bounds.height}px`}setDragGroup(newGroup){newGroup.headerVoid.addEventListener("pointerdown",e=>this.onDragStart(e)),newGroup.headerVoid.style.cursor="grab"}setToolbar(el){this.removeToolbar(),this.toolbarElement=el,this.getToolbarHost().headerActions.appendChild(el)}removeToolbar(){this.toolbarElement&&(this.toolbarElement.remove(),this.toolbarElement=null)}repositionToolbar(){this.toolbarElement&&this.getToolbarHost().headerActions.appendChild(this.toolbarElement)}getToolbarHost(){if(!this.internalLayout)return this.group;const root=this.internalLayout.getRoot();return root?FloatingOverlay.topRightGroup(root):this.group}static topRightGroup(node){return node.kind==="leaf"?node.group:node.direction==="horizontal"?FloatingOverlay.topRightGroup(node.second):FloatingOverlay.topRightGroup(node.first)}get hasToolbar(){return this.toolbarElement!==null}getAllGroups(){return this.internalLayout?.allGroups()??[this.group]}updateTotalTabCount(){const groups=this.getAllGroups();let total=0;for(const g of groups)total+=g.size;this.element.dataset.totalTabCount=String(total)}onDragStart(e){if(this._isMaximized)return;e.preventDefault();const handle=e.currentTarget,startX=e.clientX,startY=e.clientY,origLeft=this.bounds.x,origTop=this.bounds.y,iframes=disableIframePointEvents();handle.style.cursor="grabbing",handle.setPointerCapture(e.pointerId);const onMove=ev=>{const dx=ev.clientX-startX,dy=ev.clientY-startY;this.bounds.x=Math.max(0,Math.min(origLeft+dx,window.innerWidth-this.bounds.width)),this.bounds.y=Math.max(0,Math.min(origTop+dy,window.innerHeight-this.bounds.height)),this.applyBounds(),this._onDragMove?.(this.bounds.x+this.bounds.width/2,this.bounds.y+this.bounds.height/2)},onUp=()=>{iframes.release(),handle.style.cursor="grab",handle.removeEventListener("pointermove",onMove),handle.removeEventListener("pointerup",onUp),handle.removeEventListener("pointercancel",onUp),this._onDragEnd?.(this.bounds.x+this.bounds.width/2,this.bounds.y+this.bounds.height/2)};handle.addEventListener("pointermove",onMove),handle.addEventListener("pointerup",onUp),handle.addEventListener("pointercancel",onUp)}onResizeStart(e,dir){if(this._isMaximized)return;e.preventDefault(),e.stopPropagation();const startX=e.clientX,startY=e.clientY,orig={...this.bounds},handle=e.currentTarget,minW=200,minH=100,iframes=disableIframePointEvents();handle.setPointerCapture(e.pointerId);const onMove=ev=>{const dx=ev.clientX-startX,dy=ev.clientY-startY;if(dir.includes("e")&&(this.bounds.width=Math.max(minW,orig.width+dx)),dir.includes("w")){const newW=Math.max(minW,orig.width-dx);this.bounds.x=orig.x+(orig.width-newW),this.bounds.width=newW}if(dir.includes("s")&&(this.bounds.height=Math.max(minH,orig.height+dy)),dir.includes("n")){const newH=Math.max(minH,orig.height-dy);this.bounds.y=orig.y+(orig.height-newH),this.bounds.height=newH}const pad=10;this.bounds.x=Math.max(0,this.bounds.x),this.bounds.y=Math.max(0,this.bounds.y),this.bounds.x+this.bounds.width>window.innerWidth-pad&&(this.bounds.width=window.innerWidth-this.bounds.x-pad),this.bounds.y+this.bounds.height>window.innerHeight-pad&&(this.bounds.height=window.innerHeight-this.bounds.y-pad),this.applyBounds()},onUp=()=>{iframes.release(),handle.removeEventListener("pointermove",onMove),handle.removeEventListener("pointerup",onUp),handle.removeEventListener("pointercancel",onUp)};handle.addEventListener("pointermove",onMove),handle.addEventListener("pointerup",onUp),handle.addEventListener("pointercancel",onUp)}}class SplitLayout{constructor(container){this.root=null;this.element=document.createElement("div"),this.element.className="mb-layout",container.appendChild(this.element)}getRoot(){return this.root}setMainGroup(group){const leaf=this.createLeaf(group);leaf.element.style.flex="1",this.root=leaf,this.element.appendChild(leaf.element)}splitGroup(targetGroup,newGroup,direction,newGroupSize){const splitDir=this.dockToSplitDirection(direction),leafNode=this.findGroupNode(targetGroup);if(!leafNode)return!1;const newLeafEl=document.createElement("div");newLeafEl.className="mb-split-leaf",newLeafEl.style.flex="1";const splitEl=document.createElement("div");splitEl.className=`mb-split-container ${splitDir==="horizontal"?"mb-split-horizontal":"mb-split-vertical"}`,splitEl.style.flex=leafNode.element.style.flex||"1",splitEl.style.minWidth="0",splitEl.style.minHeight="0";const separator=document.createElement("div"),isVerticalSplit=splitDir==="vertical";separator.className=`mb-layout-separator ${isVerticalSplit?"mb-layout-separator-h":"mb-layout-separator-v"}`;const existingFirst=direction==="right"||direction==="bottom";leafNode.element.parentElement.insertBefore(splitEl,leafNode.element),existingFirst?(splitEl.appendChild(leafNode.element),splitEl.appendChild(separator),splitEl.appendChild(newLeafEl)):(splitEl.appendChild(newLeafEl),splitEl.appendChild(separator),splitEl.appendChild(leafNode.element)),newLeafEl.appendChild(newGroup.element),newGroupSize!==void 0&&newGroupSize>0?existingFirst?(leafNode.element.style.flex="1",newLeafEl.style.flex=`0 0 ${newGroupSize}px`):(newLeafEl.style.flex=`0 0 ${newGroupSize}px`,leafNode.element.style.flex="1"):(leafNode.element.style.flex="1",newLeafEl.style.flex="1");const newLeaf={kind:"leaf",group:newGroup,element:newLeafEl},splitNode={kind:"split",direction:splitDir,first:existingFirst?leafNode:newLeaf,second:existingFirst?newLeaf:leafNode,element:splitEl,separator};return separator.addEventListener("pointerdown",e=>this.onSeparatorDrag(e,splitNode)),this.replaceNodeInTree(leafNode,splitNode),leafNode.element.style.display==="none"&&(separator.style.display="none",newLeafEl.dataset.savedFlex=newLeafEl.style.flex,newLeafEl.style.flex="1",leafNode.element.dataset.savedFlex=leafNode.element.style.flex),!0}removeGroup(group){const leafNode=this.findGroupNode(group);if(!leafNode)return;if(this.root===leafNode){leafNode.element.remove(),this.root=null;return}this.restoreMaximizedLeaf(group);const parentSplit=this.findParentSplit(leafNode);if(!parentSplit)return;const sibling=parentSplit.first===leafNode?parentSplit.second:parentSplit.first;this.restoreMaximizedSubtree(sibling),sibling.element.style.flex=parentSplit.element.style.flex||"1",parentSplit.element.parentElement.insertBefore(sibling.element,parentSplit.element),leafNode.element.remove(),parentSplit.separator.remove(),parentSplit.element.remove(),this.replaceNodeInTree(parentSplit,sibling)}findGroupNode(group){return this.findGroupNodeIn(this.root,group)}getGroupPosition(group){const leaf=this.findGroupNode(group);if(!leaf)return null;const parent=this.findParentSplit(leaf);if(!parent)return null;const isFirst=parent.first===leaf,siblingNode=isFirst?parent.second:parent.first,siblingGroup=this.firstGroupIn(siblingNode);if(!siblingGroup)return null;let direction;return parent.direction==="horizontal"?direction=isFirst?"left":"right":direction=isFirst?"top":"bottom",{siblingGroup,direction}}firstGroupIn(node){return node.kind==="leaf"?node.group:this.firstGroupIn(node.first)}collapseLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;const parent=this.findParentSplit(leaf);if(parent){const sibling=parent.first===leaf?parent.second:parent.first;sibling.element.dataset.savedFlex=sibling.element.style.flex,sibling.element.style.flex="1",parent.separator.style.display="none"}leaf.element.dataset.savedFlex=leaf.element.style.flex,leaf.element.style.display="none"}expandLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;leaf.element.style.display="",leaf.element.dataset.savedFlex!==void 0&&(leaf.element.style.flex=leaf.element.dataset.savedFlex,delete leaf.element.dataset.savedFlex);const parent=this.findParentSplit(leaf);if(parent){parent.separator.style.display="";const sibling=parent.first===leaf?parent.second:parent.first;sibling.element.dataset.savedFlex!==void 0&&(sibling.element.style.flex=sibling.element.dataset.savedFlex,delete sibling.element.dataset.savedFlex)}}maximizeLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;let current=leaf,parent=this.findParentSplit(current);for(;parent;){const sibling=parent.first===current?parent.second:parent.first;sibling.element.dataset.maxSavedDisplay===void 0&&(sibling.element.dataset.maxSavedDisplay=sibling.element.style.display),sibling.element.style.display="none",parent.separator.dataset.maxSavedDisplay===void 0&&(parent.separator.dataset.maxSavedDisplay=parent.separator.style.display),parent.separator.style.display="none",current.element.dataset.maxSavedFlex===void 0&&(current.element.dataset.maxSavedFlex=current.element.style.flex),current.element.style.flex="1",current=parent,parent=this.findParentSplit(current)}}restoreMaximizedLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;let current=leaf,parent=this.findParentSplit(current);for(;parent;){const sibling=parent.first===current?parent.second:parent.first;sibling.element.dataset.maxSavedDisplay!==void 0&&(sibling.element.style.display=sibling.element.dataset.maxSavedDisplay,delete sibling.element.dataset.maxSavedDisplay),parent.separator.dataset.maxSavedDisplay!==void 0&&(parent.separator.style.display=parent.separator.dataset.maxSavedDisplay,delete parent.separator.dataset.maxSavedDisplay),current.element.dataset.maxSavedFlex!==void 0&&(current.element.style.flex=current.element.dataset.maxSavedFlex,delete current.element.dataset.maxSavedFlex),current=parent,parent=this.findParentSplit(current)}}restoreMaximizedSubtree(node){node.element.dataset.maxSavedDisplay!==void 0&&(node.element.style.display=node.element.dataset.maxSavedDisplay,delete node.element.dataset.maxSavedDisplay),node.element.dataset.maxSavedFlex!==void 0&&(node.element.style.flex=node.element.dataset.maxSavedFlex,delete node.element.dataset.maxSavedFlex),node.kind==="split"&&(node.separator.dataset.maxSavedDisplay!==void 0&&(node.separator.style.display=node.separator.dataset.maxSavedDisplay,delete node.separator.dataset.maxSavedDisplay),this.restoreMaximizedSubtree(node.first),this.restoreMaximizedSubtree(node.second))}allGroups(){const result=[];return this.collectGroups(this.root,result),result}toJSON(){return this.serializeNode(this.root)}restoreFlexFromSerialized(serialized){if(!serialized||!this.root)return;const flexMap=new Map;this.collectFlexValues(serialized,flexMap),this.applyFlexValues(this.root,flexMap)}animateTransition(){const cls=node=>{node&&(node.kind==="leaf"?node.element.classList.add("mb-split-leaf--animating"):(node.element.classList.add("mb-split-container--animating"),node.separator&&node.separator.classList.add("mb-layout-separator--animating"),cls(node.first),cls(node.second)))};cls(this.root);const cleanup=()=>{this.element.querySelectorAll(".mb-split-leaf--animating, .mb-split-container--animating, .mb-layout-separator--animating").forEach(el=>{el.classList.remove("mb-split-leaf--animating","mb-split-container--animating","mb-layout-separator--animating")})},timer=setTimeout(cleanup,350);this.element.addEventListener("transitionend",()=>{clearTimeout(timer),cleanup()},{once:!0})}dispose(){this.element.remove(),this.root=null}createLeaf(group){const leafEl=document.createElement("div");return leafEl.className="mb-split-leaf",leafEl.style.flex="1",leafEl.appendChild(group.element),{kind:"leaf",group,element:leafEl}}dockToSplitDirection(pos){return pos==="left"||pos==="right"?"horizontal":"vertical"}findGroupNodeIn(node,group){return node?node.kind==="leaf"?node.group===group?node:null:this.findGroupNodeIn(node.first,group)??this.findGroupNodeIn(node.second,group):null}collectGroups(node,result){node&&(node.kind==="leaf"?result.push(node.group):(this.collectGroups(node.first,result),this.collectGroups(node.second,result)))}findParentSplit(target){return this.findParentSplitIn(this.root,target)}findParentSplitIn(node,target){return!node||node.kind==="leaf"?null:node.first===target||node.second===target?node:this.findParentSplitIn(node.first,target)??this.findParentSplitIn(node.second,target)}replaceNodeInTree(oldNode,newNode){if(this.root===oldNode){this.root=newNode;return}const parent=this.findParentSplit(oldNode);parent&&(parent.first===oldNode?parent.first=newNode:parent.second=newNode)}collectFlexValues(node,map){node.kind==="leaf"?map.set(node.groupId,node.flex):(this.collectFlexValues(node.first,map),this.collectFlexValues(node.second,map))}applyFlexValues(node,map){if(node.kind==="leaf"){const saved=map.get(node.group.id);saved&&this.isValidFlex(saved)&&(node.element.style.flex=saved)}else this.applyFlexValues(node.first,map),this.applyFlexValues(node.second,map)}isValidFlex(value){if(value.includes("px"))return!0;const n=Number(value);return Number.isFinite(n)&&n>=0}serializeNode(node){return node?node.kind==="leaf"?{kind:"leaf",groupId:node.group.id,flex:node.element.style.flex||"1"}:{kind:"split",direction:node.direction,first:this.serializeNode(node.first),second:this.serializeNode(node.second),flex:node.element.style.flex||"1"}:null}onSeparatorDrag(e,splitNode){if(e.preventDefault(),splitNode.first.element.style.display==="none"||splitNode.second.element.style.display==="none")return;const isHorizontal=splitNode.direction==="horizontal",startPos=isHorizontal?e.clientX:e.clientY,firstEl=splitNode.first.element,secondEl=splitNode.second.element;this.lockDescendantSizes(splitNode.first,isHorizontal),this.lockDescendantSizes(splitNode.second,isHorizontal);const origFirstSize=isHorizontal?firstEl.offsetWidth:firstEl.offsetHeight,origSecondSize=isHorizontal?secondEl.offsetWidth:secondEl.offsetHeight,totalSize=origFirstSize+origSecondSize;if(totalSize<=0)return;const minSize=150,iframes=disableIframePointEvents();splitNode.separator.setPointerCapture(e.pointerId),splitNode.separator.classList.add("mb-layout-separator--active");const onMove=ev=>{if(firstEl.style.display==="none"||secondEl.style.display==="none"){splitNode.separator.releasePointerCapture(ev.pointerId),onUp();return}const delta=(isHorizontal?ev.clientX:ev.clientY)-startPos;let newFirst=origFirstSize+delta,newSecond=origSecondSize-delta;newFirst<minSize&&(newFirst=minSize,newSecond=totalSize-minSize),newSecond<minSize&&(newSecond=minSize,newFirst=totalSize-minSize),firstEl.style.flex=String(newFirst/totalSize),secondEl.style.flex=String(newSecond/totalSize)},onUp=()=>{iframes.release(),splitNode.separator.classList.remove("mb-layout-separator--active"),splitNode.separator.removeEventListener("pointermove",onMove),splitNode.separator.removeEventListener("pointerup",onUp),splitNode.separator.removeEventListener("pointercancel",onUp),this.unlockDescendantSizes(splitNode.first,isHorizontal),this.unlockDescendantSizes(splitNode.second,isHorizontal)};splitNode.separator.addEventListener("pointermove",onMove),splitNode.separator.addEventListener("pointerup",onUp),splitNode.separator.addEventListener("pointercancel",onUp)}lockDescendantSizes(node,isHorizontal){if(node.kind!=="split"||node.direction==="horizontal"!==isHorizontal)return;const firstSize=isHorizontal?node.first.element.getBoundingClientRect().width:node.first.element.getBoundingClientRect().height;node.first.element.style.flex=`0 0 ${firstSize}px`,node.second.element.style.flex="1",this.lockDescendantSizes(node.first,isHorizontal),this.lockDescendantSizes(node.second,isHorizontal)}unlockDescendantSizes(node,isHorizontal){if(node.kind!=="split"||node.direction==="horizontal"!==isHorizontal)return;this.unlockDescendantSizes(node.first,isHorizontal),this.unlockDescendantSizes(node.second,isHorizontal);const firstSize=isHorizontal?node.first.element.getBoundingClientRect().width:node.first.element.getBoundingClientRect().height,secondSize=isHorizontal?node.second.element.getBoundingClientRect().width:node.second.element.getBoundingClientRect().height,total=firstSize+secondSize;total>0?(node.first.element.style.flex=String(firstSize/total),node.second.element.style.flex=String(secondSize/total)):(node.first.element.style.flex="0.5",node.second.element.style.flex="0.5")}}class PanelManager{constructor(opts){this.groups=new Map;this.panels=new Map;this.floatingOverlays=new Map;this.mainGroupId=null;this.onPanelRemovedCbs=[];this.onGroupCreatedByDragCb=null;this.disposed=!1;this.dragState=null;this.portals=new Map;this.portalRaf=0;this.mainGroupCollapsed=!1;this._beforeTabClose=null;this.container=opts.container,this.splitEdgeSize=opts.splitEdgeSize??100,this.layout=new SplitLayout(this.container),opts.onPanelRemoved&&this.onPanelRemovedCbs.push(opts.onPanelRemoved),this.onGroupCreatedByDragCb=opts.onGroupCreatedByDrag??null,this.dropOverlay=document.createElement("div"),this.dropOverlay.className="mb-drop-overlay",this.container.appendChild(this.dropOverlay),this.portalLayer=document.createElement("div"),this.portalLayer.className="mb-iframe-portal-layer",this.container.appendChild(this.portalLayer),this.syncPortals()}setBeforeTabClose(cb){this._beforeTabClose=cb}addPanel(opts){const panel=new Panel(opts.id,opts.element,opts.title);this.panels.set(opts.id,panel);const groupId=opts.groupId;if(groupId){const group=this.groups.get(groupId);group&&(group.addPanel(panel),this.registerPortal(panel.id,panel.element,panel.wrapper))}return panel}removePanel(panelId){const panel=this.panels.get(panelId);if(panel){if(this.unregisterPortal(panelId),panel.group){const group=panel.group;group.removePanel(panelId),group.size===0&&group.id!==this.mainGroupId&&this.removeGroup(group.id)}this.panels.delete(panelId);for(const cb of this.onPanelRemovedCbs)cb(panel)}}getPanel(panelId){return this.panels.get(panelId)}addGroup(opts){const group=new PanelGroup(opts?.id);if(this.groups.set(group.id,group),this.wireGroupCallbacks(group),opts?.floating)this.addFloatingGroup(group,opts.floating);else if(opts?.direction){const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;mainGroup&&this.layout.splitGroup(mainGroup,group,opts.direction,opts.initialSize)}return group}removeGroup(groupId){const group=this.groups.get(groupId);if(!group)return;for(const panel of[...group.panels])this.unregisterPortal(panel.id);const overlay=this.floatingOverlays.get(groupId);if(overlay)if(overlay.internalLayout){overlay.internalLayout.removeGroup(group),this.floatingOverlays.delete(groupId);const remaining=this.cleanupOrphanedFloatingLeaf(overlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,overlay):overlay.dispose()}else overlay.dispose(),this.floatingOverlays.delete(groupId);if(!overlay){const parentOverlay=this.findOverlayForGroup(group);parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay))}this.layout.findGroupNode(group)&&this.layout.removeGroup(group),group.isInFloatingSplit=!1,group.dispose(),this.groups.delete(groupId)}getGroup(groupId){return this.groups.get(groupId)}getMainGroup(){if(this.mainGroupId)return this.groups.get(this.mainGroupId)}setMainGroup(group){this.mainGroupId=group.id,this.layout.setMainGroup(group)}collapseMainGroup(){const main=this.getMainGroup();!main||this.mainGroupCollapsed||(this.layout.collapseLeaf(main),this.mainGroupCollapsed=!0)}expandMainGroup(){const main=this.getMainGroup();!main||!this.mainGroupCollapsed||(this.layout.expandLeaf(main),this.mainGroupCollapsed=!1)}isMainGroupCollapsed(){return this.mainGroupCollapsed}getDockedGroups(){return this.layout.allGroups()}collapseDockedGroup(group){this.layout.collapseLeaf(group)}expandDockedGroup(group){this.layout.expandLeaf(group)}maximizeDockedGroup(group){this.layout.maximizeLeaf(group)}restoreMaximizedDockedGroup(group){this.layout.restoreMaximizedLeaf(group)}restoreLayoutFlex(serialized){this.layout.restoreFlexFromSerialized(serialized)}addFloatingGroup(group,opts){const existingOverlay=this.floatingOverlays.get(group.id);existingOverlay&&this.floatingOverlays.delete(group.id);const parentOverlay=existingOverlay?null:this.findOverlayForGroup(group),overlay=new FloatingOverlay(group,opts,this.container,this.portalLayer);if(this.floatingOverlays.set(group.id,overlay),this.layout.findGroupNode(group)&&this.layout.removeGroup(group),existingOverlay?.internalLayout){existingOverlay.internalLayout.removeGroup(group);const remaining=this.cleanupOrphanedFloatingLeaf(existingOverlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,existingOverlay):existingOverlay.dispose()}else existingOverlay?existingOverlay.dispose():parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay));return group.isInFloatingSplit=!1,group.location="floating",overlay.updateTotalTabCount(),overlay}dockGroup(groupId,position,initialSize){const group=this.groups.get(groupId);if(!group||groupId===this.mainGroupId)return;const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;if(!mainGroup)return;const directOverlay=this.floatingOverlays.get(groupId),parentOverlay=directOverlay?null:this.findOverlayForGroup(group);if(this.layout.splitGroup(mainGroup,group,position,initialSize)){if(directOverlay)if(directOverlay.internalLayout){directOverlay.internalLayout.removeGroup(group),this.floatingOverlays.delete(groupId);const remaining=this.cleanupOrphanedFloatingLeaf(directOverlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,directOverlay):directOverlay.dispose()}else directOverlay.dispose(),this.floatingOverlays.delete(groupId);else parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay));group.location="grid",group.isInFloatingSplit=!1}}getFloatingOverlay(groupId){return this.floatingOverlays.get(groupId)}dockOverlay(groupId){const overlay=this.floatingOverlays.get(groupId);if(!overlay)return;const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;if(!mainGroup)return;if(!overlay.internalLayout){this.dockGroup(groupId,"right");return}const allGroups=overlay.internalLayout.allGroups();if(allGroups.length===0)return;const first=allGroups[0];this.layout.splitGroup(mainGroup,first,"right"),first.location="grid",first.isInFloatingSplit=!1;for(let i=1;i<allGroups.length;i++){const g=allGroups[i];this.layout.splitGroup(first,g,"bottom"),g.location="grid",g.isInFloatingSplit=!1}overlay.internalLayout.dispose(),overlay.internalLayout=null,overlay.dispose(),this.floatingOverlays.delete(groupId)}findOverlayContaining(groupId){const group=this.groups.get(groupId);if(group)return this.findOverlayForGroup(group)??void 0}movePanel(panelId,targetGroupId){const panel=this.panels.get(panelId);if(!panel)return;const sourceGroup=panel.group;if(!sourceGroup||sourceGroup.id===targetGroupId)return;const targetGroup=this.groups.get(targetGroupId);targetGroup&&(sourceGroup.detachPanel(panelId),targetGroup.addPanel(panel),sourceGroup.size===0&&sourceGroup.id!==this.mainGroupId&&this.removeGroup(sourceGroup.id))}serializeLayout(){const floatingGroups=[];for(const[groupId,overlay]of this.floatingOverlays){const entry={groupId,bounds:overlay.getBounds(),internalLayout:overlay.internalLayout?.toJSON()??null};overlay.isMaximized&&(entry.isMaximized=!0),floatingGroups.push(entry)}const panelLocations={};for(const[panelId,panel]of this.panels)panel.group&&(panelLocations[panelId]=panel.group.id);return{mainLayout:this.layout.toJSON(),floatingGroups,panelLocations}}getFloatingOverlays(){return this.floatingOverlays}onDidRemovePanel(cb){return this.onPanelRemovedCbs.push(cb),{dispose:()=>{const idx=this.onPanelRemovedCbs.indexOf(cb);idx!==-1&&this.onPanelRemovedCbs.splice(idx,1)}}}dispose(){if(!this.disposed){this.disposed=!0,this.cancelTabDrag(),cancelAnimationFrame(this.portalRaf);for(const overlay of this.floatingOverlays.values())overlay.dispose();this.floatingOverlays.clear();for(const group of this.groups.values())group.dispose();this.groups.clear(),this.panels.clear(),this.onPanelRemovedCbs=[],this.dropOverlay.remove();for(const portal of this.portals.values())portal.entry.remove();this.portals.clear(),this.portalLayer.remove(),this.layout.dispose()}}wireGroupCallbacks(group){group.onTabClose(panelId=>{if(this._beforeTabClose){const result=this._beforeTabClose(panelId);result&&typeof result.then=="function"?result.then(allowed=>{allowed&&this.removePanel(panelId)}):result!==!1&&this.removePanel(panelId);return}this.removePanel(panelId)}),group.onTabPointerDown((panelId,e)=>{this.onTabPointerDown(panelId,group,e)}),group.onTabPopOut(panelId=>{this.detachPanelToFloating(panelId,window.innerWidth/2,window.innerHeight/2)})}onTabPointerDown(panelId,sourceGroup,e){if(this.dragState)return;this.dragState={panelId,sourceGroup,startX:e.clientX,startY:e.clientY,isDragging:!1,ghost:null,iframes:null,currentZone:null};const onMove=ev=>{if(!this.dragState)return;if(!this.dragState.isDragging){const dx=ev.clientX-this.dragState.startX,dy=ev.clientY-this.dragState.startY;if(dx*dx+dy*dy<25)return;this.dragState.isDragging=!0,this.dragState.iframes=disableIframePointEvents(),this.dragState.ghost=this.createDragGhost(panelId),this.container.appendChild(this.dragState.ghost)}this.dragState.ghost.style.left=`${ev.clientX+8}px`,this.dragState.ghost.style.top=`${ev.clientY+8}px`;let zone=this.hitTestDropZone(ev.clientX,ev.clientY);zone=this.applyDragConstraints(zone,this.dragState.sourceGroup),this.updateDropOverlay(zone)},onUp=ev=>{if(document.removeEventListener("pointermove",onMove),document.removeEventListener("pointerup",onUp),document.removeEventListener("pointercancel",onCancel),!this.dragState)return;if(!this.dragState.isDragging){sourceGroup.activatePanel(panelId),this.dragState=null;return}this.dragState.ghost?.remove(),this.dragState.iframes?.release(),this.updateDropOverlay(null);const zone=this.applyDragConstraints(this.hitTestDropZone(ev.clientX,ev.clientY),sourceGroup);if(zone)switch(zone.kind){case"header":case"content-center":zone.group.id===sourceGroup.id?sourceGroup.reorderPanel(panelId,ev.clientX):this.movePanel(panelId,zone.group.id);break;case"content-split":this.dockTabFromDrag(panelId,zone.direction,zone.group);break}this.dragState=null},onCancel=()=>{document.removeEventListener("pointermove",onMove),document.removeEventListener("pointerup",onUp),document.removeEventListener("pointercancel",onCancel),this.cancelTabDrag()};document.addEventListener("pointermove",onMove),document.addEventListener("pointerup",onUp),document.addEventListener("pointercancel",onCancel)}cancelTabDrag(){this.dragState&&(this.dragState.ghost?.remove(),this.dragState.iframes?.release(),this.updateDropOverlay(null),this.dragState=null)}createDragGhost(panelId){const panel=this.panels.get(panelId),ghost=document.createElement("div");return ghost.className="mb-drag-ghost",ghost.innerHTML=SVG_WINDOW,ghost.title=panel?.title||panelId,ghost}hitTestDropZone(x,y,skipGroupId){const floatingEntries=[...this.floatingOverlays.entries()].filter(([,overlay])=>overlay.element.style.display!=="none").sort((a,b)=>{const zA=parseInt(a[1].element.style.zIndex||"0");return parseInt(b[1].element.style.zIndex||"0")-zA});for(const[,overlay]of floatingEntries){const overlayGroups=overlay.internalLayout?overlay.internalLayout.allGroups():[overlay.group];for(const group of overlayGroups){if(group.id===skipGroupId||group.locked==="no-drop-target")continue;if(!group.headerHidden){const hr=group.headerElement.getBoundingClientRect();if(x>=hr.left&&x<=hr.right&&y>=hr.top&&y<=hr.bottom)return{kind:"header",group}}const cr=group.contentElement.getBoundingClientRect();if(x>=cr.left&&x<=cr.right&&y>=cr.top&&y<=cr.bottom)return this.classifyContentZone(x,y,cr,group)}}for(const group of this.groups.values()){if(this.floatingOverlays.has(group.id)||this.findOverlayForGroup(group)||group.id===skipGroupId)continue;if(!group.headerHidden){const hr=group.headerElement.getBoundingClientRect();if(x>=hr.left&&x<=hr.right&&y>=hr.top&&y<=hr.bottom&&group.locked!=="no-drop-target")return{kind:"header",group}}const cr=group.contentElement.getBoundingClientRect();if(x>=cr.left&&x<=cr.right&&y>=cr.top&&y<=cr.bottom)return this.classifyContentZone(x,y,cr,group)}return null}classifyContentZone(x,y,rect,group){if(group.locked==="no-drop-target"){const dT2=y-rect.top,dB2=rect.bottom-y,dL2=x-rect.left,dR2=rect.right-x;let direction;return dT2<=dB2&&dT2<=dL2&&dT2<=dR2?direction="top":dB2<=dT2&&dB2<=dL2&&dB2<=dR2?direction="bottom":dL2<=dR2?direction="left":direction="right",{kind:"content-split",group,direction}}const edgeSize=this.splitEdgeSize,dT=y-rect.top,dB=rect.bottom-y,dL=x-rect.left,dR=rect.right-x;if(Math.min(dT,dB,dL,dR)<edgeSize){let direction;return dT<=dB&&dT<=dL&&dT<=dR?direction="top":dB<=dT&&dB<=dL&&dB<=dR?direction="bottom":dL<=dR?direction="left":direction="right",{kind:"content-split",group,direction}}return{kind:"content-center",group}}applyDragConstraints(zone,sourceGroup){if(!zone)return null;if(!("group"in zone))return zone;const targetInOverlay=this.findOverlayForGroup(zone.group)!==null,targetIsLocked=!!zone.group.locked;return(zone.kind==="content-center"||zone.kind==="header")&&targetIsLocked||sourceGroup.dockingBlocked&&!targetInOverlay?null:zone.kind==="content-split"&&targetInOverlay&&sourceGroup.dialogDockingBlocked?{kind:"content-center",group:zone.group}:zone}updateDropOverlay(zone){const prev=this.dragState?.currentZone??null;if(prev&&prev.kind==="header"&&prev.group.headerElement.classList.remove("mb-group-header--drop-target"),this.dropOverlay.style.display="none",zone===null){this.dragState&&(this.dragState.currentZone=null);return}switch(zone.kind){case"header":zone.group.headerElement.classList.add("mb-group-header--drop-target");break;case"content-center":{const rect=zone.group.contentElement.getBoundingClientRect();this.positionDropOverlay(rect.left,rect.top,rect.width,rect.height),this.dropOverlay.dataset.zone="center";break}case"content-split":this.showSplitIndicator(zone.group,zone.direction);break}this.dragState&&(this.dragState.currentZone=zone)}showSplitIndicator(group,direction){const rect=group.contentElement.getBoundingClientRect();switch(direction){case"top":this.positionDropOverlay(rect.left,rect.top,rect.width,rect.height/2);break;case"bottom":this.positionDropOverlay(rect.left,rect.top+rect.height/2,rect.width,rect.height/2);break;case"left":this.positionDropOverlay(rect.left,rect.top,rect.width/2,rect.height);break;case"right":this.positionDropOverlay(rect.left+rect.width/2,rect.top,rect.width/2,rect.height);break}this.dropOverlay.dataset.zone=direction}positionDropOverlay(left,top,width,height){const el=this.dropOverlay;el.style.display="block",el.style.left=`${left}px`,el.style.top=`${top}px`,el.style.width=`${width}px`,el.style.height=`${height}px`}detachPanelToFloating(panelId,_x,_y){const panel=this.panels.get(panelId);if(!panel||!panel.group||panel.group.id===this.mainGroupId)return;const fw=Math.min(600,window.innerWidth*.8),fh=Math.min(450,window.innerHeight*.7),newGroup=this.addGroup({floating:{x:(window.innerWidth-fw)/2,y:(window.innerHeight-fh)/2,width:fw,height:fh}});this.movePanel(panelId,newGroup.id),this.onGroupCreatedByDragCb?.(newGroup)}dockTabFromDrag(panelId,direction,targetGroup){const layoutForGroup=this.getLayoutForGroup(targetGroup);if(!layoutForGroup)return;const newGroup=new PanelGroup;if(this.groups.set(newGroup.id,newGroup),this.wireGroupCallbacks(newGroup),!layoutForGroup.splitGroup(targetGroup,newGroup,direction)){this.groups.delete(newGroup.id),newGroup.dispose(),this.movePanel(panelId,targetGroup.id);return}const overlayForTarget=this.findOverlayForGroup(targetGroup);overlayForTarget?.internalLayout&&(overlayForTarget.setDragGroup(newGroup),newGroup.location="floating",this.updateFloatingSplitState(overlayForTarget)),this.movePanel(panelId,newGroup.id),overlayForTarget&&overlayForTarget.updateTotalTabCount(),this.onGroupCreatedByDragCb?.(newGroup)}getLayoutForGroup(group){if(this.layout.findGroupNode(group))return this.layout;const overlay=this.findOverlayForGroup(group);return overlay?(overlay.internalLayout||(overlay.internalLayout=new SplitLayout(overlay.element),overlay.internalLayout.setMainGroup(overlay.group)),overlay.internalLayout):null}escapeGroupFromSplit(groupId){const group=this.groups.get(groupId);if(!group||!group.isInFloatingSplit)return;const overlay=this.findOverlayForGroup(group);if(!overlay?.internalLayout)return;const rect=overlay.element.getBoundingClientRect(),wasOwner=this.floatingOverlays.get(groupId)===overlay,newOverlay=new FloatingOverlay(group,{x:Math.min(rect.left+30,window.innerWidth-320),y:Math.min(rect.top+30,window.innerHeight-220),width:Math.max(300,rect.width*.6),height:Math.max(200,rect.height*.8)},this.container,this.portalLayer);this.floatingOverlays.set(groupId,newOverlay),overlay.internalLayout.removeGroup(group);const remaining=this.cleanupOrphanedFloatingLeaf(overlay);wasOwner&&remaining.length>0?this.floatingOverlays.set(remaining[0].id,overlay):remaining.length===0&&overlay.dispose(),group.isInFloatingSplit=!1,group.location==="floating"?group.fireLocationChanged():group.location="floating"}updateFloatingSplitState(overlay){if(!overlay.internalLayout)return;const groups=overlay.internalLayout.allGroups(),isInSplit=groups.length>1;for(const g of groups)g.location="floating",g.isInFloatingSplit=isInSplit;overlay.repositionToolbar()}cleanupOrphanedFloatingLeaf(overlay){if(!overlay.internalLayout)return[];const remaining=overlay.internalLayout.allGroups();return remaining.length<=1?(remaining.length===1&&(overlay.element.appendChild(remaining[0].element),remaining[0].isInFloatingSplit=!1),overlay.internalLayout.dispose(),overlay.internalLayout=null,remaining.length===1&&(overlay.setDragGroup(remaining[0]),remaining[0].location="floating",overlay.repositionToolbar())):this.updateFloatingSplitState(overlay),overlay.updateTotalTabCount(),remaining}minimizeDocked(group){const pos=this.layout.getGroupPosition(group);return this.layout.findGroupNode(group)&&this.layout.removeGroup(group),pos?{siblingGroupId:pos.siblingGroup.id,direction:pos.direction}:null}restoreDocked(group,position,initialSize,siblingGroupId){if(siblingGroupId){const sibling=this.groups.get(siblingGroupId);if(sibling&&this.layout.findGroupNode(sibling)&&this.layout.splitGroup(sibling,group,position,initialSize))return}const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;mainGroup&&this.layout.splitGroup(mainGroup,group,position,initialSize)}findOverlayForGroup(group){const direct=this.floatingOverlays.get(group.id);if(direct)return direct;for(const overlay of this.floatingOverlays.values())if(overlay.internalLayout?.findGroupNode(group))return overlay;return null}registerPortal(panelId,element,anchor){const entry=document.createElement("div");entry.className="mb-iframe-portal",entry.dataset.portalId=panelId,this.portalLayer.appendChild(entry),entry.appendChild(element),this.portals.set(panelId,{entry,anchor})}unregisterPortal(panelId){const portal=this.portals.get(panelId);portal&&(portal.entry.remove(),this.portals.delete(panelId))}syncPortals(){if(this.disposed)return;const updates=[];for(const[,portal]of this.portals){const{entry,anchor}=portal;if(anchor.offsetParent===null)updates.push({entry,rect:null,zIndex:"0"});else{const overlay=anchor.closest(".mb-floating-overlay"),overlayZ=overlay?.style.zIndex;updates.push({entry,rect:anchor.getBoundingClientRect(),zIndex:overlay?String(parseInt(overlayZ||"100000",10)+1):"50"})}}for(const{entry,rect,zIndex}of updates)rect?(entry.style.display="",entry.style.left=`${rect.left}px`,entry.style.top=`${rect.top}px`,entry.style.width=`${rect.width}px`,entry.style.height=`${rect.height}px`,entry.style.zIndex=zIndex):entry.style.display="none";this.portalRaf=requestAnimationFrame(()=>this.syncPortals())}}export{FloatingOverlay,Panel,PanelGroup,PanelManager,SplitLayout};
1
+ import{SVG_POPOUT,SVG_WINDOW}from"./panel-setup.js";let iframeDragDepth=0;function disableIframePointEvents(){return iframeDragDepth++,document.documentElement.classList.add("mb-dragging"),{release(){--iframeDragDepth<=0&&(iframeDragDepth=0,document.documentElement.classList.remove("mb-dragging"))}}}class Panel{constructor(id,element,title){this.group=null;this.id=id,this.element=element,this.title=title||id,this.wrapper=document.createElement("div"),this.wrapper.className="mb-panel",this.wrapper.dataset.panelId=id,this.wrapper.dataset.active="false",this.wrapper.appendChild(element)}}let groupIdCounter=0;class PanelGroup{constructor(id){this._panels=[];this._activePanel=null;this._headerHidden=!1;this._locked=!1;this._onTabClose=null;this._onTabPointerDown=null;this._onTabPopOut=null;this._location="grid";this._onLocationChangedCb=null;this._isInFloatingSplit=!1;this._onSplitStateChangedCb=null;this._dragConstraint="any";this._dockingBlocked=!1;this._dialogDockingBlocked=!1;this._onPanelCountChangedCb=null;this._onActivePanelChangedCb=null;this.id=id||`group-${++groupIdCounter}`,this.element=document.createElement("div"),this.element.className="mb-group",this.element.dataset.groupId=this.id,this.headerElement=document.createElement("div"),this.headerElement.className="mb-group-header",this.headerPrefix=document.createElement("div"),this.headerPrefix.className="mb-group-header-prefix",this.tabsElement=document.createElement("div"),this.tabsElement.className="mb-group-tabs",this.headerVoid=document.createElement("div"),this.headerVoid.className="mb-group-header-void",this.headerActions=document.createElement("div"),this.headerActions.className="mb-group-header-actions",this.headerElement.appendChild(this.headerPrefix),this.headerElement.appendChild(this.tabsElement),this.headerElement.appendChild(this.headerVoid),this.headerElement.appendChild(this.headerActions),this.contentElement=document.createElement("div"),this.contentElement.className="mb-group-content",this.element.appendChild(this.headerElement),this.element.appendChild(this.contentElement)}get panels(){return this._panels}get activePanel(){return this._activePanel}get size(){return this._panels.length}get locked(){return this._locked}set locked(value){this._locked=value}setHeaderHidden(hidden){this._headerHidden=hidden,this.headerElement.style.display=hidden?"none":""}get headerHidden(){return this._headerHidden}setHeaderActions(element){this.headerActions.innerHTML="",this.headerActions.appendChild(element)}setHeaderPrefix(element){this.headerPrefix.innerHTML="",this.headerPrefix.appendChild(element)}onTabClose(cb){this._onTabClose=cb}onTabPointerDown(cb){this._onTabPointerDown=cb}get location(){return this._location}set location(value){this._location!==value&&(this._location=value,this._onLocationChangedCb?.(value))}onLocationChanged(cb){this._onLocationChangedCb=cb}fireLocationChanged(){this._onLocationChangedCb?.(this._location)}get isInFloatingSplit(){return this._isInFloatingSplit}set isInFloatingSplit(value){this._isInFloatingSplit!==value&&(this._isInFloatingSplit=value,this._onSplitStateChangedCb?.(value))}onSplitStateChanged(cb){this._onSplitStateChangedCb=cb}onTabPopOut(cb){this._onTabPopOut=cb}get dragConstraint(){return this._dragConstraint}set dragConstraint(v){this._dragConstraint=v}get dockingBlocked(){return this._dockingBlocked}set dockingBlocked(v){this._dockingBlocked=v}get dialogDockingBlocked(){return this._dialogDockingBlocked}set dialogDockingBlocked(v){this._dialogDockingBlocked=v}onPanelCountChanged(cb){this._onPanelCountChangedCb=cb}onActivePanelChanged(cb){this._onActivePanelChangedCb=cb}addPanel(panel){if(this._panels.some(p=>p.id===panel.id))return;panel.group=this,this._panels.push(panel),this.contentElement.appendChild(panel.wrapper);const tab=this.createTab(panel);this.tabsElement.appendChild(tab),this.activatePanel(panel.id),this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length)}removePanel(panelId){const idx=this._panels.findIndex(p=>p.id===panelId);if(idx===-1)return null;const panel=this._panels[idx];if(this._panels.splice(idx,1),panel.wrapper.remove(),this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`)?.remove(),panel.group=null,this._activePanel===panel&&(this._activePanel=null,this._panels.length>0)){const newActive=this._panels[Math.min(idx,this._panels.length-1)];newActive&&this.activatePanel(newActive.id)}return this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length),panel}detachPanel(panelId){const idx=this._panels.findIndex(p=>p.id===panelId);if(idx===-1)return null;const panel=this._panels[idx];if(this._panels.splice(idx,1),this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`)?.remove(),panel.group=null,this._activePanel===panel&&(this._activePanel=null,this._panels.length>0)){const newActive=this._panels[Math.min(idx,this._panels.length-1)];newActive&&this.activatePanel(newActive.id)}return this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length),panel}activatePanel(panelId){const panel=this._panels.find(p=>p.id===panelId);if(!panel)return;this._activePanel=panel;for(const p of this._panels)p.wrapper.dataset.active=p===panel?"true":"false";const tabs=this.tabsElement.querySelectorAll(".mb-tab");for(const tab of tabs){const isActive=tab.dataset.tabId===panelId;tab.dataset.active=isActive?"true":"false"}this._onActivePanelChangedCb?.(panelId)}reorderPanel(panelId,dropX){const panelIdx=this._panels.findIndex(p=>p.id===panelId);if(panelIdx===-1)return;const panel=this._panels[panelIdx],tabs=Array.from(this.tabsElement.querySelectorAll(".mb-tab"));let targetIdx=this._panels.length;for(let i=0;i<tabs.length;i++){const rect=tabs[i].getBoundingClientRect();if(dropX<rect.left+rect.width/2){targetIdx=i;break}}if(targetIdx===panelIdx||targetIdx===panelIdx+1)return;this._panels.splice(panelIdx,1);const insertAt=panelIdx<targetIdx?targetIdx-1:targetIdx;this._panels.splice(insertAt,0,panel);const tabEl=this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`);if(tabEl){const refTab=this.tabsElement.querySelectorAll(".mb-tab")[insertAt];refTab&&refTab!==tabEl?this.tabsElement.insertBefore(tabEl,refTab):this.tabsElement.appendChild(tabEl)}}createTab(panel){const tab=document.createElement("div");tab.className="mb-tab",tab.dataset.tabId=panel.id,tab.dataset.active="false";const label=document.createElement("span");label.className="mb-tab-label",label.innerHTML=SVG_WINDOW,label.title=panel.title,tab.appendChild(label);const actions=document.createElement("div");actions.className="mb-tab-actions";const popOutBtn=document.createElement("button");popOutBtn.className="mb-tab-popout",popOutBtn.title="Pop out",popOutBtn.innerHTML=SVG_POPOUT,popOutBtn.addEventListener("click",e=>{e.stopPropagation(),this._onTabPopOut?.(panel.id)}),actions.appendChild(popOutBtn);const closeBtn=document.createElement("button");return closeBtn.className="mb-tab-close",closeBtn.title="Close",closeBtn.innerHTML='<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><line x1="4" y1="4" x2="12" y2="12"/><line x1="12" y1="4" x2="4" y2="12"/></svg>',closeBtn.addEventListener("click",e=>{e.stopPropagation(),this._onTabClose?.(panel.id)}),actions.appendChild(closeBtn),tab.appendChild(actions),tab.addEventListener("pointerdown",e=>{e.target.closest(".mb-tab-close")||e.target.closest(".mb-tab-popout")||e.button===0&&(e.preventDefault(),this._onTabPointerDown?.(panel.id,e))}),tab}dispose(){this._panels=[],this._activePanel=null,this.element.remove()}}let zIndexCounter=1e5;class FloatingOverlay{constructor(group,opts,parentElement,insertBefore){this.internalLayout=null;this.toolbarElement=null;this.savedBounds=null;this._isMaximized=!1;this._onDragEnd=null;this._onDragMove=null;this.group=group,this.bounds={...opts},this.element=document.createElement("div"),this.element.className="mb-floating-overlay",this.element.dataset.groupId=group.id,this.applyBounds();const directions=["n","s","e","w","ne","nw","se","sw"];for(const dir of directions){const handle=document.createElement("div");handle.className=`mb-resize-handle mb-resize-${dir}`,handle.addEventListener("pointerdown",e=>this.onResizeStart(e,dir)),this.element.appendChild(handle)}this.element.addEventListener("pointerdown",()=>this.bringToFront(),!0),group.headerVoid.addEventListener("pointerdown",e=>this.onDragStart(e)),group.headerVoid.style.cursor="grab";const parent=parentElement??document.body;insertBefore?parent.insertBefore(this.element,insertBefore):parent.appendChild(this.element),this.element.appendChild(group.element),this.bringToFront()}get isMaximized(){return this._isMaximized}set onDragEnd(cb){this._onDragEnd=cb}set onDragMove(cb){this._onDragMove=cb}bringToFront(){zIndexCounter+=2,this.element.style.zIndex=String(zIndexCounter)}maximize(){this._isMaximized||(this.savedBounds={...this.bounds},this._isMaximized=!0,this.element.style.inset="0",this.element.style.width="auto",this.element.style.height="auto",this.element.classList.add("mb-floating-maximized"))}restore(){!this._isMaximized||!this.savedBounds||(this._isMaximized=!1,this.bounds={...this.savedBounds},this.savedBounds=null,this.element.classList.remove("mb-floating-maximized"),this.element.style.inset="",this.applyBounds())}hide(){this.element.style.display="none"}show(){this.element.style.display=""}dispose(){this.internalLayout&&(this.internalLayout.dispose(),this.internalLayout=null),this.removeToolbar(),this.element.remove()}getBounds(){return{...this.bounds}}setBounds(partial){if(this._isMaximized)return;const pad=10;partial.width!==void 0&&(this.bounds.width=Math.min(partial.width,window.innerWidth-this.bounds.x-pad)),partial.height!==void 0&&(this.bounds.height=Math.min(partial.height,window.innerHeight-this.bounds.y-pad)),this.applyBounds()}setFullBounds(bounds){if(this._isMaximized)return;const vw=window.innerWidth,vh=window.innerHeight,pad=10,minVisible=100;this.bounds={width:Math.max(minVisible,Math.min(bounds.width,vw-pad)),height:Math.max(minVisible,Math.min(bounds.height,vh-pad)),x:Math.max(0,Math.min(bounds.x,vw-minVisible)),y:Math.max(0,Math.min(bounds.y,vh-minVisible))},this.applyBounds()}applyBounds(){this.element.style.position="fixed",this.element.style.left=`${this.bounds.x}px`,this.element.style.top=`${this.bounds.y}px`,this.element.style.width=`${this.bounds.width}px`,this.element.style.height=`${this.bounds.height}px`}setDragGroup(newGroup){newGroup.headerVoid.addEventListener("pointerdown",e=>this.onDragStart(e)),newGroup.headerVoid.style.cursor="grab"}setToolbar(el){this.removeToolbar(),this.toolbarElement=el,this.getToolbarHost().headerActions.appendChild(el)}removeToolbar(){this.toolbarElement&&(this.toolbarElement.remove(),this.toolbarElement=null)}repositionToolbar(){this.toolbarElement&&this.getToolbarHost().headerActions.appendChild(this.toolbarElement)}getToolbarHost(){if(!this.internalLayout)return this.group;const root=this.internalLayout.getRoot();return root?FloatingOverlay.topRightGroup(root):this.group}static topRightGroup(node){return node.kind==="leaf"?node.group:node.direction==="horizontal"?FloatingOverlay.topRightGroup(node.second):FloatingOverlay.topRightGroup(node.first)}get hasToolbar(){return this.toolbarElement!==null}getAllGroups(){return this.internalLayout?.allGroups()??[this.group]}updateTotalTabCount(){const groups=this.getAllGroups();let total=0;for(const g of groups)total+=g.size;this.element.dataset.totalTabCount=String(total)}onDragStart(e){if(this._isMaximized)return;e.preventDefault();const handle=e.currentTarget,startX=e.clientX,startY=e.clientY,origLeft=this.bounds.x,origTop=this.bounds.y,iframes=disableIframePointEvents();handle.style.cursor="grabbing",handle.setPointerCapture(e.pointerId);const onMove=ev=>{const dx=ev.clientX-startX,dy=ev.clientY-startY;this.bounds.x=Math.max(0,Math.min(origLeft+dx,window.innerWidth-this.bounds.width)),this.bounds.y=Math.max(0,Math.min(origTop+dy,window.innerHeight-this.bounds.height)),this.applyBounds(),this._onDragMove?.(this.bounds.x+this.bounds.width/2,this.bounds.y+this.bounds.height/2)},onUp=()=>{iframes.release(),handle.style.cursor="grab",handle.removeEventListener("pointermove",onMove),handle.removeEventListener("pointerup",onUp),handle.removeEventListener("pointercancel",onUp),this._onDragEnd?.(this.bounds.x+this.bounds.width/2,this.bounds.y+this.bounds.height/2)};handle.addEventListener("pointermove",onMove),handle.addEventListener("pointerup",onUp),handle.addEventListener("pointercancel",onUp)}onResizeStart(e,dir){if(this._isMaximized)return;e.preventDefault(),e.stopPropagation();const startX=e.clientX,startY=e.clientY,orig={...this.bounds},handle=e.currentTarget,minW=200,minH=100,iframes=disableIframePointEvents();handle.setPointerCapture(e.pointerId);const onMove=ev=>{const dx=ev.clientX-startX,dy=ev.clientY-startY;if(dir.includes("e")&&(this.bounds.width=Math.max(minW,orig.width+dx)),dir.includes("w")){const newW=Math.max(minW,orig.width-dx);this.bounds.x=orig.x+(orig.width-newW),this.bounds.width=newW}if(dir.includes("s")&&(this.bounds.height=Math.max(minH,orig.height+dy)),dir.includes("n")){const newH=Math.max(minH,orig.height-dy);this.bounds.y=orig.y+(orig.height-newH),this.bounds.height=newH}const pad=10;this.bounds.x=Math.max(0,this.bounds.x),this.bounds.y=Math.max(0,this.bounds.y),this.bounds.x+this.bounds.width>window.innerWidth-pad&&(this.bounds.width=window.innerWidth-this.bounds.x-pad),this.bounds.y+this.bounds.height>window.innerHeight-pad&&(this.bounds.height=window.innerHeight-this.bounds.y-pad),this.applyBounds()},onUp=()=>{iframes.release(),handle.removeEventListener("pointermove",onMove),handle.removeEventListener("pointerup",onUp),handle.removeEventListener("pointercancel",onUp)};handle.addEventListener("pointermove",onMove),handle.addEventListener("pointerup",onUp),handle.addEventListener("pointercancel",onUp)}}class SplitLayout{constructor(container){this.root=null;this.element=document.createElement("div"),this.element.className="mb-layout",container.appendChild(this.element)}getRoot(){return this.root}setMainGroup(group){const leaf=this.createLeaf(group);leaf.element.style.flex="1",this.root=leaf,this.element.appendChild(leaf.element)}splitGroup(targetGroup,newGroup,direction,newGroupSize){const splitDir=this.dockToSplitDirection(direction),leafNode=this.findGroupNode(targetGroup);if(!leafNode)return!1;const newLeafEl=document.createElement("div");newLeafEl.className="mb-split-leaf",newLeafEl.style.flex="1";const splitEl=document.createElement("div");splitEl.className=`mb-split-container ${splitDir==="horizontal"?"mb-split-horizontal":"mb-split-vertical"}`,splitEl.style.flex=leafNode.element.style.flex||"1",splitEl.style.minWidth="0",splitEl.style.minHeight="0";const separator=document.createElement("div"),isVerticalSplit=splitDir==="vertical";separator.className=`mb-layout-separator ${isVerticalSplit?"mb-layout-separator-h":"mb-layout-separator-v"}`;const existingFirst=direction==="right"||direction==="bottom";leafNode.element.parentElement.insertBefore(splitEl,leafNode.element),existingFirst?(splitEl.appendChild(leafNode.element),splitEl.appendChild(separator),splitEl.appendChild(newLeafEl)):(splitEl.appendChild(newLeafEl),splitEl.appendChild(separator),splitEl.appendChild(leafNode.element)),newLeafEl.appendChild(newGroup.element),newGroupSize!==void 0&&newGroupSize>0?existingFirst?(leafNode.element.style.flex="1",newLeafEl.style.flex=`0 0 ${newGroupSize}px`):(newLeafEl.style.flex=`0 0 ${newGroupSize}px`,leafNode.element.style.flex="1"):(leafNode.element.style.flex="1",newLeafEl.style.flex="1");const newLeaf={kind:"leaf",group:newGroup,element:newLeafEl},splitNode={kind:"split",direction:splitDir,first:existingFirst?leafNode:newLeaf,second:existingFirst?newLeaf:leafNode,element:splitEl,separator};return separator.addEventListener("pointerdown",e=>this.onSeparatorDrag(e,splitNode)),this.replaceNodeInTree(leafNode,splitNode),leafNode.element.style.display==="none"&&(separator.style.display="none",newLeafEl.dataset.savedFlex=newLeafEl.style.flex,newLeafEl.style.flex="1",leafNode.element.dataset.savedFlex=leafNode.element.style.flex),!0}removeGroup(group){const leafNode=this.findGroupNode(group);if(!leafNode)return;if(this.root===leafNode){leafNode.element.remove(),this.root=null;return}this.restoreMaximizedLeaf(group);const parentSplit=this.findParentSplit(leafNode);if(!parentSplit)return;const sibling=parentSplit.first===leafNode?parentSplit.second:parentSplit.first;this.restoreMaximizedSubtree(sibling),sibling.element.style.flex=parentSplit.element.style.flex||"1",parentSplit.element.parentElement.insertBefore(sibling.element,parentSplit.element),leafNode.element.remove(),parentSplit.separator.remove(),parentSplit.element.remove(),this.replaceNodeInTree(parentSplit,sibling)}findGroupNode(group){return this.findGroupNodeIn(this.root,group)}getGroupPosition(group){const leaf=this.findGroupNode(group);if(!leaf)return null;const parent=this.findParentSplit(leaf);if(!parent)return null;const isFirst=parent.first===leaf,siblingNode=isFirst?parent.second:parent.first,siblingGroup=this.firstGroupIn(siblingNode);if(!siblingGroup)return null;let direction;return parent.direction==="horizontal"?direction=isFirst?"left":"right":direction=isFirst?"top":"bottom",{siblingGroup,direction}}firstGroupIn(node){return node.kind==="leaf"?node.group:this.firstGroupIn(node.first)}collapseLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;const parent=this.findParentSplit(leaf);if(parent){const sibling=parent.first===leaf?parent.second:parent.first;sibling.element.dataset.savedFlex=sibling.element.style.flex,sibling.element.style.flex="1",parent.separator.style.display="none"}leaf.element.dataset.savedFlex=leaf.element.style.flex,leaf.element.style.display="none"}expandLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;leaf.element.style.display="",leaf.element.dataset.savedFlex!==void 0&&(leaf.element.style.flex=leaf.element.dataset.savedFlex,delete leaf.element.dataset.savedFlex);const parent=this.findParentSplit(leaf);if(parent){parent.separator.style.display="";const sibling=parent.first===leaf?parent.second:parent.first;sibling.element.dataset.savedFlex!==void 0&&(sibling.element.style.flex=sibling.element.dataset.savedFlex,delete sibling.element.dataset.savedFlex)}}maximizeLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;let current=leaf,parent=this.findParentSplit(current);for(;parent;){const sibling=parent.first===current?parent.second:parent.first;sibling.element.dataset.maxSavedDisplay===void 0&&(sibling.element.dataset.maxSavedDisplay=sibling.element.style.display),sibling.element.style.display="none",parent.separator.dataset.maxSavedDisplay===void 0&&(parent.separator.dataset.maxSavedDisplay=parent.separator.style.display),parent.separator.style.display="none",current.element.dataset.maxSavedFlex===void 0&&(current.element.dataset.maxSavedFlex=current.element.style.flex),current.element.style.flex="1",current=parent,parent=this.findParentSplit(current)}}restoreMaximizedLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;let current=leaf,parent=this.findParentSplit(current);for(;parent;){const sibling=parent.first===current?parent.second:parent.first;sibling.element.dataset.maxSavedDisplay!==void 0&&(sibling.element.style.display=sibling.element.dataset.maxSavedDisplay,delete sibling.element.dataset.maxSavedDisplay),parent.separator.dataset.maxSavedDisplay!==void 0&&(parent.separator.style.display=parent.separator.dataset.maxSavedDisplay,delete parent.separator.dataset.maxSavedDisplay),current.element.dataset.maxSavedFlex!==void 0&&(current.element.style.flex=current.element.dataset.maxSavedFlex,delete current.element.dataset.maxSavedFlex),current=parent,parent=this.findParentSplit(current)}}restoreMaximizedSubtree(node){node.element.dataset.maxSavedDisplay!==void 0&&(node.element.style.display=node.element.dataset.maxSavedDisplay,delete node.element.dataset.maxSavedDisplay),node.element.dataset.maxSavedFlex!==void 0&&(node.element.style.flex=node.element.dataset.maxSavedFlex,delete node.element.dataset.maxSavedFlex),node.kind==="split"&&(node.separator.dataset.maxSavedDisplay!==void 0&&(node.separator.style.display=node.separator.dataset.maxSavedDisplay,delete node.separator.dataset.maxSavedDisplay),this.restoreMaximizedSubtree(node.first),this.restoreMaximizedSubtree(node.second))}allGroups(){const result=[];return this.collectGroups(this.root,result),result}toJSON(){return this.serializeNode(this.root)}restoreFlexFromSerialized(serialized){if(!serialized||!this.root)return;const flexMap=new Map;this.collectFlexValues(serialized,flexMap),this.applyFlexValues(this.root,flexMap)}animateTransition(){const cls=node=>{node&&(node.kind==="leaf"?node.element.classList.add("mb-split-leaf--animating"):(node.element.classList.add("mb-split-container--animating"),node.separator&&node.separator.classList.add("mb-layout-separator--animating"),cls(node.first),cls(node.second)))};cls(this.root);const cleanup=()=>{this.element.querySelectorAll(".mb-split-leaf--animating, .mb-split-container--animating, .mb-layout-separator--animating").forEach(el=>{el.classList.remove("mb-split-leaf--animating","mb-split-container--animating","mb-layout-separator--animating")})},timer=setTimeout(cleanup,350);this.element.addEventListener("transitionend",()=>{clearTimeout(timer),cleanup()},{once:!0})}dispose(){this.element.remove(),this.root=null}createLeaf(group){const leafEl=document.createElement("div");return leafEl.className="mb-split-leaf",leafEl.style.flex="1",leafEl.appendChild(group.element),{kind:"leaf",group,element:leafEl}}dockToSplitDirection(pos){return pos==="left"||pos==="right"?"horizontal":"vertical"}findGroupNodeIn(node,group){return node?node.kind==="leaf"?node.group===group?node:null:this.findGroupNodeIn(node.first,group)??this.findGroupNodeIn(node.second,group):null}collectGroups(node,result){node&&(node.kind==="leaf"?result.push(node.group):(this.collectGroups(node.first,result),this.collectGroups(node.second,result)))}findParentSplit(target){return this.findParentSplitIn(this.root,target)}findParentSplitIn(node,target){return!node||node.kind==="leaf"?null:node.first===target||node.second===target?node:this.findParentSplitIn(node.first,target)??this.findParentSplitIn(node.second,target)}replaceNodeInTree(oldNode,newNode){if(this.root===oldNode){this.root=newNode;return}const parent=this.findParentSplit(oldNode);parent&&(parent.first===oldNode?parent.first=newNode:parent.second=newNode)}collectFlexValues(node,map){node.kind==="leaf"?map.set(node.groupId,node.flex):(this.collectFlexValues(node.first,map),this.collectFlexValues(node.second,map))}applyFlexValues(node,map){if(node.kind==="leaf"){const saved=map.get(node.group.id);saved&&this.isValidFlex(saved)&&(node.element.style.flex=saved)}else this.applyFlexValues(node.first,map),this.applyFlexValues(node.second,map)}isValidFlex(value){if(value.includes("px"))return!0;const n=Number(value);return Number.isFinite(n)&&n>=0}serializeNode(node){return node?node.kind==="leaf"?{kind:"leaf",groupId:node.group.id,flex:node.element.style.flex||"1"}:{kind:"split",direction:node.direction,first:this.serializeNode(node.first),second:this.serializeNode(node.second),flex:node.element.style.flex||"1"}:null}onSeparatorDrag(e,splitNode){if(e.preventDefault(),splitNode.first.element.style.display==="none"||splitNode.second.element.style.display==="none")return;const isHorizontal=splitNode.direction==="horizontal",startPos=isHorizontal?e.clientX:e.clientY,firstEl=splitNode.first.element,secondEl=splitNode.second.element;this.lockDescendantSizes(splitNode.first,isHorizontal),this.lockDescendantSizes(splitNode.second,isHorizontal);const origFirstSize=isHorizontal?firstEl.offsetWidth:firstEl.offsetHeight,origSecondSize=isHorizontal?secondEl.offsetWidth:secondEl.offsetHeight,totalSize=origFirstSize+origSecondSize;if(totalSize<=0)return;const minSize=150,iframes=disableIframePointEvents();splitNode.separator.setPointerCapture(e.pointerId),splitNode.separator.classList.add("mb-layout-separator--active");const onMove=ev=>{if(firstEl.style.display==="none"||secondEl.style.display==="none"){splitNode.separator.releasePointerCapture(ev.pointerId),onUp();return}const delta=(isHorizontal?ev.clientX:ev.clientY)-startPos;let newFirst=origFirstSize+delta,newSecond=origSecondSize-delta;newFirst<minSize&&(newFirst=minSize,newSecond=totalSize-minSize),newSecond<minSize&&(newSecond=minSize,newFirst=totalSize-minSize),firstEl.style.flex=String(newFirst/totalSize),secondEl.style.flex=String(newSecond/totalSize)},onUp=()=>{iframes.release(),splitNode.separator.classList.remove("mb-layout-separator--active"),splitNode.separator.removeEventListener("pointermove",onMove),splitNode.separator.removeEventListener("pointerup",onUp),splitNode.separator.removeEventListener("pointercancel",onUp),this.unlockDescendantSizes(splitNode.first,isHorizontal),this.unlockDescendantSizes(splitNode.second,isHorizontal)};splitNode.separator.addEventListener("pointermove",onMove),splitNode.separator.addEventListener("pointerup",onUp),splitNode.separator.addEventListener("pointercancel",onUp)}lockDescendantSizes(node,isHorizontal){if(node.kind!=="split"||node.direction==="horizontal"!==isHorizontal)return;const firstSize=isHorizontal?node.first.element.getBoundingClientRect().width:node.first.element.getBoundingClientRect().height;node.first.element.style.flex=`0 0 ${firstSize}px`,node.second.element.style.flex="1",this.lockDescendantSizes(node.first,isHorizontal),this.lockDescendantSizes(node.second,isHorizontal)}unlockDescendantSizes(node,isHorizontal){if(node.kind!=="split"||node.direction==="horizontal"!==isHorizontal)return;this.unlockDescendantSizes(node.first,isHorizontal),this.unlockDescendantSizes(node.second,isHorizontal);const firstSize=isHorizontal?node.first.element.getBoundingClientRect().width:node.first.element.getBoundingClientRect().height,secondSize=isHorizontal?node.second.element.getBoundingClientRect().width:node.second.element.getBoundingClientRect().height,total=firstSize+secondSize;total>0?(node.first.element.style.flex=String(firstSize/total),node.second.element.style.flex=String(secondSize/total)):(node.first.element.style.flex="0.5",node.second.element.style.flex="0.5")}}class PanelManager{constructor(opts){this.groups=new Map;this.panels=new Map;this.floatingOverlays=new Map;this.mainGroupId=null;this.onPanelRemovedCbs=[];this.onGroupCreatedByDragCb=null;this.disposed=!1;this.dragState=null;this.portals=new Map;this.portalRaf=0;this.mainGroupCollapsed=!1;this._beforeTabClose=null;this.zBase=0;this.container=opts.container,this.splitEdgeSize=opts.splitEdgeSize??100,this.layout=new SplitLayout(this.container),opts.onPanelRemoved&&this.onPanelRemovedCbs.push(opts.onPanelRemoved),this.onGroupCreatedByDragCb=opts.onGroupCreatedByDrag??null,this.zBase=this.getZBase(),this.zBase!==0&&(zIndexCounter=1e5+this.zBase),this.dropOverlay=document.createElement("div"),this.dropOverlay.className="mb-drop-overlay",this.container.appendChild(this.dropOverlay),this.portalLayer=document.createElement("div"),this.portalLayer.className="mb-iframe-portal-layer",this.container.appendChild(this.portalLayer),this.syncPortals()}getZBase(){const v=getComputedStyle(this.container).getPropertyValue("--mb-adapt-z-base").trim();return parseInt(v,10)||0}setBeforeTabClose(cb){this._beforeTabClose=cb}addPanel(opts){const panel=new Panel(opts.id,opts.element,opts.title);this.panels.set(opts.id,panel);const groupId=opts.groupId;if(groupId){const group=this.groups.get(groupId);group&&(group.addPanel(panel),this.registerPortal(panel.id,panel.element,panel.wrapper))}return panel}removePanel(panelId){const panel=this.panels.get(panelId);if(panel){if(this.unregisterPortal(panelId),panel.group){const group=panel.group;group.removePanel(panelId),group.size===0&&group.id!==this.mainGroupId&&this.removeGroup(group.id)}this.panels.delete(panelId);for(const cb of this.onPanelRemovedCbs)cb(panel)}}getPanel(panelId){return this.panels.get(panelId)}addGroup(opts){const group=new PanelGroup(opts?.id);if(this.groups.set(group.id,group),this.wireGroupCallbacks(group),opts?.floating)this.addFloatingGroup(group,opts.floating);else if(opts?.direction){const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;mainGroup&&this.layout.splitGroup(mainGroup,group,opts.direction,opts.initialSize)}return group}removeGroup(groupId){const group=this.groups.get(groupId);if(!group)return;for(const panel of[...group.panels])this.unregisterPortal(panel.id);const overlay=this.floatingOverlays.get(groupId);if(overlay)if(overlay.internalLayout){overlay.internalLayout.removeGroup(group),this.floatingOverlays.delete(groupId);const remaining=this.cleanupOrphanedFloatingLeaf(overlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,overlay):overlay.dispose()}else overlay.dispose(),this.floatingOverlays.delete(groupId);if(!overlay){const parentOverlay=this.findOverlayForGroup(group);parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay))}this.layout.findGroupNode(group)&&this.layout.removeGroup(group),group.isInFloatingSplit=!1,group.dispose(),this.groups.delete(groupId)}getGroup(groupId){return this.groups.get(groupId)}getMainGroup(){if(this.mainGroupId)return this.groups.get(this.mainGroupId)}setMainGroup(group){this.mainGroupId=group.id,this.layout.setMainGroup(group)}collapseMainGroup(){const main=this.getMainGroup();!main||this.mainGroupCollapsed||(this.layout.collapseLeaf(main),this.mainGroupCollapsed=!0)}expandMainGroup(){const main=this.getMainGroup();!main||!this.mainGroupCollapsed||(this.layout.expandLeaf(main),this.mainGroupCollapsed=!1)}isMainGroupCollapsed(){return this.mainGroupCollapsed}getDockedGroups(){return this.layout.allGroups()}collapseDockedGroup(group){this.layout.collapseLeaf(group)}expandDockedGroup(group){this.layout.expandLeaf(group)}maximizeDockedGroup(group){this.layout.maximizeLeaf(group)}restoreMaximizedDockedGroup(group){this.layout.restoreMaximizedLeaf(group)}restoreLayoutFlex(serialized){this.layout.restoreFlexFromSerialized(serialized)}addFloatingGroup(group,opts){const existingOverlay=this.floatingOverlays.get(group.id);existingOverlay&&this.floatingOverlays.delete(group.id);const parentOverlay=existingOverlay?null:this.findOverlayForGroup(group),overlay=new FloatingOverlay(group,opts,this.container,this.portalLayer);if(this.floatingOverlays.set(group.id,overlay),this.layout.findGroupNode(group)&&this.layout.removeGroup(group),existingOverlay?.internalLayout){existingOverlay.internalLayout.removeGroup(group);const remaining=this.cleanupOrphanedFloatingLeaf(existingOverlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,existingOverlay):existingOverlay.dispose()}else existingOverlay?existingOverlay.dispose():parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay));return group.isInFloatingSplit=!1,group.location="floating",overlay.updateTotalTabCount(),overlay}dockGroup(groupId,position,initialSize){const group=this.groups.get(groupId);if(!group||groupId===this.mainGroupId)return;const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;if(!mainGroup)return;const directOverlay=this.floatingOverlays.get(groupId),parentOverlay=directOverlay?null:this.findOverlayForGroup(group);if(this.layout.splitGroup(mainGroup,group,position,initialSize)){if(directOverlay)if(directOverlay.internalLayout){directOverlay.internalLayout.removeGroup(group),this.floatingOverlays.delete(groupId);const remaining=this.cleanupOrphanedFloatingLeaf(directOverlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,directOverlay):directOverlay.dispose()}else directOverlay.dispose(),this.floatingOverlays.delete(groupId);else parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay));group.location="grid",group.isInFloatingSplit=!1}}getFloatingOverlay(groupId){return this.floatingOverlays.get(groupId)}dockOverlay(groupId){const overlay=this.floatingOverlays.get(groupId);if(!overlay)return;const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;if(!mainGroup)return;if(!overlay.internalLayout){this.dockGroup(groupId,"right");return}const allGroups=overlay.internalLayout.allGroups();if(allGroups.length===0)return;const first=allGroups[0];this.layout.splitGroup(mainGroup,first,"right"),first.location="grid",first.isInFloatingSplit=!1;for(let i=1;i<allGroups.length;i++){const g=allGroups[i];this.layout.splitGroup(first,g,"bottom"),g.location="grid",g.isInFloatingSplit=!1}overlay.internalLayout.dispose(),overlay.internalLayout=null,overlay.dispose(),this.floatingOverlays.delete(groupId)}findOverlayContaining(groupId){const group=this.groups.get(groupId);if(group)return this.findOverlayForGroup(group)??void 0}movePanel(panelId,targetGroupId){const panel=this.panels.get(panelId);if(!panel)return;const sourceGroup=panel.group;if(!sourceGroup||sourceGroup.id===targetGroupId)return;const targetGroup=this.groups.get(targetGroupId);targetGroup&&(sourceGroup.detachPanel(panelId),targetGroup.addPanel(panel),sourceGroup.size===0&&sourceGroup.id!==this.mainGroupId&&this.removeGroup(sourceGroup.id))}serializeLayout(){const floatingGroups=[];for(const[groupId,overlay]of this.floatingOverlays){const entry={groupId,bounds:overlay.getBounds(),internalLayout:overlay.internalLayout?.toJSON()??null};overlay.isMaximized&&(entry.isMaximized=!0),floatingGroups.push(entry)}const panelLocations={};for(const[panelId,panel]of this.panels)panel.group&&(panelLocations[panelId]=panel.group.id);return{mainLayout:this.layout.toJSON(),floatingGroups,panelLocations}}getFloatingOverlays(){return this.floatingOverlays}onDidRemovePanel(cb){return this.onPanelRemovedCbs.push(cb),{dispose:()=>{const idx=this.onPanelRemovedCbs.indexOf(cb);idx!==-1&&this.onPanelRemovedCbs.splice(idx,1)}}}dispose(){if(!this.disposed){this.disposed=!0,this.cancelTabDrag(),cancelAnimationFrame(this.portalRaf);for(const overlay of this.floatingOverlays.values())overlay.dispose();this.floatingOverlays.clear();for(const group of this.groups.values())group.dispose();this.groups.clear(),this.panels.clear(),this.onPanelRemovedCbs=[],this.dropOverlay.remove();for(const portal of this.portals.values())portal.entry.remove();this.portals.clear(),this.portalLayer.remove(),this.layout.dispose()}}wireGroupCallbacks(group){group.onTabClose(panelId=>{if(this._beforeTabClose){const result=this._beforeTabClose(panelId);result&&typeof result.then=="function"?result.then(allowed=>{allowed&&this.removePanel(panelId)}):result!==!1&&this.removePanel(panelId);return}this.removePanel(panelId)}),group.onTabPointerDown((panelId,e)=>{this.onTabPointerDown(panelId,group,e)}),group.onTabPopOut(panelId=>{this.detachPanelToFloating(panelId,window.innerWidth/2,window.innerHeight/2)})}onTabPointerDown(panelId,sourceGroup,e){if(this.dragState)return;this.dragState={panelId,sourceGroup,startX:e.clientX,startY:e.clientY,isDragging:!1,ghost:null,iframes:null,currentZone:null};const onMove=ev=>{if(!this.dragState)return;if(!this.dragState.isDragging){const dx=ev.clientX-this.dragState.startX,dy=ev.clientY-this.dragState.startY;if(dx*dx+dy*dy<25)return;this.dragState.isDragging=!0,this.dragState.iframes=disableIframePointEvents(),this.dragState.ghost=this.createDragGhost(panelId),this.container.appendChild(this.dragState.ghost)}this.dragState.ghost.style.left=`${ev.clientX+8}px`,this.dragState.ghost.style.top=`${ev.clientY+8}px`;let zone=this.hitTestDropZone(ev.clientX,ev.clientY);zone=this.applyDragConstraints(zone,this.dragState.sourceGroup),this.updateDropOverlay(zone)},onUp=ev=>{if(document.removeEventListener("pointermove",onMove),document.removeEventListener("pointerup",onUp),document.removeEventListener("pointercancel",onCancel),!this.dragState)return;if(!this.dragState.isDragging){sourceGroup.activatePanel(panelId),this.dragState=null;return}this.dragState.ghost?.remove(),this.dragState.iframes?.release(),this.updateDropOverlay(null);const zone=this.applyDragConstraints(this.hitTestDropZone(ev.clientX,ev.clientY),sourceGroup);if(zone)switch(zone.kind){case"header":case"content-center":zone.group.id===sourceGroup.id?sourceGroup.reorderPanel(panelId,ev.clientX):this.movePanel(panelId,zone.group.id);break;case"content-split":this.dockTabFromDrag(panelId,zone.direction,zone.group);break}this.dragState=null},onCancel=()=>{document.removeEventListener("pointermove",onMove),document.removeEventListener("pointerup",onUp),document.removeEventListener("pointercancel",onCancel),this.cancelTabDrag()};document.addEventListener("pointermove",onMove),document.addEventListener("pointerup",onUp),document.addEventListener("pointercancel",onCancel)}cancelTabDrag(){this.dragState&&(this.dragState.ghost?.remove(),this.dragState.iframes?.release(),this.updateDropOverlay(null),this.dragState=null)}createDragGhost(panelId){const panel=this.panels.get(panelId),ghost=document.createElement("div");return ghost.className="mb-drag-ghost",ghost.innerHTML=SVG_WINDOW,ghost.title=panel?.title||panelId,ghost}hitTestDropZone(x,y,skipGroupId){const floatingEntries=[...this.floatingOverlays.entries()].filter(([,overlay])=>overlay.element.style.display!=="none").sort((a,b)=>{const zA=parseInt(a[1].element.style.zIndex||"0");return parseInt(b[1].element.style.zIndex||"0")-zA});for(const[,overlay]of floatingEntries){const overlayGroups=overlay.internalLayout?overlay.internalLayout.allGroups():[overlay.group];for(const group of overlayGroups){if(group.id===skipGroupId||group.locked==="no-drop-target")continue;if(!group.headerHidden){const hr=group.headerElement.getBoundingClientRect();if(x>=hr.left&&x<=hr.right&&y>=hr.top&&y<=hr.bottom)return{kind:"header",group}}const cr=group.contentElement.getBoundingClientRect();if(x>=cr.left&&x<=cr.right&&y>=cr.top&&y<=cr.bottom)return this.classifyContentZone(x,y,cr,group)}}for(const group of this.groups.values()){if(this.floatingOverlays.has(group.id)||this.findOverlayForGroup(group)||group.id===skipGroupId)continue;if(!group.headerHidden){const hr=group.headerElement.getBoundingClientRect();if(x>=hr.left&&x<=hr.right&&y>=hr.top&&y<=hr.bottom&&group.locked!=="no-drop-target")return{kind:"header",group}}const cr=group.contentElement.getBoundingClientRect();if(x>=cr.left&&x<=cr.right&&y>=cr.top&&y<=cr.bottom)return this.classifyContentZone(x,y,cr,group)}return null}classifyContentZone(x,y,rect,group){if(group.locked==="no-drop-target"){const dT2=y-rect.top,dB2=rect.bottom-y,dL2=x-rect.left,dR2=rect.right-x;let direction;return dT2<=dB2&&dT2<=dL2&&dT2<=dR2?direction="top":dB2<=dT2&&dB2<=dL2&&dB2<=dR2?direction="bottom":dL2<=dR2?direction="left":direction="right",{kind:"content-split",group,direction}}const edgeSize=this.splitEdgeSize,dT=y-rect.top,dB=rect.bottom-y,dL=x-rect.left,dR=rect.right-x;if(Math.min(dT,dB,dL,dR)<edgeSize){let direction;return dT<=dB&&dT<=dL&&dT<=dR?direction="top":dB<=dT&&dB<=dL&&dB<=dR?direction="bottom":dL<=dR?direction="left":direction="right",{kind:"content-split",group,direction}}return{kind:"content-center",group}}applyDragConstraints(zone,sourceGroup){if(!zone)return null;if(!("group"in zone))return zone;const targetInOverlay=this.findOverlayForGroup(zone.group)!==null,targetIsLocked=!!zone.group.locked;return(zone.kind==="content-center"||zone.kind==="header")&&targetIsLocked||sourceGroup.dockingBlocked&&!targetInOverlay?null:zone.kind==="content-split"&&targetInOverlay&&sourceGroup.dialogDockingBlocked?{kind:"content-center",group:zone.group}:zone}updateDropOverlay(zone){const prev=this.dragState?.currentZone??null;if(prev&&prev.kind==="header"&&prev.group.headerElement.classList.remove("mb-group-header--drop-target"),this.dropOverlay.style.display="none",zone===null){this.dragState&&(this.dragState.currentZone=null);return}switch(zone.kind){case"header":zone.group.headerElement.classList.add("mb-group-header--drop-target");break;case"content-center":{const rect=zone.group.contentElement.getBoundingClientRect();this.positionDropOverlay(rect.left,rect.top,rect.width,rect.height),this.dropOverlay.dataset.zone="center";break}case"content-split":this.showSplitIndicator(zone.group,zone.direction);break}this.dragState&&(this.dragState.currentZone=zone)}showSplitIndicator(group,direction){const rect=group.contentElement.getBoundingClientRect();switch(direction){case"top":this.positionDropOverlay(rect.left,rect.top,rect.width,rect.height/2);break;case"bottom":this.positionDropOverlay(rect.left,rect.top+rect.height/2,rect.width,rect.height/2);break;case"left":this.positionDropOverlay(rect.left,rect.top,rect.width/2,rect.height);break;case"right":this.positionDropOverlay(rect.left+rect.width/2,rect.top,rect.width/2,rect.height);break}this.dropOverlay.dataset.zone=direction}positionDropOverlay(left,top,width,height){const el=this.dropOverlay;el.style.display="block",el.style.left=`${left}px`,el.style.top=`${top}px`,el.style.width=`${width}px`,el.style.height=`${height}px`}detachPanelToFloating(panelId,_x,_y){const panel=this.panels.get(panelId);if(!panel||!panel.group||panel.group.id===this.mainGroupId)return;const fw=Math.min(600,window.innerWidth*.8),fh=Math.min(450,window.innerHeight*.7),newGroup=this.addGroup({floating:{x:(window.innerWidth-fw)/2,y:(window.innerHeight-fh)/2,width:fw,height:fh}});this.movePanel(panelId,newGroup.id),this.onGroupCreatedByDragCb?.(newGroup)}dockTabFromDrag(panelId,direction,targetGroup){const layoutForGroup=this.getLayoutForGroup(targetGroup);if(!layoutForGroup)return;const newGroup=new PanelGroup;if(this.groups.set(newGroup.id,newGroup),this.wireGroupCallbacks(newGroup),!layoutForGroup.splitGroup(targetGroup,newGroup,direction)){this.groups.delete(newGroup.id),newGroup.dispose(),this.movePanel(panelId,targetGroup.id);return}const overlayForTarget=this.findOverlayForGroup(targetGroup);overlayForTarget?.internalLayout&&(overlayForTarget.setDragGroup(newGroup),newGroup.location="floating",this.updateFloatingSplitState(overlayForTarget)),this.movePanel(panelId,newGroup.id),overlayForTarget&&overlayForTarget.updateTotalTabCount(),this.onGroupCreatedByDragCb?.(newGroup)}getLayoutForGroup(group){if(this.layout.findGroupNode(group))return this.layout;const overlay=this.findOverlayForGroup(group);return overlay?(overlay.internalLayout||(overlay.internalLayout=new SplitLayout(overlay.element),overlay.internalLayout.setMainGroup(overlay.group)),overlay.internalLayout):null}escapeGroupFromSplit(groupId){const group=this.groups.get(groupId);if(!group||!group.isInFloatingSplit)return;const overlay=this.findOverlayForGroup(group);if(!overlay?.internalLayout)return;const rect=overlay.element.getBoundingClientRect(),wasOwner=this.floatingOverlays.get(groupId)===overlay,newOverlay=new FloatingOverlay(group,{x:Math.min(rect.left+30,window.innerWidth-320),y:Math.min(rect.top+30,window.innerHeight-220),width:Math.max(300,rect.width*.6),height:Math.max(200,rect.height*.8)},this.container,this.portalLayer);this.floatingOverlays.set(groupId,newOverlay),overlay.internalLayout.removeGroup(group);const remaining=this.cleanupOrphanedFloatingLeaf(overlay);wasOwner&&remaining.length>0?this.floatingOverlays.set(remaining[0].id,overlay):remaining.length===0&&overlay.dispose(),group.isInFloatingSplit=!1,group.location==="floating"?group.fireLocationChanged():group.location="floating"}updateFloatingSplitState(overlay){if(!overlay.internalLayout)return;const groups=overlay.internalLayout.allGroups(),isInSplit=groups.length>1;for(const g of groups)g.location="floating",g.isInFloatingSplit=isInSplit;overlay.repositionToolbar()}cleanupOrphanedFloatingLeaf(overlay){if(!overlay.internalLayout)return[];const remaining=overlay.internalLayout.allGroups();return remaining.length<=1?(remaining.length===1&&(overlay.element.appendChild(remaining[0].element),remaining[0].isInFloatingSplit=!1),overlay.internalLayout.dispose(),overlay.internalLayout=null,remaining.length===1&&(overlay.setDragGroup(remaining[0]),remaining[0].location="floating",overlay.repositionToolbar())):this.updateFloatingSplitState(overlay),overlay.updateTotalTabCount(),remaining}minimizeDocked(group){const pos=this.layout.getGroupPosition(group);return this.layout.findGroupNode(group)&&this.layout.removeGroup(group),pos?{siblingGroupId:pos.siblingGroup.id,direction:pos.direction}:null}restoreDocked(group,position,initialSize,siblingGroupId){if(siblingGroupId){const sibling=this.groups.get(siblingGroupId);if(sibling&&this.layout.findGroupNode(sibling)&&this.layout.splitGroup(sibling,group,position,initialSize))return}const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;mainGroup&&this.layout.splitGroup(mainGroup,group,position,initialSize)}findOverlayForGroup(group){const direct=this.floatingOverlays.get(group.id);if(direct)return direct;for(const overlay of this.floatingOverlays.values())if(overlay.internalLayout?.findGroupNode(group))return overlay;return null}registerPortal(panelId,element,anchor){const entry=document.createElement("div");entry.className="mb-iframe-portal",entry.dataset.portalId=panelId,this.portalLayer.appendChild(entry),entry.appendChild(element),this.portals.set(panelId,{entry,anchor})}unregisterPortal(panelId){const portal=this.portals.get(panelId);portal&&(portal.entry.remove(),this.portals.delete(panelId))}syncPortals(){if(this.disposed)return;const updates=[];for(const[,portal]of this.portals){const{entry,anchor}=portal;if(anchor.offsetParent===null)updates.push({entry,rect:null,zIndex:"0"});else{const overlay=anchor.closest(".mb-floating-overlay"),overlayZ=overlay?.style.zIndex;updates.push({entry,rect:anchor.getBoundingClientRect(),zIndex:String(overlay?parseInt(overlayZ||String(1e5+this.zBase),10)+1:50+this.zBase)})}}for(const{entry,rect,zIndex}of updates)rect?(entry.style.display="",entry.style.left=`${rect.left}px`,entry.style.top=`${rect.top}px`,entry.style.width=`${rect.width}px`,entry.style.height=`${rect.height}px`,entry.style.zIndex=zIndex):entry.style.display="none";this.portalRaf=requestAnimationFrame(()=>this.syncPortals())}}export{FloatingOverlay,Panel,PanelGroup,PanelManager,SplitLayout};
package/dist/styles.css CHANGED
@@ -31,6 +31,7 @@
31
31
  --_status-text: var(--mb-adapt-status-text, #374151);
32
32
  --_drag-ghost-shadow: var(--mb-adapt-drag-ghost-shadow, 0 4px 12px rgba(0, 0, 0, 0.15));
33
33
  --_border-radius: var(--mb-adapt-border-radius, 8px);
34
+ --_z-base: var(--mb-adapt-z-base, 0);
34
35
  --mb-adapt-responsive-breakpoint: 768;
35
36
  --mb-adapt-responsive-hysteresis: 40;
36
37
 
@@ -165,7 +166,7 @@
165
166
  background: var(--_fork-separator);
166
167
  transition: background 0.15s;
167
168
  position: relative;
168
- z-index: 1;
169
+ z-index: calc(1 + var(--_z-base));
169
170
  touch-action: none;
170
171
  }
171
172
 
@@ -203,7 +204,7 @@
203
204
 
204
205
  .mb-group-tabs {
205
206
  display: flex;
206
- align-items: center;
207
+ align-items: stretch;
207
208
  overflow-x: auto;
208
209
  overflow-y: hidden;
209
210
  flex: 0 1 auto;
@@ -349,7 +350,7 @@
349
350
  /* ── Floating overlay ────────────────────────────────── */
350
351
  .mb-floating-overlay {
351
352
  position: fixed;
352
- z-index: 100000;
353
+ z-index: calc(100000 + var(--_z-base));
353
354
  box-shadow: var(--_floating-shadow);
354
355
  border: var(--_floating-border);
355
356
  backdrop-filter: var(--_floating-backdrop);
@@ -400,7 +401,7 @@
400
401
  /* ── Resize handles ──────────────────────────────────── */
401
402
  .mb-resize-handle {
402
403
  position: absolute;
403
- z-index: 10;
404
+ z-index: calc(10 + var(--_z-base));
404
405
  touch-action: none;
405
406
  }
406
407
 
@@ -442,7 +443,7 @@
442
443
  display: flex;
443
444
  align-items: center;
444
445
  justify-content: center;
445
- z-index: 200000;
446
+ z-index: calc(200000 + var(--_z-base));
446
447
  background: transparent;
447
448
  pointer-events: none;
448
449
  }
@@ -515,7 +516,7 @@
515
516
  flex-direction: row;
516
517
  align-items: center;
517
518
  justify-content: center;
518
- z-index: 300000;
519
+ z-index: calc(300000 + var(--_z-base));
519
520
  background: rgba(0, 0, 0, 0.4);
520
521
  height: auto;
521
522
  min-height: 0;
@@ -592,7 +593,7 @@
592
593
  align-items: center;
593
594
  justify-content: center;
594
595
  pointer-events: none;
595
- z-index: 200000;
596
+ z-index: calc(200000 + var(--_z-base));
596
597
  }
597
598
 
598
599
  .mb-adapt-cap > * {
@@ -664,7 +665,7 @@ cap-widget::part(attribution) {
664
665
  display: none;
665
666
  height: var(--_toolbar-height);
666
667
  flex-shrink: 0;
667
- z-index: 100;
668
+ z-index: calc(100 + var(--_z-base));
668
669
  align-items: stretch;
669
670
  background: var(--_fork-tab-bg);
670
671
  border-bottom: 1px solid var(--_fork-separator);
@@ -737,7 +738,7 @@ cap-widget::part(attribution) {
737
738
  .mb-drag-ghost {
738
739
  position: fixed;
739
740
  pointer-events: none;
740
- z-index: 999999;
741
+ z-index: calc(999999 + var(--_z-base));
741
742
  padding: 4px 10px;
742
743
  background: var(--_fork-tab-bg);
743
744
  color: var(--_fork-tab-color);
@@ -767,7 +768,7 @@ cap-widget::part(attribution) {
767
768
  .mb-drop-overlay {
768
769
  position: fixed;
769
770
  pointer-events: none;
770
- z-index: 999998;
771
+ z-index: calc(999998 + var(--_z-base));
771
772
  display: none;
772
773
  box-sizing: border-box;
773
774
  border-radius: 6px;