@ngneers/controls 0.0.1-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/ngneers-controls-accordion.mjs +234 -0
- package/fesm2022/ngneers-controls-accordion.mjs.map +1 -0
- package/fesm2022/ngneers-controls-api-ng.mjs +959 -0
- package/fesm2022/ngneers-controls-api-ng.mjs.map +1 -0
- package/fesm2022/ngneers-controls-api-resize.mjs +712 -0
- package/fesm2022/ngneers-controls-api-resize.mjs.map +1 -0
- package/fesm2022/ngneers-controls-api.mjs +347 -0
- package/fesm2022/ngneers-controls-api.mjs.map +1 -0
- package/fesm2022/ngneers-controls-avatar.mjs +77 -0
- package/fesm2022/ngneers-controls-avatar.mjs.map +1 -0
- package/fesm2022/ngneers-controls-base.mjs +620 -0
- package/fesm2022/ngneers-controls-base.mjs.map +1 -0
- package/fesm2022/ngneers-controls-breadcrumb.mjs +100 -0
- package/fesm2022/ngneers-controls-breadcrumb.mjs.map +1 -0
- package/fesm2022/ngneers-controls-button-group.mjs +110 -0
- package/fesm2022/ngneers-controls-button-group.mjs.map +1 -0
- package/fesm2022/ngneers-controls-button.mjs +83 -0
- package/fesm2022/ngneers-controls-button.mjs.map +1 -0
- package/fesm2022/ngneers-controls-calendar-time-CJT5AFlA.mjs +74 -0
- package/fesm2022/ngneers-controls-calendar-time-CJT5AFlA.mjs.map +1 -0
- package/fesm2022/ngneers-controls-calendar.mjs +801 -0
- package/fesm2022/ngneers-controls-calendar.mjs.map +1 -0
- package/fesm2022/ngneers-controls-checkbox.mjs +63 -0
- package/fesm2022/ngneers-controls-checkbox.mjs.map +1 -0
- package/fesm2022/ngneers-controls-chip.mjs +55 -0
- package/fesm2022/ngneers-controls-chip.mjs.map +1 -0
- package/fesm2022/ngneers-controls-default-icons.mjs +82 -0
- package/fesm2022/ngneers-controls-default-icons.mjs.map +1 -0
- package/fesm2022/ngneers-controls-defer.mjs +72 -0
- package/fesm2022/ngneers-controls-defer.mjs.map +1 -0
- package/fesm2022/ngneers-controls-dialog.mjs +407 -0
- package/fesm2022/ngneers-controls-dialog.mjs.map +1 -0
- package/fesm2022/ngneers-controls-directives.mjs +498 -0
- package/fesm2022/ngneers-controls-directives.mjs.map +1 -0
- package/fesm2022/ngneers-controls-drawer.mjs +271 -0
- package/fesm2022/ngneers-controls-drawer.mjs.map +1 -0
- package/fesm2022/ngneers-controls-edit-inplace.mjs +127 -0
- package/fesm2022/ngneers-controls-edit-inplace.mjs.map +1 -0
- package/fesm2022/ngneers-controls-errors.mjs +329 -0
- package/fesm2022/ngneers-controls-errors.mjs.map +1 -0
- package/fesm2022/ngneers-controls-filter.mjs +708 -0
- package/fesm2022/ngneers-controls-filter.mjs.map +1 -0
- package/fesm2022/ngneers-controls-hint.mjs +153 -0
- package/fesm2022/ngneers-controls-hint.mjs.map +1 -0
- package/fesm2022/ngneers-controls-i18n-translations-de.mjs +170 -0
- package/fesm2022/ngneers-controls-i18n-translations-de.mjs.map +1 -0
- package/fesm2022/ngneers-controls-i18n-translations-en.mjs +170 -0
- package/fesm2022/ngneers-controls-i18n-translations-en.mjs.map +1 -0
- package/fesm2022/ngneers-controls-i18n.mjs +57 -0
- package/fesm2022/ngneers-controls-i18n.mjs.map +1 -0
- package/fesm2022/ngneers-controls-icon.mjs +195 -0
- package/fesm2022/ngneers-controls-icon.mjs.map +1 -0
- package/fesm2022/ngneers-controls-inplace.mjs +150 -0
- package/fesm2022/ngneers-controls-inplace.mjs.map +1 -0
- package/fesm2022/ngneers-controls-input-field.mjs +165 -0
- package/fesm2022/ngneers-controls-input-field.mjs.map +1 -0
- package/fesm2022/ngneers-controls-input.mjs +72 -0
- package/fesm2022/ngneers-controls-input.mjs.map +1 -0
- package/fesm2022/ngneers-controls-item-view.mjs +473 -0
- package/fesm2022/ngneers-controls-item-view.mjs.map +1 -0
- package/fesm2022/ngneers-controls-list-box.mjs +281 -0
- package/fesm2022/ngneers-controls-list-box.mjs.map +1 -0
- package/fesm2022/ngneers-controls-mask-input.mjs +888 -0
- package/fesm2022/ngneers-controls-mask-input.mjs.map +1 -0
- package/fesm2022/ngneers-controls-menu.mjs +371 -0
- package/fesm2022/ngneers-controls-menu.mjs.map +1 -0
- package/fesm2022/ngneers-controls-message.mjs +30 -0
- package/fesm2022/ngneers-controls-message.mjs.map +1 -0
- package/fesm2022/ngneers-controls-number-input.mjs +366 -0
- package/fesm2022/ngneers-controls-number-input.mjs.map +1 -0
- package/fesm2022/ngneers-controls-paginator.mjs +129 -0
- package/fesm2022/ngneers-controls-paginator.mjs.map +1 -0
- package/fesm2022/ngneers-controls-popover.mjs +215 -0
- package/fesm2022/ngneers-controls-popover.mjs.map +1 -0
- package/fesm2022/ngneers-controls-progress.mjs +98 -0
- package/fesm2022/ngneers-controls-progress.mjs.map +1 -0
- package/fesm2022/ngneers-controls-radio.mjs +152 -0
- package/fesm2022/ngneers-controls-radio.mjs.map +1 -0
- package/fesm2022/ngneers-controls-roving-focus.mjs +323 -0
- package/fesm2022/ngneers-controls-roving-focus.mjs.map +1 -0
- package/fesm2022/ngneers-controls-scroll-shadow.mjs +65 -0
- package/fesm2022/ngneers-controls-scroll-shadow.mjs.map +1 -0
- package/fesm2022/ngneers-controls-scroller.mjs +308 -0
- package/fesm2022/ngneers-controls-scroller.mjs.map +1 -0
- package/fesm2022/ngneers-controls-select-button.mjs +58 -0
- package/fesm2022/ngneers-controls-select-button.mjs.map +1 -0
- package/fesm2022/ngneers-controls-select.mjs +417 -0
- package/fesm2022/ngneers-controls-select.mjs.map +1 -0
- package/fesm2022/ngneers-controls-slider.mjs +167 -0
- package/fesm2022/ngneers-controls-slider.mjs.map +1 -0
- package/fesm2022/ngneers-controls-snackbar.mjs +414 -0
- package/fesm2022/ngneers-controls-snackbar.mjs.map +1 -0
- package/fesm2022/ngneers-controls-spin-buttons.mjs +126 -0
- package/fesm2022/ngneers-controls-spin-buttons.mjs.map +1 -0
- package/fesm2022/ngneers-controls-spinner.mjs +184 -0
- package/fesm2022/ngneers-controls-spinner.mjs.map +1 -0
- package/fesm2022/ngneers-controls-splitter.mjs +604 -0
- package/fesm2022/ngneers-controls-splitter.mjs.map +1 -0
- package/fesm2022/ngneers-controls-state.mjs +185 -0
- package/fesm2022/ngneers-controls-state.mjs.map +1 -0
- package/fesm2022/ngneers-controls-switch.mjs +39 -0
- package/fesm2022/ngneers-controls-switch.mjs.map +1 -0
- package/fesm2022/ngneers-controls-table.mjs +2634 -0
- package/fesm2022/ngneers-controls-table.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tabs.mjs +336 -0
- package/fesm2022/ngneers-controls-tabs.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tag.mjs +30 -0
- package/fesm2022/ngneers-controls-tag.mjs.map +1 -0
- package/fesm2022/ngneers-controls-toast.mjs +350 -0
- package/fesm2022/ngneers-controls-toast.mjs.map +1 -0
- package/fesm2022/ngneers-controls-toggle-button.mjs +70 -0
- package/fesm2022/ngneers-controls-toggle-button.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tooltip.mjs +506 -0
- package/fesm2022/ngneers-controls-tooltip.mjs.map +1 -0
- package/fesm2022/ngneers-controls-tree.mjs +599 -0
- package/fesm2022/ngneers-controls-tree.mjs.map +1 -0
- package/fesm2022/ngneers-controls-upload.mjs +377 -0
- package/fesm2022/ngneers-controls-upload.mjs.map +1 -0
- package/fesm2022/ngneers-controls-utils-ng.mjs +411 -0
- package/fesm2022/ngneers-controls-utils-ng.mjs.map +1 -0
- package/fesm2022/ngneers-controls-utils.mjs +261 -0
- package/fesm2022/ngneers-controls-utils.mjs.map +1 -0
- package/fesm2022/ngneers-controls.mjs +6 -0
- package/fesm2022/ngneers-controls.mjs.map +1 -0
- package/package.json +302 -0
- package/types/ngneers-controls-accordion.d.ts +139 -0
- package/types/ngneers-controls-api-ng.d.ts +364 -0
- package/types/ngneers-controls-api-resize.d.ts +318 -0
- package/types/ngneers-controls-api.d.ts +145 -0
- package/types/ngneers-controls-avatar.d.ts +54 -0
- package/types/ngneers-controls-base.d.ts +277 -0
- package/types/ngneers-controls-breadcrumb.d.ts +272 -0
- package/types/ngneers-controls-button-group.d.ts +46 -0
- package/types/ngneers-controls-button.d.ts +48 -0
- package/types/ngneers-controls-calendar.d.ts +466 -0
- package/types/ngneers-controls-checkbox.d.ts +40 -0
- package/types/ngneers-controls-chip.d.ts +202 -0
- package/types/ngneers-controls-default-icons.d.ts +5 -0
- package/types/ngneers-controls-defer.d.ts +48 -0
- package/types/ngneers-controls-dialog.d.ts +399 -0
- package/types/ngneers-controls-directives.d.ts +171 -0
- package/types/ngneers-controls-drawer.d.ts +308 -0
- package/types/ngneers-controls-edit-inplace.d.ts +263 -0
- package/types/ngneers-controls-errors.d.ts +155 -0
- package/types/ngneers-controls-filter.d.ts +609 -0
- package/types/ngneers-controls-hint.d.ts +88 -0
- package/types/ngneers-controls-i18n-translations-de.d.ts +164 -0
- package/types/ngneers-controls-i18n-translations-en.d.ts +164 -0
- package/types/ngneers-controls-i18n.d.ts +186 -0
- package/types/ngneers-controls-icon.d.ts +68 -0
- package/types/ngneers-controls-inplace.d.ts +98 -0
- package/types/ngneers-controls-input-field.d.ts +248 -0
- package/types/ngneers-controls-input.d.ts +30 -0
- package/types/ngneers-controls-item-view.d.ts +215 -0
- package/types/ngneers-controls-list-box.d.ts +334 -0
- package/types/ngneers-controls-mask-input.d.ts +434 -0
- package/types/ngneers-controls-menu.d.ts +192 -0
- package/types/ngneers-controls-message.d.ts +21 -0
- package/types/ngneers-controls-number-input.d.ts +146 -0
- package/types/ngneers-controls-paginator.d.ts +255 -0
- package/types/ngneers-controls-popover.d.ts +116 -0
- package/types/ngneers-controls-progress.d.ts +49 -0
- package/types/ngneers-controls-radio.d.ts +91 -0
- package/types/ngneers-controls-roving-focus.d.ts +107 -0
- package/types/ngneers-controls-scroll-shadow.d.ts +25 -0
- package/types/ngneers-controls-scroller.d.ts +151 -0
- package/types/ngneers-controls-select-button.d.ts +51 -0
- package/types/ngneers-controls-select.d.ts +409 -0
- package/types/ngneers-controls-slider.d.ts +57 -0
- package/types/ngneers-controls-snackbar.d.ts +330 -0
- package/types/ngneers-controls-spin-buttons.d.ts +69 -0
- package/types/ngneers-controls-spinner.d.ts +117 -0
- package/types/ngneers-controls-splitter.d.ts +465 -0
- package/types/ngneers-controls-state.d.ts +102 -0
- package/types/ngneers-controls-switch.d.ts +18 -0
- package/types/ngneers-controls-table.d.ts +3127 -0
- package/types/ngneers-controls-tabs.d.ts +118 -0
- package/types/ngneers-controls-tag.d.ts +21 -0
- package/types/ngneers-controls-toast.d.ts +298 -0
- package/types/ngneers-controls-toggle-button.d.ts +48 -0
- package/types/ngneers-controls-tooltip.d.ts +189 -0
- package/types/ngneers-controls-tree.d.ts +409 -0
- package/types/ngneers-controls-upload.d.ts +347 -0
- package/types/ngneers-controls-utils-ng.d.ts +129 -0
- package/types/ngneers-controls-utils.d.ts +130 -0
- package/types/ngneers-controls.d.ts +2 -0
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, model, computed, Component, signal, inject, ViewContainerRef, output, viewChild, contentChildren, untracked, runInInjectionContext, afterRenderEffect, NgModule } from '@angular/core';
|
|
3
|
+
import { NgnBase, provideSelf, NgnPt } from '@ngneers/controls/base';
|
|
4
|
+
import { generateElementId, registerState } from '@ngneers/controls/utils-ng';
|
|
5
|
+
import { splitterControlTemplate } from '@ngneers/controls-themes/templates/splitter';
|
|
6
|
+
import { NGN_CONFIG, templateTypeFn, elementSizeSignal, NgnTemplate } from '@ngneers/controls/api/ng';
|
|
7
|
+
import { I18n } from '@ngneers/controls/i18n';
|
|
8
|
+
import { throwExp, Logger, NgnError } from '@ngneers/controls/utils';
|
|
9
|
+
import { ResizeEngine } from '@ngneers/controls/api/resize';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @category control
|
|
13
|
+
*/
|
|
14
|
+
class NgnSplitterPanel extends NgnBase {
|
|
15
|
+
theme = this.injectThemeTemplate(splitterControlTemplate, 'panel');
|
|
16
|
+
_fallbackAreaName = generateElementId();
|
|
17
|
+
/**
|
|
18
|
+
* The name of the panel, used to identify it in the persisted splitter state and in {@link NgnSplitter.panelOrder}.
|
|
19
|
+
* If nullish, a generated fallback name is used.
|
|
20
|
+
*/
|
|
21
|
+
name = input(/* @ts-ignore */
|
|
22
|
+
...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
|
|
23
|
+
/**
|
|
24
|
+
* The size of the panel along the splitter's layout axis. Accepts `fr` or `px` units.
|
|
25
|
+
* @default 1fr
|
|
26
|
+
*/
|
|
27
|
+
size = model('1fr', /* @ts-ignore */
|
|
28
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
29
|
+
/**
|
|
30
|
+
* The minimum size the panel can be resized to.
|
|
31
|
+
* @default 0px
|
|
32
|
+
*/
|
|
33
|
+
minSize = model('0px', /* @ts-ignore */
|
|
34
|
+
...(ngDevMode ? [{ debugName: "minSize" }] : /* istanbul ignore next */ []));
|
|
35
|
+
/**
|
|
36
|
+
* The maximum size the panel can be resized to.
|
|
37
|
+
* @default 100%
|
|
38
|
+
*/
|
|
39
|
+
maxSize = model('100%', /* @ts-ignore */
|
|
40
|
+
...(ngDevMode ? [{ debugName: "maxSize" }] : /* istanbul ignore next */ []));
|
|
41
|
+
/**
|
|
42
|
+
* Sets the `aria-label` for the panel region.
|
|
43
|
+
*/
|
|
44
|
+
ariaLabel = input(/* @ts-ignore */
|
|
45
|
+
...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
46
|
+
/**
|
|
47
|
+
* Sets the `aria-labelledby` for the panel region.
|
|
48
|
+
*/
|
|
49
|
+
ariaLabelledBy = input(/* @ts-ignore */
|
|
50
|
+
...(ngDevMode ? [undefined, { debugName: "ariaLabelledBy" }] : /* istanbul ignore next */ []));
|
|
51
|
+
gridArea = computed(() => this.name() ?? this._fallbackAreaName, /* @ts-ignore */
|
|
52
|
+
...(ngDevMode ? [{ debugName: "gridArea" }] : /* istanbul ignore next */ []));
|
|
53
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnSplitterPanel, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
54
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.5", type: NgnSplitterPanel, isStandalone: true, selector: "ngn-splitter-panel", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { size: "sizeChange", minSize: "minSizeChange", maxSize: "maxSizeChange" }, host: { attributes: { "role": "region" }, properties: { "style.grid-area": "gridArea()", "aria-label": "ariaLabel()", "attr.aria-labelledby": "ariaLabelledBy()" } }, providers: [provideSelf(NgnSplitterPanel)], usesInheritance: true, ngImport: i0, template: "<ng-content />\n" });
|
|
55
|
+
}
|
|
56
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnSplitterPanel, decorators: [{
|
|
57
|
+
type: Component,
|
|
58
|
+
args: [{ selector: 'ngn-splitter-panel', providers: [provideSelf(NgnSplitterPanel)], host: {
|
|
59
|
+
role: 'region',
|
|
60
|
+
'[style.grid-area]': 'gridArea()',
|
|
61
|
+
'[aria-label]': 'ariaLabel()',
|
|
62
|
+
'[attr.aria-labelledby]': 'ariaLabelledBy()',
|
|
63
|
+
}, template: "<ng-content />\n" }]
|
|
64
|
+
}], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }, { type: i0.Output, args: ["sizeChange"] }], minSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSize", required: false }] }, { type: i0.Output, args: ["minSizeChange"] }], maxSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSize", required: false }] }, { type: i0.Output, args: ["maxSizeChange"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledBy", required: false }] }] } });
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Default implementation of the {@link SplitterCalculator} interface.
|
|
68
|
+
* Delegates all resize math to the generic {@link ResizeEngine}.
|
|
69
|
+
*/
|
|
70
|
+
class DefaultSplitterCalculator {
|
|
71
|
+
panels;
|
|
72
|
+
dividers;
|
|
73
|
+
panelOrder;
|
|
74
|
+
layout;
|
|
75
|
+
splitterSize;
|
|
76
|
+
_engine;
|
|
77
|
+
constructor(splitter) {
|
|
78
|
+
this.panels = splitter.panels;
|
|
79
|
+
this.dividers = splitter.dividers;
|
|
80
|
+
this.panelOrder = splitter.panelOrder;
|
|
81
|
+
this.layout = splitter.layout;
|
|
82
|
+
this.splitterSize = computed(() => this.layout() === 'vertical' ? splitter.elementSize().height : splitter.elementSize().width, /* @ts-ignore */
|
|
83
|
+
...(ngDevMode ? [{ debugName: "splitterSize" }] : /* istanbul ignore next */ []));
|
|
84
|
+
// Create the resize engine with panels mapped as ResizableItems
|
|
85
|
+
this._engine = new ResizeEngine({
|
|
86
|
+
items: computed(() => this.orderedPanels()),
|
|
87
|
+
containerSize: this.splitterSize,
|
|
88
|
+
gapSizes: this.dividerSizes,
|
|
89
|
+
distributionMode: computed(() => (splitter.resizeMode?.() ?? 'adjacent')),
|
|
90
|
+
containerConstrained: signal(true), // Splitter is always constrained
|
|
91
|
+
lockSizes: computed(() => splitter.lockSizes?.() ?? false),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
orderedPanels = computed(() => {
|
|
95
|
+
const panels = this.panels();
|
|
96
|
+
const order = this.panelOrder();
|
|
97
|
+
return order
|
|
98
|
+
? [...panels].sort((a, b) => {
|
|
99
|
+
const aIndex = order.indexOf(a['gridArea']());
|
|
100
|
+
const bIndex = order.indexOf(b['gridArea']());
|
|
101
|
+
if (aIndex === -1 && bIndex === -1)
|
|
102
|
+
return 0;
|
|
103
|
+
if (aIndex === -1)
|
|
104
|
+
return 1;
|
|
105
|
+
if (bIndex === -1)
|
|
106
|
+
return -1;
|
|
107
|
+
return aIndex - bIndex;
|
|
108
|
+
})
|
|
109
|
+
: panels;
|
|
110
|
+
}, /* @ts-ignore */
|
|
111
|
+
...(ngDevMode ? [{ debugName: "orderedPanels" }] : /* istanbul ignore next */ []));
|
|
112
|
+
gridTemplateSizes = computed(() => this._engine.gridTemplateSizes(), /* @ts-ignore */
|
|
113
|
+
...(ngDevMode ? [{ debugName: "gridTemplateSizes" }] : /* istanbul ignore next */ []));
|
|
114
|
+
gridTemplateAreas = computed(() => {
|
|
115
|
+
const panels = this.orderedPanels();
|
|
116
|
+
if (panels.length === 0)
|
|
117
|
+
return null;
|
|
118
|
+
let result = '';
|
|
119
|
+
panels.forEach((panel, i) => {
|
|
120
|
+
if (i > 0) {
|
|
121
|
+
result +=
|
|
122
|
+
this.layout() === 'horizontal' ? ` ngn-divider-${i - 1} ` : ` "ngn-divider-${i - 1}" `;
|
|
123
|
+
}
|
|
124
|
+
result += this.layout() === 'horizontal' ? panel['gridArea']() : `"${panel['gridArea']()}"`;
|
|
125
|
+
});
|
|
126
|
+
return this.layout() === 'horizontal' ? `"${result}"` : result;
|
|
127
|
+
}, /* @ts-ignore */
|
|
128
|
+
...(ngDevMode ? [{ debugName: "gridTemplateAreas" }] : /* istanbul ignore next */ []));
|
|
129
|
+
minSize = computed(() => this._engine.minTotalSize(), /* @ts-ignore */
|
|
130
|
+
...(ngDevMode ? [{ debugName: "minSize" }] : /* istanbul ignore next */ []));
|
|
131
|
+
maxSize = computed(() => this._engine.maxTotalSize(), /* @ts-ignore */
|
|
132
|
+
...(ngDevMode ? [{ debugName: "maxSize" }] : /* istanbul ignore next */ []));
|
|
133
|
+
dragContext = signal(null, /* @ts-ignore */
|
|
134
|
+
...(ngDevMode ? [{ debugName: "dragContext" }] : /* istanbul ignore next */ []));
|
|
135
|
+
dividerSizes = computed(() => this.dividers().map(d => {
|
|
136
|
+
const el = d.rootNodes.find(x => x instanceof HTMLElement);
|
|
137
|
+
return el ? (this.layout() === 'horizontal' ? el.offsetWidth : el.offsetHeight) : 0;
|
|
138
|
+
}), /* @ts-ignore */
|
|
139
|
+
...(ngDevMode ? [{ debugName: "dividerSizes" }] : /* istanbul ignore next */ []));
|
|
140
|
+
startDrag(index, event) {
|
|
141
|
+
const panels = this.orderedPanels();
|
|
142
|
+
if (index < 0 || index >= panels.length - 1)
|
|
143
|
+
return;
|
|
144
|
+
const startPosition = this.layout() === 'horizontal' ? event.clientX : event.clientY;
|
|
145
|
+
this.dragContext.set({
|
|
146
|
+
dividerIndex: index,
|
|
147
|
+
pointerId: event.pointerId,
|
|
148
|
+
startPosition,
|
|
149
|
+
});
|
|
150
|
+
this._engine.startDrag(index, startPosition);
|
|
151
|
+
}
|
|
152
|
+
drag(index, event) {
|
|
153
|
+
const ctx = this.dragContext();
|
|
154
|
+
if (!ctx || ctx.dividerIndex !== index || ctx.pointerId !== event.pointerId)
|
|
155
|
+
return;
|
|
156
|
+
const currentPosition = this.layout() === 'horizontal' ? event.clientX : event.clientY;
|
|
157
|
+
this._engine.drag(index, currentPosition);
|
|
158
|
+
}
|
|
159
|
+
endDrag(index, event, isCancel) {
|
|
160
|
+
const ctx = this.dragContext();
|
|
161
|
+
if (!ctx || ctx.dividerIndex !== index || ctx.pointerId !== event.pointerId)
|
|
162
|
+
return;
|
|
163
|
+
this._engine.endDrag(index, isCancel);
|
|
164
|
+
this.dragContext.set(null);
|
|
165
|
+
}
|
|
166
|
+
moveDivider(index, pxDelta) {
|
|
167
|
+
const panels = this.orderedPanels();
|
|
168
|
+
if (index < 0 || index >= panels.length - 1)
|
|
169
|
+
return;
|
|
170
|
+
const leftPanel = panels[index] ??
|
|
171
|
+
throwExp('NgnSplitterCalculator', `Left panel is missing for divider at index ${index}`);
|
|
172
|
+
const rightPanel = panels[index + 1] ??
|
|
173
|
+
throwExp('NgnSplitterCalculator', `Right panel is missing for divider at index ${index}`);
|
|
174
|
+
if (!this._engine.isItemSizeCalculated(leftPanel) ||
|
|
175
|
+
!this._engine.isItemSizeCalculated(rightPanel)) {
|
|
176
|
+
Logger.warn('Cannot move divider, panel sizes are not calculated');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
this._engine.moveDivider(index, pxDelta);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Ensures all panels respect their min/max size constraints.
|
|
183
|
+
* Delegates to the underlying {@link ResizeEngine}.
|
|
184
|
+
*/
|
|
185
|
+
ensureMinMaxSizes() {
|
|
186
|
+
this._engine.ensureMinMaxSizes();
|
|
187
|
+
}
|
|
188
|
+
/** @internal — used by tests to seed panel sizes into the engine. */
|
|
189
|
+
setPanelSize(panel, size) {
|
|
190
|
+
this._engine.setItemSize(panel, size);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function isSplitterPanelSize(value) {
|
|
195
|
+
if (typeof value !== 'string')
|
|
196
|
+
return false;
|
|
197
|
+
const m = value.match(/^(.+)(px|fr)$/);
|
|
198
|
+
if (!m || !m[1])
|
|
199
|
+
return false;
|
|
200
|
+
if (isNaN(parseFloat(m[1])))
|
|
201
|
+
return false;
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
function getSplitterPanelSizeUnit(value) {
|
|
205
|
+
return value.slice(-2);
|
|
206
|
+
}
|
|
207
|
+
function getSplitterPanelSizeValue(value) {
|
|
208
|
+
return parseFloat(value.slice(0, -2));
|
|
209
|
+
}
|
|
210
|
+
function isSplitterPanelSizeLimit(value) {
|
|
211
|
+
if (typeof value !== 'string')
|
|
212
|
+
return false;
|
|
213
|
+
const m = value.match(/^(.+)(px|%)$/);
|
|
214
|
+
if (!m || !m[1])
|
|
215
|
+
return false;
|
|
216
|
+
if (isNaN(parseFloat(m[1])))
|
|
217
|
+
return false;
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
function getSplitterPanelSizeLimitUnit(value) {
|
|
221
|
+
return value.endsWith('px') ? 'px' : '%';
|
|
222
|
+
}
|
|
223
|
+
function getSplitterPanelSizeLimitValue(value) {
|
|
224
|
+
return value.endsWith('px') ? parseFloat(value.slice(0, -2)) : parseFloat(value.slice(0, -1));
|
|
225
|
+
}
|
|
226
|
+
function getSplitterPanelSizeLimitInPx(value, totalSize) {
|
|
227
|
+
const unit = getSplitterPanelSizeLimitUnit(value);
|
|
228
|
+
const sizeValue = getSplitterPanelSizeLimitValue(value);
|
|
229
|
+
return unit === 'px' ? sizeValue : (sizeValue / 100) * totalSize;
|
|
230
|
+
}
|
|
231
|
+
function expandSplitterPanelSize(value) {
|
|
232
|
+
return {
|
|
233
|
+
value: getSplitterPanelSizeValue(value),
|
|
234
|
+
unit: getSplitterPanelSizeUnit(value),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function expandSplitterPanelSizeLimit(value) {
|
|
238
|
+
return {
|
|
239
|
+
value: getSplitterPanelSizeLimitValue(value),
|
|
240
|
+
unit: getSplitterPanelSizeLimitUnit(value),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function collapseSplitterPanelSize(size) {
|
|
244
|
+
return `${size.value}${size.unit}`;
|
|
245
|
+
}
|
|
246
|
+
function collapseSplitterPanelSizeLimit(size) {
|
|
247
|
+
return `${size.value}${size.unit}`;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @category control
|
|
252
|
+
*/
|
|
253
|
+
class NgnSplitter extends NgnBase {
|
|
254
|
+
_viewContainer = inject(ViewContainerRef);
|
|
255
|
+
_config = inject(NGN_CONFIG);
|
|
256
|
+
theme = this.injectThemeTemplate(splitterControlTemplate, {
|
|
257
|
+
root: true,
|
|
258
|
+
dragging: () => this.isDragging(),
|
|
259
|
+
horizontal: () => this.layout() === 'horizontal',
|
|
260
|
+
vertical: () => this.layout() === 'vertical',
|
|
261
|
+
});
|
|
262
|
+
translations = inject(I18n).translations;
|
|
263
|
+
/**
|
|
264
|
+
* The layout of the splitter.
|
|
265
|
+
*/
|
|
266
|
+
layout = model.required(/* @ts-ignore */
|
|
267
|
+
...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
|
|
268
|
+
/**
|
|
269
|
+
* A array of panel names that defines the order of panels.
|
|
270
|
+
* If nullish, the order is determined by the order the panels are defined in the template.
|
|
271
|
+
*/
|
|
272
|
+
panelOrder = model(/* @ts-ignore */
|
|
273
|
+
...(ngDevMode ? [undefined, { debugName: "panelOrder" }] : /* istanbul ignore next */ []));
|
|
274
|
+
/**
|
|
275
|
+
* The storage to use for saving the splitter state.
|
|
276
|
+
* @default `session`
|
|
277
|
+
*/
|
|
278
|
+
stateStorage = input(this._config.defaults.splitter.stateStorage, /* @ts-ignore */
|
|
279
|
+
...(ngDevMode ? [{ debugName: "stateStorage" }] : /* istanbul ignore next */ []));
|
|
280
|
+
/**
|
|
281
|
+
* The key to use for saving the splitter state.
|
|
282
|
+
* If nullish, the state will not be saved.
|
|
283
|
+
*/
|
|
284
|
+
stateKey = input(/* @ts-ignore */
|
|
285
|
+
...(ngDevMode ? [undefined, { debugName: "stateKey" }] : /* istanbul ignore next */ []));
|
|
286
|
+
/**
|
|
287
|
+
* The type of data to save in the splitter state.
|
|
288
|
+
* @default `['layout', 'panelOrder', 'panelSizes']`
|
|
289
|
+
*/
|
|
290
|
+
stateData = input([
|
|
291
|
+
'layout',
|
|
292
|
+
'panelOrder',
|
|
293
|
+
'panelSizes',
|
|
294
|
+
], /* @ts-ignore */
|
|
295
|
+
...(ngDevMode ? [{ debugName: "stateData" }] : /* istanbul ignore next */ []));
|
|
296
|
+
/**
|
|
297
|
+
* The type of calculator to use for the splitter.
|
|
298
|
+
* @default `DefaultSplitterCalculator`
|
|
299
|
+
*/
|
|
300
|
+
calculatorType = input(DefaultSplitterCalculator, /* @ts-ignore */
|
|
301
|
+
...(ngDevMode ? [{ debugName: "calculatorType" }] : /* istanbul ignore next */ []));
|
|
302
|
+
/**
|
|
303
|
+
* The resize distribution mode for the splitter.
|
|
304
|
+
* - `'adjacent'`: Only the panels adjacent to the divider are resized.
|
|
305
|
+
* - `'proportional'`: The deficit is distributed proportionally across all panels on the other side.
|
|
306
|
+
* @default adjacent
|
|
307
|
+
*/
|
|
308
|
+
resizeMode = input('adjacent', /* @ts-ignore */
|
|
309
|
+
...(ngDevMode ? [{ debugName: "resizeMode" }] : /* istanbul ignore next */ []));
|
|
310
|
+
/**
|
|
311
|
+
* Whether to lock affected panels to fixed `px` values after a resize completes.
|
|
312
|
+
* When `true`, panels whose size changed are converted from their original unit to `px`.
|
|
313
|
+
* When `false`, panels keep their original units (`fr`, `px`).
|
|
314
|
+
* @default false
|
|
315
|
+
*/
|
|
316
|
+
lockSizes = input(false, /* @ts-ignore */
|
|
317
|
+
...(ngDevMode ? [{ debugName: "lockSizes" }] : /* istanbul ignore next */ []));
|
|
318
|
+
/**
|
|
319
|
+
* The step size for moving the dividers using the keyboard.
|
|
320
|
+
* This can be a pixel value (e.g., '5px') or a percentage value (e.g., '5%').
|
|
321
|
+
* If a percentage is used, it will be calculated based on the size of the splitter element.
|
|
322
|
+
* @default '5px'
|
|
323
|
+
*/
|
|
324
|
+
step = input('5px', /* @ts-ignore */
|
|
325
|
+
...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
|
|
326
|
+
/**
|
|
327
|
+
* Event emitted when the splitter state is being saved.
|
|
328
|
+
* This can be used to modify the state before it is saved.
|
|
329
|
+
*/
|
|
330
|
+
stateSaving = output();
|
|
331
|
+
/**
|
|
332
|
+
* Event emitted when the splitter state is loaded.
|
|
333
|
+
* This can be used to modify the state before it is applied or to perform actions based on the loaded state.
|
|
334
|
+
*/
|
|
335
|
+
stateLoading = output();
|
|
336
|
+
dividerTemplateType = templateTypeFn();
|
|
337
|
+
_dividerTemplate = viewChild.required('defaultDividerTemplate');
|
|
338
|
+
/**
|
|
339
|
+
* The current dividers in the splitter.
|
|
340
|
+
*/
|
|
341
|
+
dividers = signal([], /* @ts-ignore */
|
|
342
|
+
...(ngDevMode ? [{ debugName: "dividers" }] : /* istanbul ignore next */ []));
|
|
343
|
+
/**
|
|
344
|
+
* The current panels in the splitter.
|
|
345
|
+
*/
|
|
346
|
+
panels = contentChildren(NgnSplitterPanel, /* @ts-ignore */
|
|
347
|
+
...(ngDevMode ? [{ debugName: "panels" }] : /* istanbul ignore next */ []));
|
|
348
|
+
/**
|
|
349
|
+
* The current size of the splitter element.
|
|
350
|
+
*/
|
|
351
|
+
elementSize = elementSizeSignal(this.element);
|
|
352
|
+
/**
|
|
353
|
+
* A value indicating whether the splitter is currently being dragged.
|
|
354
|
+
*/
|
|
355
|
+
isDragging = computed(() => this.calculator().dragContext() !== null, /* @ts-ignore */
|
|
356
|
+
...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
|
|
357
|
+
calculator = computed(() => {
|
|
358
|
+
const calculatorType = this.calculatorType();
|
|
359
|
+
return untracked(() => runInInjectionContext(this.injector, () => new calculatorType(this)));
|
|
360
|
+
}, /* @ts-ignore */
|
|
361
|
+
...(ngDevMode ? [{ debugName: "calculator" }] : /* istanbul ignore next */ []));
|
|
362
|
+
constructor() {
|
|
363
|
+
super();
|
|
364
|
+
afterRenderEffect(() => {
|
|
365
|
+
const panels = this.panels();
|
|
366
|
+
this.updateDividers(panels);
|
|
367
|
+
});
|
|
368
|
+
registerState({
|
|
369
|
+
storage: () => this.stateStorage(),
|
|
370
|
+
key: () => this.stateKey(),
|
|
371
|
+
valueFn: this.computeState.bind(this),
|
|
372
|
+
onLoad: this.onStateLoad.bind(this),
|
|
373
|
+
debounce: 100,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
ngOnDestroy() {
|
|
377
|
+
// Clean up dividers
|
|
378
|
+
this.dividers().forEach(divider => divider.destroy());
|
|
379
|
+
this.dividers.set([]);
|
|
380
|
+
}
|
|
381
|
+
onHandlePointerDown(index, event) {
|
|
382
|
+
const target = event.target;
|
|
383
|
+
if (!(target instanceof HTMLElement)) {
|
|
384
|
+
throw new Error('Event target is not an HTMLElement');
|
|
385
|
+
}
|
|
386
|
+
// Make sure the element is stable before capturing the pointer
|
|
387
|
+
requestAnimationFrame(() => {
|
|
388
|
+
try {
|
|
389
|
+
target.setPointerCapture(event.pointerId);
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
// Ignore errors if the element is not capable of capturing the pointer
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
this.calculator().startDrag(index, event);
|
|
396
|
+
}
|
|
397
|
+
onHandlePointerMove(index, event) {
|
|
398
|
+
this.calculator().drag(index, event);
|
|
399
|
+
}
|
|
400
|
+
onHandlePointerUp(index, event) {
|
|
401
|
+
this.calculator().endDrag(index, event, false);
|
|
402
|
+
}
|
|
403
|
+
onHandlePointerCancel(index, event) {
|
|
404
|
+
this.calculator().endDrag(index, event, true);
|
|
405
|
+
}
|
|
406
|
+
onHandleKeyDown(index, event) {
|
|
407
|
+
if ((event.key === 'ArrowLeft' && this.layout() === 'horizontal') ||
|
|
408
|
+
(event.key === 'ArrowUp' && this.layout() === 'vertical')) {
|
|
409
|
+
this.calculator().moveDivider(index, -this.getStepInPx());
|
|
410
|
+
event.preventDefault(); // Prevent default scrolling behavior
|
|
411
|
+
}
|
|
412
|
+
else if ((event.key === 'ArrowRight' && this.layout() === 'horizontal') ||
|
|
413
|
+
(event.key === 'ArrowDown' && this.layout() === 'vertical')) {
|
|
414
|
+
this.calculator().moveDivider(index, this.getStepInPx());
|
|
415
|
+
event.preventDefault(); // Prevent default scrolling behavior
|
|
416
|
+
}
|
|
417
|
+
else if (event.key === 'Home') {
|
|
418
|
+
this.calculator().moveDivider(index, Number.NEGATIVE_INFINITY);
|
|
419
|
+
event.preventDefault(); // Prevent default scrolling behavior
|
|
420
|
+
}
|
|
421
|
+
else if (event.key === 'End') {
|
|
422
|
+
this.calculator().moveDivider(index, Number.POSITIVE_INFINITY);
|
|
423
|
+
event.preventDefault(); // Prevent default scrolling behavior
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
updateDividers(panels) {
|
|
427
|
+
this.dividers.update(divider => {
|
|
428
|
+
if (divider.length === panels.length - 1) {
|
|
429
|
+
return divider; // No need to update if the number of dividers matches the number of panels
|
|
430
|
+
}
|
|
431
|
+
else if (divider.length < panels.length - 1) {
|
|
432
|
+
// Add missing dividers
|
|
433
|
+
const newDividers = [...divider];
|
|
434
|
+
for (let i = divider.length; i < panels.length - 1; i++) {
|
|
435
|
+
newDividers.push(this.createDivider(i));
|
|
436
|
+
}
|
|
437
|
+
return newDividers;
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
// More dividers than needed, remove the excess
|
|
441
|
+
divider.slice(panels.length - 1).forEach(divider => divider.destroy());
|
|
442
|
+
return divider.slice(0, panels.length - 1);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
// Move dividers to the correct positions (skip first panel — no divider before it)
|
|
446
|
+
for (let i = 1; i < panels.length; i++) {
|
|
447
|
+
const panel = panels[i];
|
|
448
|
+
const divider = this.dividers()[i - 1];
|
|
449
|
+
if (!divider) {
|
|
450
|
+
throw new NgnError('NgnSplitter', `Divider is missing for panel at index ${i}`);
|
|
451
|
+
}
|
|
452
|
+
this.moveDividerBefore(panel, divider);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
createDivider(index) {
|
|
456
|
+
const viewRef = this._viewContainer.createEmbeddedView(this._dividerTemplate(), { index });
|
|
457
|
+
viewRef.detectChanges();
|
|
458
|
+
return viewRef;
|
|
459
|
+
}
|
|
460
|
+
moveDividerBefore(panel, divider) {
|
|
461
|
+
const panelElement = panel.element.nativeElement;
|
|
462
|
+
divider.rootNodes.forEach(node => {
|
|
463
|
+
if (node instanceof HTMLElement) {
|
|
464
|
+
panelElement.parentElement?.insertBefore(node, panelElement);
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
computeState(previousState) {
|
|
469
|
+
const data = this.stateData();
|
|
470
|
+
const state = {
|
|
471
|
+
layout: data.includes('layout') ? this.layout() : undefined,
|
|
472
|
+
panelOrder: data.includes('panelOrder') ? this.panelOrder() : undefined,
|
|
473
|
+
panelSizes: data.includes('panelSizes')
|
|
474
|
+
? this.panels().reduce((acc, panel, index) => {
|
|
475
|
+
acc[panel.name() || `ngn-panel-${index}`] = panel.size();
|
|
476
|
+
return acc;
|
|
477
|
+
}, { ...previousState?.panelSizes })
|
|
478
|
+
: undefined,
|
|
479
|
+
};
|
|
480
|
+
this.stateSaving.emit(state);
|
|
481
|
+
return state;
|
|
482
|
+
}
|
|
483
|
+
onStateLoad(state) {
|
|
484
|
+
if (state) {
|
|
485
|
+
this.ensureValidState(state);
|
|
486
|
+
this.stateLoading.emit(state);
|
|
487
|
+
this.applyFromState(state);
|
|
488
|
+
}
|
|
489
|
+
return state;
|
|
490
|
+
}
|
|
491
|
+
ensureValidState(state) {
|
|
492
|
+
if (state.layout && state.layout !== 'horizontal' && state.layout !== 'vertical') {
|
|
493
|
+
Logger.warn(`Invalid layout in saved splitter state.`, { state });
|
|
494
|
+
delete state.layout;
|
|
495
|
+
}
|
|
496
|
+
if (state.panelOrder &&
|
|
497
|
+
(!Array.isArray(state.panelOrder) || state.panelOrder.some(x => typeof x !== 'string'))) {
|
|
498
|
+
Logger.warn(`Invalid panelOrder in saved splitter state.`, { state });
|
|
499
|
+
delete state.panelOrder;
|
|
500
|
+
}
|
|
501
|
+
if (state.panelSizes &&
|
|
502
|
+
(typeof state.panelSizes !== 'object' ||
|
|
503
|
+
state.panelSizes === null ||
|
|
504
|
+
Object.values(state.panelSizes).some(x => !isSplitterPanelSize(x)))) {
|
|
505
|
+
Logger.warn(`Invalid panelSizes in saved splitter state.`, { state });
|
|
506
|
+
delete state.panelSizes;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
applyFromState(state) {
|
|
510
|
+
if (state.layout && this.stateData().includes('layout')) {
|
|
511
|
+
this.layout.set(state.layout);
|
|
512
|
+
}
|
|
513
|
+
if (state.panelOrder && this.stateData().includes('panelOrder')) {
|
|
514
|
+
this.panelOrder.set(state.panelOrder);
|
|
515
|
+
}
|
|
516
|
+
if (state.panelSizes && this.stateData().includes('panelSizes')) {
|
|
517
|
+
const panels = this.panels();
|
|
518
|
+
for (let i = 0; i < panels.length; i++) {
|
|
519
|
+
const panelName = panels[i]?.name() || `ngn-panel-${i}`;
|
|
520
|
+
if (panelName in state.panelSizes) {
|
|
521
|
+
const panelSize = state.panelSizes[panelName];
|
|
522
|
+
if (!panelSize) {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
panels[i]?.size.set(panelSize);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* The divider's current position as a percentage (0–100) of the total panel
|
|
532
|
+
* content size, used for `aria-valuenow` on the `role="separator"` handle.
|
|
533
|
+
* Reads `gridTemplateSizes()` to stay reactive to resizes, then measures the
|
|
534
|
+
* rendered panel sizes on either side of the divider.
|
|
535
|
+
*/
|
|
536
|
+
dividerValueNow(index) {
|
|
537
|
+
// ponytail: DOM-offset heuristic; one CD-frame lag during drag is fine for
|
|
538
|
+
// an aria value. Swap for an engine-reported px signal if exactness matters.
|
|
539
|
+
this.calculator().gridTemplateSizes(); // reactive trigger
|
|
540
|
+
const panels = this.calculator().orderedPanels();
|
|
541
|
+
const horizontal = this.layout() === 'horizontal';
|
|
542
|
+
let before = 0;
|
|
543
|
+
let total = 0;
|
|
544
|
+
panels.forEach((panel, i) => {
|
|
545
|
+
const el = panel.element.nativeElement;
|
|
546
|
+
const size = horizontal ? el.offsetWidth : el.offsetHeight;
|
|
547
|
+
total += size;
|
|
548
|
+
if (i <= index)
|
|
549
|
+
before += size;
|
|
550
|
+
});
|
|
551
|
+
return total > 0 ? Math.round((before / total) * 100) : 0;
|
|
552
|
+
}
|
|
553
|
+
getStepInPx() {
|
|
554
|
+
const step = this.step();
|
|
555
|
+
if (step.endsWith('px')) {
|
|
556
|
+
return parseFloat(step.slice(0, -2));
|
|
557
|
+
}
|
|
558
|
+
else if (step.endsWith('%')) {
|
|
559
|
+
const size = this.layout() === 'horizontal' ? this.elementSize().width : this.elementSize().height;
|
|
560
|
+
return (parseFloat(step.slice(0, -1)) / 100) * size;
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
Logger.warn(`Invalid step value: ${step}.`);
|
|
564
|
+
return 10; // Default step in pixels
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnSplitter, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
568
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.5", type: NgnSplitter, isStandalone: true, selector: "ngn-splitter", inputs: { layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null }, panelOrder: { classPropertyName: "panelOrder", publicName: "panelOrder", 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 }, stateData: { classPropertyName: "stateData", publicName: "stateData", isSignal: true, isRequired: false, transformFunction: null }, calculatorType: { classPropertyName: "calculatorType", publicName: "calculatorType", isSignal: true, isRequired: false, transformFunction: null }, resizeMode: { classPropertyName: "resizeMode", publicName: "resizeMode", isSignal: true, isRequired: false, transformFunction: null }, lockSizes: { classPropertyName: "lockSizes", publicName: "lockSizes", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { layout: "layoutChange", panelOrder: "panelOrderChange", stateSaving: "stateSaving", stateLoading: "stateLoading" }, host: { attributes: { "role": "region" }, properties: { "style.grid-template-columns": "layout() === 'horizontal' ? calculator().gridTemplateSizes() : null", "style.grid-template-rows": "layout() === 'vertical' ? calculator().gridTemplateSizes() : null", "style.grid-template-areas": "calculator().gridTemplateAreas()", "style.max-width": "layout() === 'horizontal' ? calculator().maxSize() : null", "style.max-height": "layout() === 'vertical' ? calculator().maxSize() : null", "style.min-width": "layout() === 'horizontal' ? calculator().minSize() : null", "style.min-height": "layout() === 'vertical' ? calculator().minSize() : null" } }, providers: [provideSelf(NgnSplitter)], queries: [{ propertyName: "panels", predicate: NgnSplitterPanel, isSignal: true }], viewQueries: [{ propertyName: "_dividerTemplate", first: true, predicate: ["defaultDividerTemplate"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<ng-content />\n\n<ng-template #defaultDividerTemplate [ngnTemplate]=\"dividerTemplateType\" let-index=\"index\">\n <div\n [style.grid-area]=\"`ngn-divider-${index}`\"\n [ptInt]=\"this\"\n [ptClass]=\"{\n divider: true,\n 'divider-dragging': calculator().dragContext()?.dividerIndex === index,\n }\"\n >\n <button\n role=\"separator\"\n [aria-orientation]=\"layout()\"\n [aria-label]=\"translations['splitter_handleLabel']()\"\n [attr.aria-valuenow]=\"dividerValueNow(index)\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [ptInt]=\"this\"\n [ptClass]=\"'divider-handle'\"\n (pointerdown)=\"onHandlePointerDown(index, $event)\"\n (pointermove)=\"onHandlePointerMove(index, $event)\"\n (pointerup)=\"onHandlePointerUp(index, $event)\"\n (pointercancel)=\"onHandlePointerCancel(index, $event)\"\n (keydown)=\"onHandleKeyDown(index, $event)\"\n ></button>\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass", "ptDep"] }, { kind: "directive", type: NgnTemplate, selector: "ng-template[ngnTemplate]", inputs: ["ngnTemplate"] }] });
|
|
569
|
+
}
|
|
570
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnSplitter, decorators: [{
|
|
571
|
+
type: Component,
|
|
572
|
+
args: [{ selector: 'ngn-splitter', imports: [NgnPt, NgnTemplate], providers: [provideSelf(NgnSplitter)], host: {
|
|
573
|
+
role: 'region',
|
|
574
|
+
'[style.grid-template-columns]': `layout() === 'horizontal' ? calculator().gridTemplateSizes() : null`,
|
|
575
|
+
'[style.grid-template-rows]': `layout() === 'vertical' ? calculator().gridTemplateSizes() : null`,
|
|
576
|
+
'[style.grid-template-areas]': 'calculator().gridTemplateAreas()',
|
|
577
|
+
'[style.max-width]': `layout() === 'horizontal' ? calculator().maxSize() : null`,
|
|
578
|
+
'[style.max-height]': `layout() === 'vertical' ? calculator().maxSize() : null`,
|
|
579
|
+
'[style.min-width]': `layout() === 'horizontal' ? calculator().minSize() : null`,
|
|
580
|
+
'[style.min-height]': `layout() === 'vertical' ? calculator().minSize() : null`,
|
|
581
|
+
}, template: "<ng-content />\n\n<ng-template #defaultDividerTemplate [ngnTemplate]=\"dividerTemplateType\" let-index=\"index\">\n <div\n [style.grid-area]=\"`ngn-divider-${index}`\"\n [ptInt]=\"this\"\n [ptClass]=\"{\n divider: true,\n 'divider-dragging': calculator().dragContext()?.dividerIndex === index,\n }\"\n >\n <button\n role=\"separator\"\n [aria-orientation]=\"layout()\"\n [aria-label]=\"translations['splitter_handleLabel']()\"\n [attr.aria-valuenow]=\"dividerValueNow(index)\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [ptInt]=\"this\"\n [ptClass]=\"'divider-handle'\"\n (pointerdown)=\"onHandlePointerDown(index, $event)\"\n (pointermove)=\"onHandlePointerMove(index, $event)\"\n (pointerup)=\"onHandlePointerUp(index, $event)\"\n (pointercancel)=\"onHandlePointerCancel(index, $event)\"\n (keydown)=\"onHandleKeyDown(index, $event)\"\n ></button>\n </div>\n</ng-template>\n" }]
|
|
582
|
+
}], ctorParameters: () => [], propDecorators: { layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }, { type: i0.Output, args: ["layoutChange"] }], panelOrder: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelOrder", required: false }] }, { type: i0.Output, args: ["panelOrderChange"] }], stateStorage: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateStorage", required: false }] }], stateKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateKey", required: false }] }], stateData: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateData", required: false }] }], calculatorType: [{ type: i0.Input, args: [{ isSignal: true, alias: "calculatorType", required: false }] }], resizeMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizeMode", required: false }] }], lockSizes: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockSizes", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], stateSaving: [{ type: i0.Output, args: ["stateSaving"] }], stateLoading: [{ type: i0.Output, args: ["stateLoading"] }], _dividerTemplate: [{ type: i0.ViewChild, args: ['defaultDividerTemplate', { isSignal: true }] }], panels: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NgnSplitterPanel), { isSignal: true }] }] } });
|
|
583
|
+
|
|
584
|
+
// This module is just for grouping the Splitter and SplitterPanel components for convenience.
|
|
585
|
+
// The components are standalone and can be used without this module.
|
|
586
|
+
class NgnSplitterModule {
|
|
587
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnSplitterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
588
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: NgnSplitterModule, imports: [NgnSplitter, NgnSplitterPanel], exports: [NgnSplitter, NgnSplitterPanel] });
|
|
589
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnSplitterModule });
|
|
590
|
+
}
|
|
591
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnSplitterModule, decorators: [{
|
|
592
|
+
type: NgModule,
|
|
593
|
+
args: [{
|
|
594
|
+
imports: [NgnSplitter, NgnSplitterPanel],
|
|
595
|
+
exports: [NgnSplitter, NgnSplitterPanel],
|
|
596
|
+
}]
|
|
597
|
+
}] });
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Generated bundle index. Do not edit.
|
|
601
|
+
*/
|
|
602
|
+
|
|
603
|
+
export { DefaultSplitterCalculator, NgnSplitter, NgnSplitterModule, NgnSplitterPanel };
|
|
604
|
+
//# sourceMappingURL=ngneers-controls-splitter.mjs.map
|