@ngneers/controls 0.0.1-pre1 → 0.0.1-pre3

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.
Files changed (195) hide show
  1. package/LICENSE +21 -0
  2. package/fesm2022/ngneers-controls-accordion.mjs +194 -0
  3. package/fesm2022/ngneers-controls-accordion.mjs.map +1 -0
  4. package/fesm2022/ngneers-controls-api-ng.mjs +668 -0
  5. package/fesm2022/ngneers-controls-api-ng.mjs.map +1 -0
  6. package/fesm2022/ngneers-controls-api.mjs +256 -227
  7. package/fesm2022/ngneers-controls-api.mjs.map +1 -1
  8. package/fesm2022/ngneers-controls-avatar.mjs +70 -0
  9. package/fesm2022/ngneers-controls-avatar.mjs.map +1 -0
  10. package/fesm2022/ngneers-controls-base.mjs +397 -0
  11. package/fesm2022/ngneers-controls-base.mjs.map +1 -0
  12. package/fesm2022/ngneers-controls-breadcrumb.mjs +74 -0
  13. package/fesm2022/ngneers-controls-breadcrumb.mjs.map +1 -0
  14. package/fesm2022/ngneers-controls-button-group.mjs +51 -0
  15. package/fesm2022/ngneers-controls-button-group.mjs.map +1 -0
  16. package/fesm2022/ngneers-controls-button.mjs +62 -0
  17. package/fesm2022/ngneers-controls-button.mjs.map +1 -0
  18. package/fesm2022/ngneers-controls-calendar-time-C7UnIFzU.mjs +63 -0
  19. package/fesm2022/ngneers-controls-calendar-time-C7UnIFzU.mjs.map +1 -0
  20. package/fesm2022/ngneers-controls-calendar.mjs +468 -0
  21. package/fesm2022/ngneers-controls-calendar.mjs.map +1 -0
  22. package/fesm2022/ngneers-controls-checkbox.mjs +58 -0
  23. package/fesm2022/ngneers-controls-checkbox.mjs.map +1 -0
  24. package/fesm2022/ngneers-controls-chip.mjs +52 -0
  25. package/fesm2022/ngneers-controls-chip.mjs.map +1 -0
  26. package/fesm2022/ngneers-controls-defer.mjs +43 -0
  27. package/fesm2022/ngneers-controls-defer.mjs.map +1 -0
  28. package/fesm2022/ngneers-controls-dialog.mjs +329 -33
  29. package/fesm2022/ngneers-controls-dialog.mjs.map +1 -1
  30. package/fesm2022/ngneers-controls-directives.mjs +443 -0
  31. package/fesm2022/ngneers-controls-directives.mjs.map +1 -0
  32. package/fesm2022/ngneers-controls-drawer.mjs +232 -0
  33. package/fesm2022/ngneers-controls-drawer.mjs.map +1 -0
  34. package/fesm2022/ngneers-controls-edit-inplace.mjs +120 -0
  35. package/fesm2022/ngneers-controls-edit-inplace.mjs.map +1 -0
  36. package/fesm2022/ngneers-controls-filter.mjs +516 -0
  37. package/fesm2022/ngneers-controls-filter.mjs.map +1 -0
  38. package/fesm2022/ngneers-controls-i18n-de-CdTPeBiR.mjs +87 -0
  39. package/fesm2022/ngneers-controls-i18n-de-CdTPeBiR.mjs.map +1 -0
  40. package/fesm2022/ngneers-controls-i18n-en-Cfp2pOLY.mjs +87 -0
  41. package/fesm2022/ngneers-controls-i18n-en-Cfp2pOLY.mjs.map +1 -0
  42. package/fesm2022/ngneers-controls-i18n.mjs +57 -0
  43. package/fesm2022/ngneers-controls-i18n.mjs.map +1 -0
  44. package/fesm2022/ngneers-controls-icon-calendar-z5xA9wTT.mjs +4 -0
  45. package/fesm2022/ngneers-controls-icon-calendar-z5xA9wTT.mjs.map +1 -0
  46. package/fesm2022/ngneers-controls-icon-check-DdAQ9k-T.mjs +4 -0
  47. package/fesm2022/ngneers-controls-icon-check-DdAQ9k-T.mjs.map +1 -0
  48. package/fesm2022/ngneers-controls-icon-chevron_down-HO-z-xOr.mjs +4 -0
  49. package/fesm2022/ngneers-controls-icon-chevron_down-HO-z-xOr.mjs.map +1 -0
  50. package/fesm2022/ngneers-controls-icon-chevron_left-CC5psi16.mjs +4 -0
  51. package/fesm2022/ngneers-controls-icon-chevron_left-CC5psi16.mjs.map +1 -0
  52. package/fesm2022/ngneers-controls-icon-chevron_right-BRxlzx4G.mjs +4 -0
  53. package/fesm2022/ngneers-controls-icon-chevron_right-BRxlzx4G.mjs.map +1 -0
  54. package/fesm2022/ngneers-controls-icon-chevron_up-cqhPO7g2.mjs +4 -0
  55. package/fesm2022/ngneers-controls-icon-chevron_up-cqhPO7g2.mjs.map +1 -0
  56. package/fesm2022/ngneers-controls-icon-ellipsis-DXIGA1sk.mjs +4 -0
  57. package/fesm2022/ngneers-controls-icon-ellipsis-DXIGA1sk.mjs.map +1 -0
  58. package/fesm2022/ngneers-controls-icon-filter-oU7E6Xgr.mjs +4 -0
  59. package/fesm2022/ngneers-controls-icon-filter-oU7E6Xgr.mjs.map +1 -0
  60. package/fesm2022/ngneers-controls-icon-filter_solid-CqIKuR4N.mjs +4 -0
  61. package/fesm2022/ngneers-controls-icon-filter_solid-CqIKuR4N.mjs.map +1 -0
  62. package/fesm2022/ngneers-controls-icon-magnifying_glass-T4Hzbkig.mjs +4 -0
  63. package/fesm2022/ngneers-controls-icon-magnifying_glass-T4Hzbkig.mjs.map +1 -0
  64. package/fesm2022/ngneers-controls-icon-minus-oGDEFO4E.mjs +4 -0
  65. package/fesm2022/ngneers-controls-icon-minus-oGDEFO4E.mjs.map +1 -0
  66. package/fesm2022/ngneers-controls-icon-sort-CRD4tafz.mjs +4 -0
  67. package/fesm2022/ngneers-controls-icon-sort-CRD4tafz.mjs.map +1 -0
  68. package/fesm2022/ngneers-controls-icon-sort_down-DiFB1P6R.mjs +4 -0
  69. package/fesm2022/ngneers-controls-icon-sort_down-DiFB1P6R.mjs.map +1 -0
  70. package/fesm2022/ngneers-controls-icon-sort_up-Bq_q3hIi.mjs +4 -0
  71. package/fesm2022/ngneers-controls-icon-sort_up-Bq_q3hIi.mjs.map +1 -0
  72. package/fesm2022/ngneers-controls-icon-xmark-BZKZORiu.mjs +4 -0
  73. package/fesm2022/ngneers-controls-icon-xmark-BZKZORiu.mjs.map +1 -0
  74. package/fesm2022/ngneers-controls-icon.mjs +60 -18
  75. package/fesm2022/ngneers-controls-icon.mjs.map +1 -1
  76. package/fesm2022/ngneers-controls-inplace.mjs +107 -0
  77. package/fesm2022/ngneers-controls-inplace.mjs.map +1 -0
  78. package/fesm2022/ngneers-controls-input-field.mjs +141 -0
  79. package/fesm2022/ngneers-controls-input-field.mjs.map +1 -0
  80. package/fesm2022/ngneers-controls-input-mask.mjs +282 -0
  81. package/fesm2022/ngneers-controls-input-mask.mjs.map +1 -0
  82. package/fesm2022/ngneers-controls-input.mjs +69 -0
  83. package/fesm2022/ngneers-controls-input.mjs.map +1 -0
  84. package/fesm2022/ngneers-controls-item-view.mjs +441 -0
  85. package/fesm2022/ngneers-controls-item-view.mjs.map +1 -0
  86. package/fesm2022/ngneers-controls-list-box.mjs +157 -53
  87. package/fesm2022/ngneers-controls-list-box.mjs.map +1 -1
  88. package/fesm2022/ngneers-controls-menu.mjs +332 -0
  89. package/fesm2022/ngneers-controls-menu.mjs.map +1 -0
  90. package/fesm2022/ngneers-controls-message.mjs +29 -0
  91. package/fesm2022/ngneers-controls-message.mjs.map +1 -0
  92. package/fesm2022/ngneers-controls-paginator.mjs +111 -0
  93. package/fesm2022/ngneers-controls-paginator.mjs.map +1 -0
  94. package/fesm2022/ngneers-controls-popover.mjs +129 -40
  95. package/fesm2022/ngneers-controls-popover.mjs.map +1 -1
  96. package/fesm2022/ngneers-controls-progress.mjs +82 -0
  97. package/fesm2022/ngneers-controls-progress.mjs.map +1 -0
  98. package/fesm2022/ngneers-controls-scroller.mjs +162 -78
  99. package/fesm2022/ngneers-controls-scroller.mjs.map +1 -1
  100. package/fesm2022/ngneers-controls-select-button.mjs +55 -0
  101. package/fesm2022/ngneers-controls-select-button.mjs.map +1 -0
  102. package/fesm2022/ngneers-controls-select.mjs +313 -103
  103. package/fesm2022/ngneers-controls-select.mjs.map +1 -1
  104. package/fesm2022/ngneers-controls-slider.mjs +155 -0
  105. package/fesm2022/ngneers-controls-slider.mjs.map +1 -0
  106. package/fesm2022/ngneers-controls-spinner.mjs +169 -0
  107. package/fesm2022/ngneers-controls-spinner.mjs.map +1 -0
  108. package/fesm2022/ngneers-controls-splitter.mjs +717 -0
  109. package/fesm2022/ngneers-controls-splitter.mjs.map +1 -0
  110. package/fesm2022/ngneers-controls-switch.mjs +39 -0
  111. package/fesm2022/ngneers-controls-switch.mjs.map +1 -0
  112. package/fesm2022/ngneers-controls-table.mjs +379 -0
  113. package/fesm2022/ngneers-controls-table.mjs.map +1 -0
  114. package/fesm2022/ngneers-controls-tabs.mjs +287 -0
  115. package/fesm2022/ngneers-controls-tabs.mjs.map +1 -0
  116. package/fesm2022/ngneers-controls-tag.mjs +29 -0
  117. package/fesm2022/ngneers-controls-tag.mjs.map +1 -0
  118. package/fesm2022/ngneers-controls-toast.mjs +184 -0
  119. package/fesm2022/ngneers-controls-toast.mjs.map +1 -0
  120. package/fesm2022/ngneers-controls-toggle-button.mjs +65 -0
  121. package/fesm2022/ngneers-controls-toggle-button.mjs.map +1 -0
  122. package/fesm2022/ngneers-controls-tooltip.mjs +454 -0
  123. package/fesm2022/ngneers-controls-tooltip.mjs.map +1 -0
  124. package/fesm2022/ngneers-controls-utils-ng.mjs +227 -0
  125. package/fesm2022/ngneers-controls-utils-ng.mjs.map +1 -0
  126. package/fesm2022/ngneers-controls-utils.mjs +217 -60
  127. package/fesm2022/ngneers-controls-utils.mjs.map +1 -1
  128. package/fesm2022/ngneers-controls.mjs.map +1 -1
  129. package/package.json +167 -32
  130. package/types/ngneers-controls-accordion.d.ts +114 -0
  131. package/types/ngneers-controls-api-ng.d.ts +291 -0
  132. package/types/ngneers-controls-api.d.ts +99 -0
  133. package/types/ngneers-controls-avatar.d.ts +50 -0
  134. package/types/ngneers-controls-base.d.ts +166 -0
  135. package/types/ngneers-controls-breadcrumb.d.ts +86 -0
  136. package/types/ngneers-controls-button-group.d.ts +30 -0
  137. package/types/ngneers-controls-button.d.ts +34 -0
  138. package/types/ngneers-controls-calendar.d.ts +275 -0
  139. package/types/ngneers-controls-checkbox.d.ts +38 -0
  140. package/types/ngneers-controls-chip.d.ts +37 -0
  141. package/types/ngneers-controls-defer.d.ts +22 -0
  142. package/types/ngneers-controls-dialog.d.ts +218 -0
  143. package/types/ngneers-controls-directives.d.ts +146 -0
  144. package/types/ngneers-controls-drawer.d.ts +220 -0
  145. package/types/ngneers-controls-edit-inplace.d.ts +182 -0
  146. package/types/ngneers-controls-filter.d.ts +304 -0
  147. package/types/ngneers-controls-i18n.d.ts +108 -0
  148. package/types/ngneers-controls-icon.d.ts +74 -0
  149. package/types/ngneers-controls-inplace.d.ts +95 -0
  150. package/types/ngneers-controls-input-field.d.ts +159 -0
  151. package/types/ngneers-controls-input-mask.d.ts +83 -0
  152. package/types/ngneers-controls-input.d.ts +27 -0
  153. package/types/ngneers-controls-item-view.d.ts +211 -0
  154. package/types/ngneers-controls-list-box.d.ts +216 -0
  155. package/types/ngneers-controls-menu.d.ts +178 -0
  156. package/types/ngneers-controls-message.d.ts +19 -0
  157. package/types/ngneers-controls-paginator.d.ts +162 -0
  158. package/types/ngneers-controls-popover.d.ts +101 -0
  159. package/types/ngneers-controls-progress.d.ts +44 -0
  160. package/types/ngneers-controls-scroller.d.ts +137 -0
  161. package/types/ngneers-controls-select-button.d.ts +37 -0
  162. package/types/ngneers-controls-select.d.ts +314 -0
  163. package/types/ngneers-controls-slider.d.ts +53 -0
  164. package/types/ngneers-controls-spinner.d.ts +105 -0
  165. package/types/ngneers-controls-splitter.d.ts +391 -0
  166. package/types/ngneers-controls-switch.d.ts +18 -0
  167. package/types/ngneers-controls-table.d.ts +157 -0
  168. package/types/ngneers-controls-tabs.d.ts +106 -0
  169. package/types/ngneers-controls-tag.d.ts +19 -0
  170. package/types/ngneers-controls-toast.d.ts +70 -0
  171. package/types/ngneers-controls-toggle-button.d.ts +46 -0
  172. package/types/ngneers-controls-tooltip.d.ts +188 -0
  173. package/types/ngneers-controls-utils-ng.d.ts +57 -0
  174. package/types/ngneers-controls-utils.d.ts +130 -0
  175. package/api/index.d.ts +0 -134
  176. package/custom-types/index.d.ts +0 -7
  177. package/dialog/index.d.ts +0 -43
  178. package/fesm2022/ngneers-controls-custom-types.mjs +0 -4
  179. package/fesm2022/ngneers-controls-custom-types.mjs.map +0 -1
  180. package/fesm2022/ngneers-controls-form-field.mjs +0 -33
  181. package/fesm2022/ngneers-controls-form-field.mjs.map +0 -1
  182. package/fesm2022/ngneers-controls-lazy-cacher.mjs +0 -30
  183. package/fesm2022/ngneers-controls-lazy-cacher.mjs.map +0 -1
  184. package/fesm2022/ngneers-controls-text-field.mjs +0 -23
  185. package/fesm2022/ngneers-controls-text-field.mjs.map +0 -1
  186. package/form-field/index.d.ts +0 -19
  187. package/icon/index.d.ts +0 -30
  188. package/lazy-cacher/index.d.ts +0 -14
  189. package/list-box/index.d.ts +0 -58
  190. package/popover/index.d.ts +0 -41
  191. package/scroller/index.d.ts +0 -95
  192. package/select/index.d.ts +0 -86
  193. package/text-field/index.d.ts +0 -10
  194. package/utils/index.d.ts +0 -36
  195. /package/{index.d.ts → types/ngneers-controls.d.ts} +0 -0
@@ -0,0 +1,717 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, model, computed, ChangeDetectionStrategy, Component, afterRenderEffect, untracked, signal, inject, ViewContainerRef, output, viewChild, contentChildren, runInInjectionContext, 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
+
10
+ /**
11
+ * @category control
12
+ */
13
+ class NgnSplitterPanel extends NgnBase {
14
+ theme = this.injectThemeTemplate(splitterControlTemplate, 'panel');
15
+ _fallbackAreaName = generateElementId();
16
+ name = input(...(ngDevMode ? [undefined, { debugName: "name" }] : []));
17
+ size = model('1fr', ...(ngDevMode ? [{ debugName: "size" }] : []));
18
+ minSize = model('0px', ...(ngDevMode ? [{ debugName: "minSize" }] : []));
19
+ maxSize = model('100%', ...(ngDevMode ? [{ debugName: "maxSize" }] : []));
20
+ ariaLabel = input(...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : []));
21
+ ariaLabelledBy = input(...(ngDevMode ? [undefined, { debugName: "ariaLabelledBy" }] : []));
22
+ gridArea = computed(() => this.name() ?? this._fallbackAreaName, ...(ngDevMode ? [{ debugName: "gridArea" }] : []));
23
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnSplitterPanel, deps: null, target: i0.ɵɵFactoryTarget.Component });
24
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.0", 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 />\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
25
+ }
26
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnSplitterPanel, decorators: [{
27
+ type: Component,
28
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngn-splitter-panel', providers: [provideSelf(NgnSplitterPanel)], host: {
29
+ role: 'region',
30
+ '[style.grid-area]': 'gridArea()',
31
+ '[aria-label]': 'ariaLabel()',
32
+ '[attr.aria-labelledby]': 'ariaLabelledBy()',
33
+ }, template: "<ng-content />\r\n" }]
34
+ }], 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 }] }] } });
35
+
36
+ function isSplitterPanelSize(value) {
37
+ if (typeof value !== 'string')
38
+ return false;
39
+ const m = value.match(/^(.+)(px|fr)$/);
40
+ if (!m || !m[1])
41
+ return false;
42
+ if (isNaN(parseFloat(m[1])))
43
+ return false;
44
+ return true;
45
+ }
46
+ function getSplitterPanelSizeUnit(value) {
47
+ return value.slice(-2);
48
+ }
49
+ function getSplitterPanelSizeValue(value) {
50
+ return parseFloat(value.slice(0, -2));
51
+ }
52
+ function isSplitterPanelSizeLimit(value) {
53
+ if (typeof value !== 'string')
54
+ return false;
55
+ const m = value.match(/^(.+)(px|%)$/);
56
+ if (!m || !m[1])
57
+ return false;
58
+ if (isNaN(parseFloat(m[1])))
59
+ return false;
60
+ return true;
61
+ }
62
+ function getSplitterPanelSizeLimitUnit(value) {
63
+ return value.endsWith('px') ? 'px' : '%';
64
+ }
65
+ function getSplitterPanelSizeLimitValue(value) {
66
+ return value.endsWith('px') ? parseFloat(value.slice(0, -2)) : parseFloat(value.slice(0, -1));
67
+ }
68
+ function getSplitterPanelSizeLimitInPx(value, totalSize) {
69
+ const unit = getSplitterPanelSizeLimitUnit(value);
70
+ const sizeValue = getSplitterPanelSizeLimitValue(value);
71
+ return unit === 'px' ? sizeValue : (sizeValue / 100) * totalSize;
72
+ }
73
+ function expandSplitterPanelSize(value) {
74
+ return {
75
+ value: getSplitterPanelSizeValue(value),
76
+ unit: getSplitterPanelSizeUnit(value),
77
+ };
78
+ }
79
+ function expandSplitterPanelSizeLimit(value) {
80
+ return {
81
+ value: getSplitterPanelSizeLimitValue(value),
82
+ unit: getSplitterPanelSizeLimitUnit(value),
83
+ };
84
+ }
85
+ function collapseSplitterPanelSize(size) {
86
+ return `${size.value}${size.unit}`;
87
+ }
88
+ function collapseSplitterPanelSizeLimit(size) {
89
+ return `${size.value}${size.unit}`;
90
+ }
91
+
92
+ const LAST_CALC_SIZE_SYMBOL = Symbol('lastCalcSize');
93
+ /**
94
+ * Default implementation of the {@link SplitterCalculator} interface.
95
+ */
96
+ class DefaultSplitterCalculator {
97
+ panels;
98
+ dividers;
99
+ panelOrder;
100
+ layout;
101
+ splitterSize;
102
+ constructor(splitter) {
103
+ this.panels = splitter.panels;
104
+ this.dividers = splitter.dividers;
105
+ this.panelOrder = splitter.panelOrder;
106
+ this.layout = splitter.layout;
107
+ this.splitterSize = computed(() => this.layout() === 'vertical' ? splitter.elementSize().height : splitter.elementSize().width, ...(ngDevMode ? [{ debugName: "splitterSize" }] : []));
108
+ // Signal fires when any panel size is not calculated
109
+ const hasUncalculatedSizesSig = computed(() => this.panels().some(panel => !this.isPanelSizeCalculated(panel)), { equal: (_, b) => b === false });
110
+ // Ensure that min and max limits are handled correctly
111
+ afterRenderEffect(() => {
112
+ // Recalculate on outside changes (e.g. panel size input changes, state restore, etc.)
113
+ hasUncalculatedSizesSig();
114
+ // Recalculate on splitter size changes
115
+ this.splitterSize();
116
+ untracked(() => this.ensureMinMaxSizes());
117
+ });
118
+ }
119
+ orderedPanels = computed(() => {
120
+ const panels = this.panels();
121
+ const order = this.panelOrder();
122
+ return order
123
+ ? [...panels].sort((a, b) => {
124
+ const aIndex = order.indexOf(a['gridArea']());
125
+ const bIndex = order.indexOf(b['gridArea']());
126
+ if (aIndex === -1 && bIndex === -1)
127
+ return 0;
128
+ if (aIndex === -1)
129
+ return 1; // a is not in order, put it at the end
130
+ if (bIndex === -1)
131
+ return -1; // b is not in order, put it at the end
132
+ return aIndex - bIndex; // sort by index in panelOrder
133
+ })
134
+ : panels;
135
+ }, ...(ngDevMode ? [{ debugName: "orderedPanels" }] : []));
136
+ gridTemplateSizes = computed(() => {
137
+ const panels = this.orderedPanels();
138
+ const dividerSizes = this.dividerSizes();
139
+ if (panels.length === 0)
140
+ return 'none';
141
+ const result = [];
142
+ panels.forEach((panel, i) => {
143
+ const size = panel.size();
144
+ result.push(size);
145
+ if (i < dividerSizes.length) {
146
+ const dividerSize = dividerSizes[i] || 0;
147
+ result.push(`${dividerSize}px`);
148
+ }
149
+ });
150
+ return result.join(' ');
151
+ }, ...(ngDevMode ? [{ debugName: "gridTemplateSizes" }] : []));
152
+ gridTemplateAreas = computed(() => {
153
+ const panels = this.orderedPanels();
154
+ if (panels.length === 0)
155
+ return null;
156
+ let result = '';
157
+ panels.forEach((panel, i) => {
158
+ if (i > 0) {
159
+ result +=
160
+ this.layout() === 'horizontal' ? ` ngn-divider-${i - 1} ` : ` "ngn-divider-${i - 1}" `;
161
+ }
162
+ result += this.layout() === 'horizontal' ? panel['gridArea']() : `"${panel['gridArea']()}"`;
163
+ });
164
+ return this.layout() === 'horizontal' ? `"${result}"` : result;
165
+ }, ...(ngDevMode ? [{ debugName: "gridTemplateAreas" }] : []));
166
+ minSize = computed(() => {
167
+ const { px, '%': pc } = this.panels().reduce((acc, panel) => {
168
+ const size = panel.size();
169
+ if (getSplitterPanelSizeUnit(size) === 'px') {
170
+ acc.px += getSplitterPanelSizeValue(size);
171
+ }
172
+ else {
173
+ const minSize = panel.minSize();
174
+ acc[getSplitterPanelSizeLimitUnit(minSize)] += getSplitterPanelSizeLimitValue(minSize);
175
+ }
176
+ return acc;
177
+ }, { px: 0, '%': 0 });
178
+ return `calc(${px + this.totalDividerSize()}px + ${pc}%)`;
179
+ }, ...(ngDevMode ? [{ debugName: "minSize" }] : []));
180
+ maxSize = computed(() => {
181
+ const { px, '%': pc } = this.panels().reduce((acc, panel) => {
182
+ const size = panel.size();
183
+ if (getSplitterPanelSizeUnit(size) === 'px') {
184
+ acc.px += getSplitterPanelSizeValue(size);
185
+ }
186
+ else {
187
+ const maxSize = panel.maxSize();
188
+ acc[getSplitterPanelSizeLimitUnit(maxSize)] += getSplitterPanelSizeLimitValue(maxSize);
189
+ }
190
+ return acc;
191
+ }, { px: 0, '%': 0 });
192
+ return `calc(${px + this.totalDividerSize()}px + ${pc}%)`;
193
+ }, ...(ngDevMode ? [{ debugName: "maxSize" }] : []));
194
+ dragContext = signal(null, ...(ngDevMode ? [{ debugName: "dragContext" }] : []));
195
+ dividerSizes = computed(() => this.dividers().map(d => {
196
+ const el = d.rootNodes.find(x => x instanceof HTMLElement);
197
+ return el ? (this.layout() === 'horizontal' ? el.offsetWidth : el.offsetHeight) : 0;
198
+ }), ...(ngDevMode ? [{ debugName: "dividerSizes" }] : []));
199
+ totalDividerSize = computed(() => this.dividerSizes().reduce((acc, size) => acc + size, 0), ...(ngDevMode ? [{ debugName: "totalDividerSize" }] : []));
200
+ totalPanelSizes = computed(() => this.panels().reduce((acc, panel) => {
201
+ const size = panel.size();
202
+ acc[getSplitterPanelSizeUnit(size)] += getSplitterPanelSizeValue(size);
203
+ return acc;
204
+ }, { px: 0, fr: 0 }), ...(ngDevMode ? [{ debugName: "totalPanelSizes" }] : []));
205
+ startDrag(index, event) {
206
+ const panels = this.orderedPanels();
207
+ if (index < 0 || index >= panels.length - 1)
208
+ return;
209
+ this.dragContext.set({
210
+ dividerIndex: index,
211
+ pointerId: event.pointerId,
212
+ startPosition: this.layout() === 'horizontal' ? event.clientX : event.clientY,
213
+ panels: panels.map(panel => this.createContextPanel(panel)),
214
+ fractionFactors: this.getCurrentFractionFactors(),
215
+ });
216
+ }
217
+ drag(index, event) {
218
+ const ctx = this.dragContext();
219
+ if (!ctx || ctx.dividerIndex !== index || ctx.pointerId !== event.pointerId)
220
+ return;
221
+ const { startPosition } = ctx;
222
+ let pxDelta;
223
+ if (this.layout() === 'horizontal') {
224
+ pxDelta = event.clientX - startPosition;
225
+ }
226
+ else {
227
+ pxDelta = event.clientY - startPosition;
228
+ }
229
+ this.applyDividerDelta(index, pxDelta, ctx.panels, ctx.fractionFactors);
230
+ }
231
+ endDrag(index, event, isCancel) {
232
+ const ctx = this.dragContext();
233
+ if (!ctx || ctx.dividerIndex !== index || ctx.pointerId !== event.pointerId)
234
+ return;
235
+ if (isCancel) {
236
+ // Reset the panels to their original sizes
237
+ ctx.panels.forEach(p => p.panel.size.set(`${p.startSize.value}${p.startSize.unit}`));
238
+ }
239
+ this.dragContext.set(null);
240
+ }
241
+ moveDivider(index, pxDelta) {
242
+ const panels = this.orderedPanels();
243
+ if (index < 0 || index >= panels.length - 1)
244
+ return;
245
+ const leftPanel = panels[index] ??
246
+ throwExp('NgnSplitterCalculator', `Left panel is missing for divider at index ${index}`);
247
+ const rightPanel = panels[index + 1] ??
248
+ throwExp('NgnSplitterCalculator', `Right panel is missing for divider at index ${index}`);
249
+ // If the size is not calculated, we cannot move the divider
250
+ if (!this.isPanelSizeCalculated(leftPanel) || !this.isPanelSizeCalculated(rightPanel)) {
251
+ Logger.warn('Cannot move divider, panel sizes are not calculated');
252
+ return;
253
+ }
254
+ this.applyDividerDelta(index, pxDelta, panels.map(panel => this.createContextPanel(panel)), this.getCurrentFractionFactors());
255
+ }
256
+ ensureMinMaxSizes() {
257
+ const panels = this.orderedPanels();
258
+ if (panels.length === 0)
259
+ return;
260
+ const panelSizes = panels.map(panel => {
261
+ return {
262
+ panel,
263
+ size: {
264
+ unit: getSplitterPanelSizeUnit(panel.size()),
265
+ value: getSplitterPanelSizeValue(panel.size()),
266
+ },
267
+ minSizePx: getSplitterPanelSizeLimitInPx(panel.minSize(), this.splitterSize()),
268
+ maxSizePx: getSplitterPanelSizeLimitInPx(panel.maxSize(), this.splitterSize()),
269
+ };
270
+ });
271
+ // First make sure all px sizes are in the limits
272
+ for (const { size, minSizePx, maxSizePx } of panelSizes) {
273
+ if (size.unit === 'px') {
274
+ if (size.value < minSizePx) {
275
+ size.value = minSizePx;
276
+ }
277
+ else if (size.value > maxSizePx) {
278
+ size.value = maxSizePx;
279
+ }
280
+ }
281
+ }
282
+ // Calculate the fraction factors
283
+ const totalPanelSizes = panelSizes.reduce((acc, { size }) => {
284
+ acc[size.unit] += size.value;
285
+ return acc;
286
+ }, { px: 0, fr: 0 });
287
+ const frArea = this.splitterSize() - this.totalDividerSize() - totalPanelSizes.px;
288
+ const frPerPx = totalPanelSizes.fr / frArea;
289
+ const pxPerFr = frArea / totalPanelSizes.fr;
290
+ // Now make sure all fr sizes are in the limits
291
+ // We need to do this in a loop because we might need to adjust the fr sizes multiple times
292
+ // until all panels are within their limits while distributing the over-/underflow evenly
293
+ let frPanelsWithoutClamping = panelSizes.filter(p => p.size.unit === 'fr');
294
+ let frToDistribute = undefined; // Not needed initially
295
+ while (frPanelsWithoutClamping.length > 0 && frToDistribute !== 0) {
296
+ const frToAddPerPanel = frToDistribute ? frToDistribute / frPanelsWithoutClamping.length : 0;
297
+ const next = []; // Track panels that are still within limits
298
+ let currentTotalFrSize = totalPanelSizes.fr; // Track the total fr size after clamping
299
+ for (const p of frPanelsWithoutClamping) {
300
+ const minSizeFr = p.minSizePx * frPerPx;
301
+ const maxSizeFr = p.maxSizePx * frPerPx;
302
+ p.size.value += frToAddPerPanel;
303
+ if (p.size.value < minSizeFr) {
304
+ currentTotalFrSize = currentTotalFrSize - p.size.value + minSizeFr;
305
+ p.size.value = minSizeFr;
306
+ }
307
+ else if (p.size.value > maxSizeFr) {
308
+ currentTotalFrSize = currentTotalFrSize - p.size.value + maxSizeFr;
309
+ p.size.value = maxSizeFr;
310
+ }
311
+ else {
312
+ next.push(p);
313
+ }
314
+ }
315
+ frToDistribute = totalPanelSizes.fr - currentTotalFrSize;
316
+ if (Math.abs(frToDistribute * pxPerFr) < 1) {
317
+ frToDistribute = 0; // Stop if we are close enough to zero
318
+ }
319
+ frPanelsWithoutClamping = next;
320
+ }
321
+ // Now set all the new sizes to the panels
322
+ for (const { panel, size } of panelSizes) {
323
+ this.setPanelSize(panel, `${size.value}${size.unit}`);
324
+ }
325
+ }
326
+ createContextPanel(panel) {
327
+ return {
328
+ panel,
329
+ startSize: expandSplitterPanelSize(panel.size()),
330
+ minSize: expandSplitterPanelSizeLimit(panel.minSize()),
331
+ maxSize: expandSplitterPanelSizeLimit(panel.maxSize()),
332
+ };
333
+ }
334
+ getCurrentFractionFactors() {
335
+ const frArea = this.splitterSize() - this.totalDividerSize() - this.totalPanelSizes().px || 1; // Avoid division by zero
336
+ const totalFr = this.totalPanelSizes().fr || 1; // Avoid division by zero
337
+ return {
338
+ frPerPx: totalFr / frArea,
339
+ pxPerFr: frArea / totalFr,
340
+ };
341
+ }
342
+ setPanelSize(panel, size) {
343
+ panel.size.set(size);
344
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
345
+ panel[LAST_CALC_SIZE_SYMBOL] = size;
346
+ }
347
+ isPanelSizeCalculated(panel) {
348
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
349
+ return panel[LAST_CALC_SIZE_SYMBOL] === panel.size();
350
+ }
351
+ applyDividerDelta(dividerIndex, pxDelta, panels, fractionFactors) {
352
+ const appliedPanelDeltas = Array(panels.length).fill(0);
353
+ const recursion = (pxDelta, panelIndex, panelIndexIncrement) => {
354
+ if (panelIndex >= panels.length || panelIndex < 0)
355
+ return 0;
356
+ const panel = panels[panelIndex];
357
+ if (!panel) {
358
+ throw new NgnError('NgnSplitterCalculator', `Panel is missing at index ${panelIndex}`);
359
+ }
360
+ let unappliedDelta = 0;
361
+ const startPx = panel.startSize.unit === 'px'
362
+ ? panel.startSize.value
363
+ : fractionFactors.pxPerFr * panel.startSize.value;
364
+ const newPx = startPx + pxDelta;
365
+ if (pxDelta < 0) {
366
+ const min = panel.minSize.unit === 'px'
367
+ ? panel.minSize.value
368
+ : (panel.minSize.value / 100) * this.splitterSize();
369
+ if (min > newPx) {
370
+ unappliedDelta = -(min - newPx);
371
+ }
372
+ }
373
+ else if (pxDelta > 0) {
374
+ const max = panel.maxSize.unit === 'px'
375
+ ? panel.maxSize.value
376
+ : (panel.maxSize.value / 100) * this.splitterSize();
377
+ if (max < newPx) {
378
+ unappliedDelta = newPx - max;
379
+ }
380
+ }
381
+ const appliedDelta = pxDelta - unappliedDelta;
382
+ appliedPanelDeltas[panelIndex] = appliedDelta;
383
+ return unappliedDelta === 0
384
+ ? pxDelta
385
+ : appliedDelta +
386
+ recursion(unappliedDelta, panelIndex + panelIndexIncrement, panelIndexIncrement);
387
+ };
388
+ let appliedLeft = recursion(pxDelta, dividerIndex, -1);
389
+ let appliedRight = -recursion(-pxDelta, dividerIndex + 1, 1);
390
+ if (appliedLeft !== pxDelta || appliedRight !== pxDelta) {
391
+ pxDelta =
392
+ pxDelta < 0 ? Math.max(appliedLeft, appliedRight) : Math.min(appliedLeft, appliedRight);
393
+ appliedPanelDeltas.fill(0);
394
+ appliedLeft = recursion(pxDelta, dividerIndex, -1);
395
+ appliedRight = -recursion(-pxDelta, dividerIndex + 1, 1);
396
+ if (appliedLeft !== pxDelta || appliedRight !== pxDelta) {
397
+ return;
398
+ }
399
+ }
400
+ panels.forEach((panel, i) => {
401
+ const pxDelta = appliedPanelDeltas[i] || 0;
402
+ if (panel.startSize.unit === 'px') {
403
+ const size = panel.startSize.value + pxDelta;
404
+ this.setPanelSize(panel.panel, `${Math.max(0, size)}px`);
405
+ }
406
+ else {
407
+ const size = panel.startSize.value + pxDelta * fractionFactors.frPerPx;
408
+ this.setPanelSize(panel.panel, `${Math.max(0, size)}fr`);
409
+ }
410
+ });
411
+ }
412
+ }
413
+
414
+ /**
415
+ * @category control
416
+ */
417
+ class NgnSplitter extends NgnBase {
418
+ _viewContainer = inject(ViewContainerRef);
419
+ _config = inject(NGN_CONFIG);
420
+ theme = this.injectThemeTemplate(splitterControlTemplate, {
421
+ root: true,
422
+ dragging: () => this.isDragging(),
423
+ horizontal: () => this.layout() === 'horizontal',
424
+ vertical: () => this.layout() === 'vertical',
425
+ });
426
+ translations = inject(I18n).translations;
427
+ /**
428
+ * The layout of the splitter.
429
+ */
430
+ layout = model.required(...(ngDevMode ? [{ debugName: "layout" }] : []));
431
+ /**
432
+ * A array of panel names that defines the order of panels.
433
+ * If nullish, the order is determined by the order the panels are defined in the template.
434
+ */
435
+ panelOrder = model(...(ngDevMode ? [undefined, { debugName: "panelOrder" }] : []));
436
+ /**
437
+ * The storage to use for saving the splitter state.
438
+ * @default `session`
439
+ */
440
+ stateStorage = input(this._config.defaults.splitter.stateStorage, ...(ngDevMode ? [{ debugName: "stateStorage" }] : []));
441
+ /**
442
+ * The key to use for saving the splitter state.
443
+ * If nullish, the state will not be saved.
444
+ */
445
+ stateKey = input(...(ngDevMode ? [undefined, { debugName: "stateKey" }] : []));
446
+ /**
447
+ * The type of data to save in the splitter state.
448
+ * @default `['layout', 'panelOrder', 'panelSizes']`
449
+ */
450
+ stateData = input([
451
+ 'layout',
452
+ 'panelOrder',
453
+ 'panelSizes',
454
+ ], ...(ngDevMode ? [{ debugName: "stateData" }] : []));
455
+ /**
456
+ * The type of calculator to use for the splitter.
457
+ * @default `DefaultSplitterCalculator`
458
+ */
459
+ calculatorType = input(DefaultSplitterCalculator, ...(ngDevMode ? [{ debugName: "calculatorType" }] : []));
460
+ /**
461
+ * The step size for moving the dividers using the keyboard.
462
+ * This can be a pixel value (e.g., '5px') or a percentage value (e.g., '5%').
463
+ * If a percentage is used, it will be calculated based on the size of the splitter element.
464
+ * @default '5px'
465
+ */
466
+ step = input('5px', ...(ngDevMode ? [{ debugName: "step" }] : []));
467
+ /**
468
+ * Event emitted when the splitter state is being saved.
469
+ * This can be used to modify the state before it is saved.
470
+ */
471
+ stateSaving = output();
472
+ /**
473
+ * Event emitted when the splitter state is loaded.
474
+ * This can be used to modify the state before it is applied or to perform actions based on the loaded state.
475
+ */
476
+ stateLoading = output();
477
+ dividerTemplateType = templateTypeFn();
478
+ _dividerTemplate = viewChild.required('defaultDividerTemplate');
479
+ /**
480
+ * The current dividers in the splitter.
481
+ */
482
+ dividers = signal([], ...(ngDevMode ? [{ debugName: "dividers" }] : []));
483
+ /**
484
+ * The current panels in the splitter.
485
+ */
486
+ panels = contentChildren(NgnSplitterPanel, ...(ngDevMode ? [{ debugName: "panels" }] : []));
487
+ /**
488
+ * The current size of the splitter element.
489
+ */
490
+ elementSize = elementSizeSignal(this.element);
491
+ /**
492
+ * A value indicating whether the splitter is currently being dragged.
493
+ */
494
+ isDragging = computed(() => this.calculator().dragContext() !== null, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
495
+ calculator = computed(() => {
496
+ const calculatorType = this.calculatorType();
497
+ return untracked(() => runInInjectionContext(this.injector, () => new calculatorType(this)));
498
+ }, ...(ngDevMode ? [{ debugName: "calculator" }] : []));
499
+ constructor() {
500
+ super();
501
+ afterRenderEffect(() => {
502
+ const panels = this.panels();
503
+ this.updateDividers(panels);
504
+ });
505
+ registerState({
506
+ storage: () => this.stateStorage(),
507
+ key: () => this.stateKey(),
508
+ valueFn: this.computeState.bind(this),
509
+ onLoad: this.onStateLoad.bind(this),
510
+ debounce: 100,
511
+ });
512
+ }
513
+ ngOnDestroy() {
514
+ // Clean up dividers
515
+ this.dividers().forEach(divider => divider.destroy());
516
+ this.dividers.set([]);
517
+ }
518
+ onHandlePointerDown(index, event) {
519
+ const target = event.target;
520
+ if (!(target instanceof HTMLElement)) {
521
+ throw new Error('Event target is not an HTMLElement');
522
+ }
523
+ // Make sure the element is stable before capturing the pointer
524
+ requestAnimationFrame(() => {
525
+ try {
526
+ target.setPointerCapture(event.pointerId);
527
+ }
528
+ catch {
529
+ // Ignore errors if the element is not capable of capturing the pointer
530
+ }
531
+ });
532
+ this.calculator().startDrag(index, event);
533
+ }
534
+ onHandlePointerMove(index, event) {
535
+ this.calculator().drag(index, event);
536
+ }
537
+ onHandlePointerUp(index, event) {
538
+ this.calculator().endDrag(index, event, false);
539
+ }
540
+ onHandlePointerCancel(index, event) {
541
+ this.calculator().endDrag(index, event, true);
542
+ }
543
+ onHandleKeyDown(index, event) {
544
+ if ((event.key === 'ArrowLeft' && this.layout() === 'horizontal') ||
545
+ (event.key === 'ArrowUp' && this.layout() === 'vertical')) {
546
+ this.calculator().moveDivider(index, -this.getStepInPx());
547
+ event.preventDefault(); // Prevent default scrolling behavior
548
+ }
549
+ else if ((event.key === 'ArrowRight' && this.layout() === 'horizontal') ||
550
+ (event.key === 'ArrowDown' && this.layout() === 'vertical')) {
551
+ this.calculator().moveDivider(index, this.getStepInPx());
552
+ event.preventDefault(); // Prevent default scrolling behavior
553
+ }
554
+ else if (event.key === 'Home') {
555
+ this.calculator().moveDivider(index, Number.NEGATIVE_INFINITY);
556
+ event.preventDefault(); // Prevent default scrolling behavior
557
+ }
558
+ else if (event.key === 'End') {
559
+ this.calculator().moveDivider(index, Number.POSITIVE_INFINITY);
560
+ event.preventDefault(); // Prevent default scrolling behavior
561
+ }
562
+ }
563
+ updateDividers(panels) {
564
+ this.dividers.update(divider => {
565
+ if (divider.length === panels.length - 1) {
566
+ return divider; // No need to update if the number of dividers matches the number of panels
567
+ }
568
+ else if (divider.length < panels.length - 1) {
569
+ // Add missing dividers
570
+ const newDividers = [...divider];
571
+ for (let i = divider.length; i < panels.length - 1; i++) {
572
+ newDividers.push(this.createDivider(i));
573
+ }
574
+ return newDividers;
575
+ }
576
+ else {
577
+ // More dividers than needed, remove the excess
578
+ divider.slice(panels.length - 1).forEach(divider => divider.destroy());
579
+ return divider.slice(0, panels.length - 1);
580
+ }
581
+ });
582
+ // Move dividers to the correct positions
583
+ panels.forEach((panel, i) => {
584
+ const divider = this.dividers()[i - 1];
585
+ if (!divider) {
586
+ throw new NgnError('NgnSplitter', `Divider is missing for panel at index ${i}`);
587
+ }
588
+ this.moveDividerBefore(panel, divider);
589
+ });
590
+ }
591
+ createDivider(index) {
592
+ const viewRef = this._viewContainer.createEmbeddedView(this._dividerTemplate(), { index });
593
+ viewRef.detectChanges();
594
+ return viewRef;
595
+ }
596
+ moveDividerBefore(panel, divider) {
597
+ const panelElement = panel.element.nativeElement;
598
+ divider.rootNodes.forEach(node => {
599
+ if (node instanceof HTMLElement) {
600
+ panelElement.parentElement?.insertBefore(node, panelElement);
601
+ }
602
+ });
603
+ }
604
+ computeState(previousState) {
605
+ const data = this.stateData();
606
+ const state = {
607
+ layout: data.includes('layout') ? this.layout() : undefined,
608
+ panelOrder: data.includes('panelOrder') ? this.panelOrder() : undefined,
609
+ panelSizes: data.includes('panelSizes')
610
+ ? this.panels().reduce((acc, panel, index) => {
611
+ acc[panel.name() || `ngn-panel-${index}`] = panel.size();
612
+ return acc;
613
+ }, { ...previousState?.panelSizes })
614
+ : undefined,
615
+ };
616
+ this.stateSaving.emit(state);
617
+ return state;
618
+ }
619
+ onStateLoad(state) {
620
+ if (state) {
621
+ this.ensureValidState(state);
622
+ this.stateLoading.emit(state);
623
+ this.applyFromState(state);
624
+ }
625
+ return state;
626
+ }
627
+ ensureValidState(state) {
628
+ if (state.layout && state.layout !== 'horizontal' && state.layout !== 'vertical') {
629
+ Logger.warn(`Invalid layout in saved splitter state.`, { state });
630
+ delete state.layout;
631
+ }
632
+ if (state.panelOrder &&
633
+ (!Array.isArray(state.panelOrder) || state.panelOrder.some(x => typeof x !== 'string'))) {
634
+ Logger.warn(`Invalid panelOrder in saved splitter state.`, { state });
635
+ delete state.panelOrder;
636
+ }
637
+ if (state.panelSizes &&
638
+ (typeof state.panelSizes !== 'object' ||
639
+ state.panelSizes === null ||
640
+ Object.values(state.panelSizes).some(x => !isSplitterPanelSize(x)))) {
641
+ Logger.warn(`Invalid panelSizes in saved splitter state.`, { state });
642
+ delete state.panelSizes;
643
+ }
644
+ }
645
+ applyFromState(state) {
646
+ if (state.layout && this.stateData().includes('layout')) {
647
+ this.layout.set(state.layout);
648
+ }
649
+ if (state.panelOrder && this.stateData().includes('panelOrder')) {
650
+ this.panelOrder.set(state.panelOrder);
651
+ }
652
+ if (state.panelSizes && this.stateData().includes('panelSizes')) {
653
+ const panels = this.panels();
654
+ for (let i = 0; i < panels.length; i++) {
655
+ const panelName = panels[i]?.name() || `ngn-panel-${i}`;
656
+ if (panelName in state.panelSizes) {
657
+ const panelSize = state.panelSizes[panelName];
658
+ if (!panelSize) {
659
+ continue;
660
+ }
661
+ panels[i]?.size.set(panelSize);
662
+ }
663
+ }
664
+ }
665
+ }
666
+ getStepInPx() {
667
+ const step = this.step();
668
+ if (step.endsWith('px')) {
669
+ return parseFloat(step.slice(0, -2));
670
+ }
671
+ else if (step.endsWith('%')) {
672
+ const size = this.layout() === 'horizontal' ? this.elementSize().width : this.elementSize().height;
673
+ return (parseFloat(step.slice(0, -1)) / 100) * size;
674
+ }
675
+ else {
676
+ Logger.warn(`Invalid step value: ${step}.`);
677
+ return 10; // Default step in pixels
678
+ }
679
+ }
680
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnSplitter, deps: [], target: i0.ɵɵFactoryTarget.Component });
681
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.0", 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 }, 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 />\r\n\r\n<ng-template #defaultDividerTemplate [ngnTemplate]=\"dividerTemplateType\" let-index=\"index\">\r\n <div\r\n [style.grid-area]=\"`ngn-divider-${index}`\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"{\r\n divider: true,\r\n 'divider-dragging': calculator().dragContext()?.dividerIndex === index,\r\n }\"\r\n >\r\n <button\r\n role=\"separator\"\r\n [aria-orientation]=\"layout()\"\r\n [aria-label]=\"translations['splitter_handleLabel']()\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'divider-handle'\"\r\n (pointerdown)=\"onHandlePointerDown(index, $event)\"\r\n (pointermove)=\"onHandlePointerMove(index, $event)\"\r\n (pointerup)=\"onHandlePointerUp(index, $event)\"\r\n (pointercancel)=\"onHandlePointerCancel(index, $event)\"\r\n (keydown)=\"onHandleKeyDown(index, $event)\"\r\n ></button>\r\n </div>\r\n</ng-template>\r\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass"] }, { kind: "directive", type: NgnTemplate, selector: "ng-template[ngnTemplate]", inputs: ["ngnTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
682
+ }
683
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnSplitter, decorators: [{
684
+ type: Component,
685
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngn-splitter', imports: [NgnPt, NgnTemplate], providers: [provideSelf(NgnSplitter)], host: {
686
+ role: 'region',
687
+ '[style.grid-template-columns]': `layout() === 'horizontal' ? calculator().gridTemplateSizes() : null`,
688
+ '[style.grid-template-rows]': `layout() === 'vertical' ? calculator().gridTemplateSizes() : null`,
689
+ '[style.grid-template-areas]': 'calculator().gridTemplateAreas()',
690
+ '[style.max-width]': `layout() === 'horizontal' ? calculator().maxSize() : null`,
691
+ '[style.max-height]': `layout() === 'vertical' ? calculator().maxSize() : null`,
692
+ '[style.min-width]': `layout() === 'horizontal' ? calculator().minSize() : null`,
693
+ '[style.min-height]': `layout() === 'vertical' ? calculator().minSize() : null`,
694
+ }, template: "<ng-content />\r\n\r\n<ng-template #defaultDividerTemplate [ngnTemplate]=\"dividerTemplateType\" let-index=\"index\">\r\n <div\r\n [style.grid-area]=\"`ngn-divider-${index}`\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"{\r\n divider: true,\r\n 'divider-dragging': calculator().dragContext()?.dividerIndex === index,\r\n }\"\r\n >\r\n <button\r\n role=\"separator\"\r\n [aria-orientation]=\"layout()\"\r\n [aria-label]=\"translations['splitter_handleLabel']()\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'divider-handle'\"\r\n (pointerdown)=\"onHandlePointerDown(index, $event)\"\r\n (pointermove)=\"onHandlePointerMove(index, $event)\"\r\n (pointerup)=\"onHandlePointerUp(index, $event)\"\r\n (pointercancel)=\"onHandlePointerCancel(index, $event)\"\r\n (keydown)=\"onHandleKeyDown(index, $event)\"\r\n ></button>\r\n </div>\r\n</ng-template>\r\n" }]
695
+ }], 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 }] }], 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 }] }] } });
696
+
697
+ // This module is just for grouping the Splitter and SplitterPanel components for convenience.
698
+ // The components are standalone and can be used without this module.
699
+ class NgnSplitterModule {
700
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnSplitterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
701
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: NgnSplitterModule, imports: [NgnSplitter, NgnSplitterPanel], exports: [NgnSplitter, NgnSplitterPanel] });
702
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnSplitterModule });
703
+ }
704
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnSplitterModule, decorators: [{
705
+ type: NgModule,
706
+ args: [{
707
+ imports: [NgnSplitter, NgnSplitterPanel],
708
+ exports: [NgnSplitter, NgnSplitterPanel],
709
+ }]
710
+ }] });
711
+
712
+ /**
713
+ * Generated bundle index. Do not edit.
714
+ */
715
+
716
+ export { DefaultSplitterCalculator, NgnSplitter, NgnSplitterModule, NgnSplitterPanel };
717
+ //# sourceMappingURL=ngneers-controls-splitter.mjs.map