UNPKG

@shoelace-style/shoelace

Version:

A forward-thinking library of web components.

234 lines (229 loc) 7.42 kB
import { split_panel_styles_default } from "./chunk.UAYXD3AN.js"; import { drag } from "./chunk.ESELY2US.js"; import { clamp } from "./chunk.HF7GESMZ.js"; import { LocalizeController } from "./chunk.WLV3FVBR.js"; import { watch } from "./chunk.CCJUT23E.js"; import { component_styles_default } from "./chunk.TUVJKY7S.js"; import { ShoelaceElement } from "./chunk.UYAO2JRR.js"; import { __decorateClass } from "./chunk.B3BW2AY6.js"; // src/components/split-panel/split-panel.component.ts import { html } from "lit"; import { ifDefined } from "lit/directives/if-defined.js"; import { property, query } from "lit/decorators.js"; var SlSplitPanel = class extends ShoelaceElement { constructor() { super(...arguments); this.localize = new LocalizeController(this); this.position = 50; this.vertical = false; this.disabled = false; this.snapThreshold = 12; } connectedCallback() { super.connectedCallback(); this.resizeObserver = new ResizeObserver((entries) => this.handleResize(entries)); this.updateComplete.then(() => this.resizeObserver.observe(this)); this.detectSize(); this.cachedPositionInPixels = this.percentageToPixels(this.position); } disconnectedCallback() { var _a; super.disconnectedCallback(); (_a = this.resizeObserver) == null ? void 0 : _a.unobserve(this); } detectSize() { const { width, height } = this.getBoundingClientRect(); this.size = this.vertical ? height : width; } percentageToPixels(value) { return this.size * (value / 100); } pixelsToPercentage(value) { return value / this.size * 100; } handleDrag(event) { const isRtl = this.localize.dir() === "rtl"; if (this.disabled) { return; } if (event.cancelable) { event.preventDefault(); } drag(this, { onMove: (x, y) => { let newPositionInPixels = this.vertical ? y : x; if (this.primary === "end") { newPositionInPixels = this.size - newPositionInPixels; } if (this.snap) { const snaps = this.snap.split(" "); snaps.forEach((value) => { let snapPoint; if (value.endsWith("%")) { snapPoint = this.size * (parseFloat(value) / 100); } else { snapPoint = parseFloat(value); } if (isRtl && !this.vertical) { snapPoint = this.size - snapPoint; } if (newPositionInPixels >= snapPoint - this.snapThreshold && newPositionInPixels <= snapPoint + this.snapThreshold) { newPositionInPixels = snapPoint; } }); } this.position = clamp(this.pixelsToPercentage(newPositionInPixels), 0, 100); }, initialEvent: event }); } handleKeyDown(event) { if (this.disabled) { return; } if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) { let newPosition = this.position; const incr = (event.shiftKey ? 10 : 1) * (this.primary === "end" ? -1 : 1); event.preventDefault(); if (event.key === "ArrowLeft" && !this.vertical || event.key === "ArrowUp" && this.vertical) { newPosition -= incr; } if (event.key === "ArrowRight" && !this.vertical || event.key === "ArrowDown" && this.vertical) { newPosition += incr; } if (event.key === "Home") { newPosition = this.primary === "end" ? 100 : 0; } if (event.key === "End") { newPosition = this.primary === "end" ? 0 : 100; } this.position = clamp(newPosition, 0, 100); } } handleResize(entries) { const { width, height } = entries[0].contentRect; this.size = this.vertical ? height : width; if (isNaN(this.cachedPositionInPixels) || this.position === Infinity) { this.cachedPositionInPixels = Number(this.getAttribute("position-in-pixels")); this.positionInPixels = Number(this.getAttribute("position-in-pixels")); this.position = this.pixelsToPercentage(this.positionInPixels); } if (this.primary) { this.position = this.pixelsToPercentage(this.cachedPositionInPixels); } } handlePositionChange() { this.cachedPositionInPixels = this.percentageToPixels(this.position); this.positionInPixels = this.percentageToPixels(this.position); this.emit("sl-reposition"); } handlePositionInPixelsChange() { this.position = this.pixelsToPercentage(this.positionInPixels); } handleVerticalChange() { this.detectSize(); } render() { const gridTemplate = this.vertical ? "gridTemplateRows" : "gridTemplateColumns"; const gridTemplateAlt = this.vertical ? "gridTemplateColumns" : "gridTemplateRows"; const isRtl = this.localize.dir() === "rtl"; const primary = ` clamp( 0%, clamp( var(--min), ${this.position}% - var(--divider-width) / 2, var(--max) ), calc(100% - var(--divider-width)) ) `; const secondary = "auto"; if (this.primary === "end") { if (isRtl && !this.vertical) { this.style[gridTemplate] = `${primary} var(--divider-width) ${secondary}`; } else { this.style[gridTemplate] = `${secondary} var(--divider-width) ${primary}`; } } else { if (isRtl && !this.vertical) { this.style[gridTemplate] = `${secondary} var(--divider-width) ${primary}`; } else { this.style[gridTemplate] = `${primary} var(--divider-width) ${secondary}`; } } this.style[gridTemplateAlt] = ""; return html` <slot name="start" part="panel start" class="start"></slot> <div part="divider" class="divider" tabindex=${ifDefined(this.disabled ? void 0 : "0")} role="separator" aria-valuenow=${this.position} aria-valuemin="0" aria-valuemax="100" aria-label=${this.localize.term("resize")} @keydown=${this.handleKeyDown} @mousedown=${this.handleDrag} @touchstart=${this.handleDrag} > <slot name="divider"></slot> </div> <slot name="end" part="panel end" class="end"></slot> `; } }; SlSplitPanel.styles = [component_styles_default, split_panel_styles_default]; __decorateClass([ query(".divider") ], SlSplitPanel.prototype, "divider", 2); __decorateClass([ property({ type: Number, reflect: true }) ], SlSplitPanel.prototype, "position", 2); __decorateClass([ property({ attribute: "position-in-pixels", type: Number }) ], SlSplitPanel.prototype, "positionInPixels", 2); __decorateClass([ property({ type: Boolean, reflect: true }) ], SlSplitPanel.prototype, "vertical", 2); __decorateClass([ property({ type: Boolean, reflect: true }) ], SlSplitPanel.prototype, "disabled", 2); __decorateClass([ property() ], SlSplitPanel.prototype, "primary", 2); __decorateClass([ property() ], SlSplitPanel.prototype, "snap", 2); __decorateClass([ property({ type: Number, attribute: "snap-threshold" }) ], SlSplitPanel.prototype, "snapThreshold", 2); __decorateClass([ watch("position") ], SlSplitPanel.prototype, "handlePositionChange", 1); __decorateClass([ watch("positionInPixels") ], SlSplitPanel.prototype, "handlePositionInPixelsChange", 1); __decorateClass([ watch("vertical") ], SlSplitPanel.prototype, "handleVerticalChange", 1); export { SlSplitPanel };