primeng
Version:
PrimeNG is a premium UI library for Angular featuring a rich set of 90+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock,
854 lines (848 loc) • 41.7 kB
JavaScript
export * from 'primeng/types/splitter';
import { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
import * as i0 from '@angular/core';
import { Injectable, inject, input, numberAttribute, booleanAttribute, viewChild, ChangeDetectionStrategy, ViewEncapsulation, Component, output, contentChildren, computed, signal, effect, untracked, NgModule } from '@angular/core';
import { isRTL } from '@primeuix/utils';
import { SharedModule } from 'primeng/api';
import { BaseComponent, PARENT_INSTANCE } from 'primeng/basecomponent';
import * as i1 from 'primeng/bind';
import { Bind, BindModule } from 'primeng/bind';
import { style } from '@primeuix/styles/splitter';
import { BaseStyle } from 'primeng/base';
const classes = {
root: ({ instance }) => ['p-splitter p-component', 'p-splitter-' + instance.layout()],
panel: 'p-splitter-panel',
gutter: 'p-splitter-gutter',
gutterHandle: 'p-splitter-gutter-handle'
};
class SplitterStyle extends BaseStyle {
name = 'splitter';
style = style;
classes = classes;
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SplitterStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SplitterStyle });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SplitterStyle, decorators: [{
type: Injectable
}] });
/**
*
* Splitter is utilized to separate and resize panels.
*
* [Live Demo](https://www.primeng.org/splitter/)
*
* @module splitterstyle
*
*/
var SplitterClasses;
(function (SplitterClasses) {
/**
* Class name of the root element
*/
SplitterClasses["root"] = "p-splitter";
/**
* Class name of the panel element
*/
SplitterClasses["panel"] = "p-splitter-panel";
/**
* Class name of the gutter element
*/
SplitterClasses["gutter"] = "p-splitter-gutter";
/**
* Class name of the handle element
*/
SplitterClasses["gutterHandle"] = "p-splitter-gutter-handle";
})(SplitterClasses || (SplitterClasses = {}));
/**
* SplitterPanel is a helper component for Splitter, used to define a single resizable panel
* together with its size constraints (min/max size, collapsible behavior).
* @group Components
*/
class SplitterPanel extends BaseComponent {
componentName = 'SplitterPanel';
bindDirectiveInstance = inject(Bind, { self: true });
/**
* Initial size of the panel relative to 100%.
* @group Props
*/
size = input(undefined, { ...(ngDevMode ? { debugName: "size" } : /* istanbul ignore next */ {}), transform: (value) => (value == null ? undefined : numberAttribute(value)) });
/**
* Minimum size of the panel relative to 100%.
* @defaultValue 0
* @group Props
*/
minSize = input(0, { ...(ngDevMode ? { debugName: "minSize" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Maximum size of the panel relative to 100%.
* @defaultValue 100
* @group Props
*/
maxSize = input(100, { ...(ngDevMode ? { debugName: "maxSize" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* When enabled, the panel can collapse below its `minSize` down to `collapsedSize`.
* @defaultValue false
* @group Props
*/
collapsible = input(false, { ...(ngDevMode ? { debugName: "collapsible" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Size of the panel when collapsed, relative to 100%.
* @defaultValue 0
* @group Props
*/
collapsedSize = input(0, { ...(ngDevMode ? { debugName: "collapsedSize" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* @ignore
* Content of the panel, stamped by the parent Splitter into the panel wrapper.
*/
contentTemplate = viewChild('content', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "contentTemplate" }] : /* istanbul ignore next */ []));
/**
* @ignore
* `class`/`style` set directly on the `<p-splitterpanel>` element are forwarded by the parent
* Splitter onto the panel it renders, so authors can style the panel inline as expected.
*/
get hostClass() {
return this.el.nativeElement.className;
}
get hostStyle() {
return this.el.nativeElement.getAttribute('style');
}
_componentStyle = inject(SplitterStyle);
onAfterViewChecked() {
this.bindDirectiveInstance.setAttrs(this.ptm('root'));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SplitterPanel, deps: null, target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.6", type: SplitterPanel, isStandalone: true, selector: "p-splitterpanel, p-splitter-panel", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, minSize: { classPropertyName: "minSize", publicName: "minSize", isSignal: true, isRequired: false, transformFunction: null }, maxSize: { classPropertyName: "maxSize", publicName: "maxSize", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsedSize: { classPropertyName: "collapsedSize", publicName: "collapsedSize", isSignal: true, isRequired: false, transformFunction: null } }, providers: [SplitterStyle, { provide: PARENT_INSTANCE, useExisting: SplitterPanel }], viewQueries: [{ propertyName: "contentTemplate", first: true, predicate: ["content"], descendants: true, isSignal: true }], usesInheritance: true, hostDirectives: [{ directive: i1.Bind }], ngImport: i0, template: `
<ng-template #content>
<ng-content></ng-content>
</ng-template>
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SplitterPanel, decorators: [{
type: Component,
args: [{
selector: 'p-splitterpanel, p-splitter-panel',
standalone: true,
template: `
<ng-template #content>
<ng-content></ng-content>
</ng-template>
`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
hostDirectives: [Bind],
providers: [SplitterStyle, { provide: PARENT_INSTANCE, useExisting: SplitterPanel }]
}]
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], minSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSize", required: false }] }], maxSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSize", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsedSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedSize", required: false }] }], contentTemplate: [{ type: i0.ViewChild, args: ['content', { isSignal: true }] }] } });
/**
* Splitter is utilized to separate and resize panels.
* @group Components
*/
class Splitter extends BaseComponent {
componentName = 'Splitter';
bindDirectiveInstance = inject(Bind, { self: true });
/**
* Style class of the component.
* @group Props
*/
styleClass = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "styleClass" }] : /* istanbul ignore next */ []));
/**
* Style class of the panel.
* @group Props
*/
panelStyleClass = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "panelStyleClass" }] : /* istanbul ignore next */ []));
/**
* Inline style of the panel.
* @group Props
*/
panelStyle = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "panelStyle" }] : /* istanbul ignore next */ []));
/**
* Defines where a stateful splitter keeps its state, valid values are 'session' for sessionStorage and 'local' for localStorage.
* @group Props
*/
stateStorage = input('session', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "stateStorage" }] : /* istanbul ignore next */ []));
/**
* Storage identifier of a stateful Splitter.
* @group Props
*/
stateKey = input(null, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "stateKey" }] : /* istanbul ignore next */ []));
/**
* Orientation of the panels. Valid values are 'horizontal' and 'vertical'.
* @group Props
*/
layout = input('horizontal', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
/**
* Size of the divider in pixels.
* @group Props
*/
gutterSize = input(1, { ...(ngDevMode ? { debugName: "gutterSize" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Step factor to increment/decrement the size of the panels while pressing the arrow keys.
* @group Props
*/
step = input(5, { ...(ngDevMode ? { debugName: "step" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Minimum size of the elements relative to 100%. Used when panels are defined via `#panel` templates;
* when SplitterPanel components are used, the per-panel `minSize` input takes precedence.
* @group Props
*/
minSizes = input([], /* @ts-ignore */
...(ngDevMode ? [{ debugName: "minSizes" }] : /* istanbul ignore next */ []));
/**
* Size of the elements relative to 100%. Used when panels are defined via `#panel` templates;
* when SplitterPanel components are used, the per-panel `size` input takes precedence.
* @group Props
*/
panelSizes = input([], /* @ts-ignore */
...(ngDevMode ? [{ debugName: "panelSizes" }] : /* istanbul ignore next */ []));
/**
* When present, it disables the component and prevents resizing.
* @defaultValue false
* @group Props
*/
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Callback to invoke when resize ends.
* @param {SplitterResizeEndEvent} event - Custom panel resize end event
* @group Emits
*/
onResizeEnd = output();
/**
* Callback to invoke when resize starts.
* @param {SplitterResizeStartEvent} event - Custom panel resize start event
* @group Emits
*/
onResizeStart = output();
/**
* Callback to invoke continuously while a gutter is being dragged.
* @param {SplitterResizeEvent} event - Custom panel resize event
* @group Emits
*/
onResize = output();
/**
* Callback to invoke when a collapsible panel collapses or expands.
* @param {SplitterCollapseEvent} event - Custom collapse event
* @group Emits
*/
onCollapse = output();
/**
* Panels declared via SplitterPanel components.
* @ignore
*/
panelComponents = contentChildren(SplitterPanel, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "panelComponents" }] : /* istanbul ignore next */ []));
/**
* Panels declared via `<ng-template #panel>` (backward compatible API).
* @ignore
*/
panelChildren = contentChildren('panel', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "panelChildren" }] : /* istanbul ignore next */ []));
/**
* Resolved panel content templates, sourced from SplitterPanel components when present,
* otherwise from `#panel` templates.
*/
panels = computed(() => {
const components = this.panelComponents();
if (components && components.length) {
const templates = components.map((panel) => panel.contentTemplate());
return templates.every((template) => !!template) ? templates : [];
}
return [...this.panelChildren()];
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "panels" }] : /* istanbul ignore next */ []));
/**
* Resolved per-panel configuration (min/max/collapsible/collapsedSize/size).
*/
panelMetas = computed(() => {
const components = this.panelComponents();
if (components && components.length) {
return components.map((panel) => ({
minSize: panel.minSize() ?? 0,
maxSize: panel.maxSize() ?? 100,
collapsible: panel.collapsible() ?? false,
collapsedSize: panel.collapsedSize() ?? 0,
size: panel.size()
}));
}
const count = this.panelChildren().length;
const minSizes = this.minSizes();
const panelSizes = this.panelSizes();
return Array.from({ length: count }, (_, i) => ({
minSize: minSizes[i] ?? 0,
maxSize: 100,
collapsible: false,
collapsedSize: 0,
size: panelSizes[i]
}));
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "panelMetas" }] : /* istanbul ignore next */ []));
/**
* Value-based signature of the panel configuration. Lets the (re)initialization effect ignore
* array-literal input bindings that change identity but not value on every parent change detection.
*/
panelSignature = computed(() => {
const metaSig = this.panelMetas()
.map((meta) => `${meta.size ?? ''}:${meta.minSize}:${meta.maxSize}:${meta.collapsible}:${meta.collapsedSize}`)
.join(',');
return `${metaSig}#${this.panelSizes().join(',')}`;
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "panelSignature" }] : /* istanbul ignore next */ []));
/**
* Class for each panel wrapper: the base panel class plus the splitter-level `panelStyleClass`
* and the `class` set directly on the matching SplitterPanel.
*/
panelClass = computed(() => {
const components = this.panelComponents();
const base = this.cn(this.cx('panel'), this.panelStyleClass());
return this.panels().map((_, i) => this.cn(base, components[i]?.hostClass));
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "panelClass" }] : /* istanbul ignore next */ []));
/**
* Inline style for each panel wrapper: the `style` set directly on the matching SplitterPanel,
* falling back to the splitter-level `panelStyle`.
*/
panelInlineStyle = computed(() => {
const components = this.panelComponents();
const fallback = this.panelStyle();
return this.panels().map((_, i) => components[i]?.hostStyle ?? fallback);
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "panelInlineStyle" }] : /* istanbul ignore next */ []));
dragging = false;
isResizing = signal(false, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "isResizing" }] : /* istanbul ignore next */ []));
resizingIndex = signal(null, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "resizingIndex" }] : /* istanbul ignore next */ []));
collapsed = signal([], /* @ts-ignore */
...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
/**
* Flex values applied to each panel wrapper, e.g. `35 1 0px`. Bound declaratively so panel sizing
* never depends on imperative DOM timing.
*/
panelFlex = signal([], /* @ts-ignore */
...(ngDevMode ? [{ debugName: "panelFlex" }] : /* istanbul ignore next */ []));
dataResizing = computed(() => (this.isResizing() ? '' : null), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "dataResizing" }] : /* istanbul ignore next */ []));
pointerMoveListener;
pointerUpListener;
size;
gutterElement;
startPos;
_panelSizes = [];
panelRegistry = [];
initialSizes = [];
initialCollapsed = [];
reportedCollapsed = [];
initialTotal = 100;
prevPanelIndex;
timer;
prevSize;
_componentStyle = inject(SplitterStyle);
rootClass = computed(() => this.cn(this.cx('root'), this.styleClass()), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "rootClass" }] : /* istanbul ignore next */ []));
constructor() {
super();
effect(() => {
// Re-initialize whenever the set of panels or their (value-based) size configuration changes.
const panels = this.panels();
this.panelSignature();
if (!isPlatformBrowser(this.platformId) || panels.length === 0) {
return;
}
// Never clobber sizes mid-drag; the resizing flag is read untracked so ending a drag
// does not by itself re-trigger initialization.
if (untracked(() => this.isResizing())) {
return;
}
this.initializePanels();
});
}
onAfterViewChecked() {
this.bindDirectiveInstance.setAttrs(this.ptms(['host', 'root']));
}
buildPanelRegistry() {
const metas = this.panelMetas();
const prev = this.panelRegistry ?? [];
this.panelRegistry = metas.map((meta, i) => ({
index: i,
minSize: meta.minSize ?? 0,
maxSize: meta.maxSize ?? 100,
collapsible: meta.collapsible ?? false,
collapsedSize: meta.collapsedSize ?? 0,
size: meta.size,
collapsed: prev[i]?.collapsed ?? false
}));
}
initializePanels() {
const panels = this.panels();
if (!panels.length) {
return;
}
this.buildPanelRegistry();
let initialized = false;
if (this.isStateful()) {
initialized = this.restoreState();
}
if (!initialized) {
const _panelSizes = [];
const inputPanelSizes = this.panelSizes();
panels.forEach((_, i) => {
const meta = this.panelRegistry[i];
// Splitter-level `panelSizes` takes precedence, then the panel's own `size`, then an equal split.
_panelSizes[i] = inputPanelSizes[i] ?? meta?.size ?? 100 / panels.length;
});
this.panelRegistry.forEach((info, i) => {
if (info?.collapsible) {
info.collapsed = _panelSizes[i] <= (info.collapsedSize ?? 0);
}
});
this._panelSizes = _panelSizes;
this.prevSize = parseFloat(String(_panelSizes[0])).toFixed(4);
}
this.syncCollapsedState();
this.updateFlex();
}
updateFlex() {
this.panelFlex.set(this._panelSizes.map((panelSize) => panelSize + ' 1 0px'));
}
syncCollapsedState() {
this.collapsed.set(this.panelRegistry.map((info) => info.collapsed));
}
getPanelMinSize(index) {
return this.panelRegistry?.[index]?.minSize ?? 0;
}
getPanelMaxSize(index) {
return this.panelRegistry?.[index]?.maxSize ?? 100;
}
resizeStart(event, index, isKeyDown) {
const currentTarget = event.currentTarget || event.target;
if (currentTarget) {
this.gutterElement = currentTarget;
}
const panelElements = this.el.nativeElement.querySelectorAll(':scope > [data-index]');
let totalPanelPx = 0;
for (const el of panelElements) {
const rect = el.getBoundingClientRect();
totalPanelPx += this.horizontal() ? rect.width : rect.height;
}
this.size = totalPanelPx;
if (!isKeyDown) {
const pointerEvent = event;
this.dragging = true;
this.startPos = this.horizontal() ? pointerEvent.pageX : pointerEvent.pageY;
this.isResizing.set(true);
this.resizingIndex.set(index);
}
this.initialSizes = [...this._panelSizes];
this.initialCollapsed = this.panelRegistry.map((info) => info.collapsed);
this.reportedCollapsed = this.panelRegistry.map((info) => info.collapsed);
this.initialTotal = this.initialSizes.reduce((a, b) => a + b, 0) || 100;
this.prevPanelIndex = index;
if (!isKeyDown) {
this.onResizeStart.emit({ originalEvent: event, sizes: [...this._panelSizes] });
}
}
onResizeMove(event, step, isKeyDown) {
if (this.size === null || this.prevPanelIndex === null || this.initialSizes.length === 0) {
return;
}
const gutterIdx = this.prevPanelIndex;
const total = this.initialTotal;
let delta;
if (isKeyDown) {
delta = (total * (step ?? 0)) / this.size;
}
else {
const pointerEvent = event;
const pos = this.horizontal() ? pointerEvent.pageX : pointerEvent.pageY;
if (this.horizontal() && isRTL(this.el.nativeElement)) {
delta = (((this.startPos ?? 0) - pos) * total) / this.size;
}
else {
delta = ((pos - (this.startPos ?? 0)) * total) / this.size;
}
}
const newSizes = [...this.initialSizes];
this.panelRegistry.forEach((info, i) => {
if (this.initialCollapsed[i] !== undefined) {
info.collapsed = this.initialCollapsed[i];
}
});
if (delta > 0) {
this.distribute(newSizes, gutterIdx, delta, isKeyDown, 'forward');
}
else if (delta < 0) {
this.distribute(newSizes, gutterIdx + 1, -delta, isKeyDown, 'backward');
}
this.panelRegistry.forEach((info, i) => {
if (info.collapsed !== this.reportedCollapsed[i]) {
this.reportedCollapsed[i] = info.collapsed;
this.onCollapse.emit({ index: i, collapsed: info.collapsed, sizes: [...newSizes] });
}
});
this._panelSizes = newSizes;
this.prevSize = newSizes[gutterIdx].toFixed(4);
this.updateFlex();
this.syncCollapsedState();
this.onResize.emit({ originalEvent: event, sizes: [...newSizes] });
}
distribute(newSizes, growIdx, requested, isKeyDown, direction) {
const growInfo = this.panelRegistry[growIdx];
const max = this.getPanelMaxSize(growIdx);
let toGrow = Math.min(requested, Math.max(0, max - newSizes[growIdx]));
if (growInfo?.collapsible && growInfo.collapsed) {
// Re-open symmetrically: any outward drag/step pops a collapsed panel back to (at least) its minimum size.
const gapSize = this.getPanelMinSize(growIdx) - growInfo.collapsedSize;
toGrow = Math.max(toGrow, gapSize);
toGrow = Math.min(toGrow, Math.max(0, max - newSizes[growIdx]));
}
let shrunk = 0;
const range = direction === 'forward' ? this.range(growIdx + 1, newSizes.length, 1) : this.range(growIdx - 1, -1, -1);
for (const i of range) {
if (shrunk >= toGrow)
break;
const info = this.panelRegistry[i];
const min = this.getPanelMinSize(i);
if (info?.collapsed)
continue;
const effectiveMin = info?.collapsible ? (info.collapsedSize ?? 0) : min;
const available = Math.max(0, newSizes[i] - effectiveMin);
const amount = Math.min(toGrow - shrunk, available);
const rawSize = newSizes[i] - amount;
const validated = this.validatePanelSize(rawSize, info, min, isKeyDown);
const actualShrunk = newSizes[i] - validated.size;
newSizes[i] = validated.size;
shrunk += actualShrunk;
if (info)
info.collapsed = validated.collapsed;
}
newSizes[growIdx] += shrunk;
if (growInfo?.collapsible && growInfo.collapsed && newSizes[growIdx] >= this.getPanelMinSize(growIdx)) {
growInfo.collapsed = false;
}
}
validatePanelSize(rawSize, info, min, isKeyDown) {
if (!info?.collapsible) {
return { size: Math.max(rawSize, min), collapsed: false };
}
const collapsedSize = info.collapsedSize ?? 0;
if (rawSize >= min) {
return { size: rawSize, collapsed: false };
}
// The panel stops shrinking at its minimum size; the moment the user keeps dragging (or
// stepping) past that minimum, a collapsible panel snaps to its collapsed state.
return { size: collapsedSize, collapsed: true };
}
range(start, end, step) {
const out = [];
for (let i = start; step > 0 ? i < end : i > end; i += step)
out.push(i);
return out;
}
resizeEnd(event) {
if (this.isStateful()) {
this.saveState();
}
this.onResizeEnd.emit({ originalEvent: event, sizes: [...this._panelSizes] });
this.isResizing.set(false);
this.resizingIndex.set(null);
this.updateFlex();
this.clear();
}
onGutterPointerDown(event, index) {
if (this.disabled()) {
return;
}
this.resizeStart(event, index);
this.bindPointerListeners();
}
repeat(event, index, step) {
this.resizeStart(event, index, true);
this.onResizeMove(event, step, true);
}
setTimer(event, index, step) {
if (!this.timer) {
this.onResizeStart.emit({ originalEvent: event, sizes: [...this._panelSizes] });
this.repeat(event, index, step);
this.timer = setInterval(() => {
this.repeat(event, index, step);
}, 40);
}
}
clearTimer() {
if (this.timer) {
clearInterval(this.timer);
this.timer = undefined;
}
}
onGutterKeyUp(event) {
if (!this.timer)
return;
this.clearTimer();
this.resizeEnd(event);
}
onGutterKeyDown(event, index) {
if (this.disabled()) {
return;
}
switch (event.code) {
case 'ArrowLeft': {
if (this.layout() === 'horizontal') {
this.setTimer(event, index, this.step() * -1);
}
event.preventDefault();
break;
}
case 'ArrowRight': {
if (this.layout() === 'horizontal') {
this.setTimer(event, index, this.step());
}
event.preventDefault();
break;
}
case 'ArrowDown': {
if (this.layout() === 'vertical') {
this.setTimer(event, index, this.step());
}
event.preventDefault();
break;
}
case 'ArrowUp': {
if (this.layout() === 'vertical') {
this.setTimer(event, index, this.step() * -1);
}
event.preventDefault();
break;
}
default:
//no op
break;
}
}
bindPointerListeners() {
if (!this.pointerMoveListener) {
this.pointerMoveListener = this.renderer.listen(this.document, 'pointermove', (event) => {
this.onResizeMove(event);
});
}
if (!this.pointerUpListener) {
this.pointerUpListener = this.renderer.listen(this.document, 'pointerup', (event) => {
this.resizeEnd(event);
this.unbindPointerListeners();
});
}
}
unbindPointerListeners() {
if (this.pointerMoveListener) {
this.pointerMoveListener();
this.pointerMoveListener = null;
}
if (this.pointerUpListener) {
this.pointerUpListener();
this.pointerUpListener = null;
}
}
clear() {
this.dragging = false;
this.size = null;
this.startPos = null;
this.initialSizes = [];
this.initialCollapsed = [];
this.reportedCollapsed = [];
this.initialTotal = 100;
this.gutterElement = null;
this.prevPanelIndex = null;
}
isStateful() {
return this.stateKey() != null;
}
getStorage() {
if (isPlatformBrowser(this.platformId)) {
switch (this.stateStorage()) {
case 'local':
return this.document.defaultView?.localStorage;
case 'session':
return this.document.defaultView?.sessionStorage;
default:
throw new Error(this.stateStorage() + ' is not a valid value for the state storage, supported values are "local" and "session".');
}
}
else {
throw new Error('Storage is not a available by default on the server.');
}
}
saveState() {
this.getStorage()?.setItem(this.stateKey(), JSON.stringify(this._panelSizes));
}
restoreState() {
const storage = this.getStorage();
const stateString = storage?.getItem(this.stateKey());
if (stateString) {
this._panelSizes = JSON.parse(stateString);
this.panelRegistry.forEach((info, i) => {
if (info?.collapsible) {
info.collapsed = this._panelSizes[i] <= (info.collapsedSize ?? 0);
}
});
this.prevSize = parseFloat(String(this._panelSizes[0])).toFixed(4);
return true;
}
return false;
}
/**
* Resets the panel sizes using the stored state (for a stateful Splitter), the configured
* sizes, or the default equal distribution.
*/
resetState() {
this.initializePanels();
}
gutterInlineStyle() {
return {
'touch-action': 'none',
'user-select': 'none',
...(this.horizontal() ? { width: this.gutterSize() + 'px' } : { height: this.gutterSize() + 'px' })
};
}
horizontal() {
return this.layout() === 'horizontal';
}
round(value) {
return Math.round(value ?? 0);
}
onDestroy() {
this.unbindPointerListeners();
this.clearTimer();
}
dataP = computed(() => {
return this.cn({
[this.layout()]: this.layout(),
resizing: this.isResizing(),
disabled: this.disabled()
});
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "dataP" }] : /* istanbul ignore next */ []));
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: Splitter, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: Splitter, isStandalone: true, selector: "p-splitter", inputs: { styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, panelStyleClass: { classPropertyName: "panelStyleClass", publicName: "panelStyleClass", isSignal: true, isRequired: false, transformFunction: null }, panelStyle: { classPropertyName: "panelStyle", publicName: "panelStyle", isSignal: true, isRequired: false, transformFunction: null }, stateStorage: { classPropertyName: "stateStorage", publicName: "stateStorage", isSignal: true, isRequired: false, transformFunction: null }, stateKey: { classPropertyName: "stateKey", publicName: "stateKey", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, gutterSize: { classPropertyName: "gutterSize", publicName: "gutterSize", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, minSizes: { classPropertyName: "minSizes", publicName: "minSizes", isSignal: true, isRequired: false, transformFunction: null }, panelSizes: { classPropertyName: "panelSizes", publicName: "panelSizes", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onResizeEnd: "onResizeEnd", onResizeStart: "onResizeStart", onResize: "onResize", onCollapse: "onCollapse" }, host: { properties: { "class": "rootClass()", "attr.data-orientation": "layout()", "attr.data-resizing": "dataResizing()", "attr.data-disabled": "disabled() ? '' : null", "attr.data-p": "dataP()" } }, providers: [SplitterStyle, { provide: PARENT_INSTANCE, useExisting: Splitter }], queries: [{ propertyName: "panelComponents", predicate: SplitterPanel, isSignal: true }, { propertyName: "panelChildren", predicate: ["panel"], isSignal: true }], usesInheritance: true, hostDirectives: [{ directive: i1.Bind }], ngImport: i0, template: `
(panel of panels(); track $index; let i = $index) {
<div
[pBind]="ptm('panel')"
[class]="panelClass()[i]"
[style]="panelInlineStyle()[i]"
[style.flex]="panelFlex()[i]"
[style.overflow]="'hidden'"
[style.min-width]="layout() === 'horizontal' ? '0' : null"
[style.min-height]="layout() === 'vertical' ? '0' : null"
tabindex="-1"
[attr.data-index]="i"
[attr.data-collapsed]="collapsed()[i] ? '' : null"
[attr.data-resizing]="isResizing() && resizingIndex() === i ? '' : null"
>
<ng-container *ngTemplateOutlet="panel"></ng-container>
</div>
(i !== panels().length - 1) {
<div
[pBind]="ptm('gutter')"
[class]="cx('gutter')"
role="separator"
[attr.tabindex]="disabled() ? -1 : 0"
[attr.aria-orientation]="layout()"
[attr.aria-valuenow]="prevSize"
[attr.aria-valuemin]="round(panelMetas()[i]?.minSize)"
[attr.aria-valuemax]="round(100 - (panelMetas()[i + 1]?.minSize ?? 0))"
[attr.aria-disabled]="disabled() || null"
[attr.data-orientation]="layout()"
[attr.data-resizing]="isResizing() && resizingIndex() === i ? '' : null"
[attr.data-disabled]="disabled() ? '' : null"
[style]="gutterInlineStyle()"
(pointerdown)="onGutterPointerDown($event, i)"
(keyup)="onGutterKeyUp($event)"
(keydown)="onGutterKeyDown($event, i)"
>
<div [pBind]="ptm('gutterHandle')" [class]="cx('gutterHandle')" [attr.data-orientation]="layout()" [attr.data-resizing]="isResizing() && resizingIndex() === i ? '' : null"></div>
</div>
}
}
`, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: SharedModule }, { kind: "ngmodule", type: BindModule }, { kind: "directive", type: i1.Bind, selector: "[pBind]", inputs: ["pBind"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: Splitter, decorators: [{
type: Component,
args: [{
selector: 'p-splitter',
standalone: true,
imports: [NgTemplateOutlet, SharedModule, BindModule],
template: `
(panel of panels(); track $index; let i = $index) {
<div
[pBind]="ptm('panel')"
[class]="panelClass()[i]"
[style]="panelInlineStyle()[i]"
[style.flex]="panelFlex()[i]"
[style.overflow]="'hidden'"
[style.min-width]="layout() === 'horizontal' ? '0' : null"
[style.min-height]="layout() === 'vertical' ? '0' : null"
tabindex="-1"
[attr.data-index]="i"
[attr.data-collapsed]="collapsed()[i] ? '' : null"
[attr.data-resizing]="isResizing() && resizingIndex() === i ? '' : null"
>
<ng-container *ngTemplateOutlet="panel"></ng-container>
</div>
(i !== panels().length - 1) {
<div
[pBind]="ptm('gutter')"
[class]="cx('gutter')"
role="separator"
[attr.tabindex]="disabled() ? -1 : 0"
[attr.aria-orientation]="layout()"
[attr.aria-valuenow]="prevSize"
[attr.aria-valuemin]="round(panelMetas()[i]?.minSize)"
[attr.aria-valuemax]="round(100 - (panelMetas()[i + 1]?.minSize ?? 0))"
[attr.aria-disabled]="disabled() || null"
[attr.data-orientation]="layout()"
[attr.data-resizing]="isResizing() && resizingIndex() === i ? '' : null"
[attr.data-disabled]="disabled() ? '' : null"
[style]="gutterInlineStyle()"
(pointerdown)="onGutterPointerDown($event, i)"
(keyup)="onGutterKeyUp($event)"
(keydown)="onGutterKeyDown($event, i)"
>
<div [pBind]="ptm('gutterHandle')" [class]="cx('gutterHandle')" [attr.data-orientation]="layout()" [attr.data-resizing]="isResizing() && resizingIndex() === i ? '' : null"></div>
</div>
}
}
`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
'[class]': 'rootClass()',
'[attr.data-orientation]': 'layout()',
'[attr.data-resizing]': 'dataResizing()',
'[attr.data-disabled]': "disabled() ? '' : null",
'[attr.data-p]': 'dataP()'
},
providers: [SplitterStyle, { provide: PARENT_INSTANCE, useExisting: Splitter }],
hostDirectives: [Bind]
}]
}], ctorParameters: () => [], propDecorators: { styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }], panelStyleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelStyleClass", required: false }] }], panelStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelStyle", required: false }] }], stateStorage: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateStorage", required: false }] }], stateKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateKey", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], gutterSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "gutterSize", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], minSizes: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSizes", required: false }] }], panelSizes: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelSizes", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], onResizeEnd: [{ type: i0.Output, args: ["onResizeEnd"] }], onResizeStart: [{ type: i0.Output, args: ["onResizeStart"] }], onResize: [{ type: i0.Output, args: ["onResize"] }], onCollapse: [{ type: i0.Output, args: ["onCollapse"] }], panelComponents: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SplitterPanel), { isSignal: true }] }], panelChildren: [{ type: i0.ContentChildren, args: ['panel', { isSignal: true }] }] } });
class SplitterModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SplitterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: SplitterModule, imports: [Splitter, SplitterPanel, SharedModule, BindModule], exports: [Splitter, SplitterPanel, SharedModule, BindModule] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SplitterModule, imports: [Splitter, SharedModule, BindModule, SharedModule, BindModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SplitterModule, decorators: [{
type: NgModule,
args: [{
imports: [Splitter, SplitterPanel, SharedModule, BindModule],
exports: [Splitter, SplitterPanel, SharedModule, BindModule]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { Splitter, SplitterClasses, SplitterModule, SplitterPanel, SplitterStyle };
//# sourceMappingURL=primeng-splitter.mjs.map