@kris701/ez-ui 0.0.1

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 (31) hide show
  1. package/README.md +64 -0
  2. package/ng-package.json +7 -0
  3. package/package.json +18 -0
  4. package/src/components/dateinput.ts +58 -0
  5. package/src/components/floatfileupload.ts +52 -0
  6. package/src/components/floattable/filters/tuiThDateFilter.ts +159 -0
  7. package/src/components/floattable/filters/tuiThSelectFilter.ts +178 -0
  8. package/src/components/floattable/filters/tuiThTextFilter.ts +161 -0
  9. package/src/components/floattable/floattable.presets.ts +197 -0
  10. package/src/components/floattable/floattable.ts +309 -0
  11. package/src/components/floattable/helpers/floattable.filterhelpers.ts +23 -0
  12. package/src/components/floattable/models/FloatTableFilter.ts +5 -0
  13. package/src/components/floattable/models/FloatTableFilterMethod.ts +5 -0
  14. package/src/components/floattable/models/FloatTableSort.ts +4 -0
  15. package/src/components/floattable/models/FloatTableSortFilterPreset.ts +10 -0
  16. package/src/components/floattable/models/FloatTableSortFilterPresetSave.ts +6 -0
  17. package/src/components/floattable/models/FloatTableSortMethod.ts +4 -0
  18. package/src/components/floattable/services/floattable.filterservice.ts +110 -0
  19. package/src/components/floattable/sorts/tuiThSortable.ts +75 -0
  20. package/src/components/markdowneditor.ts +340 -0
  21. package/src/components/menubar.ts +144 -0
  22. package/src/components/multiselect.ts +77 -0
  23. package/src/components/numberinput.ts +45 -0
  24. package/src/components/passwordinput.ts +44 -0
  25. package/src/components/textinput.ts +40 -0
  26. package/src/helpers/compressImage.ts +20 -0
  27. package/src/interfaces/baseCRUDInterface.ts +181 -0
  28. package/src/interfaces/baseListService.ts +62 -0
  29. package/src/public-api.ts +15 -0
  30. package/tsconfig.lib.json +12 -0
  31. package/tsconfig.lib.prod.json +11 -0
@@ -0,0 +1,75 @@
1
+ import { CommonModule } from "@angular/common";
2
+ import { Component, Input, signal } from "@angular/core";
3
+ import { TuiButton } from "@taiga-ui/core";
4
+ import { FloatTable } from "../floattable";
5
+ import { FloatTableSort } from "../models/FloatTableSort";
6
+
7
+ @Component({
8
+ selector: 'tuiThSortable',
9
+ imports: [CommonModule, TuiButton],
10
+ template: `
11
+ @if(tuiThSortable){
12
+ <button tuiButton style="opacity:0.72" [iconStart]="icon()" size="s" appearance="flat-grayscale" (click)="sort()"></button>
13
+ }
14
+ `
15
+ })
16
+ export class TableSortableColumn {
17
+ @Input() tuiThSortable!: string;
18
+
19
+ table : FloatTable;
20
+ state : 'asc' | 'desc' | 'none' = 'none';
21
+ icon = signal<string | null | undefined>("text-align-justify");
22
+
23
+ constructor(table : FloatTable){
24
+ this.table = table;
25
+
26
+ this.table.onPresetChange.subscribe(x => {
27
+ if (!x)
28
+ {
29
+ this.state = 'none'
30
+ this.icon.set('text-align-justify');
31
+ return;
32
+ }
33
+ var sort = x.sorts.find(x => x.column == this.tuiThSortable);
34
+ if (!sort)
35
+ {
36
+ this.state = 'none'
37
+ this.icon.set('text-align-justify');
38
+ return;
39
+ }
40
+ this.state = sort.state;
41
+
42
+ switch(sort.state){
43
+ case 'none':
44
+ this.icon.set('text-align-justify');
45
+ break;
46
+ case 'asc':
47
+ this.icon.set('arrow-up-wide-narrow');
48
+ break;
49
+ case 'desc':
50
+ this.icon.set('arrow-down-wide-narrow');
51
+ break;
52
+ }
53
+ })
54
+ }
55
+
56
+ sort(){
57
+ switch(this.state){
58
+ case 'none':
59
+ this.state = 'asc';
60
+ this.table.setSort({ column: this.tuiThSortable, state: this.state } as FloatTableSort)
61
+ this.icon.set('arrow-up-wide-narrow');
62
+ break;
63
+ case 'asc':
64
+ this.state = 'desc';
65
+ this.table.setSort({ column: this.tuiThSortable, state: this.state } as FloatTableSort)
66
+ this.icon.set('arrow-down-wide-narrow');
67
+ break;
68
+ case 'desc':
69
+ this.state = 'none';
70
+ this.table.clearSort(this.tuiThSortable);
71
+ this.icon.set('text-align-justify');
72
+ break;
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,340 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, ElementRef, EventEmitter, Input, OnChanges, Output, signal, SimpleChanges, ViewChild } from '@angular/core';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { TuiButton, TuiScrollbar } from '@taiga-ui/core';
5
+ import { TuiTextarea } from '@taiga-ui/kit';
6
+ import { marked } from 'marked';
7
+ import { compressImage } from '../helpers/compressImage';
8
+ import { EzUIMenuBar, MenuBarItem } from "./menubar";
9
+
10
+ @Component({
11
+ selector: 'ezui-markdowneditor',
12
+ imports: [FormsModule, CommonModule, TuiTextarea, TuiButton, TuiScrollbar, EzUIMenuBar],
13
+ template: `
14
+ @if(isEditing() && !disabled){
15
+ <div class="editor-container">
16
+ <div class="editor">
17
+ <ezui-menubar [items]="items()"/>
18
+
19
+ <tui-textfield class="editor-field">
20
+ <textarea
21
+ #editor
22
+ placeholder="Markdown Content"
23
+ tuiTextarea
24
+ [(ngModel)]="unsavedValue"
25
+ (input)="formatPreview()"
26
+ ></textarea>
27
+ </tui-textfield>
28
+ </div>
29
+
30
+ <div class="preview-container">
31
+ <tui-scrollbar>
32
+ <div class="preview" #preview>Rendering...</div>
33
+ </tui-scrollbar>
34
+ </div>
35
+
36
+ <input type="file" (change)="onFileSelected($event)" #fileUpload [style]="{ display: 'none' }" accept="image/png, image/jpeg" />
37
+ </div>
38
+ }
39
+ @else {
40
+ <div class="preview-readonly-container">
41
+ @if(!disabled){
42
+ <button tuiButton class="edit-button" iconStart="edit" appearance="flat" size="s"(click)="toggleEdit(false)"></button>
43
+ }
44
+ <tui-scrollbar>
45
+ <div class="preview" #preview>Rendering...</div>
46
+ </tui-scrollbar>
47
+ </div>
48
+ }
49
+ `,
50
+ host: {
51
+ class: 'flex h-full w-full'
52
+ },
53
+ styles: `
54
+ .editor-container {
55
+ display:flex;
56
+ flex-direction: row;
57
+ width: 100%;
58
+ outline: 0.125rem solid var(--tui-background-accent-1);
59
+ border-radius: var(--tui-radius-l);
60
+
61
+ .editor {
62
+ display:flex;
63
+ flex-direction: column;
64
+ width: 100%;
65
+
66
+ .editor-field {
67
+ block-size:100%;
68
+ border-radius: 0px 0px 0px var(--tui-radius-l);
69
+ }
70
+ }
71
+ }
72
+
73
+ .preview-container {
74
+ width:100%;
75
+ border-radius: 0px var(--tui-radius-l) var(--tui-radius-l) 0px;
76
+ transition-property: box-shadow, background-color, outline-color, border-color, color;
77
+ transition-duration: calc(var(--tui-duration) / 2);
78
+ transition-timing-function: var(--tui-curve-productive-standard);
79
+ --t-shadow: 0 0.125rem 0.1875rem rgba(0, 0, 0, 0.1);
80
+ background-color: var(--tui-background-base);
81
+ color: var(--tui-text-tertiary);
82
+ box-shadow: var(--t-shadow);
83
+ outline: 1px solid var(--tui-border-normal);
84
+ outline-offset: -1px;
85
+ border-width: 0;
86
+ block-size:100%;
87
+
88
+ ::ng-deep tui-scrollbar {
89
+ height:100%;
90
+ }
91
+
92
+ ::ng-deep .t-content {
93
+ display:flex;
94
+ block-size:auto !important;
95
+ }
96
+
97
+ .preview {
98
+ padding:10px;
99
+ }
100
+ }
101
+
102
+ .preview-readonly-container {
103
+ width:100%;
104
+ border-radius: var(--tui-radius-l);
105
+ transition-property: box-shadow, background-color, outline-color, border-color, color;
106
+ transition-duration: calc(var(--tui-duration) / 2);
107
+ transition-timing-function: var(--tui-curve-productive-standard);
108
+ --t-shadow: 0 0.125rem 0.1875rem rgba(0, 0, 0, 0.1);
109
+ background-color: var(--tui-background-base);
110
+ color: var(--tui-text-tertiary);
111
+ box-shadow: var(--t-shadow);
112
+ outline: 1px solid var(--tui-border-normal);
113
+ outline-offset: -1px;
114
+ border-width: 0;
115
+ block-size:100%;
116
+
117
+ .edit-button {
118
+ position:absolute;
119
+ z-index: 999;
120
+ }
121
+
122
+ ::ng-deep tui-scrollbar {
123
+ height:100%;
124
+ }
125
+
126
+ ::ng-deep .t-content {
127
+ display:flex;
128
+ block-size:auto !important;
129
+ }
130
+
131
+ .preview {
132
+ padding:10px;
133
+ }
134
+ }
135
+ `
136
+ })
137
+ export class EzUIMarkdownEditor implements OnChanges {
138
+ @ViewChild('preview') preview: ElementRef<HTMLDivElement> | undefined;
139
+ @ViewChild('editor') editor: ElementRef<HTMLTextAreaElement> | undefined;
140
+ @ViewChild('fileUpload') fileUpload: ElementRef<HTMLInputElement> | undefined;
141
+
142
+ @Input() disabled: boolean = false;
143
+
144
+ @Input() value: string | null = null;
145
+ @Output() valueChange = new EventEmitter<string | null>();
146
+
147
+ unsavedValue = signal<string>("");
148
+
149
+ isFirst : boolean = true;
150
+ isEditing = signal<boolean>(false);
151
+
152
+ items = signal<MenuBarItem[]>([
153
+ {
154
+ icon: 'save',
155
+ command: async () => await this.toggleEdit(true)
156
+ } as MenuBarItem,
157
+ {
158
+ icon: 'x',
159
+ command: async () => await this.toggleEdit(false)
160
+ } as MenuBarItem,
161
+ {
162
+ label: 'B',
163
+ command: async () => {
164
+ if (this.editor){
165
+ var editor = this.editor.nativeElement;
166
+ var start = editor.selectionStart;
167
+ var finish = editor.selectionEnd;
168
+ var sel = editor.value.substring(start, finish);
169
+ var newStr = "**" + sel + "**"
170
+ await this.replaceSection(newStr, start + 2, finish + 2);
171
+ }
172
+ }
173
+ } as MenuBarItem,
174
+ {
175
+ label: 'I',
176
+ command: async () => {
177
+ if (this.editor){
178
+ var editor = this.editor.nativeElement;
179
+ var start = editor.selectionStart;
180
+ var finish = editor.selectionEnd;
181
+ var sel = editor.value.substring(start, finish);
182
+ var newStr = "*" + sel + "*"
183
+ await this.replaceSection(newStr, start + 1, finish + 1);
184
+ }
185
+ }
186
+ } as MenuBarItem,
187
+ {
188
+ label: 'H',
189
+ items: [
190
+ {
191
+ label: 'H1',
192
+ command: async () => {
193
+ if (this.editor){
194
+ var editor = this.editor.nativeElement;
195
+ var start = editor.selectionStart;
196
+ var finish = editor.selectionEnd;
197
+ var sel = editor.value.substring(start, finish);
198
+ var newStr = "# " + sel
199
+ await this.replaceSection(newStr, start + 2, finish + 2);
200
+ }
201
+ }
202
+ } as MenuBarItem,
203
+ {
204
+ label: 'H2',
205
+ command: async () => {
206
+ if (this.editor){
207
+ var editor = this.editor.nativeElement;
208
+ var start = editor.selectionStart;
209
+ var finish = editor.selectionEnd;
210
+ var sel = editor.value.substring(start, finish);
211
+ var newStr = "## " + sel
212
+ await this.replaceSection(newStr, start + 3, finish + 3);
213
+ }
214
+ }
215
+ } as MenuBarItem,
216
+ {
217
+ label: 'H3',
218
+ command: async () => {
219
+ if (this.editor){
220
+ var editor = this.editor.nativeElement;
221
+ var start = editor.selectionStart;
222
+ var finish = editor.selectionEnd;
223
+ var sel = editor.value.substring(start, finish);
224
+ var newStr = "### " + sel
225
+ await this.replaceSection(newStr, start + 4, finish + 4);
226
+ }
227
+ }
228
+ } as MenuBarItem,
229
+ ]
230
+ } as MenuBarItem,
231
+
232
+ {
233
+ icon: 'link',
234
+ command: async () => {
235
+ if (this.editor){
236
+ var editor = this.editor.nativeElement;
237
+ var start = editor.selectionStart;
238
+ var finish = editor.selectionEnd;
239
+ var sel = editor.value.substring(start, finish);
240
+ var newStr = "[" + sel + "](link)"
241
+ await this.replaceSection(newStr, start + 1, finish + 1);
242
+ }
243
+ }
244
+ } as MenuBarItem,
245
+
246
+ {
247
+ icon: 'image',
248
+ command: async () => {
249
+ if (this.editor){
250
+ this.fileUpload?.nativeElement.click();
251
+ }
252
+ }
253
+ } as MenuBarItem,
254
+ ])
255
+
256
+ async onFileSelected(event: any) {
257
+ var files: File[] = Array.from(event.target.files);
258
+ if (files && files.length > 0) {
259
+ var file = files[0];
260
+ await this.insertImageInEditor(file);
261
+ this.fileUpload!.nativeElement.value = '';
262
+ }
263
+ }
264
+
265
+ toBase65(file : File){
266
+ return new Promise((resolve, reject) => {
267
+ var reader = new FileReader();
268
+ reader.readAsDataURL(file);
269
+ reader.onload = () => resolve(reader.result);
270
+ reader.onerror = reject;
271
+ })
272
+ }
273
+
274
+ async onPaste(event : any){
275
+ const items = (event.clipboardData || event.originalEvent.clipboardData).items;
276
+ let blob = null;
277
+ for (const item of items) {
278
+ if (item.type.indexOf('image') === 0) {
279
+ blob = item.getAsFile();
280
+ await this.insertImageInEditor(blob);
281
+ }
282
+ }
283
+ }
284
+
285
+ async insertImageInEditor(file : File){
286
+ var compressed = await compressImage(file, 0.5, 300, 300);
287
+ var asBase64 = await this.toBase65(compressed as File);
288
+ if (asBase64 && this.editor){
289
+ var editor = this.editor.nativeElement;
290
+ var start = editor.selectionStart;
291
+ var finish = editor.selectionEnd;
292
+ var sel = editor.value.substring(start, finish);
293
+ var newStr = "![" + sel + "](" + asBase64 + ")"
294
+ await this.replaceSection(newStr, start + newStr.length, finish + newStr.length);
295
+ }
296
+ }
297
+
298
+ async replaceSection(newStr : string, finalStart : number, finalFinish : number){
299
+ var editor = this.editor!.nativeElement;
300
+ editor.focus();
301
+ document.execCommand("insertText", false, newStr);
302
+ await this.formatPreview();
303
+ editor.focus();
304
+ editor.setSelectionRange(finalStart, finalFinish);
305
+ }
306
+
307
+ async ngOnChanges(changes: SimpleChanges) {
308
+ if (changes['value']) {
309
+ if (changes['value'].currentValue != changes['value'].previousValue) {
310
+ this.value = changes['value'].currentValue;
311
+ await this.formatPreview();
312
+ if (this.isFirst){
313
+ setTimeout(async () => await this.formatPreview(), 500);
314
+ this.isFirst = false;
315
+ }
316
+ }
317
+ }
318
+ }
319
+
320
+ async formatPreview(){
321
+ if(this.preview){
322
+ if(this.isEditing())
323
+ this.preview.nativeElement.innerHTML = await marked(this.unsavedValue());
324
+ else if (this.value)
325
+ this.preview.nativeElement.innerHTML = await marked(this.value);
326
+ }
327
+ }
328
+
329
+ async toggleEdit(save : boolean){
330
+ if (!this.isEditing() && this.value){
331
+ this.unsavedValue.set(this.value)
332
+ }
333
+ if (save && this.isEditing()){
334
+ this.value = this.unsavedValue();
335
+ this.valueChange.emit(this.value);
336
+ }
337
+ this.isEditing.set(!this.isEditing());
338
+ setTimeout(async () => await this.formatPreview(), 500);
339
+ }
340
+ }
@@ -0,0 +1,144 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { TuiButton, TuiDropdown, TuiGroup, TuiOption } from '@taiga-ui/core';
5
+ import { TuiChevron } from '@taiga-ui/kit';
6
+
7
+ export interface MenuBarItem {
8
+ label: string | null;
9
+ icon: string | null;
10
+ items : MenuBarItem[];
11
+ disabled: boolean;
12
+ expanded: boolean;
13
+ command() : Promise<any>;
14
+ }
15
+
16
+ @Component({
17
+ selector: 'tui-data-list[subdatalist]',
18
+ standalone: true,
19
+ imports: [
20
+ TuiDropdown,
21
+ TuiOption,
22
+ TuiChevron
23
+ ],
24
+ template: `
25
+ @for(item of subdatalist; track $index){
26
+ @if(item.items){
27
+ <button
28
+ tuiOption
29
+ tuiChevron
30
+ [iconStart]="item.icon"
31
+ [disabled]="item.disabled"
32
+ [tuiDropdown]="dropdownContent"
33
+ [(tuiDropdownOpen)]="item.expanded"
34
+ tuiDropdownLimitWidth="fixed"
35
+ tuiDropdownSided="true"
36
+ >
37
+ {{item.label}}
38
+ </button>
39
+
40
+ <ng-template #dropdownContent>
41
+ <tui-data-list
42
+ class="subdatalist"
43
+ [subdatalist]="item.items">
44
+ </tui-data-list>
45
+ </ng-template>
46
+ }
47
+ @else {
48
+ <button
49
+ tuiOption
50
+ [iconStart]="item.icon"
51
+ [disabled]="item.disabled"
52
+ (click)="item.command()"
53
+ >
54
+ {{item.label}}
55
+ </button>
56
+ }
57
+ }
58
+ `,
59
+ styles: `
60
+ .subdatalist {
61
+ display:flex;
62
+ flex-direction: column;
63
+ }
64
+ `
65
+ })
66
+ export class EzUIMenuBarSubDataList {
67
+ @Input() subdatalist: MenuBarItem[] = [];
68
+ }
69
+
70
+ @Component({
71
+ selector: 'ezui-menubar',
72
+ standalone: true,
73
+ imports: [
74
+ FormsModule,
75
+ CommonModule,
76
+ TuiGroup,
77
+ TuiButton,
78
+ TuiDropdown,
79
+ TuiChevron,
80
+ EzUIMenuBarSubDataList
81
+ ],
82
+ template: `
83
+ <div tuiGroup class="group" [collapsed]="true">
84
+ @for(item of items; track $index){
85
+ @if(item.items){
86
+ <button
87
+ tuiButton
88
+ tuiChevron
89
+ size="s"
90
+ appearance="outline"
91
+ type="button"
92
+ [iconStart]="item.icon"
93
+ [disabled]="item.disabled"
94
+ [tuiDropdown]="dropdownContent"
95
+ [(tuiDropdownOpen)]="item.expanded"
96
+ tuiDropdownLimitWidth="fixed"
97
+ >
98
+ {{item.label}}
99
+ </button>
100
+
101
+ <ng-template #dropdownContent>
102
+ <tui-data-list
103
+ class="subdatalist"
104
+ [subdatalist]="item.items">
105
+ </tui-data-list>
106
+ </ng-template>
107
+ }
108
+ @else {
109
+ <button
110
+ appearance="outline"
111
+ size="s"
112
+ tuiButton
113
+ type="button"
114
+ [iconStart]="item.icon"
115
+ [disabled]="item.disabled"
116
+ (click)="item.command()"
117
+ >
118
+ {{item.label}}
119
+ </button>
120
+ }
121
+ }
122
+ </div>
123
+ `,
124
+ styles: `
125
+ .group {
126
+ width:100%;
127
+ white-space: nowrap;
128
+ }
129
+
130
+ .subdatalist {
131
+ display:flex;
132
+ flex-direction: column;
133
+ }
134
+ `
135
+ })
136
+ export class EzUIMenuBar implements OnChanges {
137
+ @Input() items: MenuBarItem[] = [];
138
+
139
+ ngOnChanges(changes: SimpleChanges) {
140
+ if (changes['items'] && changes['items'].currentValue != changes['items'].previousValue) {
141
+ this.items = changes['items'].currentValue;
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,77 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { TuiDataList, TuiDropdown, TuiSelectLike, TuiTextfield } from '@taiga-ui/core';
5
+ import { TuiChevron, TuiInputChip, TuiInputNumber, TuiMultiSelect } from '@taiga-ui/kit';
6
+
7
+ @Component({
8
+ selector: 'ezui-multiselect',
9
+ imports: [
10
+ FormsModule,
11
+ CommonModule,
12
+ TuiMultiSelect,
13
+ TuiInputNumber,
14
+ TuiDataList,
15
+ TuiTextfield,
16
+ TuiInputChip,
17
+ TuiSelectLike,
18
+ TuiMultiSelect,
19
+ TuiDropdown,
20
+ TuiChevron
21
+ ],
22
+ template: `
23
+ <tui-textfield multi tuiChevron [stringify]="stringify" [tuiTextfieldSize]="size" [iconStart]="icon">
24
+ @if(label != ''){
25
+ <label tuiLabel>{{label}}</label>
26
+ }
27
+ <input tuiInputChip tuiSelectLike [(ngModel)]="selected" (ngModelChange)="selectedChange.emit(this.selected)" [disabled]="disabled"/>
28
+ <tui-input-chip *tuiItem />
29
+ <tui-data-list *tuiDropdown tuiMultiSelectGroup >
30
+ @for (item of options; track getOptionValue(item)) {
31
+ <button tuiOption [value]="getOptionValue(item)">
32
+ {{ getOptionLabel(item) }}
33
+ </button>
34
+ }
35
+ </tui-data-list>
36
+ </tui-textfield>
37
+ `,
38
+ styles: `
39
+ `
40
+ })
41
+ export class EzUIMultiSelect implements OnChanges {
42
+ @Input() icon: string = '';
43
+ @Input() label: string = '';
44
+
45
+ @Input() size: "l" | "m" | "s" = 'm';
46
+
47
+ @Input() optionLabel: string | undefined = undefined;
48
+ @Input() optionValue: string | undefined = undefined;
49
+
50
+ @Input() options: any[] = [];
51
+ @Input() disabled: boolean = false;
52
+
53
+ @Input() selected: any[] | null | undefined = undefined;
54
+ @Output() selectedChange = new EventEmitter<any[] | null | undefined>();
55
+
56
+ ngOnChanges(changes: SimpleChanges) {
57
+ if (changes['selected'] && changes['selected'].currentValue != changes['selected'].previousValue) {
58
+ this.selected = changes['selected'].currentValue;
59
+ }
60
+ }
61
+
62
+ stringify = (value: string): string => this.getOptionLabel(this.options.find((item) => this.getOptionValue(item) === value));
63
+
64
+ getOptionLabel(item: any) {
65
+ if (!item)
66
+ return "";
67
+ if (this.optionLabel == undefined || this.optionLabel == '') return item;
68
+ return item[this.optionLabel];
69
+ }
70
+
71
+ getOptionValue(item: any) {
72
+ if (!item)
73
+ return "";
74
+ if (this.optionValue == undefined || this.optionValue == '') return item;
75
+ return item[this.optionValue];
76
+ }
77
+ }
@@ -0,0 +1,45 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { TuiInput } from '@taiga-ui/core';
5
+ import { TuiInputNumber } from '@taiga-ui/kit';
6
+
7
+ @Component({
8
+ selector: 'ezui-numberinput',
9
+ imports: [
10
+ FormsModule,
11
+ CommonModule,
12
+ TuiInput,
13
+ TuiInputNumber
14
+ ],
15
+ template: `
16
+ <tui-textfield [tuiTextfieldSize]="size" [iconStart]="icon">
17
+ @if(label){
18
+ <label tuiLabel>{{label}}</label>
19
+ }
20
+ <input tuiInputNumber [(ngModel)]="value" (ngModelChange)="valueChange.emit(value)" [disabled]="disabled" [min]="min" [max]="max"/>
21
+ </tui-textfield>
22
+ `,
23
+ styles: `
24
+ `
25
+ })
26
+ export class EzUINumberInput implements OnChanges {
27
+ @Input() icon: string = '';
28
+ @Input() label: string = '';
29
+
30
+ @Input() size: "l" | "m" | "s" = 'm';
31
+
32
+ @Input() disabled: boolean = false;
33
+
34
+ @Input() min : number | null = null;
35
+ @Input() max : number | null = null;
36
+
37
+ @Input() value: number | string = "";
38
+ @Output() valueChange = new EventEmitter<number | string>();
39
+
40
+ ngOnChanges(changes: SimpleChanges) {
41
+ if (changes['value'] && changes['value'].currentValue != changes['value'].previousValue) {
42
+ this.value = changes['value'].currentValue;
43
+ }
44
+ }
45
+ }