@smallpearl/ngx-helper 0.29.23

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 (117) hide show
  1. package/README.md +230 -0
  2. package/core/index.d.ts +2 -0
  3. package/core/src/ngx-helper.d.ts +7 -0
  4. package/core/src/version.d.ts +1 -0
  5. package/entity-field/index.d.ts +2 -0
  6. package/entity-field/src/entity-field-spec.d.ts +69 -0
  7. package/entity-field/src/provider.d.ts +27 -0
  8. package/fesm2022/smallpearl-ngx-helper-core.mjs +23 -0
  9. package/fesm2022/smallpearl-ngx-helper-core.mjs.map +1 -0
  10. package/fesm2022/smallpearl-ngx-helper-entity-field.mjs +112 -0
  11. package/fesm2022/smallpearl-ngx-helper-entity-field.mjs.map +1 -0
  12. package/fesm2022/smallpearl-ngx-helper-forms.mjs +112 -0
  13. package/fesm2022/smallpearl-ngx-helper-forms.mjs.map +1 -0
  14. package/fesm2022/smallpearl-ngx-helper-hover-dropdown.mjs +108 -0
  15. package/fesm2022/smallpearl-ngx-helper-hover-dropdown.mjs.map +1 -0
  16. package/fesm2022/smallpearl-ngx-helper-locale.mjs +296 -0
  17. package/fesm2022/smallpearl-ngx-helper-locale.mjs.map +1 -0
  18. package/fesm2022/smallpearl-ngx-helper-mat-busy-wheel.mjs +504 -0
  19. package/fesm2022/smallpearl-ngx-helper-mat-busy-wheel.mjs.map +1 -0
  20. package/fesm2022/smallpearl-ngx-helper-mat-context-menu.mjs +184 -0
  21. package/fesm2022/smallpearl-ngx-helper-mat-context-menu.mjs.map +1 -0
  22. package/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs +1486 -0
  23. package/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs.map +1 -0
  24. package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs +800 -0
  25. package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs.map +1 -0
  26. package/fesm2022/smallpearl-ngx-helper-mat-file-input.mjs +328 -0
  27. package/fesm2022/smallpearl-ngx-helper-mat-file-input.mjs.map +1 -0
  28. package/fesm2022/smallpearl-ngx-helper-mat-form-error.mjs +468 -0
  29. package/fesm2022/smallpearl-ngx-helper-mat-form-error.mjs.map +1 -0
  30. package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs +854 -0
  31. package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs.map +1 -0
  32. package/fesm2022/smallpearl-ngx-helper-mat-side-menu-layout.mjs +930 -0
  33. package/fesm2022/smallpearl-ngx-helper-mat-side-menu-layout.mjs.map +1 -0
  34. package/fesm2022/smallpearl-ngx-helper-mat-tel-input.mjs +926 -0
  35. package/fesm2022/smallpearl-ngx-helper-mat-tel-input.mjs.map +1 -0
  36. package/fesm2022/smallpearl-ngx-helper-sideload.mjs +111 -0
  37. package/fesm2022/smallpearl-ngx-helper-sideload.mjs.map +1 -0
  38. package/fesm2022/smallpearl-ngx-helper-stationary-with-line-items.mjs +384 -0
  39. package/fesm2022/smallpearl-ngx-helper-stationary-with-line-items.mjs.map +1 -0
  40. package/fesm2022/smallpearl-ngx-helper.mjs +13 -0
  41. package/fesm2022/smallpearl-ngx-helper.mjs.map +1 -0
  42. package/forms/index.d.ts +1 -0
  43. package/forms/src/validation-error-handler.d.ts +52 -0
  44. package/hover-dropdown/index.d.ts +1 -0
  45. package/hover-dropdown/src/hover-dropdown.directive.d.ts +41 -0
  46. package/index.d.ts +5 -0
  47. package/locale/index.d.ts +5 -0
  48. package/locale/src/currency.pipe.d.ts +14 -0
  49. package/locale/src/date.pipe.d.ts +14 -0
  50. package/locale/src/format-currency.d.ts +1 -0
  51. package/locale/src/format-date.d.ts +2 -0
  52. package/locale/src/is-empty.d.ts +1 -0
  53. package/locale/src/providers.d.ts +20 -0
  54. package/mat-busy-wheel/index.d.ts +4 -0
  55. package/mat-busy-wheel/src/busy-wheel-op.d.ts +65 -0
  56. package/mat-busy-wheel/src/busy-wheel.component.d.ts +12 -0
  57. package/mat-busy-wheel/src/busy-wheel.service.d.ts +42 -0
  58. package/mat-busy-wheel/src/host-busy-wheel.directive.d.ts +35 -0
  59. package/mat-context-menu/index.d.ts +1 -0
  60. package/mat-context-menu/src/mat-context-menu.component.d.ts +54 -0
  61. package/mat-entity-crud/index.d.ts +5 -0
  62. package/mat-entity-crud/src/default-config.d.ts +9 -0
  63. package/mat-entity-crud/src/form-view-host.component.d.ts +34 -0
  64. package/mat-entity-crud/src/mat-entity-crud-form-base.d.ts +95 -0
  65. package/mat-entity-crud/src/mat-entity-crud-internal-types.d.ts +66 -0
  66. package/mat-entity-crud/src/mat-entity-crud-types.d.ts +141 -0
  67. package/mat-entity-crud/src/mat-entity-crud.component.d.ts +267 -0
  68. package/mat-entity-crud/src/preview-host.component.d.ts +19 -0
  69. package/mat-entity-crud/src/preview-pane.component.d.ts +27 -0
  70. package/mat-entity-crud/src/providers.d.ts +3 -0
  71. package/mat-entity-list/index.d.ts +3 -0
  72. package/mat-entity-list/src/config.d.ts +6 -0
  73. package/mat-entity-list/src/mat-entity-list-types.d.ts +53 -0
  74. package/mat-entity-list/src/mat-entity-list.component.d.ts +209 -0
  75. package/mat-entity-list/src/providers.d.ts +3 -0
  76. package/mat-file-input/README.md +63 -0
  77. package/mat-file-input/index.d.ts +1 -0
  78. package/mat-file-input/src/mat-file-input.component.d.ts +58 -0
  79. package/mat-form-error/README.md +306 -0
  80. package/mat-form-error/index.d.ts +6 -0
  81. package/mat-form-error/src/locales/en.d.ts +4 -0
  82. package/mat-form-error/src/locales/hu.d.ts +4 -0
  83. package/mat-form-error/src/locales/index.d.ts +3 -0
  84. package/mat-form-error/src/locales/pt-br.d.ts +4 -0
  85. package/mat-form-error/src/ngx-error-list.component.d.ts +9 -0
  86. package/mat-form-error/src/ngx-mat-error-control.d.ts +17 -0
  87. package/mat-form-error/src/ngx-mat-error-def.directive.d.ts +30 -0
  88. package/mat-form-error/src/ngx-mat-errors-for-date-range-picker.directive.d.ts +8 -0
  89. package/mat-form-error/src/ngx-mat-errors.component.d.ts +23 -0
  90. package/mat-form-error/src/types.d.ts +68 -0
  91. package/mat-form-error/src/utils/coerce-to-observable.d.ts +3 -0
  92. package/mat-form-error/src/utils/distinct-until-error-changed.d.ts +2 -0
  93. package/mat-form-error/src/utils/find-error-for-control.d.ts +9 -0
  94. package/mat-form-error/src/utils/get-abstract-controls.d.ts +3 -0
  95. package/mat-form-error/src/utils/get-control-with-error.d.ts +3 -0
  96. package/mat-select-entity/index.d.ts +2 -0
  97. package/mat-select-entity/src/mat-select-entity.component.d.ts +207 -0
  98. package/mat-select-entity/src/providers.d.ts +9 -0
  99. package/mat-side-menu-layout/index.d.ts +6 -0
  100. package/mat-side-menu-layout/src/layout.service.d.ts +23 -0
  101. package/mat-side-menu-layout/src/mat-menu-layout.component.d.ts +39 -0
  102. package/mat-side-menu-layout/src/mat-menu-layout.module.d.ts +18 -0
  103. package/mat-side-menu-layout/src/mat-menu-list-item.component.d.ts +36 -0
  104. package/mat-side-menu-layout/src/mat-menu-pane.component.d.ts +66 -0
  105. package/mat-side-menu-layout/src/nav-item.d.ts +10 -0
  106. package/mat-tel-input/README.md +18 -0
  107. package/mat-tel-input/index.d.ts +2 -0
  108. package/mat-tel-input/src/country-codes.d.ts +5 -0
  109. package/mat-tel-input/src/mat-telephone.component.d.ts +129 -0
  110. package/mat-tel-input/src/providers.d.ts +38 -0
  111. package/ngx-helper.d.ts +2 -0
  112. package/package.json +114 -0
  113. package/public-api.d.ts +1 -0
  114. package/sideload/index.d.ts +1 -0
  115. package/sideload/src/sideload.d.ts +17 -0
  116. package/stationary-with-line-items/index.d.ts +1 -0
  117. package/stationary-with-line-items/src/stationary-with-line-items.component.d.ts +74 -0
@@ -0,0 +1,384 @@
1
+ import * as i1 from '@angular/common';
2
+ import { CommonModule, UpperCasePipe } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { input, computed, Component, ChangeDetectionStrategy, inject } from '@angular/core';
5
+ import { getNgxHelperConfig } from '@smallpearl/ngx-helper/core';
6
+ import { SP_ENTITY_FIELD_CONFIG, SPEntityField } from '@smallpearl/ngx-helper/entity-field';
7
+
8
+ // @Component({
9
+ // standalone: true,
10
+ // imports: [],
11
+ // selector: 'sp-string-or-object-renderer',
12
+ // template: `
13
+ // @if (isString()) {
14
+ // {{ value() }}
15
+ // } @else {
16
+ // <table>
17
+ // @for (row of objectAsArray(); track $index) {
18
+ // <tr>
19
+ // @for (col of row; track $index) {
20
+ // <td [style]="'text-align: ' + valueAlignment()">{{ col }}</td>
21
+ // }
22
+ // </tr>
23
+ // }
24
+ // </table>
25
+ // }
26
+ // `,
27
+ // changeDetection: ChangeDetectionStrategy.OnPush
28
+ // })
29
+ // export class StringOrObjectRendererComponent implements OnInit {
30
+ // value = input.required<any>();
31
+ // valueAlignment = input<string>()
32
+ // isString = computed(() => typeof this.value() === 'string');
33
+ // objectAsArray = computed(() => {
34
+ // const arrayValues = [];
35
+ // const value = this.value();
36
+ // if (typeof value !== 'string') {
37
+ // for (const key in this.value()) {
38
+ // const keyValue = this.value()[key];
39
+ // arrayValues.push([key, keyValue]);
40
+ // }
41
+ // }
42
+ // return arrayValues;
43
+ // });
44
+ // constructor() { }
45
+ // ngOnInit() { }
46
+ // }
47
+ class FieldsRendererComponent {
48
+ cdr;
49
+ entity = input.required();
50
+ fields = input.required();
51
+ isString = computed(() => typeof this.fields() === 'string');
52
+ // If the field is a single string, looks up entity's properties
53
+ // for matching field name as the string and if it doesn't exist returns
54
+ // the string itself as the value.
55
+ stringValue = computed(() => {
56
+ const fields = this.fields();
57
+ if (typeof fields === 'string') {
58
+ return this.entity()[fields] ?? fields;
59
+ }
60
+ return '';
61
+ });
62
+ ngxHelperConfig = getNgxHelperConfig();
63
+ constructor(cdr) {
64
+ this.cdr = cdr;
65
+ }
66
+ ngOnInit() { }
67
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: FieldsRendererComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
68
+ /** @nocollapse */ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.6", type: FieldsRendererComponent, isStandalone: true, selector: "sp-fields-renderer", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: true, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
69
+ @if (isString()) {
70
+ {{ stringValue() }}
71
+ } @else {
72
+ <div class="">
73
+ <table>
74
+ <tbody>
75
+ @for (field of fields(); track $index) {
76
+ <tr>
77
+ <td [class]="field.class">{{ field.label() }}&colon;</td>
78
+ <td [class]="field.class">{{ field.value(entity()) }}</td>
79
+ </tr>
80
+ }
81
+ </tbody>
82
+ </table>
83
+ </div>
84
+ }
85
+ `, isInline: true, styles: [".field-values{padding:.2em 0;text-align:end}tr td:first-of-type{padding-right:1em}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
86
+ }
87
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: FieldsRendererComponent, decorators: [{
88
+ type: Component,
89
+ args: [{ imports: [], selector: 'sp-fields-renderer', template: `
90
+ @if (isString()) {
91
+ {{ stringValue() }}
92
+ } @else {
93
+ <div class="">
94
+ <table>
95
+ <tbody>
96
+ @for (field of fields(); track $index) {
97
+ <tr>
98
+ <td [class]="field.class">{{ field.label() }}&colon;</td>
99
+ <td [class]="field.class">{{ field.value(entity()) }}</td>
100
+ </tr>
101
+ }
102
+ </tbody>
103
+ </table>
104
+ </div>
105
+ }
106
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".field-values{padding:.2em 0;text-align:end}tr td:first-of-type{padding-right:1em}\n"] }]
107
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
108
+ /**
109
+ * A component that renders a stationary with line items, such as invoice,
110
+ * payment receipt, bill, bill payment record, journal entry, etc. All these
111
+ * documents have a uniform format and this component abstracts out the
112
+ * information displayed in this type of document as properties that the client
113
+ * can provide while it takes care of the rendering.
114
+ *
115
+ * Ideally we would declare this as a wrapper class with the actual rendering
116
+ * to be performed by an inner replaceable component. This way the app will be
117
+ * able to support multiple stationary designs, which eventually can be
118
+ * chosen by the user. Perhaps even providing them a feature to design the
119
+ * stationary.
120
+ *
121
+ * This is the first towards that long path ahead.
122
+ */
123
+ class StationaryWithLineItemsComponent {
124
+ entity = input.required();
125
+ title = input.required();
126
+ number = input();
127
+ leftHeader = input();
128
+ _leftHeaderFields = computed(() => this.getSPEntityFields(this.leftHeader()));
129
+ leftHeaderTemplate = input();
130
+ rightHeader = input();
131
+ _rightHeaderFields = computed(() => this.getSPEntityFields(this.rightHeader()));
132
+ rightHeaderTemplate = input();
133
+ items = input();
134
+ leftFooter = input();
135
+ _leftFooterFields = computed(() => this.getSPEntityFields(this.leftFooter()));
136
+ leftFooterTemplate = input();
137
+ rightFooter = input();
138
+ _rightFooterFields = computed(() => this.getSPEntityFields(this.rightFooter()));
139
+ rightFooterTemplate = input();
140
+ itemFieldName = input('items');
141
+ itemColumnFields = input();
142
+ _itemColumnFields = computed(() => this.getSPEntityFields(this.itemColumnFields()));
143
+ _items = computed(() => this.entity()[this.itemFieldName()]);
144
+ ngxHelperConfig = getNgxHelperConfig();
145
+ ngxEntityFieldConfig = inject(SP_ENTITY_FIELD_CONFIG, { optional: true });
146
+ constructor() { }
147
+ ngOnInit() { }
148
+ isString(value) {
149
+ return typeof value === 'string';
150
+ }
151
+ /**
152
+ * Make the method a generic as we'll be using it for both TEntity and its
153
+ * child TEntityLineItem objects.
154
+ * @param fieldSpecs
155
+ * @returns
156
+ */
157
+ getSPEntityFields(fieldSpecs) {
158
+ if (fieldSpecs && typeof fieldSpecs !== 'string') {
159
+ return fieldSpecs.map(spec => new SPEntityField(spec, this.ngxHelperConfig, this.ngxEntityFieldConfig));
160
+ }
161
+ return [];
162
+ }
163
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: StationaryWithLineItemsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
164
+ /** @nocollapse */ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.6", type: StationaryWithLineItemsComponent, isStandalone: true, selector: "sp-stationary-with-line-items", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, number: { classPropertyName: "number", publicName: "number", isSignal: true, isRequired: false, transformFunction: null }, leftHeader: { classPropertyName: "leftHeader", publicName: "leftHeader", isSignal: true, isRequired: false, transformFunction: null }, leftHeaderTemplate: { classPropertyName: "leftHeaderTemplate", publicName: "leftHeaderTemplate", isSignal: true, isRequired: false, transformFunction: null }, rightHeader: { classPropertyName: "rightHeader", publicName: "rightHeader", isSignal: true, isRequired: false, transformFunction: null }, rightHeaderTemplate: { classPropertyName: "rightHeaderTemplate", publicName: "rightHeaderTemplate", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, leftFooter: { classPropertyName: "leftFooter", publicName: "leftFooter", isSignal: true, isRequired: false, transformFunction: null }, leftFooterTemplate: { classPropertyName: "leftFooterTemplate", publicName: "leftFooterTemplate", isSignal: true, isRequired: false, transformFunction: null }, rightFooter: { classPropertyName: "rightFooter", publicName: "rightFooter", isSignal: true, isRequired: false, transformFunction: null }, rightFooterTemplate: { classPropertyName: "rightFooterTemplate", publicName: "rightFooterTemplate", isSignal: true, isRequired: false, transformFunction: null }, itemFieldName: { classPropertyName: "itemFieldName", publicName: "itemFieldName", isSignal: true, isRequired: false, transformFunction: null }, itemColumnFields: { classPropertyName: "itemColumnFields", publicName: "itemColumnFields", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
165
+ <div class="stationary-wrapper mat-body">
166
+ <div class="title">{{ title() }}</div>
167
+ @if (number()) {
168
+ <div class="number">#{{ number() }}</div>
169
+ }
170
+ <div class="header">
171
+ <div class="left-header">
172
+ @if (leftHeaderTemplate()) {
173
+ <ng-container *ngTemplateOutlet="leftHeaderTemplate() ?? null"></ng-container>
174
+ } @else {
175
+ @if (leftHeader()) {
176
+ @if (isString(leftHeader())) {
177
+ {{ leftHeader() }}
178
+ } @else {
179
+ <sp-fields-renderer
180
+ [entity]="entity()"
181
+ [fields]="_leftHeaderFields()"
182
+ ></sp-fields-renderer>
183
+ }
184
+ }
185
+ }
186
+ </div>
187
+ <div class="right-header">
188
+ @if (rightHeaderTemplate()) {
189
+ <ng-container *ngTemplateOutlet="rightHeaderTemplate() ?? null"></ng-container>
190
+ } @else {
191
+ @if (rightHeader()) {
192
+ @if (isString(rightHeader())) {
193
+ {{ rightHeader() }}
194
+ } @else {
195
+ <sp-fields-renderer
196
+ [entity]="entity()"
197
+ [fields]="_rightHeaderFields()"
198
+ ></sp-fields-renderer>
199
+ }
200
+ }
201
+ }
202
+ </div>
203
+ </div> <!-- end <div class="header"> -->
204
+
205
+ <!-- items -->
206
+ @if (itemColumnFields()) {
207
+ <div class="items">
208
+ <table>
209
+ <thead>
210
+ @for (field of _itemColumnFields(); track $index) {
211
+ <th [class]="field.class" [style.text-align]="field.spec.valueOptions?.alignment">{{ field.label() | uppercase }}</th>
212
+ }
213
+ </thead>
214
+ <tbody>
215
+ <!-- enumerate each element of the 'items' array and render the
216
+ specified columns for each. -->
217
+ @for (row of _items(); track $index) {
218
+ <tr>
219
+ @for (field of _itemColumnFields(); track $index) {
220
+ <td [class]="field.class" [style.text-align]="field.spec.valueOptions?.alignment" [innerHtml]="field.value(row)"></td>
221
+ }
222
+ </tr>
223
+ }
224
+ </tbody>
225
+ </table>
226
+ </div>
227
+ }
228
+ <!-- end items -->
229
+
230
+ <!-- footer -->
231
+ <div class="footer">
232
+ <div class="left-footer">
233
+ @if (leftFooterTemplate()) {
234
+ <ng-container *ngTemplateOutlet="leftFooterTemplate() ?? null"></ng-container>
235
+ } @else {
236
+ @if (leftFooter()) {
237
+ @if (isString(leftFooter())) {
238
+ {{ leftFooter() }}
239
+ } @else {
240
+ <sp-fields-renderer
241
+ [entity]="entity()"
242
+ [fields]="_leftFooterFields()"
243
+ ></sp-fields-renderer>
244
+ }
245
+ }
246
+ }
247
+ </div>
248
+ <div class="right-footer">
249
+ @if (rightFooterTemplate()) {
250
+ <ng-container *ngTemplateOutlet="rightFooterTemplate() ?? null"></ng-container>
251
+ } @else {
252
+ @if (rightFooter()) {
253
+ @if (isString(rightFooter())) {
254
+ {{ rightFooter() }}
255
+ } @else {
256
+ <sp-fields-renderer
257
+ [entity]="entity()"
258
+ [fields]="_rightFooterFields()"
259
+ ></sp-fields-renderer>
260
+ }
261
+ }
262
+ }
263
+ </div>
264
+ </div>
265
+ </div>
266
+ `, isInline: true, styles: [".stationary-wrapper{padding:2em 1em}.title{font-size:1.6em;font-weight:600;text-align:end;margin-bottom:.5em}.number{font-size:1.1em;font-weight:500;text-align:end;margin-bottom:.5em}.header,.footer{display:flex;flex-direction:row;margin-top:1em}.left-header,.left-footer{display:flex;align-items:bottom;text-align:start;padding-right:1em;min-width:50%;overflow-wrap:break-word;text-wrap:wrap}.right-header,.right-footer{display:flex;justify-content:flex-end;min-width:50%;overflow:clip}.items{margin:2em 0}.items table{width:100%;border:0px solid lightgray}.items table thead{background-color:#000;color:#fff}.items table thead th{padding:.4em}.items table td{padding:.8em .4em;border-bottom:1px solid lightgray;border-right:0px solid lightgray}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.UpperCasePipe, name: "uppercase" }, { kind: "component", type: FieldsRendererComponent, selector: "sp-fields-renderer", inputs: ["entity", "fields"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
267
+ }
268
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: StationaryWithLineItemsComponent, decorators: [{
269
+ type: Component,
270
+ args: [{ imports: [
271
+ CommonModule,
272
+ UpperCasePipe,
273
+ FieldsRendererComponent
274
+ ], selector: 'sp-stationary-with-line-items', template: `
275
+ <div class="stationary-wrapper mat-body">
276
+ <div class="title">{{ title() }}</div>
277
+ @if (number()) {
278
+ <div class="number">#{{ number() }}</div>
279
+ }
280
+ <div class="header">
281
+ <div class="left-header">
282
+ @if (leftHeaderTemplate()) {
283
+ <ng-container *ngTemplateOutlet="leftHeaderTemplate() ?? null"></ng-container>
284
+ } @else {
285
+ @if (leftHeader()) {
286
+ @if (isString(leftHeader())) {
287
+ {{ leftHeader() }}
288
+ } @else {
289
+ <sp-fields-renderer
290
+ [entity]="entity()"
291
+ [fields]="_leftHeaderFields()"
292
+ ></sp-fields-renderer>
293
+ }
294
+ }
295
+ }
296
+ </div>
297
+ <div class="right-header">
298
+ @if (rightHeaderTemplate()) {
299
+ <ng-container *ngTemplateOutlet="rightHeaderTemplate() ?? null"></ng-container>
300
+ } @else {
301
+ @if (rightHeader()) {
302
+ @if (isString(rightHeader())) {
303
+ {{ rightHeader() }}
304
+ } @else {
305
+ <sp-fields-renderer
306
+ [entity]="entity()"
307
+ [fields]="_rightHeaderFields()"
308
+ ></sp-fields-renderer>
309
+ }
310
+ }
311
+ }
312
+ </div>
313
+ </div> <!-- end <div class="header"> -->
314
+
315
+ <!-- items -->
316
+ @if (itemColumnFields()) {
317
+ <div class="items">
318
+ <table>
319
+ <thead>
320
+ @for (field of _itemColumnFields(); track $index) {
321
+ <th [class]="field.class" [style.text-align]="field.spec.valueOptions?.alignment">{{ field.label() | uppercase }}</th>
322
+ }
323
+ </thead>
324
+ <tbody>
325
+ <!-- enumerate each element of the 'items' array and render the
326
+ specified columns for each. -->
327
+ @for (row of _items(); track $index) {
328
+ <tr>
329
+ @for (field of _itemColumnFields(); track $index) {
330
+ <td [class]="field.class" [style.text-align]="field.spec.valueOptions?.alignment" [innerHtml]="field.value(row)"></td>
331
+ }
332
+ </tr>
333
+ }
334
+ </tbody>
335
+ </table>
336
+ </div>
337
+ }
338
+ <!-- end items -->
339
+
340
+ <!-- footer -->
341
+ <div class="footer">
342
+ <div class="left-footer">
343
+ @if (leftFooterTemplate()) {
344
+ <ng-container *ngTemplateOutlet="leftFooterTemplate() ?? null"></ng-container>
345
+ } @else {
346
+ @if (leftFooter()) {
347
+ @if (isString(leftFooter())) {
348
+ {{ leftFooter() }}
349
+ } @else {
350
+ <sp-fields-renderer
351
+ [entity]="entity()"
352
+ [fields]="_leftFooterFields()"
353
+ ></sp-fields-renderer>
354
+ }
355
+ }
356
+ }
357
+ </div>
358
+ <div class="right-footer">
359
+ @if (rightFooterTemplate()) {
360
+ <ng-container *ngTemplateOutlet="rightFooterTemplate() ?? null"></ng-container>
361
+ } @else {
362
+ @if (rightFooter()) {
363
+ @if (isString(rightFooter())) {
364
+ {{ rightFooter() }}
365
+ } @else {
366
+ <sp-fields-renderer
367
+ [entity]="entity()"
368
+ [fields]="_rightFooterFields()"
369
+ ></sp-fields-renderer>
370
+ }
371
+ }
372
+ }
373
+ </div>
374
+ </div>
375
+ </div>
376
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".stationary-wrapper{padding:2em 1em}.title{font-size:1.6em;font-weight:600;text-align:end;margin-bottom:.5em}.number{font-size:1.1em;font-weight:500;text-align:end;margin-bottom:.5em}.header,.footer{display:flex;flex-direction:row;margin-top:1em}.left-header,.left-footer{display:flex;align-items:bottom;text-align:start;padding-right:1em;min-width:50%;overflow-wrap:break-word;text-wrap:wrap}.right-header,.right-footer{display:flex;justify-content:flex-end;min-width:50%;overflow:clip}.items{margin:2em 0}.items table{width:100%;border:0px solid lightgray}.items table thead{background-color:#000;color:#fff}.items table thead th{padding:.4em}.items table td{padding:.8em .4em;border-bottom:1px solid lightgray;border-right:0px solid lightgray}\n"] }]
377
+ }], ctorParameters: () => [] });
378
+
379
+ /**
380
+ * Generated bundle index. Do not edit.
381
+ */
382
+
383
+ export { FieldsRendererComponent, StationaryWithLineItemsComponent };
384
+ //# sourceMappingURL=smallpearl-ngx-helper-stationary-with-line-items.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smallpearl-ngx-helper-stationary-with-line-items.mjs","sources":["../../../../projects/smallpearl/ngx-helper/stationary-with-line-items/src/stationary-with-line-items.component.ts","../../../../projects/smallpearl/ngx-helper/stationary-with-line-items/smallpearl-ngx-helper-stationary-with-line-items.ts"],"sourcesContent":["import { CommonModule, UpperCasePipe } from '@angular/common';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, inject, input, OnInit, TemplateRef } from '@angular/core';\nimport { getNgxHelperConfig } from '@smallpearl/ngx-helper/core';\nimport { SP_ENTITY_FIELD_CONFIG, SPEntityField, SPEntityFieldSpec } from '@smallpearl/ngx-helper/entity-field';\n\n\n// @Component({\n// standalone: true,\n// imports: [],\n// selector: 'sp-string-or-object-renderer',\n// template: `\n// @if (isString()) {\n// {{ value() }}\n// } @else {\n// <table>\n// @for (row of objectAsArray(); track $index) {\n// <tr>\n// @for (col of row; track $index) {\n// <td [style]=\"'text-align: ' + valueAlignment()\">{{ col }}</td>\n// }\n// </tr>\n// }\n// </table>\n// }\n// `,\n// changeDetection: ChangeDetectionStrategy.OnPush\n// })\n// export class StringOrObjectRendererComponent implements OnInit {\n// value = input.required<any>();\n// valueAlignment = input<string>()\n// isString = computed(() => typeof this.value() === 'string');\n// objectAsArray = computed(() => {\n// const arrayValues = [];\n// const value = this.value();\n// if (typeof value !== 'string') {\n// for (const key in this.value()) {\n// const keyValue = this.value()[key];\n// arrayValues.push([key, keyValue]);\n// }\n// }\n// return arrayValues;\n// });\n\n// constructor() { }\n\n// ngOnInit() { }\n// }\n\n@Component({\n imports: [],\n selector: 'sp-fields-renderer',\n template: `\n @if (isString()) {\n {{ stringValue() }}\n } @else {\n <div class=\"\">\n <table>\n <tbody>\n @for (field of fields(); track $index) {\n <tr>\n <td [class]=\"field.class\">{{ field.label() }}&colon;</td>\n <td [class]=\"field.class\">{{ field.value(entity()) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n `,\n styles: `\n .field-values {\n padding: 0.2em 0;\n text-align: end;\n }\n tr td:first-of-type {\n padding-right: 1em;\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class FieldsRendererComponent<TEntity extends { [P in IdKey]: PropertyKey }, IdKey extends string = 'id'> implements OnInit {\n entity = input.required<TEntity>();\n fields = input.required<SPEntityField<TEntity, IdKey>[]>();\n\n isString = computed(() => typeof this.fields() === 'string');\n // If the field is a single string, looks up entity's properties\n // for matching field name as the string and if it doesn't exist returns\n // the string itself as the value.\n stringValue = computed(() => {\n const fields = this.fields();\n if (typeof fields === 'string') {\n return (this.entity() as any)[fields] ?? fields;\n }\n return '';\n });\n\n ngxHelperConfig = getNgxHelperConfig();\n\n constructor(public cdr: ChangeDetectorRef) {}\n\n ngOnInit() {}\n}\n\n/**\n * A component that renders a stationary with line items, such as invoice,\n * payment receipt, bill, bill payment record, journal entry, etc. All these\n * documents have a uniform format and this component abstracts out the\n * information displayed in this type of document as properties that the client\n * can provide while it takes care of the rendering.\n *\n * Ideally we would declare this as a wrapper class with the actual rendering\n * to be performed by an inner replaceable component. This way the app will be\n * able to support multiple stationary designs, which eventually can be\n * chosen by the user. Perhaps even providing them a feature to design the\n * stationary.\n *\n * This is the first towards that long path ahead.\n */\n@Component({\n imports: [\n CommonModule,\n UpperCasePipe,\n FieldsRendererComponent\n ],\n selector: 'sp-stationary-with-line-items',\n template: `\n <div class=\"stationary-wrapper mat-body\">\n <div class=\"title\">{{ title() }}</div>\n @if (number()) {\n <div class=\"number\">#{{ number() }}</div>\n }\n <div class=\"header\">\n <div class=\"left-header\">\n @if (leftHeaderTemplate()) {\n <ng-container *ngTemplateOutlet=\"leftHeaderTemplate() ?? null\"></ng-container>\n } @else {\n @if (leftHeader()) {\n @if (isString(leftHeader())) {\n {{ leftHeader() }}\n } @else {\n <sp-fields-renderer\n [entity]=\"entity()\"\n [fields]=\"_leftHeaderFields()\"\n ></sp-fields-renderer>\n }\n }\n }\n </div>\n <div class=\"right-header\">\n @if (rightHeaderTemplate()) {\n <ng-container *ngTemplateOutlet=\"rightHeaderTemplate() ?? null\"></ng-container>\n } @else {\n @if (rightHeader()) {\n @if (isString(rightHeader())) {\n {{ rightHeader() }}\n } @else {\n <sp-fields-renderer\n [entity]=\"entity()\"\n [fields]=\"_rightHeaderFields()\"\n ></sp-fields-renderer>\n }\n }\n }\n </div>\n </div> <!-- end <div class=\"header\"> -->\n\n <!-- items -->\n @if (itemColumnFields()) {\n <div class=\"items\">\n <table>\n <thead>\n @for (field of _itemColumnFields(); track $index) {\n <th [class]=\"field.class\" [style.text-align]=\"field.spec.valueOptions?.alignment\">{{ field.label() | uppercase }}</th>\n }\n </thead>\n <tbody>\n <!-- enumerate each element of the 'items' array and render the\n specified columns for each. -->\n @for (row of _items(); track $index) {\n <tr>\n @for (field of _itemColumnFields(); track $index) {\n <td [class]=\"field.class\" [style.text-align]=\"field.spec.valueOptions?.alignment\" [innerHtml]=\"field.value(row)\"></td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n <!-- end items -->\n\n <!-- footer -->\n <div class=\"footer\">\n <div class=\"left-footer\">\n @if (leftFooterTemplate()) {\n <ng-container *ngTemplateOutlet=\"leftFooterTemplate() ?? null\"></ng-container>\n } @else {\n @if (leftFooter()) {\n @if (isString(leftFooter())) {\n {{ leftFooter() }}\n } @else {\n <sp-fields-renderer\n [entity]=\"entity()\"\n [fields]=\"_leftFooterFields()\"\n ></sp-fields-renderer>\n }\n }\n }\n </div>\n <div class=\"right-footer\">\n @if (rightFooterTemplate()) {\n <ng-container *ngTemplateOutlet=\"rightFooterTemplate() ?? null\"></ng-container>\n } @else {\n @if (rightFooter()) {\n @if (isString(rightFooter())) {\n {{ rightFooter() }}\n } @else {\n <sp-fields-renderer\n [entity]=\"entity()\"\n [fields]=\"_rightFooterFields()\"\n ></sp-fields-renderer>\n }\n }\n }\n </div>\n </div>\n </div>\n `,\n styles: `\n .stationary-wrapper {\n padding: 2em 1em;\n }\n .title {\n font-size: 1.6em;\n font-weight: 600;\n text-align: end;\n margin-bottom: 0.5em;\n }\n .number {\n font-size: 1.1em;\n font-weight: 500;\n text-align: end;\n margin-bottom: 0.5em;\n }\n .header, .footer {\n display: flex;\n flex-direction: row;\n margin-top: 1em;\n }\n .left-header, .left-footer {\n display: flex;\n align-items: bottom;\n text-align: start;\n padding-right: 1em;\n min-width: 50%;\n overflow-wrap: break-word;\n text-wrap: wrap;\n }\n .right-header, .right-footer {\n display: flex;\n justify-content: flex-end;\n min-width: 50%;\n overflow: clip;\n }\n .items {\n margin: 2em 0;\n }\n .items table {\n width: 100%;\n border: 0px solid lightgray;\n }\n .items table thead {\n background-color: black;\n color: white;\n & th {\n padding: 0.4em;\n }\n }\n .items table td {\n padding: 0.8em 0.4em;\n border-bottom: 1px solid lightgray;\n border-right: 0px solid lightgray\n }\n .footer {\n\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class StationaryWithLineItemsComponent<TEntity extends { [P in IdKey]: PropertyKey }, TEntityLineItem extends { [P in IdKey]: PropertyKey }, IdKey extends string = 'id'> implements OnInit {\n entity = input.required<TEntity>();\n title = input.required<string>();\n number = input<string|number>();\n\n leftHeader = input<Array<SPEntityFieldSpec<TEntity, IdKey> | string>|string>();\n _leftHeaderFields = computed(() => this.getSPEntityFields(this.leftHeader()));\n leftHeaderTemplate = input<TemplateRef<any>>();\n\n rightHeader = input<Array<SPEntityFieldSpec<TEntity, IdKey> | string>|string>();\n _rightHeaderFields = computed(() => this.getSPEntityFields(this.rightHeader()));\n rightHeaderTemplate = input<TemplateRef<any>>();\n\n items = input<{[key: string]: string}[]>();\n\n leftFooter = input<Array<SPEntityFieldSpec<TEntity, IdKey> | string>|string>();\n _leftFooterFields = computed(() => this.getSPEntityFields(this.leftFooter()));\n leftFooterTemplate = input<TemplateRef<any>>();\n\n rightFooter = input<Array<SPEntityFieldSpec<TEntity, IdKey> | string>|string>();\n _rightFooterFields = computed(() => this.getSPEntityFields(this.rightFooter()));\n rightFooterTemplate = input<TemplateRef<any>>();\n\n itemFieldName = input<string>('items');\n itemColumnFields = input<Array<SPEntityFieldSpec<TEntity, IdKey> | string>>();\n _itemColumnFields = computed(() => this.getSPEntityFields(this.itemColumnFields()));\n\n _items = computed(() => (this.entity() as any)[this.itemFieldName()]);\n\n ngxHelperConfig = getNgxHelperConfig();\n ngxEntityFieldConfig = inject(SP_ENTITY_FIELD_CONFIG, { optional: true })!;\n\n constructor() {}\n\n ngOnInit() {}\n\n isString(value: any) {\n return typeof value === 'string';\n }\n\n /**\n * Make the method a generic as we'll be using it for both TEntity and its\n * child TEntityLineItem objects.\n * @param fieldSpecs\n * @returns\n */\n getSPEntityFields<T>(fieldSpecs: Array<SPEntityFieldSpec<TEntity, IdKey> | string>|string|undefined): Array<SPEntityField<TEntity, IdKey>> {\n if (fieldSpecs && typeof fieldSpecs !== 'string') {\n return fieldSpecs.map(spec => new SPEntityField<TEntity, IdKey>(spec, this.ngxHelperConfig, this.ngxEntityFieldConfig));\n }\n return [];\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /** Version of the ngx-helper library */
2
+ const VERSION = '0.1.0';
3
+
4
+ /*
5
+ * Public API Surface of ngx-helper
6
+ */
7
+
8
+ /**
9
+ * Generated bundle index. Do not edit.
10
+ */
11
+
12
+ export { VERSION };
13
+ //# sourceMappingURL=smallpearl-ngx-helper.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smallpearl-ngx-helper.mjs","sources":["../../../../projects/smallpearl/ngx-helper/src/ngx-helper.ts","../../../../projects/smallpearl/ngx-helper/src/public-api.ts","../../../../projects/smallpearl/ngx-helper/src/smallpearl-ngx-helper.ts"],"sourcesContent":["/** Version of the ngx-helper library */\nexport const VERSION = '0.1.0';\n","/*\n * Public API Surface of ngx-helper\n */\n\nexport * from './ngx-helper';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;AACO,MAAM,OAAO,GAAG;;ACDvB;;AAEG;;ACFH;;AAEG;;;;"}
@@ -0,0 +1 @@
1
+ export * from './src/validation-error-handler';
@@ -0,0 +1,52 @@
1
+ import { HttpErrorResponse } from '@angular/common/http';
2
+ import { ChangeDetectorRef } from '@angular/core';
3
+ import { UntypedFormGroup } from '@angular/forms';
4
+ import { Observable } from 'rxjs';
5
+ /**
6
+ * Handle's form validation errors sent from the server by setting the returned
7
+ * error code in the respective control. Errors not associated with any control
8
+ * in the form are attached to the form itself.
9
+ *
10
+ * These errors can then be rendered using error-tailor. All that needs to be
11
+ * done is to import errorTailorImports in the respective page's module and set
12
+ * the 'errorTailor' directive on the <form..> element.
13
+ *
14
+ * @param form FormGroup instance
15
+ * @param error error object
16
+ */
17
+ export declare function handleValidationErrors(form: UntypedFormGroup, error: HttpErrorResponse, cdr?: ChangeDetectorRef): Observable<any>;
18
+ /**
19
+ * Returns an rxjs operator that would track an http request's error
20
+ * state and if the return code is 400, would enumerate the error codes
21
+ * set in the response body and set the error state of corresponding
22
+ * form controls.
23
+ *
24
+ * Use it like below:
25
+ *
26
+ * this.http.get<User>('https://google.com/..').pipe(
27
+ * setServerErrorsAsFormErrors(form),
28
+ * tap(user => {
29
+ * if (user) { // if user = null, it means there was a server validation
30
+ * // error.
31
+ * this.user = user;
32
+ * }
33
+ * })
34
+ * ).subscribe();
35
+ *
36
+ * Note that setServerErrorsAsFormErrors() is the last operator in
37
+ * the operators list. This is important because if a server validation
38
+ * error is encountered, setServerErrorsAsFormErrors(), would place
39
+ * the error on the respective form control and in the end would
40
+ * return Observable<null>. Any subsequent opeators that are added
41
+ * to the list after this should check for this null value in its
42
+ * handler.
43
+ *
44
+ * @param form The FormGroup instance where the controls corresponding
45
+ * to the errors are looked up and its control.error is set to the
46
+ * returned error code.
47
+ * @param cdr ChangeDetectorRef instance. If provided, it would be
48
+ * used to detect changes after the error codes are set on the form
49
+ * controls.
50
+ * @returns An rxjs op that can be added to the pipe() arg list.
51
+ */
52
+ export declare function setServerErrorsAsFormErrors(form: UntypedFormGroup, cdr?: ChangeDetectorRef): <T>(source: Observable<T>) => Observable<T>;
@@ -0,0 +1 @@
1
+ export * from './src/hover-dropdown.directive';
@@ -0,0 +1,41 @@
1
+ import { ElementRef, OnInit } from '@angular/core';
2
+ import { MatMenuTrigger } from '@angular/material/menu';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * A directive to make a button triggered mat-menu open during mouse hover.
6
+ * Use it like this:
7
+
8
+ <button #menuTrigger="matMenuTrigger"
9
+ mat-icon-button
10
+ [matMenuTriggerFor]="children"
11
+ hoverDropDown
12
+ [menu]="children"
13
+ [hoverTrigger]="menuTrigger">
14
+ <mat-icon>menu</mat-icon>
15
+ </button>
16
+ <mat-menu #children="matMenu" hasBackdrop="false">
17
+ <button mat-menu-item (click)="onEdit()">Edit</button>
18
+ <button mat-menu-item (click)="onDelete()">Delete</button>
19
+ </mat-menu>
20
+
21
+ Note how hoverDropDown and [hoverTrigger] are used to wire up the button
22
+ and the associated mat-menu to the directive. Once setup like this, the
23
+ mat-menu will be opened whenever the mouse cursor hovers over the menu
24
+ trigger button.
25
+
26
+ Copied from:
27
+ https://stackoverflow.com/questions/54301126/how-to-show-the-angular-material-drop-down-on-mouse-over
28
+ */
29
+ export declare class HoverDropDownDirective implements OnInit {
30
+ private el;
31
+ static _menuClicked: boolean;
32
+ isInHoverBlock: boolean;
33
+ constructor(el: ElementRef);
34
+ hoverTrigger: import("@angular/core").InputSignal<MatMenuTrigger | null | undefined>;
35
+ menu: import("@angular/core").InputSignal<any>;
36
+ ngOnInit(): void;
37
+ private setHoverState;
38
+ private checkHover;
39
+ static ɵfac: i0.ɵɵFactoryDeclaration<HoverDropDownDirective, never>;
40
+ static ɵdir: i0.ɵɵDirectiveDeclaration<HoverDropDownDirective, "[hoverDropDown]", never, { "hoverTrigger": { "alias": "hoverTrigger"; "required": false; "isSignal": true; }; "menu": { "alias": "menu"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
41
+ }
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="@smallpearl/ngx-helper" />
5
+ export * from './public-api';
@@ -0,0 +1,5 @@
1
+ export * from './src/providers';
2
+ export * from './src/format-date';
3
+ export * from './src/date.pipe';
4
+ export * from './src/currency.pipe';
5
+ export * from './src/format-currency';
@@ -0,0 +1,14 @@
1
+ import { PipeTransform } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * This is a replacement for Angular's native currency pipe. This uses
5
+ * web standardized Intl.NumberFormat() API to format currency. The advantage
6
+ * of this over Angular's version is that this pipe allows the locale and
7
+ * currency parameters to be dynamically changed during runtime.
8
+ */
9
+ export declare class SPCurrencyPipe implements PipeTransform {
10
+ constructor();
11
+ transform(value: number | bigint | string, currency?: string): string | null;
12
+ static ɵfac: i0.ɵɵFactoryDeclaration<SPCurrencyPipe, never>;
13
+ static ɵpipe: i0.ɵɵPipeDeclaration<SPCurrencyPipe, "spCurrency", true>;
14
+ }
@@ -0,0 +1,14 @@
1
+ import { PipeTransform } from '@angular/core';
2
+ import { SPIntlDateFormat } from './providers';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * An alternative to the Angular built-in `DatePipe` based on the native `Intl.DateTimeFormat` API.
6
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat
7
+ * https://angular.io/api/common/DatePipe
8
+ */
9
+ export declare class SPDatePipe implements PipeTransform {
10
+ #private;
11
+ transform(value: Date | number | string, format?: SPIntlDateFormat, timeZone?: string): string | null;
12
+ static ɵfac: i0.ɵɵFactoryDeclaration<SPDatePipe, never>;
13
+ static ɵpipe: i0.ɵɵPipeDeclaration<SPDatePipe, "spDate", true>;
14
+ }
@@ -0,0 +1 @@
1
+ export declare function spFormatCurrency(value: number | bigint | string, currency?: string): string | null;
@@ -0,0 +1,2 @@
1
+ import { SPIntlDateFormat } from "./providers";
2
+ export declare function spFormatDate(value: Date | number | string, format?: SPIntlDateFormat, timeZone?: string): string;
@@ -0,0 +1 @@
1
+ export declare const isEmpty: (value: any) => boolean;
@@ -0,0 +1,20 @@
1
+ export type SPIntlDateFormat = 'short' | 'medium' | 'long' | 'full' | 'shortDate' | 'mediumDate' | 'longDate' | 'fullDate' | 'shortTime' | 'mediumTime' | 'longTime' | 'fullTime';
2
+ export interface SPNgxI18nConfig {
3
+ locale: string;
4
+ currency: string;
5
+ timezone: string;
6
+ datetimeFormat: SPIntlDateFormat;
7
+ }
8
+ /**
9
+ * The object that will hold the mini library config.
10
+ */
11
+ export declare let _config: SPNgxI18nConfig;
12
+ /**
13
+ * Call this function update the _config dynamically as the need arises.
14
+ * @param config
15
+ */
16
+ export declare function setSPLocaleConfig(config: Partial<SPNgxI18nConfig>): void;
17
+ /**
18
+ * @returns Current config object.
19
+ */
20
+ export declare function getSPLocaleConfig(): SPNgxI18nConfig;
@@ -0,0 +1,4 @@
1
+ export * from './src/busy-wheel-op';
2
+ export * from './src/busy-wheel.component';
3
+ export * from './src/busy-wheel.service';
4
+ export * from './src/host-busy-wheel.directive';