@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.
- package/README.md +230 -0
- package/core/index.d.ts +2 -0
- package/core/src/ngx-helper.d.ts +7 -0
- package/core/src/version.d.ts +1 -0
- package/entity-field/index.d.ts +2 -0
- package/entity-field/src/entity-field-spec.d.ts +69 -0
- package/entity-field/src/provider.d.ts +27 -0
- package/fesm2022/smallpearl-ngx-helper-core.mjs +23 -0
- package/fesm2022/smallpearl-ngx-helper-core.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-entity-field.mjs +112 -0
- package/fesm2022/smallpearl-ngx-helper-entity-field.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-forms.mjs +112 -0
- package/fesm2022/smallpearl-ngx-helper-forms.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-hover-dropdown.mjs +108 -0
- package/fesm2022/smallpearl-ngx-helper-hover-dropdown.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-locale.mjs +296 -0
- package/fesm2022/smallpearl-ngx-helper-locale.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-busy-wheel.mjs +504 -0
- package/fesm2022/smallpearl-ngx-helper-mat-busy-wheel.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-context-menu.mjs +184 -0
- package/fesm2022/smallpearl-ngx-helper-mat-context-menu.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs +1486 -0
- package/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs +800 -0
- package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-file-input.mjs +328 -0
- package/fesm2022/smallpearl-ngx-helper-mat-file-input.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-form-error.mjs +468 -0
- package/fesm2022/smallpearl-ngx-helper-mat-form-error.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs +854 -0
- package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-side-menu-layout.mjs +930 -0
- package/fesm2022/smallpearl-ngx-helper-mat-side-menu-layout.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-tel-input.mjs +926 -0
- package/fesm2022/smallpearl-ngx-helper-mat-tel-input.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-sideload.mjs +111 -0
- package/fesm2022/smallpearl-ngx-helper-sideload.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-stationary-with-line-items.mjs +384 -0
- package/fesm2022/smallpearl-ngx-helper-stationary-with-line-items.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper.mjs +13 -0
- package/fesm2022/smallpearl-ngx-helper.mjs.map +1 -0
- package/forms/index.d.ts +1 -0
- package/forms/src/validation-error-handler.d.ts +52 -0
- package/hover-dropdown/index.d.ts +1 -0
- package/hover-dropdown/src/hover-dropdown.directive.d.ts +41 -0
- package/index.d.ts +5 -0
- package/locale/index.d.ts +5 -0
- package/locale/src/currency.pipe.d.ts +14 -0
- package/locale/src/date.pipe.d.ts +14 -0
- package/locale/src/format-currency.d.ts +1 -0
- package/locale/src/format-date.d.ts +2 -0
- package/locale/src/is-empty.d.ts +1 -0
- package/locale/src/providers.d.ts +20 -0
- package/mat-busy-wheel/index.d.ts +4 -0
- package/mat-busy-wheel/src/busy-wheel-op.d.ts +65 -0
- package/mat-busy-wheel/src/busy-wheel.component.d.ts +12 -0
- package/mat-busy-wheel/src/busy-wheel.service.d.ts +42 -0
- package/mat-busy-wheel/src/host-busy-wheel.directive.d.ts +35 -0
- package/mat-context-menu/index.d.ts +1 -0
- package/mat-context-menu/src/mat-context-menu.component.d.ts +54 -0
- package/mat-entity-crud/index.d.ts +5 -0
- package/mat-entity-crud/src/default-config.d.ts +9 -0
- package/mat-entity-crud/src/form-view-host.component.d.ts +34 -0
- package/mat-entity-crud/src/mat-entity-crud-form-base.d.ts +95 -0
- package/mat-entity-crud/src/mat-entity-crud-internal-types.d.ts +66 -0
- package/mat-entity-crud/src/mat-entity-crud-types.d.ts +141 -0
- package/mat-entity-crud/src/mat-entity-crud.component.d.ts +267 -0
- package/mat-entity-crud/src/preview-host.component.d.ts +19 -0
- package/mat-entity-crud/src/preview-pane.component.d.ts +27 -0
- package/mat-entity-crud/src/providers.d.ts +3 -0
- package/mat-entity-list/index.d.ts +3 -0
- package/mat-entity-list/src/config.d.ts +6 -0
- package/mat-entity-list/src/mat-entity-list-types.d.ts +53 -0
- package/mat-entity-list/src/mat-entity-list.component.d.ts +209 -0
- package/mat-entity-list/src/providers.d.ts +3 -0
- package/mat-file-input/README.md +63 -0
- package/mat-file-input/index.d.ts +1 -0
- package/mat-file-input/src/mat-file-input.component.d.ts +58 -0
- package/mat-form-error/README.md +306 -0
- package/mat-form-error/index.d.ts +6 -0
- package/mat-form-error/src/locales/en.d.ts +4 -0
- package/mat-form-error/src/locales/hu.d.ts +4 -0
- package/mat-form-error/src/locales/index.d.ts +3 -0
- package/mat-form-error/src/locales/pt-br.d.ts +4 -0
- package/mat-form-error/src/ngx-error-list.component.d.ts +9 -0
- package/mat-form-error/src/ngx-mat-error-control.d.ts +17 -0
- package/mat-form-error/src/ngx-mat-error-def.directive.d.ts +30 -0
- package/mat-form-error/src/ngx-mat-errors-for-date-range-picker.directive.d.ts +8 -0
- package/mat-form-error/src/ngx-mat-errors.component.d.ts +23 -0
- package/mat-form-error/src/types.d.ts +68 -0
- package/mat-form-error/src/utils/coerce-to-observable.d.ts +3 -0
- package/mat-form-error/src/utils/distinct-until-error-changed.d.ts +2 -0
- package/mat-form-error/src/utils/find-error-for-control.d.ts +9 -0
- package/mat-form-error/src/utils/get-abstract-controls.d.ts +3 -0
- package/mat-form-error/src/utils/get-control-with-error.d.ts +3 -0
- package/mat-select-entity/index.d.ts +2 -0
- package/mat-select-entity/src/mat-select-entity.component.d.ts +207 -0
- package/mat-select-entity/src/providers.d.ts +9 -0
- package/mat-side-menu-layout/index.d.ts +6 -0
- package/mat-side-menu-layout/src/layout.service.d.ts +23 -0
- package/mat-side-menu-layout/src/mat-menu-layout.component.d.ts +39 -0
- package/mat-side-menu-layout/src/mat-menu-layout.module.d.ts +18 -0
- package/mat-side-menu-layout/src/mat-menu-list-item.component.d.ts +36 -0
- package/mat-side-menu-layout/src/mat-menu-pane.component.d.ts +66 -0
- package/mat-side-menu-layout/src/nav-item.d.ts +10 -0
- package/mat-tel-input/README.md +18 -0
- package/mat-tel-input/index.d.ts +2 -0
- package/mat-tel-input/src/country-codes.d.ts +5 -0
- package/mat-tel-input/src/mat-telephone.component.d.ts +129 -0
- package/mat-tel-input/src/providers.d.ts +38 -0
- package/ngx-helper.d.ts +2 -0
- package/package.json +114 -0
- package/public-api.d.ts +1 -0
- package/sideload/index.d.ts +1 -0
- package/sideload/src/sideload.d.ts +17 -0
- package/stationary-with-line-items/index.d.ts +1 -0
- 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() }}:</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() }}:</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() }}:</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 @@
|
|
|
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;;;;"}
|
package/forms/index.d.ts
ADDED
|
@@ -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,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 @@
|
|
|
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;
|