UNPKG

@progress/kendo-angular-layout

Version:

Kendo UI for Angular Layout Package - a collection of components to create professional application layoyts

332 lines (331 loc) 15.4 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ /* eslint-disable @typescript-eslint/no-explicit-any */ import { ChangeDetectorRef, Component, ElementRef, Host, HostBinding, Input, Renderer2 } from '@angular/core'; import { LocalizationService } from '@progress/kendo-angular-l10n'; import { DraggableDirective, Keys, isObjectPresent, parseAttributes, removeHTMLAttributes, setHTMLAttributes } from '@progress/kendo-angular-common'; import { SplitterService } from './splitter.service'; import { Subscription, of } from 'rxjs'; import { delay, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; import { shouldToggleOrResize } from './util'; import { caretAltDownIcon, caretAltLeftIcon, caretAltRightIcon, caretAltUpIcon } from '@progress/kendo-svg-icons'; import { IconWrapperComponent } from '@progress/kendo-angular-icons'; import { NgIf } from '@angular/common'; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-common"; import * as i2 from "@progress/kendo-angular-l10n"; import * as i3 from "./splitter.service"; const stopPropagation = ({ originalEvent: event }) => { event.stopPropagation(); event.preventDefault(); }; const preventOnDblClick = release => mouseDown => of(mouseDown).pipe(delay(150), takeUntil(release)); const classFromObject = classes => Object.keys(classes).filter(c => classes[c]).join(' '); const createMoveStream = (draggable) => mouseDown => draggable.kendoDrag .pipe(takeUntil(draggable.kendoRelease), map(({ pageX, pageY }) => ({ originalX: mouseDown.pageX, originalY: mouseDown.pageY, pageX, pageY }))); /** * @hidden */ export class SplitterBarComponent { draggable; localization; splitterService; element; renderer; cdr; ariaRole = 'separator'; ariaLabel = 'Splitter pane'; focused = false; get hostOrientation() { return this.orientation === 'horizontal' ? 'vertical' : 'horizontal'; } get tabIndex() { return this.splitterService.isStatic(this.index) ? -1 : 0; } get hostClasses() { const isHorizontal = this.orientation === 'horizontal'; const isDraggable = this.splitterService.isDraggable(this.index); const isStatic = this.splitterService.isStatic(this.index); return classFromObject({ 'k-focus': this.focused, 'k-splitbar': true, 'k-splitbar-horizontal': isHorizontal, 'k-splitbar-vertical': !isHorizontal, 'k-splitbar-draggable-horizontal': isHorizontal && isDraggable, 'k-splitbar-draggable-vertical': !isHorizontal && isDraggable, 'k-splitbar-static-horizontal': isHorizontal && isStatic, 'k-splitbar-static-vertical': !isHorizontal && isStatic, 'k-touch-action-none': isDraggable }); } get order() { return 2 * this.index + 1; } orientation = 'horizontal'; index = 0; set htmlAttributes(attributes) { if (isObjectPresent(this.parsedAttributes)) { removeHTMLAttributes(this.parsedAttributes, this.renderer, this.element.nativeElement); } this._htmlAttributes = attributes; this.parsedAttributes = this.htmlAttributes ? parseAttributes(this.htmlAttributes, this.defaultAttributes) : this.htmlAttributes; this.setHtmlAttributes(); } get htmlAttributes() { return this._htmlAttributes; } subscriptions = new Subscription(); _htmlAttributes; parsedAttributes = {}; get defaultAttributes() { return { 'aria-orientation': this.hostOrientation, role: this.ariaRole }; } get mutableAttributes() { return { 'tabindex': this.tabIndex }; } constructor(draggable, localization, splitterService, element, renderer, cdr) { this.draggable = draggable; this.localization = localization; this.splitterService = splitterService; this.element = element; this.renderer = renderer; this.cdr = cdr; } ngOnInit() { let state; const listener = this.draggable.kendoPress.pipe(tap(stopPropagation), filter(() => this.splitterService.isDraggable(this.index)), tap(() => state = this.splitterService.dragState(this.index)), tap(() => this.splitterService.toggleContentOverlay(this.index, true)), switchMap(preventOnDblClick(this.draggable.kendoRelease)), switchMap(createMoveStream(this.draggable))).subscribe(({ pageX, pageY, originalX, originalY }) => { let delta; if (this.orientation === 'vertical') { delta = pageY - originalY; } else if (this.direction === 'rtl') { delta = originalX - pageX; } else { delta = pageX - originalX; } this.splitterService.setSize(state, delta); }); this.subscriptions.add(listener); this.subscriptions.add(this.draggable.kendoRelease.subscribe(() => this.splitterService.toggleContentOverlay(this.index, false))); const element = this.element.nativeElement; this.subscriptions.add(this.renderer.listen(element, 'keydown', event => this.onKeyDown(event))); this.subscriptions.add(this.renderer.listen(element, 'focusin', () => this.focused = true)); this.subscriptions.add(this.renderer.listen(element, 'focusout', () => this.focused = false)); this.subscriptions.add(this.renderer.listen(element, 'dblclick', () => this.togglePane())); } ngOnDestroy() { if (this.subscriptions) { this.subscriptions.unsubscribe(); } } togglePrevious() { this.splitterService.tryToggle(this.index); } toggleNext() { this.splitterService.tryToggle(this.index + 1); } get direction() { return this.localization.rtl ? 'rtl' : 'ltr'; } shouldShowIcon(iconName) { const paneIndex = iconName === 'prev' ? this.index : this.index + 1; const relatedPaneIndex = iconName === 'prev' ? this.index + 1 : this.index; const pane = this.splitterService.pane(paneIndex); const relatedPane = this.splitterService.pane(relatedPaneIndex); const isCollapsible = pane?.collapsible; return isCollapsible && !relatedPane?.isHidden; } previousArrowClass() { const pane = this.splitterService.pane(this.index); const isCollapsible = pane?.collapsible; const isCollapsed = pane?.collapsed; const isHorizontal = this.orientation === 'horizontal'; const isRTL = this.direction === 'rtl'; return classFromObject({ 'caret-alt-left': isCollapsible && isHorizontal && ((!isCollapsed && !isRTL) || (isCollapsed && isRTL)), 'caret-alt-right': isCollapsible && isHorizontal && ((isCollapsed && !isRTL) || (!isCollapsed && isRTL)), 'caret-alt-up': isCollapsible && !isHorizontal && !isCollapsed, 'caret-alt-down': isCollapsible && !isHorizontal && isCollapsed }); } previousSVGArrowClass() { const pane = this.splitterService.pane(this.index); const isCollapsible = pane?.collapsible; const isCollapsed = pane?.collapsed; const isHorizontal = this.orientation === 'horizontal'; const isRTL = this.direction === 'rtl'; if (isCollapsible && isHorizontal && ((!isCollapsed && !isRTL) || (isCollapsed && isRTL))) { return caretAltLeftIcon; } if (isCollapsible && isHorizontal && ((isCollapsed && !isRTL) || (!isCollapsed && isRTL))) { return caretAltRightIcon; } if (isCollapsible && !isHorizontal && !isCollapsed) { return caretAltUpIcon; } if (isCollapsible && !isHorizontal && isCollapsed) { return caretAltDownIcon; } } nextArrowClass() { const pane = this.splitterService.pane(this.index + 1); const isCollapsible = pane?.collapsible; const isCollapsed = pane?.collapsed; const isHorizontal = this.orientation === 'horizontal'; const isRTL = this.direction === 'rtl'; return classFromObject({ 'caret-alt-right': isCollapsible && isHorizontal && ((!isCollapsed && !isRTL) || (isCollapsed && isRTL)), 'caret-alt-left': isCollapsible && isHorizontal && ((isCollapsed && !isRTL) || (!isCollapsed && isRTL)), 'caret-alt-down': isCollapsible && !isHorizontal && !isCollapsed, 'caret-alt-up': isCollapsible && !isHorizontal && isCollapsed }); } nextSVGArrowClass() { const pane = this.splitterService.pane(this.index + 1); const isCollapsible = pane?.collapsible; const isCollapsed = pane?.collapsed; const isHorizontal = this.orientation === 'horizontal'; const isRTL = this.direction === 'rtl'; if (isCollapsible && isHorizontal && ((!isCollapsed && !isRTL) || (isCollapsed && isRTL))) { return caretAltRightIcon; } if (isCollapsible && isHorizontal && ((isCollapsed && !isRTL) || (!isCollapsed && isRTL))) { return caretAltLeftIcon; } if (isCollapsible && !isHorizontal && !isCollapsed) { return caretAltDownIcon; } if (isCollapsible && !isHorizontal && isCollapsed) { return caretAltUpIcon; } } togglePane() { if (this.expandLast) { this.toggleNext(); } else { this.tryToggleNearest(); } this.cdr.markForCheck(); } get expandLast() { const panes = this.splitterService.panes; return panes.length === 2 && panes[1].collapsed; } onKeyDown(event) { const keyCode = event.keyCode; const shouldToggle = event.ctrlKey || event.metaKey; if (keyCode === Keys.Enter) { event.preventDefault(); this.togglePane(); } else if (shouldToggleOrResize(keyCode, this.orientation)) { event.preventDefault(); if (shouldToggle) { this.splitterService.togglePane(keyCode, this.index); } else { this.splitterService.resizePane(keyCode, this.index); } } } tryToggleNearest() { const prev = this.index; const next = this.index + 1; if (!this.splitterService.tryToggle(prev)) { this.splitterService.tryToggle(next); } } setHtmlAttributes() { const attributesToRender = { ...this.mutableAttributes, ...this.parsedAttributes }; setHTMLAttributes(attributesToRender, this.renderer, this.element.nativeElement); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SplitterBarComponent, deps: [{ token: i1.DraggableDirective, host: true }, { token: i2.LocalizationService }, { token: i3.SplitterService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SplitterBarComponent, isStandalone: true, selector: "kendo-splitter-bar", inputs: { orientation: "orientation", index: "index", htmlAttributes: "htmlAttributes" }, host: { properties: { "attr.role": "this.ariaRole", "attr.aria-label": "this.ariaLabel", "class.k-focus": "this.focused", "attr.aria-orientation": "this.hostOrientation", "attr.tabindex": "this.tabIndex", "class": "this.hostClasses", "style.-ms-flex-order": "this.order", "style.order": "this.order" } }, ngImport: i0, template: ` <div *ngIf="shouldShowIcon('prev')" class="k-collapse-prev" (click)="togglePrevious()"> <kendo-icon-wrapper size="xsmall" [name]="previousArrowClass()" [svgIcon]="previousSVGArrowClass()" ></kendo-icon-wrapper> </div> <div class="k-resize-handle"></div> <div *ngIf="shouldShowIcon('next')" class="k-collapse-next" (click)="toggleNext()"> <kendo-icon-wrapper size="xsmall" [name]="nextArrowClass()" [svgIcon]="nextSVGArrowClass()" ></kendo-icon-wrapper> </div> `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SplitterBarComponent, decorators: [{ type: Component, args: [{ selector: 'kendo-splitter-bar', template: ` <div *ngIf="shouldShowIcon('prev')" class="k-collapse-prev" (click)="togglePrevious()"> <kendo-icon-wrapper size="xsmall" [name]="previousArrowClass()" [svgIcon]="previousSVGArrowClass()" ></kendo-icon-wrapper> </div> <div class="k-resize-handle"></div> <div *ngIf="shouldShowIcon('next')" class="k-collapse-next" (click)="toggleNext()"> <kendo-icon-wrapper size="xsmall" [name]="nextArrowClass()" [svgIcon]="nextSVGArrowClass()" ></kendo-icon-wrapper> </div> `, standalone: true, imports: [NgIf, IconWrapperComponent] }] }], ctorParameters: function () { return [{ type: i1.DraggableDirective, decorators: [{ type: Host }] }, { type: i2.LocalizationService }, { type: i3.SplitterService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { ariaRole: [{ type: HostBinding, args: ['attr.role'] }], ariaLabel: [{ type: HostBinding, args: ['attr.aria-label'] }], focused: [{ type: HostBinding, args: ['class.k-focus'] }], hostOrientation: [{ type: HostBinding, args: ['attr.aria-orientation'] }], tabIndex: [{ type: HostBinding, args: ['attr.tabindex'] }], hostClasses: [{ type: HostBinding, args: ['class'] }], order: [{ type: HostBinding, args: ['style.-ms-flex-order'] }, { type: HostBinding, args: ['style.order'] }], orientation: [{ type: Input }], index: [{ type: Input }], htmlAttributes: [{ type: Input }] } });