@ngneers/controls 0.0.1-pre1 → 0.0.1-pre2

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 +155 -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
@@ -1,79 +1,121 @@
1
1
  import { NgTemplateOutlet } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { input, viewChild, contentChild, computed, inject, ElementRef, effect, untracked, Component } from '@angular/core';
4
- import { toSignal } from '@angular/core/rxjs-interop';
5
- import { elementSizeSignal, templateTypesFn } from '@ngneers/controls/api';
6
- import { fromEvent, map } from 'rxjs';
3
+ import { input, contentChild, computed, Directive, inject, ElementRef, booleanAttribute, effect, untracked, ChangeDetectionStrategy, Component, signal } from '@angular/core';
4
+ import { templateTypesFn, elementSizeSignal } from '@ngneers/controls/api/ng';
5
+ import { NgnBase, NgnPt, provideSelf, getNearestNgnInstance } from '@ngneers/controls/base';
6
+ import * as i1 from '@ngneers/controls/directives';
7
+ import { NgnScrollAmount } from '@ngneers/controls/directives';
8
+ import { NgnError, getScrollTop, toggleClass } from '@ngneers/controls/utils';
9
+ import { scrollerControlTemplate } from '@ngneers/controls-themes/templates/scroller';
7
10
 
8
- class Scroller {
11
+ class ScrollerTemplates extends NgnBase {
12
+ /**
13
+ * The template to be used for rendering each item in the scroller.
14
+ * Can also be set using the `item` content child.
15
+ */
16
+ templateItem = input(null, ...(ngDevMode ? [{ debugName: "templateItem" }] : []));
17
+ _userItemTemplate = contentChild('item', ...(ngDevMode ? [{ debugName: "_userItemTemplate" }] : []));
18
+ itemTemplate = computed(() => this._userItemTemplate() ?? this.templateItem(), ...(ngDevMode ? [{ debugName: "itemTemplate" }] : []));
19
+ /**
20
+ * Template types for the scroller.
21
+ * Can be used with the {@link NgnTemplate} directive for type safe ng-templates.
22
+ */
23
+ templateTypes = templateTypesFn();
24
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ScrollerTemplates, deps: null, target: i0.ɵɵFactoryTarget.Directive });
25
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.1.0", type: ScrollerTemplates, isStandalone: true, inputs: { templateItem: { classPropertyName: "templateItem", publicName: "templateItem", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "_userItemTemplate", first: true, predicate: ["item"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0 });
26
+ }
27
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ScrollerTemplates, decorators: [{
28
+ type: Directive
29
+ }], propDecorators: { templateItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateItem", required: false }] }], _userItemTemplate: [{ type: i0.ContentChild, args: ['item', { isSignal: true }] }] } });
30
+
31
+ /**
32
+ * @category control
33
+ */
34
+ class NgnScroller extends ScrollerTemplates {
35
+ theme = this.injectThemeTemplate(scrollerControlTemplate, {
36
+ root: true,
37
+ virtual: () => !!this.virtual(),
38
+ });
39
+ _el = inject(ElementRef);
40
+ _scrollAmount = inject(NgnScrollAmount);
9
41
  /**
10
42
  * The items to be displayed in the scroller.
11
- * This is a required input and should be an array of items of type T.
43
+ * This is a required input and should be an array of items of type {@link T}.
44
+ */
45
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
46
+ /**
47
+ * The field of the item that uniquely identifies it.
12
48
  */
13
- items = input.required();
49
+ fieldId = input(...(ngDevMode ? [undefined, { debugName: "fieldId" }] : []));
14
50
  /**
15
51
  * Whether the scroller should use virtual scrolling.
16
52
  * When set to true, the scroller will only render the items that are currently visible
17
53
  * on the screen, improving performance for large lists.
18
54
  *
19
55
  * When virtual scrolling is enabled, {@link itemHeight} must be set to a non-zero value.
20
- * @defaultValue `false`
56
+ * @default `false`
21
57
  */
22
- virtual = input(false);
58
+ virtual = input(false, ...(ngDevMode ? [{ debugName: "virtual" }] : []));
23
59
  /**
24
60
  * When {@link virtual} scrolling is enabled, this input is required to define the height of each item in pixels.
25
61
  */
26
- itemHeight = input(0);
62
+ itemHeight = input(undefined, ...(ngDevMode ? [{ debugName: "itemHeight" }] : []));
27
63
  /**
28
64
  * When {@link virtual} scrolling is enabled, this input defines the number of items to be rendered above and below the visible area.
29
65
  * This can help to reduce flickering when scrolling.
30
- * @defaultValue `2`
66
+ * @default `2`
31
67
  */
32
- padding = input(2);
68
+ virtualPadding = input(2, ...(ngDevMode ? [{ debugName: "virtualPadding" }] : []));
33
69
  /**
34
70
  * Determines whether the scroller should have a tab index and be focusable.
35
- * @defaultValue `false`
71
+ * @default `false`
36
72
  */
37
- focusable = input(false);
73
+ focusable = input(false, { ...(ngDevMode ? { debugName: "focusable" } : {}), transform: booleanAttribute });
38
74
  /**
39
75
  * Determines whether an item is sticky or not.
40
76
  * If set, the scroller will stick the items with a truthy value for the specified field to the top of the scroller.
41
77
  */
42
- fieldSticky = input(null);
43
- _itemList = viewChild.required('itemList');
78
+ fieldSticky = input(null, ...(ngDevMode ? [{ debugName: "fieldSticky" }] : []));
79
+ _elementSize = elementSizeSignal(this._el);
80
+ _itemHeightPx = computed(() => this.itemHeight() ?? 0, ...(ngDevMode ? [{ debugName: "_itemHeightPx" }] : []));
81
+ _visibleItemCount = computed(() => this.virtual()
82
+ ? Math.ceil(this._elementSize().height / this._itemHeightPx() + this.virtualPadding() * 2)
83
+ : 0, ...(ngDevMode ? [{ debugName: "_visibleItemCount" }] : []));
84
+ _scrollTop = computed(() => this._scrollAmount.scrollTop(), ...(ngDevMode ? [{ debugName: "_scrollTop" }] : []));
44
85
  /**
45
- * The template to be used for rendering each item in the scroller.
46
- * Can also be set using the `item` content child.
86
+ * The index of the first item that is rendered in the (virtual) scroller.
47
87
  */
48
- templateItem = input(null);
49
- _userItemTemplate = contentChild('item');
50
- itemTemplate = computed(() => this._userItemTemplate() ?? this.templateItem());
51
- _el = inject((ElementRef));
52
- _scrollElement = this._el.nativeElement;
53
- _elementSize = elementSizeSignal(this._scrollElement);
54
- _visibleItemCount = computed(() => this.virtual()
55
- ? Math.ceil(this._elementSize().height / this.itemHeight() + this.padding() * 2)
56
- : 0);
57
- _scrollTop = toSignal(fromEvent(this._scrollElement, 'scroll').pipe(map(e => e.target.scrollTop)), { initialValue: 0 });
58
- _itemStartIndex = computed(() => this.virtual()
59
- ? Math.max(0, Math.ceil(this._scrollTop() / this.itemHeight()) - this.padding())
60
- : 0);
88
+ itemStartIndex = computed(() => this.virtual()
89
+ ? Math.max(0, Math.ceil(this._scrollTop() / this._itemHeightPx()) - this.virtualPadding())
90
+ : 0, ...(ngDevMode ? [{ debugName: "itemStartIndex" }] : []));
61
91
  _itemEndIndex = computed(() => this.virtual()
62
- ? Math.min(this.items().length, this._itemStartIndex() + this._visibleItemCount())
63
- : 0);
92
+ ? Math.min(this.items().length, this.itemStartIndex() + this._visibleItemCount())
93
+ : 0, ...(ngDevMode ? [{ debugName: "_itemEndIndex" }] : []));
94
+ paddingTop = computed(() => {
95
+ if (!this.virtual()) {
96
+ return 0;
97
+ }
98
+ return (this.itemStartIndex() - (this.latestStickyItem() ? 1 : 0)) * this._itemHeightPx();
99
+ }, ...(ngDevMode ? [{ debugName: "paddingTop" }] : []));
100
+ paddingBottom = computed(() => {
101
+ if (!this.virtual()) {
102
+ return 0;
103
+ }
104
+ return (this.items().length - this._itemEndIndex()) * this._itemHeightPx();
105
+ }, ...(ngDevMode ? [{ debugName: "paddingBottom" }] : []));
64
106
  visibleItems = computed(() => {
65
107
  if (!this.virtual()) {
66
108
  return this.items().map((item, index) => ({ item, index }));
67
109
  }
68
110
  return this.items()
69
- .slice(this._itemStartIndex(), this._itemEndIndex())
111
+ .slice(this.itemStartIndex(), this._itemEndIndex())
70
112
  .map((item, index) => {
71
113
  return {
72
114
  item,
73
- index: this._itemStartIndex() + index,
115
+ index: this.itemStartIndex() + index,
74
116
  };
75
117
  });
76
- });
118
+ }, ...(ngDevMode ? [{ debugName: "visibleItems" }] : []));
77
119
  /**
78
120
  * Returns the last sticky item that is not rendered regularly in the list.
79
121
  * Required because sticky items might need to be rendered longer than they would.
@@ -88,24 +130,19 @@ class Scroller {
88
130
  return null;
89
131
  }
90
132
  const unrenderedItemsAtTop = this.items()
91
- .slice(0, this._itemStartIndex())
133
+ .slice(0, this.itemStartIndex())
92
134
  .map((item, index) => ({
93
135
  item,
94
136
  index,
95
137
  }));
96
138
  const stickyItems = unrenderedItemsAtTop.filter(item => item.item[stickyField]);
97
139
  return stickyItems[stickyItems.length - 1] ?? null;
98
- });
99
- itemsTop = computed(() => {
100
- return (this._itemStartIndex() - (this.latestStickyItem() ? 1 : 0)) * this.itemHeight();
101
- });
102
- dummyHeight = computed(() => {
103
- return this.items().length * this.itemHeight();
104
- });
140
+ }, ...(ngDevMode ? [{ debugName: "latestStickyItem" }] : []));
105
141
  constructor() {
142
+ super();
106
143
  effect(() => {
107
144
  if (this.virtual() && !this.itemHeight()) {
108
- throw new Error('Item height must be set when virtual is true');
145
+ throw new NgnError('scroller', 'itemHeight must be set when virtual is true');
109
146
  }
110
147
  });
111
148
  }
@@ -113,51 +150,91 @@ class Scroller {
113
150
  * Scrolls the item with the given index into view.
114
151
  * @param index The index of the item to scroll to.
115
152
  */
116
- scrollToIndex(index) {
153
+ scrollToIndex(index, position = 'nearest') {
117
154
  untracked(() => {
118
- if (this.virtual()) {
119
- const scrollTop = this._scrollTop();
120
- const visibleHeight = this._elementSize().height;
121
- const itemTop = index * this.itemHeight();
122
- const itemBottom = itemTop + this.itemHeight();
123
- if (itemTop < scrollTop) {
124
- this._scrollElement.scrollTo({
125
- top: itemTop - 10,
126
- });
127
- }
128
- else if (itemBottom > scrollTop + visibleHeight) {
129
- this._scrollElement.scrollTo({
130
- top: itemBottom - visibleHeight + 10,
131
- });
155
+ const getItemSize = () => {
156
+ if (this.virtual()) {
157
+ const itemHeight = this._itemHeightPx();
158
+ const itemTop = index * itemHeight;
159
+ return { itemHeight, itemTop };
132
160
  }
133
- }
134
- else {
135
- const itemElement = this._itemList().nativeElement.querySelector(`:nth-child(${index + 1})`);
136
- if (itemElement) {
137
- itemElement.scrollIntoView({ block: 'nearest' });
161
+ else {
162
+ // index +1 because of the padding/spacer element at the top
163
+ const itemElement = this._el.nativeElement.children[index + 1];
164
+ if (itemElement) {
165
+ const itemTop = itemElement.offsetTop;
166
+ const itemHeight = itemElement.clientHeight;
167
+ return { itemTop, itemHeight };
168
+ }
169
+ return null;
138
170
  }
171
+ };
172
+ const size = getItemSize();
173
+ if (!size) {
174
+ return;
139
175
  }
176
+ const { itemTop, itemHeight } = size;
177
+ this._el.nativeElement.scrollTo({
178
+ top: getScrollTop(itemTop, itemHeight, this._el.nativeElement.clientHeight, this._el.nativeElement.scrollTop, position),
179
+ });
140
180
  });
141
181
  }
142
- /**
143
- * Template types for the scroller.
144
- * Can be used with the {@link @ngneers/controls/api#NgnTemplate | NgnTemplate} directive for type safe ng-templates.
145
- */
146
- templateTypes = templateTypesFn();
147
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: Scroller, deps: [], target: i0.ɵɵFactoryTarget.Component });
148
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.5", type: Scroller, isStandalone: true, selector: "ngn-scroller", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, virtual: { classPropertyName: "virtual", publicName: "virtual", isSignal: true, isRequired: false, transformFunction: null }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, focusable: { classPropertyName: "focusable", publicName: "focusable", isSignal: true, isRequired: false, transformFunction: null }, fieldSticky: { classPropertyName: "fieldSticky", publicName: "fieldSticky", isSignal: true, isRequired: false, transformFunction: null }, templateItem: { classPropertyName: "templateItem", publicName: "templateItem", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "tabIndex": "focusable() ? 0 : -1" }, styleAttribute: "position: relative; overflow: auto; display: block; height: 100%; width: 100%;" }, queries: [{ propertyName: "_userItemTemplate", first: true, predicate: ["item"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "_itemList", first: true, predicate: ["itemList"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (virtual()) {\r\n <div [style.height.px]=\"dummyHeight()\"></div>\r\n}\r\n<div #itemList [style.top.px]=\"itemsTop()\" [style.position]=\"virtual() ? 'absolute' : 'unset'\">\r\n @if (latestStickyItem(); as latestStickyItem) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n itemTemplate();\r\n context: { $implicit: latestStickyItem.item, index: latestStickyItem.index }\r\n \"\r\n ></ng-container>\r\n }\r\n @for (item of visibleItems(); track item.index) {\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTemplate(); context: { $implicit: item.item, index: item.index }\"\r\n ></ng-container>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
182
+ track(item) {
183
+ const fieldId = this.fieldId();
184
+ if (fieldId) {
185
+ return item.item[fieldId];
186
+ }
187
+ return item.index;
188
+ }
189
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnScroller, deps: [], target: i0.ɵɵFactoryTarget.Component });
190
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: NgnScroller, isStandalone: true, selector: "ngn-scroller, [ngn-scroller]", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, fieldId: { classPropertyName: "fieldId", publicName: "fieldId", isSignal: true, isRequired: false, transformFunction: null }, virtual: { classPropertyName: "virtual", publicName: "virtual", isSignal: true, isRequired: false, transformFunction: null }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: false, transformFunction: null }, virtualPadding: { classPropertyName: "virtualPadding", publicName: "virtualPadding", isSignal: true, isRequired: false, transformFunction: null }, focusable: { classPropertyName: "focusable", publicName: "focusable", isSignal: true, isRequired: false, transformFunction: null }, fieldSticky: { classPropertyName: "fieldSticky", publicName: "fieldSticky", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "tabIndex": "focusable() ? 0 : -1", "style.--ngn-scroller-item-height.px": "itemHeight() ?? \"auto\"" } }, providers: [provideSelf(NgnScroller)], usesInheritance: true, hostDirectives: [{ directive: i1.NgnScrollAmount }], ngImport: i0, template: "<div aria-hidden=\"true\" [ptInt]=\"this\" [ptClass]=\"'spacer'\" [style.height.px]=\"paddingTop()\"></div>\r\n\r\n@if (latestStickyItem(); as latestStickyItem) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n itemTemplate();\r\n context: { $implicit: latestStickyItem.item, index: latestStickyItem.index }\r\n \"\r\n ></ng-container>\r\n}\r\n\r\n@for (item of visibleItems(); track track(item)) {\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTemplate(); context: { $implicit: item.item, index: item.index }\"\r\n ></ng-container>\r\n}\r\n\r\n<div\r\n aria-hidden=\"true\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'spacer'\"\r\n [style.height.px]=\"paddingBottom()\"\r\n></div>\r\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
149
191
  }
150
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: Scroller, decorators: [{
192
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnScroller, decorators: [{
151
193
  type: Component,
152
- args: [{ selector: 'ngn-scroller', imports: [NgTemplateOutlet], host: {
153
- style: 'position: relative; overflow: auto; display: block; height: 100%; width: 100%;',
194
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngn-scroller, [ngn-scroller]', imports: [NgnPt, NgTemplateOutlet], providers: [provideSelf(NgnScroller)], hostDirectives: [{ directive: NgnScrollAmount }], host: {
154
195
  '[tabIndex]': 'focusable() ? 0 : -1',
155
- }, template: "@if (virtual()) {\r\n <div [style.height.px]=\"dummyHeight()\"></div>\r\n}\r\n<div #itemList [style.top.px]=\"itemsTop()\" [style.position]=\"virtual() ? 'absolute' : 'unset'\">\r\n @if (latestStickyItem(); as latestStickyItem) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n itemTemplate();\r\n context: { $implicit: latestStickyItem.item, index: latestStickyItem.index }\r\n \"\r\n ></ng-container>\r\n }\r\n @for (item of visibleItems(); track item.index) {\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTemplate(); context: { $implicit: item.item, index: item.index }\"\r\n ></ng-container>\r\n }\r\n</div>\r\n" }]
156
- }], ctorParameters: () => [] });
196
+ '[style.--ngn-scroller-item-height.px]': 'itemHeight() ?? "auto"',
197
+ }, template: "<div aria-hidden=\"true\" [ptInt]=\"this\" [ptClass]=\"'spacer'\" [style.height.px]=\"paddingTop()\"></div>\r\n\r\n@if (latestStickyItem(); as latestStickyItem) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n itemTemplate();\r\n context: { $implicit: latestStickyItem.item, index: latestStickyItem.index }\r\n \"\r\n ></ng-container>\r\n}\r\n\r\n@for (item of visibleItems(); track track(item)) {\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTemplate(); context: { $implicit: item.item, index: item.index }\"\r\n ></ng-container>\r\n}\r\n\r\n<div\r\n aria-hidden=\"true\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'spacer'\"\r\n [style.height.px]=\"paddingBottom()\"\r\n></div>\r\n" }]
198
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], fieldId: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldId", required: false }] }], virtual: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtual", required: false }] }], itemHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemHeight", required: false }] }], virtualPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualPadding", required: false }] }], focusable: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusable", required: false }] }], fieldSticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldSticky", required: false }] }] } });
199
+
200
+ class NgnScrollerItem {
201
+ _el = inject((ElementRef));
202
+ ngnScrollerItem = input.required(...(ngDevMode ? [{ debugName: "ngnScrollerItem" }] : []));
203
+ _scroller = signal(null, ...(ngDevMode ? [{ debugName: "_scroller" }] : []));
204
+ ngAfterViewInit() {
205
+ if (!this._el.nativeElement.isConnected) {
206
+ return;
207
+ }
208
+ const parentInstance = getNearestNgnInstance(this._el.nativeElement, NgnScroller);
209
+ if (!parentInstance) {
210
+ throw new NgnError('scroller', 'ngnScrollerItem must be used within an NgnScroller component');
211
+ }
212
+ this._scroller.set(parentInstance);
213
+ }
214
+ constructor() {
215
+ effect(() => {
216
+ const item = this.ngnScrollerItem();
217
+ const scroller = this._scroller();
218
+ if (!item || !scroller) {
219
+ return;
220
+ }
221
+ const stickyField = scroller.fieldSticky();
222
+ const isSticky = !!stickyField && stickyField in item ? !!item[stickyField] : false;
223
+ toggleClass(this._el.nativeElement, scroller['theme'].class('item-sticky'), isSticky);
224
+ toggleClass(this._el.nativeElement, scroller['theme'].class('item'), true);
225
+ });
226
+ }
227
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnScrollerItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
228
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: NgnScrollerItem, isStandalone: true, selector: "[ngnScrollerItem]", inputs: { ngnScrollerItem: { classPropertyName: "ngnScrollerItem", publicName: "ngnScrollerItem", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
229
+ }
230
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnScrollerItem, decorators: [{
231
+ type: Directive,
232
+ args: [{ selector: '[ngnScrollerItem]' }]
233
+ }], ctorParameters: () => [], propDecorators: { ngnScrollerItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngnScrollerItem", required: true }] }] } });
157
234
 
158
235
  /**
159
236
  * Generated bundle index. Do not edit.
160
237
  */
161
238
 
162
- export { Scroller };
239
+ export { NgnScroller, NgnScrollerItem };
163
240
  //# sourceMappingURL=ngneers-controls-scroller.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ngneers-controls-scroller.mjs","sources":["../../../packages/controls/src/scroller/scroller.ts","../../../packages/controls/src/scroller/scroller.html","../../../packages/controls/src/scroller/ngneers-controls-scroller.ts"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\r\nimport {\r\n Component,\r\n computed,\r\n contentChild,\r\n effect,\r\n ElementRef,\r\n inject,\r\n input,\r\n TemplateRef,\r\n untracked,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { toSignal } from '@angular/core/rxjs-interop';\r\nimport { elementSizeSignal, templateTypesFn } from '@ngneers/controls/api';\r\nimport { fromEvent, map } from 'rxjs';\r\n\r\n@Component({\r\n selector: 'ngn-scroller',\r\n templateUrl: './scroller.html',\r\n imports: [NgTemplateOutlet],\r\n host: {\r\n style: 'position: relative; overflow: auto; display: block; height: 100%; width: 100%;',\r\n '[tabIndex]': 'focusable() ? 0 : -1',\r\n },\r\n})\r\nexport class Scroller<T> {\r\n /**\r\n * The items to be displayed in the scroller.\r\n * This is a required input and should be an array of items of type T.\r\n */\r\n public readonly items = input.required<readonly T[]>();\r\n /**\r\n * Whether the scroller should use virtual scrolling.\r\n * When set to true, the scroller will only render the items that are currently visible\r\n * on the screen, improving performance for large lists.\r\n *\r\n * When virtual scrolling is enabled, {@link itemHeight} must be set to a non-zero value.\r\n * @defaultValue `false`\r\n */\r\n public readonly virtual = input<boolean | undefined>(false);\r\n /**\r\n * When {@link virtual} scrolling is enabled, this input is required to define the height of each item in pixels.\r\n */\r\n public readonly itemHeight = input<number>(0);\r\n /**\r\n * When {@link virtual} scrolling is enabled, this input defines the number of items to be rendered above and below the visible area.\r\n * This can help to reduce flickering when scrolling.\r\n * @defaultValue `2`\r\n */\r\n public readonly padding = input<number>(2);\r\n /**\r\n * Determines whether the scroller should have a tab index and be focusable.\r\n * @defaultValue `false`\r\n */\r\n public readonly focusable = input<boolean>(false);\r\n /**\r\n * Determines whether an item is sticky or not.\r\n * If set, the scroller will stick the items with a truthy value for the specified field to the top of the scroller.\r\n */\r\n public readonly fieldSticky = input<keyof T | null>(null);\r\n\r\n private readonly _itemList = viewChild.required<ElementRef<HTMLElement>>('itemList');\r\n /**\r\n * The template to be used for rendering each item in the scroller.\r\n * Can also be set using the `item` content child.\r\n */\r\n public readonly templateItem = input<TemplateRef<typeof this.templateTypes.item> | null>(null);\r\n private readonly _userItemTemplate =\r\n contentChild<TemplateRef<typeof this.templateTypes.item>>('item');\r\n protected readonly itemTemplate = computed(() => this._userItemTemplate() ?? this.templateItem());\r\n\r\n private readonly _el = inject(ElementRef<HTMLElement>);\r\n private readonly _scrollElement: HTMLElement = this._el.nativeElement;\r\n private readonly _elementSize = elementSizeSignal(this._scrollElement);\r\n\r\n private readonly _visibleItemCount = computed(() =>\r\n this.virtual()\r\n ? Math.ceil(this._elementSize().height / this.itemHeight() + this.padding() * 2)\r\n : 0\r\n );\r\n private readonly _scrollTop = toSignal(\r\n fromEvent(this._scrollElement, 'scroll').pipe(map(e => (e.target as HTMLElement).scrollTop)),\r\n { initialValue: 0 }\r\n );\r\n private readonly _itemStartIndex = computed(() =>\r\n this.virtual()\r\n ? Math.max(0, Math.ceil(this._scrollTop() / this.itemHeight()) - this.padding())\r\n : 0\r\n );\r\n private readonly _itemEndIndex = computed(() =>\r\n this.virtual()\r\n ? Math.min(this.items().length, this._itemStartIndex() + this._visibleItemCount())\r\n : 0\r\n );\r\n\r\n protected readonly visibleItems = computed(() => {\r\n if (!this.virtual()) {\r\n return this.items().map((item, index) => ({ item, index }));\r\n }\r\n return this.items()\r\n .slice(this._itemStartIndex(), this._itemEndIndex())\r\n .map((item, index) => {\r\n return {\r\n item,\r\n index: this._itemStartIndex() + index,\r\n };\r\n });\r\n });\r\n\r\n /**\r\n * Returns the last sticky item that is not rendered regularly in the list.\r\n * Required because sticky items might need to be rendered longer than they would.\r\n * Only applicable when virtual scrolling is enabled.\r\n */\r\n protected readonly latestStickyItem = computed(() => {\r\n if (!this.virtual()) {\r\n return null;\r\n }\r\n const stickyField = this.fieldSticky();\r\n if (!stickyField) {\r\n return null;\r\n }\r\n const unrenderedItemsAtTop = this.items()\r\n .slice(0, this._itemStartIndex())\r\n .map((item, index) => ({\r\n item,\r\n index,\r\n }));\r\n const stickyItems = unrenderedItemsAtTop.filter(item => item.item[stickyField]);\r\n return stickyItems[stickyItems.length - 1] ?? null;\r\n });\r\n\r\n protected readonly itemsTop = computed(() => {\r\n return (this._itemStartIndex() - (this.latestStickyItem() ? 1 : 0)) * this.itemHeight();\r\n });\r\n\r\n protected readonly dummyHeight = computed(() => {\r\n return this.items().length * this.itemHeight();\r\n });\r\n\r\n constructor() {\r\n effect(() => {\r\n if (this.virtual() && !this.itemHeight()) {\r\n throw new Error('Item height must be set when virtual is true');\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Scrolls the item with the given index into view.\r\n * @param index The index of the item to scroll to.\r\n */\r\n public scrollToIndex(index: number) {\r\n untracked(() => {\r\n if (this.virtual()) {\r\n const scrollTop = this._scrollTop();\r\n const visibleHeight = this._elementSize().height;\r\n const itemTop = index * this.itemHeight();\r\n const itemBottom = itemTop + this.itemHeight();\r\n\r\n if (itemTop < scrollTop) {\r\n this._scrollElement.scrollTo({\r\n top: itemTop - 10,\r\n });\r\n } else if (itemBottom > scrollTop + visibleHeight) {\r\n this._scrollElement.scrollTo({\r\n top: itemBottom - visibleHeight + 10,\r\n });\r\n }\r\n } else {\r\n const itemElement = this._itemList().nativeElement.querySelector(\r\n `:nth-child(${index + 1})`\r\n );\r\n if (itemElement) {\r\n itemElement.scrollIntoView({ block: 'nearest' });\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Template types for the scroller.\r\n * Can be used with the {@link @ngneers/controls/api#NgnTemplate | NgnTemplate} directive for type safe ng-templates.\r\n */\r\n public readonly templateTypes = templateTypesFn<{\r\n item: {\r\n $implicit: T;\r\n index: number;\r\n };\r\n }>();\r\n}\r\n","@if (virtual()) {\r\n <div [style.height.px]=\"dummyHeight()\"></div>\r\n}\r\n<div #itemList [style.top.px]=\"itemsTop()\" [style.position]=\"virtual() ? 'absolute' : 'unset'\">\r\n @if (latestStickyItem(); as latestStickyItem) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n itemTemplate();\r\n context: { $implicit: latestStickyItem.item, index: latestStickyItem.index }\r\n \"\r\n ></ng-container>\r\n }\r\n @for (item of visibleItems(); track item.index) {\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTemplate(); context: { $implicit: item.item, index: item.index }\"\r\n ></ng-container>\r\n }\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;MA0Ba,QAAQ,CAAA;AACnB;;;AAGG;AACa,IAAA,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAgB;AACtD;;;;;;;AAOG;AACa,IAAA,OAAO,GAAG,KAAK,CAAsB,KAAK,CAAC;AAC3D;;AAEG;AACa,IAAA,UAAU,GAAG,KAAK,CAAS,CAAC,CAAC;AAC7C;;;;AAIG;AACa,IAAA,OAAO,GAAG,KAAK,CAAS,CAAC,CAAC;AAC1C;;;AAGG;AACa,IAAA,SAAS,GAAG,KAAK,CAAU,KAAK,CAAC;AACjD;;;AAGG;AACa,IAAA,WAAW,GAAG,KAAK,CAAiB,IAAI,CAAC;AAExC,IAAA,SAAS,GAAG,SAAS,CAAC,QAAQ,CAA0B,UAAU,CAAC;AACpF;;;AAGG;AACa,IAAA,YAAY,GAAG,KAAK,CAAqD,IAAI,CAAC;AAC7E,IAAA,iBAAiB,GAChC,YAAY,CAA8C,MAAM,CAAC;AAChD,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,iBAAiB,EAAE,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;AAEhF,IAAA,GAAG,GAAG,MAAM,EAAC,UAAuB,EAAC;AACrC,IAAA,cAAc,GAAgB,IAAI,CAAC,GAAG,CAAC,aAAa;AACpD,IAAA,YAAY,GAAG,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC;IAErD,iBAAiB,GAAG,QAAQ,CAAC,MAC5C,IAAI,CAAC,OAAO;UACR,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC;UAC7E,CAAC,CACN;AACgB,IAAA,UAAU,GAAG,QAAQ,CACpC,SAAS,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAK,CAAC,CAAC,MAAsB,CAAC,SAAS,CAAC,CAAC,EAC5F,EAAE,YAAY,EAAE,CAAC,EAAE,CACpB;IACgB,eAAe,GAAG,QAAQ,CAAC,MAC1C,IAAI,CAAC,OAAO;UACR,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE;UAC7E,CAAC,CACN;IACgB,aAAa,GAAG,QAAQ,CAAC,MACxC,IAAI,CAAC,OAAO;UACR,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE;UAC/E,CAAC,CACN;AAEkB,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;AAC9C,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;YACnB,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;;QAE7D,OAAO,IAAI,CAAC,KAAK;aACd,KAAK,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,IAAI,CAAC,aAAa,EAAE;AAClD,aAAA,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,KAAI;YACnB,OAAO;gBACL,IAAI;AACJ,gBAAA,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,KAAK;aACtC;AACH,SAAC,CAAC;AACN,KAAC,CAAC;AAEF;;;;AAIG;AACgB,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAK;AAClD,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;AACnB,YAAA,OAAO,IAAI;;AAEb,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE;QACtC,IAAI,CAAC,WAAW,EAAE;AAChB,YAAA,OAAO,IAAI;;AAEb,QAAA,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK;AACpC,aAAA,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE;aAC/B,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,MAAM;YACrB,IAAI;YACJ,KAAK;AACN,SAAA,CAAC,CAAC;AACL,QAAA,MAAM,WAAW,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC/E,OAAO,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI;AACpD,KAAC,CAAC;AAEiB,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAK;QAC1C,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,IAAI,CAAC,gBAAgB,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE;AACzF,KAAC,CAAC;AAEiB,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;QAC7C,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE;AAChD,KAAC,CAAC;AAEF,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;YACV,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE;AACxC,gBAAA,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC;;AAEnE,SAAC,CAAC;;AAGJ;;;AAGG;AACI,IAAA,aAAa,CAAC,KAAa,EAAA;QAChC,SAAS,CAAC,MAAK;AACb,YAAA,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;AAClB,gBAAA,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE;gBACnC,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM;gBAChD,MAAM,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE;gBACzC,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE;AAE9C,gBAAA,IAAI,OAAO,GAAG,SAAS,EAAE;AACvB,oBAAA,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC;wBAC3B,GAAG,EAAE,OAAO,GAAG,EAAE;AAClB,qBAAA,CAAC;;AACG,qBAAA,IAAI,UAAU,GAAG,SAAS,GAAG,aAAa,EAAE;AACjD,oBAAA,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC;AAC3B,wBAAA,GAAG,EAAE,UAAU,GAAG,aAAa,GAAG,EAAE;AACrC,qBAAA,CAAC;;;iBAEC;AACL,gBAAA,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,aAAa,CAAC,aAAa,CAC9D,CAAA,WAAA,EAAc,KAAK,GAAG,CAAC,CAAA,CAAA,CAAG,CAC3B;gBACD,IAAI,WAAW,EAAE;oBACf,WAAW,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;;;AAGtD,SAAC,CAAC;;AAGJ;;;AAGG;IACa,aAAa,GAAG,eAAe,EAK3C;uGApKO,QAAQ,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAR,QAAQ,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,UAAA,EAAA,sBAAA,EAAA,EAAA,cAAA,EAAA,gFAAA,EAAA,EAAA,OAAA,EAAA,CAAA,EAAA,YAAA,EAAA,mBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,MAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,WAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,UAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC1BrB,upBAkBA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDEY,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;2FAMf,QAAQ,EAAA,UAAA,EAAA,CAAA;kBATpB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,EAAA,OAAA,EAEf,CAAC,gBAAgB,CAAC,EAAA,IAAA,EACrB;AACJ,wBAAA,KAAK,EAAE,gFAAgF;AACvF,wBAAA,YAAY,EAAE,sBAAsB;AACrC,qBAAA,EAAA,QAAA,EAAA,upBAAA,EAAA;;;AExBH;;AAEG;;;;"}
1
+ {"version":3,"file":"ngneers-controls-scroller.mjs","sources":["../../src/scroller/scroller-templates.ts","../../src/scroller/scroller.ts","../../src/scroller/scroller.html","../../src/scroller/scroller-item.ts","../../src/scroller/ngneers-controls-scroller.ts"],"sourcesContent":["import { computed, contentChild, Directive, input, TemplateRef } from '@angular/core';\r\nimport { templateTypesFn } from '@ngneers/controls/api/ng';\r\nimport { NgnBase } from '@ngneers/controls/base';\r\n\r\n@Directive()\r\nexport abstract class ScrollerTemplates<T> extends NgnBase<'scroller'> {\r\n /**\r\n * The template to be used for rendering each item in the scroller.\r\n * Can also be set using the `item` content child.\r\n */\r\n public readonly templateItem = input<TemplateRef<typeof this.templateTypes.item> | null>(null);\r\n private readonly _userItemTemplate =\r\n contentChild<TemplateRef<typeof this.templateTypes.item>>('item');\r\n protected readonly itemTemplate = computed(() => this._userItemTemplate() ?? this.templateItem());\r\n\r\n /**\r\n * Template types for the scroller.\r\n * Can be used with the {@link NgnTemplate} directive for type safe ng-templates.\r\n */\r\n public readonly templateTypes = templateTypesFn<{\r\n item: {\r\n $implicit: T;\r\n index: number;\r\n };\r\n }>();\r\n}\r\n","import { NgTemplateOutlet } from '@angular/common';\r\nimport {\r\n booleanAttribute,\r\n Component,\r\n computed,\r\n effect,\r\n ElementRef,\r\n inject,\r\n input,\r\n untracked,\r\n ChangeDetectionStrategy,\r\n} from '@angular/core';\r\nimport { elementSizeSignal } from '@ngneers/controls/api/ng';\r\nimport { NgnPt, provideSelf } from '@ngneers/controls/base';\r\nimport { NgnScrollAmount } from '@ngneers/controls/directives';\r\nimport { type AllKeysOfUnion, getScrollTop, NgnError } from '@ngneers/controls/utils';\r\nimport { scrollerControlTemplate } from '@ngneers/controls-themes/templates/scroller';\r\n\r\nimport { ScrollerTemplates } from './scroller-templates';\r\n\r\n/**\r\n * @category control\r\n */\r\n@Component({\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n selector: 'ngn-scroller, [ngn-scroller]',\r\n templateUrl: './scroller.html',\r\n imports: [NgnPt, NgTemplateOutlet],\r\n providers: [provideSelf(NgnScroller)],\r\n hostDirectives: [{ directive: NgnScrollAmount }],\r\n host: {\r\n '[tabIndex]': 'focusable() ? 0 : -1',\r\n '[style.--ngn-scroller-item-height.px]': 'itemHeight() ?? \"auto\"',\r\n },\r\n})\r\nexport class NgnScroller<T> extends ScrollerTemplates<T> {\r\n protected readonly theme = this.injectThemeTemplate(scrollerControlTemplate, {\r\n root: true,\r\n virtual: () => !!this.virtual(),\r\n });\r\n private readonly _el = inject<ElementRef<HTMLElement>>(ElementRef);\r\n private readonly _scrollAmount = inject(NgnScrollAmount);\r\n\r\n /**\r\n * The items to be displayed in the scroller.\r\n * This is a required input and should be an array of items of type {@link T}.\r\n */\r\n public readonly items = input.required<readonly T[]>();\r\n /**\r\n * The field of the item that uniquely identifies it.\r\n */\r\n public readonly fieldId = input<keyof T>();\r\n /**\r\n * Whether the scroller should use virtual scrolling.\r\n * When set to true, the scroller will only render the items that are currently visible\r\n * on the screen, improving performance for large lists.\r\n *\r\n * When virtual scrolling is enabled, {@link itemHeight} must be set to a non-zero value.\r\n * @default `false`\r\n */\r\n public readonly virtual = input<boolean | undefined>(false);\r\n /**\r\n * When {@link virtual} scrolling is enabled, this input is required to define the height of each item in pixels.\r\n */\r\n public readonly itemHeight = input<number | undefined>(undefined);\r\n /**\r\n * When {@link virtual} scrolling is enabled, this input defines the number of items to be rendered above and below the visible area.\r\n * This can help to reduce flickering when scrolling.\r\n * @default `2`\r\n */\r\n public readonly virtualPadding = input<number>(2);\r\n /**\r\n * Determines whether the scroller should have a tab index and be focusable.\r\n * @default `false`\r\n */\r\n public readonly focusable = input(false, { transform: booleanAttribute });\r\n /**\r\n * Determines whether an item is sticky or not.\r\n * If set, the scroller will stick the items with a truthy value for the specified field to the top of the scroller.\r\n */\r\n public readonly fieldSticky = input<AllKeysOfUnion<T> | null>(null);\r\n\r\n private readonly _elementSize = elementSizeSignal(this._el);\r\n\r\n private readonly _itemHeightPx = computed(() => this.itemHeight() ?? 0);\r\n\r\n private readonly _visibleItemCount = computed(() =>\r\n this.virtual()\r\n ? Math.ceil(this._elementSize().height / this._itemHeightPx() + this.virtualPadding() * 2)\r\n : 0\r\n );\r\n private readonly _scrollTop = computed(() => this._scrollAmount.scrollTop());\r\n /**\r\n * The index of the first item that is rendered in the (virtual) scroller.\r\n */\r\n public readonly itemStartIndex = computed(() =>\r\n this.virtual()\r\n ? Math.max(0, Math.ceil(this._scrollTop() / this._itemHeightPx()) - this.virtualPadding())\r\n : 0\r\n );\r\n private readonly _itemEndIndex = computed(() =>\r\n this.virtual()\r\n ? Math.min(this.items().length, this.itemStartIndex() + this._visibleItemCount())\r\n : 0\r\n );\r\n\r\n protected readonly paddingTop = computed(() => {\r\n if (!this.virtual()) {\r\n return 0;\r\n }\r\n return (this.itemStartIndex() - (this.latestStickyItem() ? 1 : 0)) * this._itemHeightPx();\r\n });\r\n\r\n protected readonly paddingBottom = computed(() => {\r\n if (!this.virtual()) {\r\n return 0;\r\n }\r\n return (this.items().length - this._itemEndIndex()) * this._itemHeightPx();\r\n });\r\n\r\n protected readonly visibleItems = computed(() => {\r\n if (!this.virtual()) {\r\n return this.items().map((item, index) => ({ item, index }));\r\n }\r\n return this.items()\r\n .slice(this.itemStartIndex(), this._itemEndIndex())\r\n .map((item, index) => {\r\n return {\r\n item,\r\n index: this.itemStartIndex() + index,\r\n };\r\n });\r\n });\r\n\r\n /**\r\n * Returns the last sticky item that is not rendered regularly in the list.\r\n * Required because sticky items might need to be rendered longer than they would.\r\n * Only applicable when virtual scrolling is enabled.\r\n */\r\n protected readonly latestStickyItem = computed(() => {\r\n if (!this.virtual()) {\r\n return null;\r\n }\r\n const stickyField = this.fieldSticky();\r\n if (!stickyField) {\r\n return null;\r\n }\r\n const unrenderedItemsAtTop = this.items()\r\n .slice(0, this.itemStartIndex())\r\n .map((item, index) => ({\r\n item,\r\n index,\r\n }));\r\n const stickyItems = unrenderedItemsAtTop.filter(item => item.item[stickyField]);\r\n return stickyItems[stickyItems.length - 1] ?? null;\r\n });\r\n\r\n constructor() {\r\n super();\r\n effect(() => {\r\n if (this.virtual() && !this.itemHeight()) {\r\n throw new NgnError('scroller', 'itemHeight must be set when virtual is true');\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Scrolls the item with the given index into view.\r\n * @param index The index of the item to scroll to.\r\n */\r\n public scrollToIndex(index: number, position: ScrollLogicalPosition = 'nearest') {\r\n untracked(() => {\r\n const getItemSize = () => {\r\n if (this.virtual()) {\r\n const itemHeight = this._itemHeightPx();\r\n const itemTop = index * itemHeight;\r\n return { itemHeight, itemTop };\r\n } else {\r\n // index +1 because of the padding/spacer element at the top\r\n const itemElement = this._el.nativeElement.children[index + 1] as HTMLElement | null;\r\n if (itemElement) {\r\n const itemTop = itemElement.offsetTop;\r\n const itemHeight = itemElement.clientHeight;\r\n return { itemTop, itemHeight };\r\n }\r\n return null;\r\n }\r\n };\r\n const size = getItemSize();\r\n if (!size) {\r\n return;\r\n }\r\n const { itemTop, itemHeight } = size;\r\n this._el.nativeElement.scrollTo({\r\n top: getScrollTop(\r\n itemTop,\r\n itemHeight,\r\n this._el.nativeElement.clientHeight,\r\n this._el.nativeElement.scrollTop,\r\n position\r\n ),\r\n });\r\n });\r\n }\r\n\r\n protected track(item: { item: T; index: number }): unknown {\r\n const fieldId = this.fieldId();\r\n if (fieldId) {\r\n return item.item[fieldId];\r\n }\r\n return item.index;\r\n }\r\n}\r\n","<div aria-hidden=\"true\" [ptInt]=\"this\" [ptClass]=\"'spacer'\" [style.height.px]=\"paddingTop()\"></div>\r\n\r\n@if (latestStickyItem(); as latestStickyItem) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n itemTemplate();\r\n context: { $implicit: latestStickyItem.item, index: latestStickyItem.index }\r\n \"\r\n ></ng-container>\r\n}\r\n\r\n@for (item of visibleItems(); track track(item)) {\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTemplate(); context: { $implicit: item.item, index: item.index }\"\r\n ></ng-container>\r\n}\r\n\r\n<div\r\n aria-hidden=\"true\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'spacer'\"\r\n [style.height.px]=\"paddingBottom()\"\r\n></div>\r\n","import {\r\n type AfterViewInit,\r\n Directive,\r\n effect,\r\n ElementRef,\r\n inject,\r\n input,\r\n signal,\r\n} from '@angular/core';\r\nimport { getNearestNgnInstance } from '@ngneers/controls/base';\r\nimport { NgnError, toggleClass } from '@ngneers/controls/utils';\r\n\r\nimport { NgnScroller } from './scroller';\r\n\r\n@Directive({ selector: '[ngnScrollerItem]' })\r\nexport class NgnScrollerItem implements AfterViewInit {\r\n private readonly _el = inject(ElementRef<HTMLElement>);\r\n public readonly ngnScrollerItem = input.required<object>();\r\n private readonly _scroller = signal<NgnScroller<unknown> | null>(null);\r\n\r\n public ngAfterViewInit() {\r\n if (!this._el.nativeElement.isConnected) {\r\n return;\r\n }\r\n const parentInstance = getNearestNgnInstance(this._el.nativeElement, NgnScroller);\r\n if (!parentInstance) {\r\n throw new NgnError(\r\n 'scroller',\r\n 'ngnScrollerItem must be used within an NgnScroller component'\r\n );\r\n }\r\n this._scroller.set(parentInstance);\r\n }\r\n\r\n constructor() {\r\n effect(() => {\r\n const item = this.ngnScrollerItem() as Record<string, unknown> | null;\r\n const scroller = this._scroller();\r\n if (!item || !scroller) {\r\n return;\r\n }\r\n const stickyField = scroller.fieldSticky() as unknown as string | null;\r\n const isSticky = !!stickyField && stickyField in item ? !!item[stickyField] : false;\r\n\r\n toggleClass(this._el.nativeElement, scroller['theme'].class('item-sticky'), isSticky);\r\n toggleClass(this._el.nativeElement, scroller['theme'].class('item'), true);\r\n });\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { ValueControlBase, NgnPt, provideSelf } from '@ngneers/controls/base';
4
+ import { NgnButtonGroup } from '@ngneers/controls/button-group';
5
+ import { NgnToggleButton } from '@ngneers/controls/toggle-button';
6
+ import { maybeCallback } from '@ngneers/controls/utils';
7
+ import { selectButtonControlTemplate } from '@ngneers/controls-themes/templates/select-button';
8
+
9
+ /**
10
+ * @category control
11
+ */
12
+ class NgnSelectButton extends ValueControlBase {
13
+ theme = this.injectThemeTemplate(selectButtonControlTemplate, {
14
+ root: true,
15
+ invalid: () => this.invalid(),
16
+ });
17
+ /**
18
+ * Defines the orientation of the select buttons.
19
+ * - 'auto' - The orientation is determined based on the available space.
20
+ * - 'horizontal' - The buttons are arranged horizontally. (Default for `auto` if enough space)
21
+ * - 'vertical' - The buttons are arranged vertically.
22
+ * @default 'auto'
23
+ */
24
+ orientation = input('auto', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
25
+ /**
26
+ * Defines the options for the select button.
27
+ */
28
+ options = input.required(...(ngDevMode ? [{ debugName: "options" }] : []));
29
+ /**
30
+ * When `true`, allows unselecting the currently selected option by clicking on it again.
31
+ * If `false`, clicking on the selected option will not change the selection.
32
+ * @default false
33
+ */
34
+ allowUnselect = input(false, ...(ngDevMode ? [{ debugName: "allowUnselect" }] : []));
35
+ maybeCallback = maybeCallback;
36
+ valueChange(value) {
37
+ if (this.value() === value && !this.allowUnselect()) {
38
+ return;
39
+ }
40
+ this.value.set(value);
41
+ }
42
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnSelectButton, deps: null, target: i0.ɵɵFactoryTarget.Component });
43
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: NgnSelectButton, isStandalone: true, selector: "ngn-select-button", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, allowUnselect: { classPropertyName: "allowUnselect", publicName: "allowUnselect", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideSelf(NgnSelectButton)], usesInheritance: true, ngImport: i0, template: "<ngn-button-group [orientation]=\"orientation()\">\r\n @for (item of options(); track item.value) {\r\n <ngn-toggle-button\r\n [label]=\"maybeCallback(item.label)\"\r\n [icon]=\"item.icon\"\r\n [fixedWidth]=\"true\"\r\n (valueChange)=\"valueChange(item.value)\"\r\n [value]=\"value() === item.value\"\r\n [readonly]=\"readonly() || (value() === item.value && !allowUnselect())\"\r\n [attr.data-testid]=\"item.testId\"\r\n [disabled]=\"disabled()\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'button'\"\r\n />\r\n }\r\n</ngn-button-group>\r\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass"] }, { kind: "component", type: NgnButtonGroup, selector: "ngn-button-group", inputs: ["orientation"] }, { kind: "component", type: NgnToggleButton, selector: "ngn-toggle-button", inputs: ["labelOn", "labelOff", "icon", "iconOn", "iconOff", "fixedWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
44
+ }
45
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnSelectButton, decorators: [{
46
+ type: Component,
47
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngn-select-button', imports: [NgnPt, NgnButtonGroup, NgnToggleButton], providers: [provideSelf(NgnSelectButton)], template: "<ngn-button-group [orientation]=\"orientation()\">\r\n @for (item of options(); track item.value) {\r\n <ngn-toggle-button\r\n [label]=\"maybeCallback(item.label)\"\r\n [icon]=\"item.icon\"\r\n [fixedWidth]=\"true\"\r\n (valueChange)=\"valueChange(item.value)\"\r\n [value]=\"value() === item.value\"\r\n [readonly]=\"readonly() || (value() === item.value && !allowUnselect())\"\r\n [attr.data-testid]=\"item.testId\"\r\n [disabled]=\"disabled()\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'button'\"\r\n />\r\n }\r\n</ngn-button-group>\r\n" }]
48
+ }], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], allowUnselect: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowUnselect", required: false }] }] } });
49
+
50
+ /**
51
+ * Generated bundle index. Do not edit.
52
+ */
53
+
54
+ export { NgnSelectButton };
55
+ //# sourceMappingURL=ngneers-controls-select-button.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngneers-controls-select-button.mjs","sources":["../../src/select-button/select-button.ts","../../src/select-button/select-button.html","../../src/select-button/ngneers-controls-select-button.ts"],"sourcesContent":["import { Component, ChangeDetectionStrategy, input } from '@angular/core';\r\nimport { NgnPt, provideSelf, ValueControlBase } from '@ngneers/controls/base';\r\nimport { NgnButtonGroup } from '@ngneers/controls/button-group';\r\nimport { NgnToggleButton } from '@ngneers/controls/toggle-button';\r\nimport { maybeCallback } from '@ngneers/controls/utils';\r\nimport { selectButtonControlTemplate } from '@ngneers/controls-themes/templates/select-button';\r\n\r\nimport type { NgnActionItemFlat, NgnItem } from '@ngneers/controls/api';\r\n\r\n/**\r\n * @category control\r\n */\r\n@Component({\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n selector: 'ngn-select-button',\r\n templateUrl: './select-button.html',\r\n imports: [NgnPt, NgnButtonGroup, NgnToggleButton],\r\n providers: [provideSelf(NgnSelectButton)],\r\n})\r\nexport class NgnSelectButton<V> extends ValueControlBase<'selectButton', V> {\r\n protected readonly theme = this.injectThemeTemplate(selectButtonControlTemplate, {\r\n root: true,\r\n invalid: () => this.invalid(),\r\n });\r\n\r\n /**\r\n * Defines the orientation of the select buttons.\r\n * - 'auto' - The orientation is determined based on the available space.\r\n * - 'horizontal' - The buttons are arranged horizontally. (Default for `auto` if enough space)\r\n * - 'vertical' - The buttons are arranged vertically.\r\n * @default 'auto'\r\n */\r\n public readonly orientation = input<'auto' | 'horizontal' | 'vertical'>('auto');\r\n /**\r\n * Defines the options for the select button.\r\n */\r\n public readonly options = input.required<readonly NgnActionItemFlat<NgnItem<unknown, V>>[]>();\r\n /**\r\n * When `true`, allows unselecting the currently selected option by clicking on it again.\r\n * If `false`, clicking on the selected option will not change the selection.\r\n * @default false\r\n */\r\n public readonly allowUnselect = input<boolean>(false);\r\n\r\n protected readonly maybeCallback = maybeCallback;\r\n\r\n protected valueChange(value: V) {\r\n if (this.value() === value && !this.allowUnselect()) {\r\n return;\r\n }\r\n this.value.set(value);\r\n }\r\n}\r\n","<ngn-button-group [orientation]=\"orientation()\">\r\n @for (item of options(); track item.value) {\r\n <ngn-toggle-button\r\n [label]=\"maybeCallback(item.label)\"\r\n [icon]=\"item.icon\"\r\n [fixedWidth]=\"true\"\r\n (valueChange)=\"valueChange(item.value)\"\r\n [value]=\"value() === item.value\"\r\n [readonly]=\"readonly() || (value() === item.value && !allowUnselect())\"\r\n [attr.data-testid]=\"item.testId\"\r\n [disabled]=\"disabled()\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'button'\"\r\n />\r\n }\r\n</ngn-button-group>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;AASA;;AAEG;AAQG,MAAO,eAAmB,SAAQ,gBAAmC,CAAA;AACtD,IAAA,KAAK,GAAG,IAAI,CAAC,mBAAmB,CAAC,2BAA2B,EAAE;AAC/E,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,OAAO,EAAE,MAAM,IAAI,CAAC,OAAO,EAAE;AAC9B,KAAA,CAAC;AAEF;;;;;;AAMG;AACa,IAAA,WAAW,GAAG,KAAK,CAAqC,MAAM,uDAAC;AAC/E;;AAEG;AACa,IAAA,OAAO,GAAG,KAAK,CAAC,QAAQ,kDAAqD;AAC7F;;;;AAIG;AACa,IAAA,aAAa,GAAG,KAAK,CAAU,KAAK,yDAAC;IAElC,aAAa,GAAG,aAAa;AAEtC,IAAA,WAAW,CAAC,KAAQ,EAAA;AAC5B,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE;YACnD;QACF;AACA,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;IACvB;uGAhCW,eAAe,EAAA,IAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAf,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAe,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,SAAA,EAFf,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,EAAA,eAAA,EAAA,IAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECjB3C,mlBAgBA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDAY,KAAK,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,cAAc,sFAAE,eAAe,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,SAAA,EAAA,YAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAGrC,eAAe,EAAA,UAAA,EAAA,CAAA;kBAP3B,SAAS;AACS,YAAA,IAAA,EAAA,CAAA,EAAA,eAAA,EAAA,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,mBAAmB,EAAA,OAAA,EAEpB,CAAC,KAAK,EAAE,cAAc,EAAE,eAAe,CAAC,EAAA,SAAA,EACtC,CAAC,WAAW,iBAAiB,CAAC,EAAA,QAAA,EAAA,mlBAAA,EAAA;;;AEjB3C;;AAEG;;;;"}