@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,107 @@
1
+ import { NgTemplateOutlet } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { contentChild, input, computed, Directive, model, booleanAttribute, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import { NgnBase, NgnPt, provideSelf } from '@ngneers/controls/base';
5
+ import { NgnDefer } from '@ngneers/controls/defer';
6
+ import { inplaceControlTemplate } from '@ngneers/controls-themes/templates/inplace';
7
+ import { templateTypesFn } from '@ngneers/controls/api/ng';
8
+
9
+ class InplaceTemplates extends NgnBase {
10
+ // Display template
11
+ _userDisplayTemplate = contentChild('display', ...(ngDevMode ? [{ debugName: "_userDisplayTemplate" }] : []));
12
+ /**
13
+ * Set a custom template for the display.
14
+ * Can also be set using an `<ng-template>` element with `#display` template reference variable.
15
+ */
16
+ templateDisplay = input(null, ...(ngDevMode ? [{ debugName: "templateDisplay" }] : []));
17
+ displayTemplate = computed(() => this._userDisplayTemplate() ?? this.templateDisplay(), ...(ngDevMode ? [{ debugName: "displayTemplate" }] : []));
18
+ /**
19
+ * Context for the display template.
20
+ */
21
+ templateDisplayContext = input(...(ngDevMode ? [undefined, { debugName: "templateDisplayContext" }] : []));
22
+ // Content template
23
+ _userContentTemplate = contentChild('content', ...(ngDevMode ? [{ debugName: "_userContentTemplate" }] : []));
24
+ /**
25
+ * Set a custom template for the content.
26
+ * Can also be set using an `<ng-template>` element with `#content` template reference variable.
27
+ */
28
+ templateContent = input(null, ...(ngDevMode ? [{ debugName: "templateContent" }] : []));
29
+ contentTemplate = computed(() => this._userContentTemplate() ?? this.templateContent(), ...(ngDevMode ? [{ debugName: "contentTemplate" }] : []));
30
+ /**
31
+ * Context for the content template.
32
+ */
33
+ templateContentContext = input(...(ngDevMode ? [undefined, { debugName: "templateContentContext" }] : []));
34
+ /**
35
+ * Types for the drawer templates.
36
+ */
37
+ templateTypes = templateTypesFn();
38
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: InplaceTemplates, deps: null, target: i0.ɵɵFactoryTarget.Directive });
39
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.1.0", type: InplaceTemplates, isStandalone: true, inputs: { templateDisplay: { classPropertyName: "templateDisplay", publicName: "templateDisplay", isSignal: true, isRequired: false, transformFunction: null }, templateDisplayContext: { classPropertyName: "templateDisplayContext", publicName: "templateDisplayContext", isSignal: true, isRequired: false, transformFunction: null }, templateContent: { classPropertyName: "templateContent", publicName: "templateContent", isSignal: true, isRequired: false, transformFunction: null }, templateContentContext: { classPropertyName: "templateContentContext", publicName: "templateContentContext", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "_userDisplayTemplate", first: true, predicate: ["display"], descendants: true, isSignal: true }, { propertyName: "_userContentTemplate", first: true, predicate: ["content"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0 });
40
+ }
41
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: InplaceTemplates, decorators: [{
42
+ type: Directive
43
+ }], propDecorators: { _userDisplayTemplate: [{ type: i0.ContentChild, args: ['display', { isSignal: true }] }], templateDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateDisplay", required: false }] }], templateDisplayContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateDisplayContext", required: false }] }], _userContentTemplate: [{ type: i0.ContentChild, args: ['content', { isSignal: true }] }], templateContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateContent", required: false }] }], templateContentContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateContentContext", required: false }] }] } });
44
+
45
+ /**
46
+ * @category control
47
+ */
48
+ class NgnInplace extends InplaceTemplates {
49
+ theme = this.injectThemeTemplate(inplaceControlTemplate, {
50
+ root: true,
51
+ disabled: () => this.disabled(),
52
+ });
53
+ closeContent = this.switchToDisplay.bind(this);
54
+ /**
55
+ * Controls the visibility of the content.
56
+ */
57
+ contentVisible = model(false, ...(ngDevMode ? [{ debugName: "contentVisible" }] : []));
58
+ /**
59
+ * Whether the content is loaded lazily.
60
+ * @default true
61
+ */
62
+ lazy = input(true, { ...(ngDevMode ? { debugName: "lazy" } : {}), transform: booleanAttribute });
63
+ /**
64
+ * Whether the content is cached when closed.
65
+ * @default false
66
+ */
67
+ cache = input(false, { ...(ngDevMode ? { debugName: "cache" } : {}), transform: booleanAttribute });
68
+ /**
69
+ * Explicitly apply disabled state styling
70
+ * @default false
71
+ */
72
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : {}), transform: booleanAttribute });
73
+ /**
74
+ * Switches to the content view.
75
+ */
76
+ switchToContent() {
77
+ if (this.disabled()) {
78
+ return;
79
+ }
80
+ this.contentVisible.set(true);
81
+ }
82
+ /**
83
+ * Switches to the display view.
84
+ */
85
+ switchToDisplay() {
86
+ this.contentVisible.set(false);
87
+ }
88
+ /**
89
+ * Toggles between the display and content views.
90
+ */
91
+ toggle() {
92
+ this.contentVisible.update(v => !v);
93
+ }
94
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnInplace, deps: null, target: i0.ɵɵFactoryTarget.Component });
95
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: NgnInplace, isStandalone: true, selector: "ngn-inplace", inputs: { contentVisible: { classPropertyName: "contentVisible", publicName: "contentVisible", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, cache: { classPropertyName: "cache", publicName: "cache", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentVisible: "contentVisibleChange" }, providers: [provideSelf(NgnInplace)], usesInheritance: true, ngImport: i0, template: "@if (contentVisible()) {\r\n <div [ptInt]=\"this\" [ptClass]=\"'content'\">\r\n <ngn-defer\r\n [open]=\"contentVisible()\"\r\n [lazyContent]=\"contentTemplate()\"\r\n [lazyContentContext]=\"templateContentContext() ?? { $implicit: { close: closeContent } }\"\r\n [lazy]=\"lazy()\"\r\n [cache]=\"cache()\"\r\n />\r\n </div>\r\n} @else {\r\n <button [ptInt]=\"this\" [ptClass]=\"'display'\" role=\"button\" (click)=\"switchToContent()\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"displayTemplate()\"\r\n [ngTemplateOutletContext]=\"templateDisplayContext()\"\r\n />\r\n </button>\r\n}\r\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NgnDefer, selector: "ngn-defer", inputs: ["lazyContent", "lazyContentContext", "open", "lazy", "cache", "hiddenOnClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
96
+ }
97
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnInplace, decorators: [{
98
+ type: Component,
99
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngn-inplace', imports: [NgnPt, NgTemplateOutlet, NgnDefer], providers: [provideSelf(NgnInplace)], template: "@if (contentVisible()) {\r\n <div [ptInt]=\"this\" [ptClass]=\"'content'\">\r\n <ngn-defer\r\n [open]=\"contentVisible()\"\r\n [lazyContent]=\"contentTemplate()\"\r\n [lazyContentContext]=\"templateContentContext() ?? { $implicit: { close: closeContent } }\"\r\n [lazy]=\"lazy()\"\r\n [cache]=\"cache()\"\r\n />\r\n </div>\r\n} @else {\r\n <button [ptInt]=\"this\" [ptClass]=\"'display'\" role=\"button\" (click)=\"switchToContent()\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"displayTemplate()\"\r\n [ngTemplateOutletContext]=\"templateDisplayContext()\"\r\n />\r\n </button>\r\n}\r\n" }]
100
+ }], propDecorators: { contentVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentVisible", required: false }] }, { type: i0.Output, args: ["contentVisibleChange"] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], cache: [{ type: i0.Input, args: [{ isSignal: true, alias: "cache", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
101
+
102
+ /**
103
+ * Generated bundle index. Do not edit.
104
+ */
105
+
106
+ export { NgnInplace };
107
+ //# sourceMappingURL=ngneers-controls-inplace.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngneers-controls-inplace.mjs","sources":["../../src/inplace/inplace-templates.ts","../../src/inplace/inplace.ts","../../src/inplace/inplace.html","../../src/inplace/ngneers-controls-inplace.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\nimport type { ContentTemplateType } from './types';\r\n\r\n@Directive()\r\nexport abstract class InplaceTemplates extends NgnBase<'inplace'> {\r\n // Display template\r\n private readonly _userDisplayTemplate = contentChild<TemplateRef<unknown>>('display');\r\n /**\r\n * Set a custom template for the display.\r\n * Can also be set using an `<ng-template>` element with `#display` template reference variable.\r\n */\r\n public readonly templateDisplay = input<TemplateRef<unknown> | null>(null);\r\n protected readonly displayTemplate = computed(\r\n () => this._userDisplayTemplate() ?? this.templateDisplay()\r\n );\r\n /**\r\n * Context for the display template.\r\n */\r\n public readonly templateDisplayContext = input<unknown>();\r\n\r\n // Content template\r\n private readonly _userContentTemplate =\r\n contentChild<TemplateRef<typeof this.templateTypes.content>>('content');\r\n /**\r\n * Set a custom template for the content.\r\n * Can also be set using an `<ng-template>` element with `#content` template reference variable.\r\n */\r\n public readonly templateContent = input<TemplateRef<typeof this.templateTypes.content> | null>(\r\n null\r\n );\r\n protected readonly contentTemplate = computed(\r\n () => this._userContentTemplate() ?? this.templateContent()\r\n );\r\n /**\r\n * Context for the content template.\r\n */\r\n public readonly templateContentContext = input<unknown>();\r\n\r\n /**\r\n * Types for the drawer templates.\r\n */\r\n public readonly templateTypes = templateTypesFn<{\r\n /**\r\n * Type of the template variable for the display template.\r\n */\r\n content: ContentTemplateType;\r\n }>();\r\n}\r\n","import { NgTemplateOutlet } from '@angular/common';\r\nimport { booleanAttribute, Component, input, model, ChangeDetectionStrategy } from '@angular/core';\r\nimport { NgnPt, provideSelf } from '@ngneers/controls/base';\r\nimport { NgnDefer } from '@ngneers/controls/defer';\r\nimport { inplaceControlTemplate } from '@ngneers/controls-themes/templates/inplace';\r\n\r\nimport { InplaceTemplates } from './inplace-templates';\r\n\r\n/**\r\n * @category control\r\n */\r\n@Component({\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n selector: 'ngn-inplace',\r\n templateUrl: './inplace.html',\r\n imports: [NgnPt, NgTemplateOutlet, NgnDefer],\r\n providers: [provideSelf(NgnInplace)],\r\n})\r\nexport class NgnInplace extends InplaceTemplates {\r\n protected readonly theme = this.injectThemeTemplate(inplaceControlTemplate, {\r\n root: true,\r\n disabled: () => this.disabled(),\r\n });\r\n\r\n protected readonly closeContent = this.switchToDisplay.bind(this);\r\n\r\n /**\r\n * Controls the visibility of the content.\r\n */\r\n public readonly contentVisible = model<boolean>(false);\r\n /**\r\n * Whether the content is loaded lazily.\r\n * @default true\r\n */\r\n public readonly lazy = input(true, { transform: booleanAttribute });\r\n /**\r\n * Whether the content is cached when closed.\r\n * @default false\r\n */\r\n public readonly cache = input(false, { transform: booleanAttribute });\r\n /**\r\n * Explicitly apply disabled state styling\r\n * @default false\r\n */\r\n public readonly disabled = input(false, { transform: booleanAttribute });\r\n\r\n /**\r\n * Switches to the content view.\r\n */\r\n public switchToContent() {\r\n if (this.disabled()) {\r\n return;\r\n }\r\n this.contentVisible.set(true);\r\n }\r\n\r\n /**\r\n * Switches to the display view.\r\n */\r\n public switchToDisplay() {\r\n this.contentVisible.set(false);\r\n }\r\n\r\n /**\r\n * Toggles between the display and content views.\r\n */\r\n public toggle() {\r\n this.contentVisible.update(v => !v);\r\n }\r\n}\r\n","@if (contentVisible()) {\r\n <div [ptInt]=\"this\" [ptClass]=\"'content'\">\r\n <ngn-defer\r\n [open]=\"contentVisible()\"\r\n [lazyContent]=\"contentTemplate()\"\r\n [lazyContentContext]=\"templateContentContext() ?? { $implicit: { close: closeContent } }\"\r\n [lazy]=\"lazy()\"\r\n [cache]=\"cache()\"\r\n />\r\n </div>\r\n} @else {\r\n <button [ptInt]=\"this\" [ptClass]=\"'display'\" role=\"button\" (click)=\"switchToContent()\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"displayTemplate()\"\r\n [ngTemplateOutletContext]=\"templateDisplayContext()\"\r\n />\r\n </button>\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,141 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, input, booleanAttribute, contentChild, effect, forwardRef, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { NgnBase, NgnPt, provideSelf } from '@ngneers/controls/base';
4
+ import { NgnButton } from '@ngneers/controls/button';
5
+ import { I18n } from '@ngneers/controls/i18n';
6
+ import { NgnIcon } from '@ngneers/controls/icon';
7
+ import { NgnInput } from '@ngneers/controls/input';
8
+ import { generateElementId } from '@ngneers/controls/utils-ng';
9
+ import { inputFieldControlTemplate } from '@ngneers/controls-themes/templates/input-field';
10
+
11
+ const INPUT_FIELD = new InjectionToken('Inputfield');
12
+
13
+ /**
14
+ * @category control
15
+ */
16
+ class NgnInputField extends NgnBase {
17
+ theme = this.injectThemeTemplate(inputFieldControlTemplate, 'host');
18
+ i18n = inject(I18n).translations;
19
+ _parentInputfield = inject(INPUT_FIELD, { optional: true, skipSelf: true });
20
+ hasParentInputfield = !!this._parentInputfield;
21
+ /**
22
+ * Label for the input field
23
+ * @default null
24
+ */
25
+ label = input(null, ...(ngDevMode ? [{ debugName: "label" }] : []));
26
+ /**
27
+ * Sets the `aria-labelledby` attribute on the input element
28
+ * @default null
29
+ */
30
+ labelledBy = input(null, ...(ngDevMode ? [{ debugName: "labelledBy" }] : []));
31
+ /**
32
+ * The kind of label presentation
33
+ * @todo add link to custom kind documentation subsection label
34
+ * @default undefined
35
+ */
36
+ labelKind = input(undefined, ...(ngDevMode ? [{ debugName: "labelKind" }] : []));
37
+ /**
38
+ * ID for the input element
39
+ */
40
+ inputId = input(generateElementId(), ...(ngDevMode ? [{ debugName: "inputId" }] : []));
41
+ /**
42
+ * Show clear button
43
+ * @default false
44
+ */
45
+ showClearButton = input(false, { ...(ngDevMode ? { debugName: "showClearButton" } : {}), transform: booleanAttribute });
46
+ /**
47
+ * Custom icon for the clear button. Use with `showClearButton`.
48
+ */
49
+ iconClearButton = input(...(ngDevMode ? [undefined, { debugName: "iconClearButton" }] : []));
50
+ /**
51
+ * Tabindex for the input field itself.
52
+ * When another focusable (input) element is present inside the input field, this should be set to -1.
53
+ * @default -1
54
+ */
55
+ tabindex = input(-1, ...(ngDevMode ? [{ debugName: "tabindex" }] : []));
56
+ /**
57
+ * Explicitly apply invalid state styling
58
+ * @default false
59
+ */
60
+ invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : {}), transform: booleanAttribute });
61
+ /**
62
+ * Explicitly apply readonly state styling
63
+ * @default false
64
+ */
65
+ readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : {}), transform: booleanAttribute });
66
+ /**
67
+ * Explicitly apply disabled state styling
68
+ * @default false
69
+ */
70
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : {}), transform: booleanAttribute });
71
+ _ngnInput = contentChild(NgnInput, ...(ngDevMode ? [{ debugName: "_ngnInput" }] : []));
72
+ constructor() {
73
+ super();
74
+ this.initializeAutoThemeClasses('labelKind', this.labelKind);
75
+ effect(() => {
76
+ const ngnInput = this._ngnInput();
77
+ if (!ngnInput) {
78
+ return;
79
+ }
80
+ ngnInput.element.nativeElement.id = this.inputId();
81
+ });
82
+ effect(() => {
83
+ const ngnInput = this._ngnInput();
84
+ if (!ngnInput) {
85
+ return;
86
+ }
87
+ const labelledBy = this.labelledBy();
88
+ ngnInput.element.nativeElement.setAttribute('aria-labelledby', labelledBy ?? '');
89
+ });
90
+ }
91
+ clicked(event) {
92
+ // Prevent click event from propagating to parent input field
93
+ if (this.hasParentInputfield) {
94
+ return;
95
+ }
96
+ if (event.target instanceof HTMLElement) {
97
+ // Focus the input element when the input field is clicked
98
+ const inputElement = event.target.querySelector('input, textarea');
99
+ if (inputElement) {
100
+ inputElement.focus();
101
+ }
102
+ }
103
+ }
104
+ clearButtonClicked(event) {
105
+ event.stopPropagation();
106
+ const inputElement = this.element.nativeElement.querySelector('input, textarea');
107
+ if (inputElement) {
108
+ inputElement.value = '';
109
+ inputElement.dispatchEvent(new Event('input', { bubbles: true }));
110
+ inputElement.dispatchEvent(new Event('change', { bubbles: true }));
111
+ inputElement.focus();
112
+ }
113
+ }
114
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnInputField, deps: [], target: i0.ɵɵFactoryTarget.Component });
115
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: NgnInputField, isStandalone: true, selector: "ngn-input-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelledBy: { classPropertyName: "labelledBy", publicName: "labelledBy", isSignal: true, isRequired: false, transformFunction: null }, labelKind: { classPropertyName: "labelKind", publicName: "labelKind", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, iconClearButton: { classPropertyName: "iconClearButton", publicName: "iconClearButton", isSignal: true, isRequired: false, transformFunction: null }, tabindex: { classPropertyName: "tabindex", publicName: "tabindex", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "inert": "disabled()" } }, providers: [
116
+ {
117
+ provide: INPUT_FIELD,
118
+ useExisting: forwardRef(() => NgnInputField),
119
+ },
120
+ provideSelf(NgnInputField),
121
+ ], queries: [{ propertyName: "_ngnInput", first: true, predicate: NgnInput, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (label(); as label) {\r\n <label [ptInt]=\"this\" [ptClass]=\"'label'\" [for]=\"inputId()\">{{ label }}</label>\r\n}\r\n<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n<div\r\n [ptInt]=\"this\"\r\n [ptClass]=\"{\r\n root: !hasParentInputfield,\r\n invalid: invalid(),\r\n readonly: readonly(),\r\n disabled: disabled(),\r\n }\"\r\n (click)=\"clicked($event)\"\r\n [tabindex]=\"tabindex()\"\r\n>\r\n <ng-content select=\"input, textarea\" />\r\n @if (showClearButton()) {\r\n <button\r\n tabindex=\"-1\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'clear-button'\"\r\n ngnButton\r\n type=\"button\"\r\n [kind]=\"'icon'\"\r\n inline\r\n (click)=\"clearButtonClicked($event)\"\r\n [attr.aria-label]=\"i18n['inputField_clearInput']()\"\r\n >\r\n <ngn-icon defaultIcon=\"xmark\" [icon]=\"iconClearButton()\" />\r\n </button>\r\n }\r\n <ng-content />\r\n</div>\r\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass"] }, { kind: "component", type: NgnIcon, selector: "ngn-icon", inputs: ["defaultIcon", "icon"] }, { kind: "directive", type: NgnButton, selector: "button[ngnButton], a[ngnButton]", inputs: ["inline"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
122
+ }
123
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnInputField, decorators: [{
124
+ type: Component,
125
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgnPt, NgnIcon, NgnButton], selector: 'ngn-input-field', host: {
126
+ '[inert]': 'disabled()',
127
+ }, providers: [
128
+ {
129
+ provide: INPUT_FIELD,
130
+ useExisting: forwardRef(() => NgnInputField),
131
+ },
132
+ provideSelf(NgnInputField),
133
+ ], template: "@if (label(); as label) {\r\n <label [ptInt]=\"this\" [ptClass]=\"'label'\" [for]=\"inputId()\">{{ label }}</label>\r\n}\r\n<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n<div\r\n [ptInt]=\"this\"\r\n [ptClass]=\"{\r\n root: !hasParentInputfield,\r\n invalid: invalid(),\r\n readonly: readonly(),\r\n disabled: disabled(),\r\n }\"\r\n (click)=\"clicked($event)\"\r\n [tabindex]=\"tabindex()\"\r\n>\r\n <ng-content select=\"input, textarea\" />\r\n @if (showClearButton()) {\r\n <button\r\n tabindex=\"-1\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'clear-button'\"\r\n ngnButton\r\n type=\"button\"\r\n [kind]=\"'icon'\"\r\n inline\r\n (click)=\"clearButtonClicked($event)\"\r\n [attr.aria-label]=\"i18n['inputField_clearInput']()\"\r\n >\r\n <ngn-icon defaultIcon=\"xmark\" [icon]=\"iconClearButton()\" />\r\n </button>\r\n }\r\n <ng-content />\r\n</div>\r\n" }]
134
+ }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelledBy", required: false }] }], labelKind: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelKind", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], iconClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconClearButton", required: false }] }], tabindex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabindex", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], _ngnInput: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NgnInput), { isSignal: true }] }] } });
135
+
136
+ /**
137
+ * Generated bundle index. Do not edit.
138
+ */
139
+
140
+ export { INPUT_FIELD, NgnInputField };
141
+ //# sourceMappingURL=ngneers-controls-input-field.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngneers-controls-input-field.mjs","sources":["../../src/input-field/token.ts","../../src/input-field/input-field.ts","../../src/input-field/input-field.html","../../src/input-field/ngneers-controls-input-field.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\n\r\nimport { NgnInputField } from './input-field';\r\n\r\nexport const INPUT_FIELD = new InjectionToken<NgnInputField>('Inputfield');\r\n","import {\r\n booleanAttribute,\r\n Component,\r\n forwardRef,\r\n inject,\r\n input,\r\n ChangeDetectionStrategy,\r\n effect,\r\n contentChild,\r\n} from '@angular/core';\r\nimport { NgnBase, provideSelf, NgnPt } from '@ngneers/controls/base';\r\nimport { NgnButton } from '@ngneers/controls/button';\r\nimport { I18n } from '@ngneers/controls/i18n';\r\nimport { NgnIcon } from '@ngneers/controls/icon';\r\nimport { NgnInput } from '@ngneers/controls/input';\r\nimport { generateElementId } from '@ngneers/controls/utils-ng';\r\nimport { inputFieldControlTemplate } from '@ngneers/controls-themes/templates/input-field';\r\n\r\nimport { INPUT_FIELD } from './token';\r\n\r\nimport type { CustomKind, IconType } from '@ngneers/controls-custom-types';\r\n\r\n/**\r\n * @category control\r\n */\r\n@Component({\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [NgnPt, NgnIcon, NgnButton],\r\n selector: 'ngn-input-field',\r\n templateUrl: './input-field.html',\r\n host: {\r\n '[inert]': 'disabled()',\r\n },\r\n providers: [\r\n {\r\n provide: INPUT_FIELD,\r\n useExisting: forwardRef(() => NgnInputField),\r\n },\r\n provideSelf(NgnInputField),\r\n ],\r\n})\r\nexport class NgnInputField extends NgnBase<'inputField'> {\r\n protected readonly theme = this.injectThemeTemplate(inputFieldControlTemplate, 'host');\r\n protected readonly i18n = inject(I18n).translations;\r\n private readonly _parentInputfield = inject(INPUT_FIELD, { optional: true, skipSelf: true });\r\n protected readonly hasParentInputfield = !!this._parentInputfield;\r\n\r\n /**\r\n * Label for the input field\r\n * @default null\r\n */\r\n public readonly label = input<string | null>(null);\r\n /**\r\n * Sets the `aria-labelledby` attribute on the input element\r\n * @default null\r\n */\r\n public readonly labelledBy = input<string | null>(null);\r\n /**\r\n * The kind of label presentation\r\n * @todo add link to custom kind documentation subsection label\r\n * @default undefined\r\n */\r\n public readonly labelKind = input<CustomKind<'inputFieldLabel'>>(undefined as never);\r\n /**\r\n * ID for the input element\r\n */\r\n public readonly inputId = input<string>(generateElementId());\r\n /**\r\n * Show clear button\r\n * @default false\r\n */\r\n public readonly showClearButton = input(false, { transform: booleanAttribute });\r\n /**\r\n * Custom icon for the clear button. Use with `showClearButton`.\r\n */\r\n public readonly iconClearButton = input<IconType>();\r\n /**\r\n * Tabindex for the input field itself.\r\n * When another focusable (input) element is present inside the input field, this should be set to -1.\r\n * @default -1\r\n */\r\n public readonly tabindex = input<number>(-1);\r\n /**\r\n * Explicitly apply invalid state styling\r\n * @default false\r\n */\r\n public readonly invalid = input(false, { transform: booleanAttribute });\r\n /**\r\n * Explicitly apply readonly state styling\r\n * @default false\r\n */\r\n public readonly readonly = input(false, { transform: booleanAttribute });\r\n /**\r\n * Explicitly apply disabled state styling\r\n * @default false\r\n */\r\n public readonly disabled = input(false, { transform: booleanAttribute });\r\n\r\n private readonly _ngnInput = contentChild(NgnInput);\r\n\r\n constructor() {\r\n super();\r\n this.initializeAutoThemeClasses('labelKind', this.labelKind);\r\n effect(() => {\r\n const ngnInput = this._ngnInput();\r\n if (!ngnInput) {\r\n return;\r\n }\r\n ngnInput.element.nativeElement.id = this.inputId();\r\n });\r\n effect(() => {\r\n const ngnInput = this._ngnInput();\r\n if (!ngnInput) {\r\n return;\r\n }\r\n const labelledBy = this.labelledBy();\r\n ngnInput.element.nativeElement.setAttribute('aria-labelledby', labelledBy ?? '');\r\n });\r\n }\r\n\r\n protected clicked(event: MouseEvent) {\r\n // Prevent click event from propagating to parent input field\r\n if (this.hasParentInputfield) {\r\n return;\r\n }\r\n if (event.target instanceof HTMLElement) {\r\n // Focus the input element when the input field is clicked\r\n const inputElement = event.target.querySelector('input, textarea');\r\n if (inputElement) {\r\n (inputElement as HTMLInputElement | HTMLTextAreaElement).focus();\r\n }\r\n }\r\n }\r\n\r\n protected clearButtonClicked(event: MouseEvent) {\r\n event.stopPropagation();\r\n const inputElement = this.element.nativeElement.querySelector('input, textarea');\r\n if (inputElement) {\r\n (inputElement as HTMLInputElement | HTMLTextAreaElement).value = '';\r\n inputElement.dispatchEvent(new Event('input', { bubbles: true }));\r\n inputElement.dispatchEvent(new Event('change', { bubbles: true }));\r\n (inputElement as HTMLInputElement | HTMLTextAreaElement).focus();\r\n }\r\n }\r\n}\r\n","@if (label(); as label) {\r\n <label [ptInt]=\"this\" [ptClass]=\"'label'\" [for]=\"inputId()\">{{ label }}</label>\r\n}\r\n<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n<div\r\n [ptInt]=\"this\"\r\n [ptClass]=\"{\r\n root: !hasParentInputfield,\r\n invalid: invalid(),\r\n readonly: readonly(),\r\n disabled: disabled(),\r\n }\"\r\n (click)=\"clicked($event)\"\r\n [tabindex]=\"tabindex()\"\r\n>\r\n <ng-content select=\"input, textarea\" />\r\n @if (showClearButton()) {\r\n <button\r\n tabindex=\"-1\"\r\n [ptInt]=\"this\"\r\n [ptClass]=\"'clear-button'\"\r\n ngnButton\r\n type=\"button\"\r\n [kind]=\"'icon'\"\r\n inline\r\n (click)=\"clearButtonClicked($event)\"\r\n [attr.aria-label]=\"i18n['inputField_clearInput']()\"\r\n >\r\n <ngn-icon defaultIcon=\"xmark\" [icon]=\"iconClearButton()\" />\r\n </button>\r\n }\r\n <ng-content />\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;MAIa,WAAW,GAAG,IAAI,cAAc,CAAgB,YAAY;;ACkBzE;;AAEG;AAiBG,MAAO,aAAc,SAAQ,OAAqB,CAAA;IACnC,KAAK,GAAG,IAAI,CAAC,mBAAmB,CAAC,yBAAyB,EAAE,MAAM,CAAC;AACnE,IAAA,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY;AAClC,IAAA,iBAAiB,GAAG,MAAM,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACzE,IAAA,mBAAmB,GAAG,CAAC,CAAC,IAAI,CAAC,iBAAiB;AAEjE;;;AAGG;AACa,IAAA,KAAK,GAAG,KAAK,CAAgB,IAAI,iDAAC;AAClD;;;AAGG;AACa,IAAA,UAAU,GAAG,KAAK,CAAgB,IAAI,sDAAC;AACvD;;;;AAIG;AACa,IAAA,SAAS,GAAG,KAAK,CAAgC,SAAkB,qDAAC;AACpF;;AAEG;AACa,IAAA,OAAO,GAAG,KAAK,CAAS,iBAAiB,EAAE,mDAAC;AAC5D;;;AAGG;IACa,eAAe,GAAG,KAAK,CAAC,KAAK,4DAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAC/E;;AAEG;IACa,eAAe,GAAG,KAAK,CAAA,IAAA,SAAA,GAAA,CAAA,SAAA,EAAA,EAAA,SAAA,EAAA,iBAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAY;AACnD;;;;AAIG;AACa,IAAA,QAAQ,GAAG,KAAK,CAAS,CAAC,CAAC,oDAAC;AAC5C;;;AAGG;IACa,OAAO,GAAG,KAAK,CAAC,KAAK,oDAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AACvE;;;AAGG;IACa,QAAQ,GAAG,KAAK,CAAC,KAAK,qDAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AACxE;;;AAGG;IACa,QAAQ,GAAG,KAAK,CAAC,KAAK,qDAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAEvD,IAAA,SAAS,GAAG,YAAY,CAAC,QAAQ,qDAAC;AAEnD,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,0BAA0B,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC;QAC5D,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE;YACjC,IAAI,CAAC,QAAQ,EAAE;gBACb;YACF;YACA,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE;AACpD,QAAA,CAAC,CAAC;QACF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE;YACjC,IAAI,CAAC,QAAQ,EAAE;gBACb;YACF;AACA,YAAA,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE;AACpC,YAAA,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,iBAAiB,EAAE,UAAU,IAAI,EAAE,CAAC;AAClF,QAAA,CAAC,CAAC;IACJ;AAEU,IAAA,OAAO,CAAC,KAAiB,EAAA;;AAEjC,QAAA,IAAI,IAAI,CAAC,mBAAmB,EAAE;YAC5B;QACF;AACA,QAAA,IAAI,KAAK,CAAC,MAAM,YAAY,WAAW,EAAE;;YAEvC,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,iBAAiB,CAAC;YAClE,IAAI,YAAY,EAAE;gBACf,YAAuD,CAAC,KAAK,EAAE;YAClE;QACF;IACF;AAEU,IAAA,kBAAkB,CAAC,KAAiB,EAAA;QAC5C,KAAK,CAAC,eAAe,EAAE;AACvB,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,aAAa,CAAC,iBAAiB,CAAC;QAChF,IAAI,YAAY,EAAE;AACf,YAAA,YAAuD,CAAC,KAAK,GAAG,EAAE;AACnE,YAAA,YAAY,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AACjE,YAAA,YAAY,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACjE,YAAuD,CAAC,KAAK,EAAE;QAClE;IACF;uGAtGW,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,aAAa,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,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,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,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,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,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,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,YAAA,EAAA,EAAA,EAAA,SAAA,EARb;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,WAAW;AACpB,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,aAAa,CAAC;AAC7C,aAAA;YACD,WAAW,CAAC,aAAa,CAAC;SAC3B,EAAA,OAAA,EAAA,CAAA,EAAA,YAAA,EAAA,WAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EA2DyC,QAAQ,uFClGpD,q9BAiCA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDNY,KAAK,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,OAAO,sFAAE,SAAS,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,CAAA,QAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAcxB,aAAa,EAAA,UAAA,EAAA,CAAA;kBAhBzB,SAAS;AACS,YAAA,IAAA,EAAA,CAAA,EAAA,eAAA,EAAA,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,EAAA,QAAA,EAC1B,iBAAiB,EAAA,IAAA,EAErB;AACJ,wBAAA,SAAS,EAAE,YAAY;qBACxB,EAAA,SAAA,EACU;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,WAAW;AACpB,4BAAA,WAAW,EAAE,UAAU,CAAC,mBAAmB,CAAC;AAC7C,yBAAA;AACD,wBAAA,WAAW,CAAA,aAAA,CAAe;AAC3B,qBAAA,EAAA,QAAA,EAAA,q9BAAA,EAAA;glCA2DyC,QAAQ,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AElGpD;;AAEG;;;;"}
@@ -0,0 +1,282 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, contentChild, computed, afterRenderEffect, signal, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { domEventHandler } from '@ngneers/controls/api/ng';
4
+ import { NgnBase, NgnPt, provideSelf } from '@ngneers/controls/base';
5
+ import { NgnInput } from '@ngneers/controls/input';
6
+ import { inputMaskControlTemplate } from '@ngneers/controls-themes/templates/input-mask';
7
+
8
+ const time = [
9
+ {
10
+ accepts: /^\d$/,
11
+ default: '0',
12
+ placeholder: 'H',
13
+ },
14
+ {
15
+ accepts: /^\d$/,
16
+ default: '0',
17
+ placeholder: 'H',
18
+ },
19
+ ':',
20
+ {
21
+ accepts: /^\d$/,
22
+ default: '0',
23
+ placeholder: 'M',
24
+ },
25
+ {
26
+ accepts: /^\d$/,
27
+ default: '0',
28
+ placeholder: 'M',
29
+ },
30
+ ];
31
+ const timeSeconds = [
32
+ ...time,
33
+ ':',
34
+ {
35
+ accepts: /^\d$/,
36
+ default: '0',
37
+ placeholder: 'S',
38
+ },
39
+ {
40
+ accepts: /^\d$/,
41
+ default: '0',
42
+ placeholder: 'S',
43
+ },
44
+ ];
45
+ const MASKS = {
46
+ time,
47
+ timeSeconds,
48
+ };
49
+
50
+ /**
51
+ * Helper class for handling masked input functionality
52
+ */
53
+ class MaskHelper {
54
+ _data;
55
+ constructor(data) {
56
+ this._data = data;
57
+ }
58
+ /**
59
+ * Ensure the mask is in the correct format
60
+ * Converts string masks to TextFieldMaskCfg format
61
+ * Returns null if no mask is provided
62
+ */
63
+ ensureMask(mask) {
64
+ if (!mask)
65
+ return null;
66
+ if (typeof mask === 'string') {
67
+ if (mask === 'time') {
68
+ return MASKS.time;
69
+ }
70
+ // Convert string mask to TextFieldMaskCfg
71
+ // 0 => digit, A => letter, * => alphanumeric
72
+ return mask.split('').map(char => {
73
+ if (char === '0') {
74
+ return { placeholder: char, accepts: /\d/, default: '0' };
75
+ }
76
+ else if (char === 'A') {
77
+ return { placeholder: char, accepts: /[a-zA-Z]/, default: 'A' };
78
+ }
79
+ else if (char === '*') {
80
+ return { placeholder: char, accepts: /[a-zA-Z0-9]/, default: 'A' };
81
+ }
82
+ return char;
83
+ });
84
+ }
85
+ return mask;
86
+ }
87
+ /**
88
+ * Handle key down events to manage special keys like Backspace and Delete
89
+ */
90
+ handleKeyDown(event, mask) {
91
+ if (!mask || this._shouldIgnoreEvent(event)) {
92
+ return;
93
+ }
94
+ const el = event.target;
95
+ const key = event.key;
96
+ const currentPosition = el.selectionStart ?? 0;
97
+ if (this._isSpecialKey(key)) {
98
+ this._handleSpecialKey(event, el, key, currentPosition, mask);
99
+ }
100
+ }
101
+ /**
102
+ * Handle before input event to manage character input with mask validation
103
+ */
104
+ handleBeforeInput(event, mask) {
105
+ const el = event.target;
106
+ const key = event.data;
107
+ const currentPosition = el.selectionStart ?? 0;
108
+ if (!key) {
109
+ // If no key data, just return
110
+ return;
111
+ }
112
+ // Route to appropriate handler based on key type
113
+ if (!this._isSpecialKey(key)) {
114
+ this._handleCharacterInput(event, el, key, currentPosition, mask);
115
+ }
116
+ }
117
+ /**
118
+ * Check if the event should be ignored (modifier keys)
119
+ */
120
+ _shouldIgnoreEvent(event) {
121
+ return event.ctrlKey || event.metaKey || event.altKey;
122
+ }
123
+ /**
124
+ * Check if key is a special key (Backspace/Delete)
125
+ */
126
+ _isSpecialKey(key) {
127
+ return key.length > 1;
128
+ }
129
+ /**
130
+ * Handle special keys like Backspace and Delete
131
+ */
132
+ _handleSpecialKey(event, el, key, currentPosition, mask) {
133
+ if (key === 'Backspace' && currentPosition > 0) {
134
+ const maskEntry = mask[currentPosition - 1];
135
+ if (!maskEntry) {
136
+ return;
137
+ }
138
+ // Get the default character for this position
139
+ const defaultChar = typeof maskEntry === 'string' ? maskEntry : maskEntry.default;
140
+ if (currentPosition === el.value.length) {
141
+ return;
142
+ }
143
+ const newVal = el.value.slice(0, currentPosition - 1) + defaultChar + el.value.slice(currentPosition);
144
+ this._data.updateValue(el, newVal, currentPosition - 1);
145
+ event.preventDefault();
146
+ }
147
+ else if (key === 'Delete' && currentPosition < el.value.length) {
148
+ const maskEntry = mask[currentPosition];
149
+ if (!maskEntry) {
150
+ return;
151
+ }
152
+ // Get the default character for this position
153
+ const defaultChar = typeof maskEntry === 'string' ? maskEntry : maskEntry.default;
154
+ const newVal = el.value.slice(0, currentPosition) + defaultChar + el.value.slice(currentPosition + 1);
155
+ this._data.updateValue(el, newVal, currentPosition + 1);
156
+ event.preventDefault();
157
+ }
158
+ }
159
+ /**
160
+ * Handle regular character input with mask validation
161
+ */
162
+ _handleCharacterInput(event, el, key, currentPosition, mask) {
163
+ // Skip over static characters and find the next input position
164
+ const { position, autoPrintChars } = this._processStaticCharacters(el, currentPosition, mask);
165
+ const maskEntry = mask[position];
166
+ // Check if we're at a valid input position
167
+ if (!maskEntry || typeof maskEntry === 'string') {
168
+ event.preventDefault();
169
+ return;
170
+ }
171
+ // Validate the character against the mask requirements
172
+ if (!maskEntry.accepts.test(key)) {
173
+ event.preventDefault();
174
+ setTimeout(() => {
175
+ // Ensure the cursor position is set after the value update for android compatibility
176
+ el.setSelectionRange(position, position);
177
+ });
178
+ return;
179
+ }
180
+ // Build the new value with auto-inserted static characters
181
+ const newVal = el.value.slice(0, position) + autoPrintChars + key + el.value.slice(position + 1);
182
+ this._data.updateValue(el, newVal, position + 1);
183
+ event.preventDefault();
184
+ }
185
+ /**
186
+ * Process static characters in the mask and auto-insert them
187
+ * Returns the next input position and any static characters to insert
188
+ */
189
+ _processStaticCharacters(el, startPosition, mask) {
190
+ let currentPosition = startPosition;
191
+ let autoPrintChars = '';
192
+ let currentMaskEntry = mask[currentPosition];
193
+ // Skip over static characters and collect them for auto-insertion
194
+ while (currentMaskEntry && typeof currentMaskEntry === 'string') {
195
+ if (el.value.charAt(currentPosition) !== currentMaskEntry) {
196
+ autoPrintChars += currentMaskEntry;
197
+ }
198
+ currentPosition++;
199
+ currentMaskEntry = mask[currentPosition];
200
+ }
201
+ return { position: currentPosition, autoPrintChars };
202
+ }
203
+ }
204
+
205
+ /**
206
+ * @category control
207
+ */
208
+ class NgnInputMask extends NgnBase {
209
+ theme = this.injectThemeTemplate(inputMaskControlTemplate);
210
+ /**
211
+ * The mask to apply to the input. Can be a predefined mask key, a custom mask configuration, or a string pattern.
212
+ */
213
+ mask = input(null, ...(ngDevMode ? [{ debugName: "mask" }] : []));
214
+ _ngnInput = contentChild.required(NgnInput);
215
+ _inputElement = computed(() => this._ngnInput().element.nativeElement, ...(ngDevMode ? [{ debugName: "_inputElement" }] : []));
216
+ constructor() {
217
+ super();
218
+ domEventHandler(this._inputElement, 'keydown', event => this.onKeyDown(event));
219
+ domEventHandler(this._inputElement, 'beforeinput', event => this.onBeforeInput(event));
220
+ afterRenderEffect(() => {
221
+ if (this._ngnInput().value() !== this.currentInputValue()) {
222
+ this.currentInputValue.set(this._ngnInput().value() ?? '');
223
+ }
224
+ });
225
+ }
226
+ _maskHelper = new MaskHelper({
227
+ updateValue: (e, v, i) => this._updateValue(e, v, i),
228
+ });
229
+ onInput(event) {
230
+ // Update the current input value
231
+ this.currentInputValue.set(event.target.value);
232
+ }
233
+ currentInputValue = signal('', ...(ngDevMode ? [{ debugName: "currentInputValue" }] : []));
234
+ _mask = computed(() => this._maskHelper.ensureMask(this.mask()), ...(ngDevMode ? [{ debugName: "_mask" }] : []));
235
+ maskWatermark = computed(() => {
236
+ const mask = this._mask();
237
+ if (!mask)
238
+ return null;
239
+ const maskString = mask
240
+ .map(entry => {
241
+ if (typeof entry === 'string')
242
+ return entry;
243
+ return entry.placeholder;
244
+ })
245
+ .join('');
246
+ return maskString.substring(this.currentInputValue().length, maskString.length);
247
+ }, ...(ngDevMode ? [{ debugName: "maskWatermark" }] : []));
248
+ onKeyDown(event) {
249
+ const mask = this._mask();
250
+ if (!mask)
251
+ return;
252
+ this._maskHelper.handleKeyDown(event, mask);
253
+ }
254
+ onBeforeInput(event) {
255
+ const mask = this._mask();
256
+ if (!mask)
257
+ return;
258
+ this._maskHelper.handleBeforeInput(event, mask);
259
+ }
260
+ _updateValue(el, newValue, cursorPosition) {
261
+ el.value = newValue;
262
+ this.currentInputValue.set(newValue);
263
+ setTimeout(() => {
264
+ // Ensure the cursor position is set after the value update for android compatibility
265
+ el.setSelectionRange(cursorPosition, cursorPosition);
266
+ });
267
+ this._inputElement().dispatchEvent(new Event('input', { bubbles: true }));
268
+ }
269
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnInputMask, deps: [], target: i0.ɵɵFactoryTarget.Component });
270
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.0", type: NgnInputMask, isStandalone: true, selector: "ngn-input-mask", inputs: { mask: { classPropertyName: "mask", publicName: "mask", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideSelf(NgnInputMask)], queries: [{ propertyName: "_ngnInput", first: true, predicate: NgnInput, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div [ptInt]=\"this\" [ptClass]=\"'root'\">\r\n <ng-content />\r\n <span [ptInt]=\"this\" [ptClass]=\"'mask'\">\r\n <span [ptInt]=\"this\" [ptClass]=\"'mask-placeholder'\" aria-hidden=\"true\" style=\"opacity: 0\">{{\r\n currentInputValue()\r\n }}</span>\r\n <span [ptInt]=\"this\" [ptClass]=\"'mask-text'\">{{ maskWatermark() }}</span>\r\n </span>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
271
+ }
272
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgnInputMask, decorators: [{
273
+ type: Component,
274
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngn-input-mask', imports: [NgnPt], providers: [provideSelf(NgnInputMask)], template: "<div [ptInt]=\"this\" [ptClass]=\"'root'\">\r\n <ng-content />\r\n <span [ptInt]=\"this\" [ptClass]=\"'mask'\">\r\n <span [ptInt]=\"this\" [ptClass]=\"'mask-placeholder'\" aria-hidden=\"true\" style=\"opacity: 0\">{{\r\n currentInputValue()\r\n }}</span>\r\n <span [ptInt]=\"this\" [ptClass]=\"'mask-text'\">{{ maskWatermark() }}</span>\r\n </span>\r\n</div>\r\n" }]
275
+ }], ctorParameters: () => [], propDecorators: { mask: [{ type: i0.Input, args: [{ isSignal: true, alias: "mask", required: false }] }], _ngnInput: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NgnInput), { isSignal: true }] }] } });
276
+
277
+ /**
278
+ * Generated bundle index. Do not edit.
279
+ */
280
+
281
+ export { MASKS, NgnInputMask };
282
+ //# sourceMappingURL=ngneers-controls-input-mask.mjs.map