regular-layout 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,29 @@
1
- # `<regular-layout>`
2
-
3
- A library for resizable panel layouts using CSS `grid`.
4
-
5
- - 7kb, zero dependencies
6
- - Web Component
7
- -
1
+ <br />
2
+ <a href="https://perspective-dev.github.io">
3
+ <p align="center">
4
+ <picture>
5
+ <source media="(prefers-color-scheme: dark)" srcset="./logo.svg">
6
+ <img width="260" src="./logo.svg">
7
+ </picture>
8
+ <br/>
9
+ <br/>
10
+ <a href="https://www.npmjs.com/package/regular-table"><img alt="NPM Version" src="https://img.shields.io/github/actions/workflow/status/texodus/regular-layout/build.yaml?event=push&style=flat-square"></a>
11
+ <a href="https://www.npmjs.com/package/regular-table"><img alt="NPM Version" src="https://img.shields.io/npm/v/regular-layout.svg?color=brightgreen&style=flat-square"></a>
12
+ <a href="https://www.npmjs.com/package/regular-table"><img alt="Bundlephobia (Minified)" src="https://img.shields.io/bundlephobia/min/regular-layout?style=flat-square"></a>
13
+ <!-- <a href="https://www.npmjs.com/package/regular-table"><img alt="Bundlephobia (Minzipped)" src="https://img.shields.io/bundlephobia/minzip/regular-layout?style=flat-square"></a> -->
14
+ <br/>
15
+ <br/>
16
+ </p>
17
+
18
+
19
+
20
+ A library for resizable & repositionable panel layouts, using
21
+ [CSS `grid`](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout).
22
+
23
+ - Zero depedencies, pure TypeScript, tiny.
24
+ - Implemented as a [Web Component](https://developer.mozilla.org/en-US/docs/Web/API/Web_components),
25
+ interoperable with any framework and fully customizable.
26
+ - Covered in bees.
8
27
 
9
28
  ## Installation
10
29
 
@@ -0,0 +1,15 @@
1
+ import type { Layout, LayoutPath } from "./layout_config";
2
+ /**
3
+ * Calculates an insertion point (which may involve splitting a single
4
+ * `"child-panel"` into a new `"split-panel"`), based on the cursor position.
5
+ * *
6
+ * @param col - The cursor column.
7
+ * @param row - The cursor row.
8
+ * @param panel - The `Layout` to insert into.
9
+ * @param slot - The slot identifier where the insert should occur
10
+ * @param drop_target - The `LayoutPath` (from `calculateIntersect`) of the
11
+ * panel to either insert next to, or split by.
12
+ * @returns A new `LayoutPath` reflecting the updated (maybe) `"split-panel"`,
13
+ * which is enough to draw the overlay.
14
+ */
15
+ export declare function calculate_edge(col: number, row: number, panel: Layout, slot: string, drop_target: LayoutPath): LayoutPath;
@@ -0,0 +1,29 @@
1
+ import type { OverlayMode } from "./layout_config";
2
+ /**
3
+ * The minimum number of pixels the mouse must move to be considered a drag.
4
+ */
5
+ export declare const MIN_DRAG_DISTANCE = 10;
6
+ /**
7
+ * Class name to use for child elements in overlay position (dragging).
8
+ */
9
+ export declare const OVERLAY_CLASSNAME = "overlay";
10
+ /**
11
+ * The percentage of the maximum resize distance that will be clamped.
12
+ *
13
+ */
14
+ export declare const MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD = 0.15;
15
+ /**
16
+ * Threshold from panel edge that is considered a split vs drop action.
17
+ */
18
+ export declare const SPLIT_EDGE_TOLERANCE = 0.25;
19
+ /**
20
+ * Tolerance threshold for considering two grid track positions as identical.
21
+ *
22
+ * When collecting and deduplicating track positions, any positions closer than
23
+ * this value are treated as the same position to avoid redundant grid tracks.
24
+ */
25
+ export declare const GRID_TRACK_COLLAPSE_TOLERANCE = 0.001;
26
+ /**
27
+ * The overlay default behavior.
28
+ */
29
+ export declare const OVERLAY_DEFAULT: OverlayMode;
@@ -1,4 +1,4 @@
1
- import { type Layout } from "./layout_config.ts";
1
+ import type { Layout } from "./layout_config.ts";
2
2
  /**
3
3
  * Generates CSS Grid styles to render a layout tree.
4
4
  * Creates grid-template-rows, grid-template-columns, and positioning rules for
@@ -1,2 +1,2 @@
1
1
  import type { LayoutPath } from "./layout_config";
2
- export declare function updateOverlaySheet({ view_window: { row_start, row_end, col_start, col_end }, box, }: LayoutPath<DOMRect>): string;
2
+ export declare function updateOverlaySheet(slot: string, { view_window: { row_start, row_end, col_start, col_end }, box, }: LayoutPath<DOMRect>): string;
@@ -12,4 +12,4 @@ import type { Layout } from "./layout_config.ts";
12
12
  * "horizontal".
13
13
  * @returns A new layout tree with the child inserted (original is not mutated).
14
14
  */
15
- export declare function insert_child(panel: Layout, child: string, path: number[], orientation?: "horizontal" | "vertical"): Layout;
15
+ export declare function insert_child(panel: Layout, child: string, path: number[], orientation?: "horizontal" | "vertical", is_edge?: boolean): Layout;
@@ -1,19 +1,7 @@
1
1
  /**
2
- * The percentage of the maximum resize distance that will be clamped.
3
- *
4
- */
5
- export declare const MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD = 0.15;
6
- /**
7
- * Threshold from panel edge that is considered a split vs drop action.
8
- */
9
- export declare const SPLIT_EDGE_TOLERANCE = 0.15;
10
- /**
11
- * Tolerance threshold for considering two grid track positions as identical.
12
- *
13
- * When collecting and deduplicating track positions, any positions closer than
14
- * this value are treated as the same position to avoid redundant grid tracks.
2
+ * The overlay behavior type.
15
3
  */
16
- export declare const GRID_TRACK_COLLAPSE_TOLERANCE = 0.0001;
4
+ export type OverlayMode = "grid" | "absolute";
17
5
  /**
18
6
  * The representation of a CSS grid, in JSON form.
19
7
  */
@@ -49,7 +37,8 @@ export interface SplitLayout {
49
37
  */
50
38
  export interface TabLayout {
51
39
  type: "child-panel";
52
- child: string;
40
+ child: string[];
41
+ selected?: number;
53
42
  }
54
43
  /**
55
44
  * Represents a draggable divider between two panels in the layout.
@@ -71,11 +60,15 @@ export interface LayoutDivider {
71
60
  export interface LayoutPath<T = undefined> {
72
61
  type: "layout-path";
73
62
  slot: string;
63
+ panel: TabLayout;
74
64
  path: number[];
75
65
  view_window: ViewWindow;
66
+ column: number;
67
+ row: number;
76
68
  column_offset: number;
77
69
  row_offset: number;
78
70
  orientation: Orientation;
71
+ is_edge: boolean;
79
72
  box: T;
80
73
  }
81
74
  /**
@@ -1,4 +1,4 @@
1
- import { type Layout } from "./layout_config.ts";
1
+ import type { Layout } from "./layout_config.ts";
2
2
  /**
3
3
  * Adjusts panel sizes during a drag operation on a divider.
4
4
  *
@@ -1,5 +1,6 @@
1
1
  import { RegularLayout } from "./regular-layout.ts";
2
2
  import { RegularLayoutFrame } from "./regular-layout-frame.ts";
3
+ import type { Layout } from "./common/layout_config.ts";
3
4
  declare global {
4
5
  interface Document {
5
6
  createElement(tagName: "regular-layout", options?: ElementCreationOptions): RegularLayout;
@@ -12,4 +13,17 @@ declare global {
12
13
  get(tagName: "regular-layout"): typeof RegularLayout;
13
14
  get(tagName: "regular-layout-frame"): typeof RegularLayoutFrame;
14
15
  }
16
+ interface HTMLElement {
17
+ addEventListener(name: "regular-layout-update", cb: (e: RegularLayoutEvent) => void, options?: {
18
+ signal: AbortSignal;
19
+ }): void;
20
+ addEventListener(name: "regular-layout-before-update", cb: (e: RegularLayoutEvent) => void, options?: {
21
+ signal: AbortSignal;
22
+ }): void;
23
+ removeEventListener(name: "regular-layout-update", cb: (e: RegularLayoutEvent) => void): void;
24
+ removeEventListener(name: "regular-layout-before-update", cb: (e: RegularLayoutEvent) => void): void;
25
+ }
26
+ }
27
+ export interface RegularLayoutEvent extends CustomEvent {
28
+ detail: Layout;
15
29
  }
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- function*C(o){if(o.type==="split-panel")for(let t of o.children)yield*C(t);else yield o.child}var P={type:"split-panel",orientation:"horizontal",sizes:[],children:[]};function f(o,t){if(o.type==="child-panel")return structuredClone(P);let e=structuredClone(o),s=e.children.findIndex(i=>i.type==="child-panel"?i.child===t:!1);if(s!==-1){let i=e.children.filter((h,u)=>u!==s),l=$(e.sizes,s);return i.length===1?i[0]:(e.children=i,e.sizes=l,e)}let r=!1,n=e.children.map(i=>{if(i.type==="split-panel"){let l=f(i,t);return l!==i&&(r=!0),l}return i});return r&&(e.children=n),e}function $(o,t){let e=[],s=o[t],r=0;for(let n=0;n<o.length;n++)n!==t&&(r+=o[n]);for(let n=0;n<o.length;n++)if(n!==t){let i=o[n]/r;e.push(o[n]+s*i)}return e}function T(o){if(o.length===0)return[];let t=o.sort((s,r)=>s-r),e=[t[0]];for(let s=1;s<t.length;s++)Math.abs(t[s]-e[e.length-1])>1e-4&&e.push(t[s]);return e}function E(o,t,e,s){if(o.type==="child-panel")return[e,s];if(o.orientation===t){let r=[e,s],n=e;for(let i=0;i<o.children.length;i++){let l=o.sizes[i],h=E(o.children[i],t,n,n+l*(s-e));r.push(...h),n=n+l*(s-e)}return T(r)}else{let r=[e,s];for(let n of o.children){let i=E(n,t,e,s);r.push(...i)}return T(r)}}function v(o,t){for(let e=0;e<o.length;e++)if(Math.abs(o[e]-t)<1e-4)return e;throw new Error(`Position ${t} not found in ${o}`)}function z(o,t,e,s,r,n,i){if(o.type==="child-panel")return[{child:o.child,colStart:v(t,s),colEnd:v(t,r),rowStart:v(e,n),rowEnd:v(e,i)}];let l=[],{children:h,sizes:u,orientation:c}=o;if(c==="horizontal"){let a=s;for(let p=0;p<h.length;p++){let _=a+u[p]*(r-s);l.push(...z(h[p],t,e,a,_,n,i)),a=_}}else{let a=n;for(let p=0;p<h.length;p++){let _=a+u[p]*(i-n);l.push(...z(h[p],t,e,s,r,a,_)),a=_}}return l}var D=(o,t)=>`:host { display: grid; gap: 0px; grid-template-rows: ${o}; grid-template-columns: ${t}; }`,x=(o,t,e)=>`:host ::slotted([slot=${o}]) { grid-column: ${e}; grid-row: ${t}; }`;function y(o,t=!1,e){if(e&&(o=f(o,e[0])),o.type==="child-panel")return`${D("100%","100%")}
2
- ${x(o.child,"1","1")}`;let s=E(o,"horizontal",0,1),r=[];for(let a=0;a<s.length-1;a++)r.push(s[a+1]-s[a]);let n=r.map(a=>`${t?Math.round(a*100):a*100}%`).join(" "),i=E(o,"vertical",0,1),l=[];for(let a=0;a<i.length-1;a++)l.push(i[a+1]-i[a]);let h=l.map(a=>`${t?Math.round(a*100):a*100}%`).join(" "),u=z(o,s,i,0,1,0,1),c=[D(h,n)];for(let a of u){let p=a.colEnd-a.colStart===1?`${a.colStart+1}`:`${a.colStart+1} / ${a.colEnd+1}`,_=a.rowEnd-a.rowStart===1?`${a.rowStart+1}`:`${a.rowStart+1} / ${a.rowEnd+1}`;c.push(`${x(a.child,_,p)}`),a.child===e?.[1]&&(c.push(`${x(e[0],_,p)}`),c.push(`:host ::slotted([slot=${e[0]}]) { z-index: 1; }`))}return c.join(`
3
- `)}function m(o,t,e,s=!0){return R(o,t,e,s)}var N={row_start:0,row_end:1,col_start:0,col_end:1};function R(o,t,e,s,r="horizontal",n=structuredClone(N),i=[]){if(e.type==="child-panel")return{type:"layout-path",box:void 0,slot:e.child,path:i,view_window:n,column_offset:(o-n.col_start)/(n.col_end-n.col_start),row_offset:(t-n.row_start)/(n.row_end-n.row_start),orientation:r};if(e.orientation==="vertical"){let l=n.row_start;for(let h=0;h<e.children.length;h++){let c=(n.row_end-n.row_start)*e.sizes[h]+l;if(s&&Math.abs(t-c)<.01)return{path:[...i,h],type:"vertical",view_window:{...n,row_start:l,row_end:c}};if(t>=l&&t<c)return R(o,t,e.children[h],s,"vertical",{...n,row_start:l,row_end:c},[...i,h]);l=c}}else{let l=n.col_start;for(let h=0;h<e.children.length;h++){let u=n.col_end-n.col_start,c=l+u*e.sizes[h];if(s&&Math.abs(o-c)<.01)return{path:[...i,h],type:"horizontal",view_window:{...n,col_start:l,col_end:c}};if(o>=l&&o<c)return R(o,t,e.children[h],s,"horizontal",{...n,col_start:l,col_end:c},[...i,h]);l=c}}return null}function d(o,t,e,s="horizontal"){if(e.length===0){if(o.type==="child-panel")return{type:"split-panel",orientation:s,children:[o,{type:"child-panel",child:t}],sizes:[.5,.5]};{let u=[...o.children,{type:"child-panel",child:t}],c=u.length,a=Array(c).fill(1/c);return{...o,children:u,sizes:a}}}let[r,...n]=e;if(o.type==="child-panel")return d({type:"split-panel",orientation:s,children:[o],sizes:[1]},t,e,s);if(n.length===0||r===o.children.length){let u=[...o.children];u.splice(r,0,{type:"child-panel",child:t});let c=u.length,a=Array(c).fill(1/c);return{...o,children:u,sizes:a}}let i=o.children[r];if(i.type==="child-panel"&&n.length>0){let u=o.orientation==="horizontal"?"vertical":"horizontal",c=d(i,t,n,u),a=[...o.children];return a[r]=c,{...o,children:a}}let l=d(i,t,n,s),h=[...o.children];return h[r]=l,{...o,children:h}}function S(o,t,e){let s=structuredClone(o),r=s,n={horizontal:e,vertical:e};for(let i=0;i<t.length-1;i++)r.type==="split-panel"&&(n[r.orientation]/=r.sizes[t[i]],r=r.children[t[i]]);if(r.type==="split-panel"){let i=n[r.orientation],l=t[t.length-1];r.sizes=H(r.sizes,l,i)}return s}function H(o,t,e){let s=[...o],r=0;for(let i=0;i<=t;i++)r+=o[i];let n=0;for(let i=t+1;i<o.length;i++)n+=o[i];e=Math.sign(e)*Math.min(Math.abs(e),(1-.15)*(e>0?r:n));for(let i=0;i<=t;i++){let l=o[i]/r;s[i]=o[i]-e*l}for(let i=t+1;i<o.length;i++){let l=o[i]/n;s[i]=o[i]+e*l}return s}function O({view_window:{row_start:o,row_end:t,col_start:e,col_end:s},box:r}){let i=o*r.height+0,l=e*r.width+0/2,h=(t-o)*r.height-0,u=(s-e)*r.width-0;return`::slotted(:not([slot])){${`position:absolute!important;z-index:1;top:${i}px;left:${l}px;height:${h}px;width:${u}px;`}}`}function M(o,t,e,s,r){if(r.column_offset<.15||r.column_offset>1-.15)if(r.orientation==="vertical"){let n=d(e,s,[...r.path,r.column_offset<.15?0:1]);r=m(o,t,n,!1)}else{let n=d(e,s,r.path);r=m(o,t,n,!1)}if(r.row_offset<.15&&r.row_offset<r.column_offset||r.row_offset>1-.15&&r.row_offset>r.column_offset)if(r.orientation==="horizontal"){let n=d(e,s,[...r.path,r.row_offset<.15?0:1]);r=m(o,t,n,!1)}else{let n=d(e,s,r.path);r=m(o,t,n,!1)}return r}function w(o){if(o.type==="child-panel")return o;let t=[],e=[];for(let s=0;s<o.children.length;s++){let r=o.children[s],n=o.sizes[s],i=w(r);if(i.type==="split-panel"&&i.orientation===o.orientation)for(let l=0;l<i.children.length;l++)t.push(i.children[l]),e.push(i.sizes[l]*n);else t.push(i),e.push(n)}return{type:"split-panel",orientation:o.orientation,children:t,sizes:e}}var I="absolute",L=class extends HTMLElement{_shadowRoot;_panel;_stylesheet;_dragPath;_slots;_unslotted_slot;constructor(){super(),this._panel=structuredClone(P),this._stylesheet=new CSSStyleSheet,this._unslotted_slot=document.createElement("slot"),this._shadowRoot=this.attachShadow({mode:"open"}),this._shadowRoot.adoptedStyleSheets=[this._stylesheet],this._shadowRoot.appendChild(this._unslotted_slot),this._slots=new Map,this.onPointerDown=this.onPointerDown.bind(this),this.onPointerMove=this.onPointerMove.bind(this),this.onPointerUp=this.onPointerUp.bind(this)}connectedCallback(){this.addEventListener("pointerdown",this.onPointerDown),this.addEventListener("pointerup",this.onPointerUp),this.addEventListener("pointermove",this.onPointerMove)}disconnectedCallback(){this.removeEventListener("pointerdown",this.onPointerDown),this.removeEventListener("pointerup",this.onPointerUp),this.removeEventListener("pointermove",this.onPointerMove)}setOverlayState(t,e,{slot:s},r=I){let n=this._panel;r==="absolute"&&(n=f(n,s),this._slots.get(s)?.assignedElements()[0]?.removeAttribute("slot"));let[i,l,h]=this.relativeCoordinates(t,e),u=m(i,l,n,!1);if(u&&(u=M(i,l,n,s,u)),u){if(r==="interactive"){let c=f(this._panel,s);c=w(d(c,s,u.path));let a=y(c);this._stylesheet.replaceSync(a)}else if(r==="grid"){let c=[s,u.slot],a=y(this._panel,!1,c);this._stylesheet.replaceSync(a)}else if(r==="absolute"){let c=`${y(n)}
4
- ${O({...u,box:h})}`;this._stylesheet.replaceSync(c)}}}clearOverlayState(t,e,s,r=I){let n=this._panel;r==="absolute"&&(n=f(n,s.slot),this._unslotted_slot.assignedElements()[0]?.setAttribute("slot",s.slot));let[i,l,h]=this.relativeCoordinates(t,e),u=m(i,l,n,!1);u&&(u=M(i,l,n,s.slot,u));let{path:c}=u||s;this.removePanel(s.slot),this.insertPanel(s.slot,c)}insertPanel(t,e=[]){this.restore(d(this._panel,t,e))}removePanel(t){this.restore(f(this._panel,t))}calculateIntersect(t,e,s=!1){let[r,n,i]=this.relativeCoordinates(t,e),l=m(r,n,this._panel,s);return l?.type==="layout-path"?{...l,box:i}:null}restore(t,e=!1){this._panel=e?t:w(t);let s=y(t);this._stylesheet.replaceSync(s);let r=new Set(this._slots.keys());for(let n of C(t))if(r.delete(n),!this._slots.has(n)){let i=document.createElement("slot");i.setAttribute("name",n),this._shadowRoot.appendChild(i),this._slots.set(n,i)}for(let n of r){let i=this._slots.get(n);i&&(this._shadowRoot.removeChild(i),this._slots.delete(n))}}save(){return structuredClone(this._panel)}relativeCoordinates(t,e){let s=this.getBoundingClientRect(),r=(t-s.left)/(s.right-s.left),n=(e-s.top)/(s.bottom-s.top);return[r,n,s]}onPointerDown(t){let[e,s]=this.relativeCoordinates(t.clientX,t.clientY),r=m(e,s,this._panel);r&&r.type!=="layout-path"&&(this._dragPath=[r,e,s],this.setPointerCapture(t.pointerId),t.preventDefault(),t.stopImmediatePropagation())}onPointerMove(t){if(this._dragPath){let[e,s]=this.relativeCoordinates(t.clientX,t.clientY),r=this._panel,[{path:n,type:i},l,h]=this._dragPath,u=i==="horizontal"?l-e:h-s,c=S(r,n,u);this._stylesheet.replaceSync(y(c))}}onPointerUp(t){if(this._dragPath){this.releasePointerCapture(t.pointerId);let[e,s]=this.relativeCoordinates(t.clientX,t.clientY),r=this._panel,[{path:n},i,l]=this._dragPath;if(this._dragPath[0].type==="horizontal"){let h=S(r,n,i-e);this.restore(h,!0)}else{let h=S(r,n,l-s);this.restore(h,!0)}this._dragPath=void 0}}};var Y=`
1
+ function*C(r){if(r.type==="split-panel")for(let t of r.children)yield*C(t);else yield r.child[r.selected||0]}var b={type:"split-panel",orientation:"horizontal",sizes:[],children:[]};var m="overlay";var x="absolute";function y(r,t){if(r.type==="child-panel"){if(r.child.includes(t)){let o=r.child.filter(a=>a!==t);return o.length===0?structuredClone(b):{type:"child-panel",child:o}}return structuredClone(r)}let e=structuredClone(r),i=e.children.findIndex(o=>o.type==="child-panel"?o.child.includes(t):!1);if(i!==-1){let o=e.children[i];if(o.child.length===1){let a=e.children.filter((h,c)=>c!==i),u=H(e.sizes,i);if(a.length===1)return a[0];e.children=a,e.sizes=u}else o.child.splice(o.child.indexOf(t),1),o.selected&&o.selected>=o.child.length&&o.selected--;return e}let n=!1,s=e.children.map(o=>{if(o.type==="split-panel"){let a=y(o,t);return a!==o&&(n=!0),a}return o});return n&&(e.children=s),e}function H(r,t){let e=[],i=r[t],n=0;for(let s=0;s<r.length;s++)s!==t&&(n+=r[s]);for(let s=0;s<r.length;s++)if(s!==t){let o=r[s]/n;e.push(r[s]+i*o)}return e}function D(r){if(r.length===0)return[];let t=r.sort((i,n)=>i-n),e=[t[0]];for(let i=1;i<t.length;i++)Math.abs(t[i]-e[e.length-1])>.001&&e.push(t[i]);return e}function S(r,t,e,i){if(r.type==="child-panel")return[e,i];if(r.orientation===t){let n=[e,i],s=e;for(let o=0;o<r.children.length;o++){let a=r.sizes[o],u=S(r.children[o],t,s,s+a*(i-e));n.push(...u),s=s+a*(i-e)}return D(n)}else{let n=[e,i];for(let s of r.children){let o=S(s,t,e,i);n.push(...o)}return D(n)}}function P(r,t){for(let e=0;e<r.length;e++)if(Math.abs(r[e]-t)<.001)return e;throw new Error(`Position ${t} not found in ${r}`)}function M(r,t,e,i,n,s,o){if(r.type==="child-panel"){let l=r.selected??0;return[{child:r.child[l],colStart:P(t,i),colEnd:P(t,n),rowStart:P(e,s),rowEnd:P(e,o)}]}let a=[],{children:u,sizes:h,orientation:c}=r;if(c==="horizontal"){let l=i;for(let d=0;d<u.length;d++){let p=l+h[d]*(n-i);a.push(...M(u[d],t,e,l,p,s,o)),l=p}}else{let l=s;for(let d=0;d<u.length;d++){let p=l+h[d]*(o-s);a.push(...M(u[d],t,e,i,n,l,p)),l=p}}return a}var A=(r,t)=>`:host { display: grid; gap: 0px; grid-template-rows: ${r}; grid-template-columns: ${t}; }`,T=(r,t,e)=>`:host ::slotted([slot=${r}]) { grid-column: ${e}; grid-row: ${t}; }`;function g(r,t=!1,e){if(e&&(r=y(r,e[0])),r.type==="child-panel"){let l=r.selected??0;return`${A("100%","100%")}
2
+ ${T(r.child[l],"1","1")}`}let i=S(r,"horizontal",0,1),n=[];for(let l=0;l<i.length-1;l++)n.push(i[l+1]-i[l]);let s=n.map(l=>`${t?Math.round(l*100):l*100}%`).join(" "),o=S(r,"vertical",0,1),a=[];for(let l=0;l<o.length-1;l++)a.push(o[l+1]-o[l]);let u=a.map(l=>`${t?Math.round(l*100):l*100}%`).join(" "),h=M(r,i,o,0,1,0,1),c=[A(u,s)];for(let l of h){let d=l.colEnd-l.colStart===1?`${l.colStart+1}`:`${l.colStart+1} / ${l.colEnd+1}`,p=l.rowEnd-l.rowStart===1?`${l.rowStart+1}`:`${l.rowStart+1} / ${l.rowEnd+1}`;c.push(`${T(l.child,p,d)}`),l.child===e?.[1]&&(c.push(`${T(e[0],p,d)}`),c.push(`:host ::slotted([slot=${e[0]}]) { z-index: 1; }`))}return c.join(`
3
+ `)}function f(r,t,e,i=!0){return R(r,t,e,i)}var k={row_start:0,row_end:1,col_start:0,col_end:1};function R(r,t,e,i,n=null,s=structuredClone(k),o=[]){if(r<0||t<0||r>1||t>1)return null;if(e.type==="child-panel"){let a=e.selected??0,u=(r-s.col_start)/(s.col_end-s.col_start),h=(t-s.row_start)/(s.row_end-s.row_start);return{type:"layout-path",box:void 0,slot:e.child[a],panel:structuredClone(e),path:o,view_window:s,is_edge:!1,column:r,row:t,column_offset:u,row_offset:h,orientation:n||"horizontal"}}if(e.orientation==="vertical"){let a=s.row_start;for(let u=0;u<e.children.length;u++){let c=(s.row_end-s.row_start)*e.sizes[u]+a;if(i&&Math.abs(t-c)<.01)return{path:[...o,u],type:"vertical",view_window:{...s,row_start:a,row_end:c}};if(t>=a&&t<c)return R(r,t,e.children[u],i,"vertical",{...s,row_start:a,row_end:c},[...o,u]);a=c}}else{let a=s.col_start;for(let u=0;u<e.children.length;u++){let h=s.col_end-s.col_start,c=a+h*e.sizes[u];if(i&&Math.abs(r-c)<.01)return{path:[...o,u],type:"horizontal",view_window:{...s,col_start:a,col_end:c}};if(r>=a&&r<c)return R(r,t,e.children[u],i,"horizontal",{...s,col_start:a,col_end:c},[...o,u]);a=c}}return null}function _(r,t,e,i="horizontal",n){if(e.length===0){if(r.type==="child-panel")return{type:"child-panel",child:[t,...r.child]};{let c=[...r.children,{type:"child-panel",child:[t]}],l=c.length,d=Array(l).fill(1/l);return{...r,children:c,sizes:d}}}let[s,...o]=e;if(r.type==="child-panel")return _({type:"split-panel",orientation:i,children:[r],sizes:[1]},t,e,i,n);if(o.length===0||s===r.children.length){if(n&&r.children[s]?.type==="child-panel")return r.children[s].child.unshift(t),r.children[s].selected=0,r;let c=[...r.children];c.splice(s,0,{type:"child-panel",child:[t]});let l=c.length,d=Array(l).fill(1/l);return{...r,children:c,sizes:d}}let a=r.children[s];if(a.type==="child-panel"&&o.length>0){let c=r.orientation==="horizontal"?"vertical":"horizontal",l=_(a,t,o,c,n),d=[...r.children];return d[s]=l,{...r,children:d}}let u=_(a,t,o,i,n),h=[...r.children];return h[s]=u,{...r,children:h}}function w(r,t,e){let i=structuredClone(r),n=i,s={horizontal:e,vertical:e};for(let o=0;o<t.length-1;o++)n.type==="split-panel"&&(s[n.orientation]/=n.sizes[t[o]],n=n.children[t[o]]);if(n.type==="split-panel"){let o=s[n.orientation],a=t[t.length-1];a<n.sizes.length-1&&(n.sizes=U(n.sizes,a,o))}return i}function U(r,t,e){let i=[...r],n=0;for(let o=0;o<=t;o++)n+=r[o];let s=0;for(let o=t+1;o<r.length;o++)s+=r[o];e=Math.sign(e)*Math.min(Math.abs(e),(1-.15)*(e>0?n:s));for(let o=0;o<=t;o++){let a=r[o]/n;i[o]=r[o]-e*a}for(let o=t+1;o<r.length;o++){let a=r[o]/s;i[o]=r[o]+e*a}return i}function $(r,{view_window:{row_start:t,row_end:e,col_start:i,col_end:n},box:s}){let a=t*s.height+0,u=i*s.width+0/2,h=(e-t)*s.height-0,c=(n-i)*s.width-0,l=`position:absolute!important;z-index:1;top:${a}px;left:${u}px;height:${h}px;width:${c}px;`;return`::slotted([slot="${r}"]){${l}}`}function z(r,t,e,i,n){let s=n.column_offset<.25||n.column_offset>1-.25,o=n.row_offset<.25||n.row_offset>1-.25;return s?N(r,t,e,i,n,n.column_offset,"horizontal"):o?N(r,t,e,i,n,n.row_offset,"vertical"):n}function N(r,t,e,i,n,s,o){let a=s<.25;if(n.orientation===o)if(n.path.length===0){let h=_(e,i,[a?0:1]);n=f(r,t,h,!1)}else{let u=n.path.slice(0,-1),h=n.path[n.path.length-1],c=a?h:h+1,l=_(e,i,[...u,c]);n=f(r,t,l,!1)}else{let u=[...n.path,a?0:1],h=_(e,i,u,o);n=f(r,t,h,!1)}return n.is_edge=!0,n}function O(r){if(r.type==="child-panel")return r.selected=r.selected||0,r;let t=[],e=[];for(let i=0;i<r.children.length;i++){let n=r.children[i],s=r.sizes[i],o=O(n);if(o.type==="split-panel"&&o.orientation===r.orientation)for(let a=0;a<o.children.length;a++)t.push(o.children[a]),e.push(o.sizes[a]*s);else t.push(o),e.push(s)}return t.length===1?t[0]:{type:"split-panel",orientation:r.orientation,children:t,sizes:e}}var v=class extends HTMLElement{_shadowRoot;_panel;_stylesheet;_dragPath;_slots;_unslotted_slot;constructor(){super(),this._panel=structuredClone(b),this._stylesheet=new CSSStyleSheet,this._unslotted_slot=document.createElement("slot"),this._shadowRoot=this.attachShadow({mode:"open"}),this._shadowRoot.adoptedStyleSheets=[this._stylesheet],this._shadowRoot.appendChild(this._unslotted_slot),this._slots=new Map}connectedCallback(){this.addEventListener("pointerdown",this.onPointerDown),this.addEventListener("pointerup",this.onPointerUp),this.addEventListener("pointermove",this.onPointerMove)}disconnectedCallback(){this.removeEventListener("pointerdown",this.onPointerDown),this.removeEventListener("pointerup",this.onPointerUp),this.removeEventListener("pointermove",this.onPointerMove)}setOverlayState=(t,e,{slot:i},n=m,s=x)=>{let o=this._panel;s==="absolute"&&(o=y(o,i),this.updateSlots(o,i),this._slots.get(i)?.assignedElements()[0]?.classList.add(n));let[a,u,h]=this.relativeCoordinates(t,e),c=f(a,u,o,!1);if(c){if(c=z(a,u,o,i,c),s==="grid"){let d=[i,c.slot],p=g(this._panel,!1,d);this._stylesheet.replaceSync(p)}else if(s==="absolute"){let d=g(o),p=$(i,{...c,box:h});this._stylesheet.replaceSync([d,p].join(`
4
+ `))}}else{let d=`${g(o)}}`;this._stylesheet.replaceSync(d)}let l=new CustomEvent("regular-layout-before-update",{detail:o});this.dispatchEvent(l)};clearOverlayState=(t,e,i,n=m,s=x)=>{let o=this._panel;s==="absolute"&&(o=y(o,i.slot),this._slots.get(i.slot)?.assignedElements()[0]?.classList.remove(n));let[a,u,h]=this.relativeCoordinates(t,e),c=f(a,u,o,!1);c&&(c=z(a,u,o,i.slot,c));let{path:l,orientation:d}=c||i;this.restore(_(o,i.slot,l,d,!c?.is_edge))};insertPanel=(t,e=[])=>{this.restore(_(this._panel,t,e))};removePanel=t=>{this.restore(y(this._panel,t))};getPanel=(t,e=this._panel)=>{if(e.type==="child-panel")return e.child.includes(t)?e:null;for(let i of e.children){let n=this.getPanel(t,i);if(n)return n}return null};calculateIntersect=(t,e,i=!1)=>{let[n,s,o]=this.relativeCoordinates(t,e),a=f(n,s,this._panel,i);return a?.type==="layout-path"?{...a,box:o}:null};clear=()=>{this.restore(b)};restore=(t,e=!1)=>{this._panel=e?t:O(t);let i=g(this._panel);this._stylesheet.replaceSync(i),this.updateSlots(this._panel);let n=new CustomEvent("regular-layout-update",{detail:this._panel});this.dispatchEvent(n)};save=()=>structuredClone(this._panel);relativeCoordinates=(t,e)=>{let i=this.getBoundingClientRect(),n=(t-i.left)/(i.right-i.left),s=(e-i.top)/(i.bottom-i.top);return[n,s,i]};updateSlots=(t,e)=>{let i=new Set(this._slots.keys());e&&i.delete(e);for(let n of C(t))if(i.delete(n),!this._slots.has(n)){let s=document.createElement("slot");s.setAttribute("name",n),this._shadowRoot.appendChild(s),this._slots.set(n,s)}for(let n of i){let s=this._slots.get(n);s&&(this._shadowRoot.removeChild(s),this._slots.delete(n))}};onPointerDown=t=>{if(t.target===this){let[e,i]=this.relativeCoordinates(t.clientX,t.clientY),n=f(e,i,this._panel);n&&n.type!=="layout-path"&&(this._dragPath=[n,e,i],this.setPointerCapture(t.pointerId),t.preventDefault())}};onPointerMove=t=>{if(this._dragPath){let[e,i]=this.relativeCoordinates(t.clientX,t.clientY),n=this._panel,[{path:s,type:o},a,u]=this._dragPath,h=o==="horizontal"?a-e:u-i,c=w(n,s,h);this._stylesheet.replaceSync(g(c))}};onPointerUp=t=>{if(this._dragPath){this.releasePointerCapture(t.pointerId);let[e,i]=this.relativeCoordinates(t.clientX,t.clientY),n=this._panel,[{path:s},o,a]=this._dragPath;if(this._dragPath[0].type==="horizontal"){let u=w(n,s,o-e);this.restore(u,!0)}else{let u=w(n,s,a-i);this.restore(u,!0)}this._dragPath=void 0}}};var G=r=>`
5
5
  :host{--titlebar--height:24px;box-sizing:border-box}
6
- :host([slot]){margin-top:calc(var(--titlebar--height) + 3px)!important;}
7
- :host([slot])::part(container){position:absolute;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;background-color:inherit;border-radius:inherit}
8
- :host([slot])::part(titlebar){height:var(--titlebar--height);margin-top:calc(-2px - var(--titlebar--height));user-select: none;}
9
- :host([slot])::part(body){flex:1 1 auto;}
10
- `,g=class extends HTMLElement{_shadowRoot;_container_sheet;_layout;_header;_drag_state=null;constructor(){super(),this._container_sheet=new CSSStyleSheet,this._container_sheet.replaceSync(Y),this._shadowRoot=this.attachShadow({mode:"open"}),this._shadowRoot.adoptedStyleSheets=[this._container_sheet],this._shadowRoot.innerHTML='<slot part="container"><slot part="titlebar">header</slot><slot part="body"><slot></slot></slot></slot>',this._layout=this.parentElement,this._header=this._shadowRoot.children[0].children[0]}connectedCallback(){this._header.addEventListener("pointerdown",this.onPointerDown),this._header.addEventListener("pointermove",this.onPointerMove),this._header.addEventListener("pointerup",this.onPointerUp)}disconnectedCallback(){this._header.removeEventListener("pointerdown",this.onPointerDown),this._header.removeEventListener("pointermove",this.onPointerMove),this._header.removeEventListener("pointerup",this.onPointerUp)}onPointerDown=t=>{this._drag_state=this._layout.calculateIntersect(t.clientX,t.clientY),this._drag_state&&(this._header.setPointerCapture(t.pointerId),t.preventDefault(),t.stopImmediatePropagation())};onPointerMove=t=>{this._drag_state&&this._layout.setOverlayState(t.clientX,t.clientY,this._drag_state)};onPointerUp=t=>{this._drag_state&&(this._layout.clearOverlayState(t.clientX,t.clientY,this._drag_state),this._header.releasePointerCapture(t.pointerId),this._drag_state=null)}};customElements.define("regular-layout-frame",g);customElements.define("regular-layout",L);export{L as RegularLayout,g as RegularLayoutFrame};
6
+ :host(:not(.${r})){margin-top:calc(var(--titlebar--height) + 3px)!important;}
7
+ :host(:not(.${r}))::part(container){position:absolute;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;background-color:inherit;border-radius:inherit}
8
+ :host(:not(.${r}))::part(titlebar){height:var(--titlebar--height);margin-top:calc(0px - var(--titlebar--height));user-select: none;}
9
+ :host(:not(.${r}))::part(body){flex:1 1 auto;}
10
+ `,W='<slot part="container"><slot part="titlebar"></slot><slot part="body"><slot></slot></slot></slot>',E=class extends HTMLElement{_shadowRoot;_container_sheet;_layout;_header;_drag_state=null;_drag_moved=!1;_tab_to_index_map=new WeakMap;_tab_panel_state=null;constructor(){super(),this._container_sheet=new CSSStyleSheet,this._container_sheet.replaceSync(G(m)),this._shadowRoot=this.attachShadow({mode:"open"}),this._shadowRoot.adoptedStyleSheets=[this._container_sheet]}connectedCallback(){this._shadowRoot.innerHTML=W,this._layout=this.parentElement,this._header=this._shadowRoot.children[0].children[0],this._header.addEventListener("pointerdown",this.onPointerDown),this._header.addEventListener("pointermove",this.onPointerMove),this._header.addEventListener("pointerup",this.onPointerUp),this._header.addEventListener("lostpointercapture",this.onPointerLost),this._layout.addEventListener("regular-layout-update",this.drawTabs),this._layout.addEventListener("regular-layout-before-update",this.drawTabs)}disconnectedCallback(){this._header.removeEventListener("pointerdown",this.onPointerDown),this._header.removeEventListener("pointermove",this.onPointerMove),this._header.removeEventListener("pointerup",this.onPointerUp),this._header.removeEventListener("lostpointercapture",this.onPointerLost),this._layout.removeEventListener("regular-layout-update",this.drawTabs),this._layout.removeEventListener("regular-layout-before-update",this.drawTabs)}onPointerDown=t=>{let e=t.target;if(e.part.contains("tab")&&(this._drag_state=this._layout.calculateIntersect(t.clientX,t.clientY),this._drag_state)){this._header.setPointerCapture(t.pointerId),t.preventDefault();let i=this._drag_state.path.length-1,n=this._tab_to_index_map.get(e);n&&(this._drag_state.path[i]=n)}};onPointerMove=t=>{if(this._drag_state){if(!this._drag_moved){let[e,i,n]=this._layout.relativeCoordinates(t.clientX,t.clientY),s=(e-this._drag_state.column)*n.width,o=(i-this._drag_state.row)*n.height;if(Math.sqrt(s*s+o*o)<=10)return}this._drag_moved=!0,this._layout.setOverlayState(t.clientX,t.clientY,this._drag_state,m)}};onPointerUp=t=>{this._drag_state&&this._drag_moved&&this._layout.clearOverlayState(t.clientX,t.clientY,this._drag_state,m),this._header.releasePointerCapture(t.pointerId),this._drag_state=null,this._drag_moved=!1};onPointerLost=t=>{this._drag_state&&this._layout.clearOverlayState(-1,-1,this._drag_state),this._header.releasePointerCapture(t.pointerId),this._drag_state=null,this._drag_moved=!1};drawTabs=t=>{let e=this.assignedSlot;if(!e)return;let i=t.detail,n=this._layout.getPanel(e.name,i);if(!n)return;for(let o=0;o<n.child.length;o++)if(o>=this._header.children.length){let a=this.createTab(n,o);this._header.appendChild(a)}else{let a=o===n.selected!=(o===this._tab_panel_state?.selected),u=this._header.children[o];if(a||this._tab_panel_state?.child[o]!==n.child[o]){let c=this.createTab(n,o);this._header.replaceChild(c,u)}}let s=n.child.length;for(let o=this._header.children.length-1;o>=s;o--)this._header.removeChild(this._header.children[o]);this._tab_panel_state=n};createTab=(t,e)=>{let i=t.selected||0,n=document.createElement("div");return this._tab_to_index_map.set(n,e),n.textContent=t.child[e]||"",e===i?n.setAttribute("part","tab active-tab"):(n.setAttribute("part","tab"),n.addEventListener("pointerdown",s=>this.onTabClick(t,e))),n};onTabClick=(t,e)=>{let i=this._layout.save(),n=this._layout.getPanel(t.child[e],i);n&&(n.selected=e,this._layout.restore(i))}};customElements.define("regular-layout",v);customElements.define("regular-layout-frame",E);export{v as RegularLayout,E as RegularLayoutFrame};
11
11
  //# sourceMappingURL=index.js.map