UNPKG

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
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: ` @for (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> @if (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: ` @for (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> @if (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