import { LitElement, css, nothing } from "lit" ;
import { property } from "lit/decorators.js" ;
/**
* A draggable divider for resizable split views.
* Dispatches 'resize' events with { splitRatio: number } detail.
*/
export class ResizableDivider extends LitElement {
@property({ type: Number }) splitRatio = 0 .6 ;
@property({ type: Number }) minRatio = 0 .4 ;
@property({ type: Number }) maxRatio = 0 .7 ;
private isDragging = false ;
private startX = 0 ;
private startRatio = 0 ;
static styles = css`
:host {
width: 4 px;
cursor: col-resize;
background: var (--border, #333 );
transition: background 150 ms ease-out;
flex-shrink: 0 ;
position: relative;
}
:host::before {
content: "" ;
position: absolute;
top: 0 ;
left: -4 px;
right: -4 px;
bottom: 0 ;
}
:host(:hover) {
background: var (--accent, #007 bff);
}
:host(.dragging) {
background: var (--accent, #007 bff);
}
`;
render() {
return nothing;
}
connectedCallback() {
super .connectedCallback();
this .addEventListener("mousedown" , this .handleMouseDown);
}
disconnectedCallback() {
super .disconnectedCallback();
this .removeEventListener("mousedown" , this .handleMouseDown);
document.removeEventListener("mousemove" , this .handleMouseMove);
document.removeEventListener("mouseup" , this .handleMouseUp);
}
private handleMouseDown = (e: MouseEvent) => {
this .isDragging = true ;
this .startX = e.clientX;
this .startRatio = this .splitRatio;
this .classList.add("dragging" );
document.addEventListener("mousemove" , this .handleMouseMove);
document.addEventListener("mouseup" , this .handleMouseUp);
e.preventDefault();
};
private handleMouseMove = (e: MouseEvent) => {
if (!this .isDragging) {
return ;
}
const container = this .parentElement;
if (!container) {
return ;
}
const containerWidth = container.getBoundingClientRect().width;
const deltaX = e.clientX - this .startX;
const deltaRatio = deltaX / containerWidth;
let newRatio = this .startRatio + deltaRatio;
newRatio = Math.max(this .minRatio, Math.min(this .maxRatio, newRatio));
this .dispatchEvent(
new CustomEvent("resize" , {
detail: { splitRatio: newRatio },
bubbles: true ,
composed: true ,
}),
);
};
private handleMouseUp = () => {
this .isDragging = false ;
this .classList.remove("dragging" );
document.removeEventListener("mousemove" , this .handleMouseMove);
document.removeEventListener("mouseup" , this .handleMouseUp);
};
}
if (!customElements.get("resizable-divider" )) {
customElements.define("resizable-divider" , ResizableDivider);
}
declare global {
interface HTMLElementTagNameMap {
"resizable-divider" : ResizableDivider;
}
}
Messung V0.5 in Prozent C=99 H=98 G=98
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland