@yuuvis/client-framework 0.7.4 → 0.9.0

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 (98) hide show
  1. package/actions/lib/actions/delete-action/delete-action.d.ts +1 -0
  2. package/common/index.d.ts +1 -0
  3. package/common/lib/services/error-messages/error-messages.service.d.ts +7 -0
  4. package/common/lib/services/index.d.ts +1 -0
  5. package/esm2022/actions/lib/actions/delete-action/delete-action.mjs +4 -10
  6. package/esm2022/actions/lib/components/contextmenu/contextmenu.component.mjs +2 -2
  7. package/esm2022/common/index.mjs +2 -1
  8. package/esm2022/common/lib/directives/drag-select.directive.mjs +2 -2
  9. package/esm2022/common/lib/services/error-messages/error-messages.service.mjs +68 -0
  10. package/esm2022/common/lib/services/index.mjs +2 -0
  11. package/esm2022/forms/index.mjs +13 -8
  12. package/esm2022/forms/lib/elements/data-grid/data-grid/data-grid.component.mjs +172 -0
  13. package/esm2022/forms/lib/elements/data-grid/edit-table-data/edit-data.component.mjs +95 -0
  14. package/esm2022/forms/lib/elements/data-grid/model/data-grid.interface.mjs +9 -0
  15. package/esm2022/forms/lib/elements/datetime-range/datetime-range.component.mjs +32 -32
  16. package/esm2022/forms/lib/elements/index.mjs +11 -0
  17. package/esm2022/forms/lib/elements/number/number.component.mjs +3 -3
  18. package/esm2022/forms/lib/elements/number-range/number-range.component.mjs +3 -3
  19. package/esm2022/forms/lib/elements/organization/organization.component.mjs +47 -29
  20. package/esm2022/forms/lib/elements/range-select-date/date-range-picker/date-range-picker.component.mjs +38 -0
  21. package/esm2022/forms/lib/elements/range-select-date/range-select-date.component.mjs +181 -0
  22. package/esm2022/forms/lib/elements/range-select-date/range-select-date.interface.mjs +2 -0
  23. package/esm2022/forms/lib/elements/range-select-filesize/range-select-filesize.component.mjs +98 -0
  24. package/esm2022/forms/lib/elements/range-select-filesize/range-select-filesize.interface.mjs +2 -0
  25. package/esm2022/forms/lib/elements/string/string.component.mjs +10 -3
  26. package/esm2022/icons/lib/icons.mjs +3 -2
  27. package/esm2022/list/lib/list.component.mjs +6 -4
  28. package/esm2022/metadata-form/lib/metadata-default-templates/metadata-default-templates.component.mjs +5 -4
  29. package/esm2022/metadata-form/lib/metadata-form-element-registry.service.mjs +1 -1
  30. package/esm2022/metadata-form/lib/metadata-form-field/metadata-form-field.component.mjs +9 -52
  31. package/esm2022/object-details/index.mjs +2 -1
  32. package/esm2022/object-details/lib/object-audit/object-audit.component.mjs +3 -3
  33. package/esm2022/object-details/lib/object-metadata/object-metadata.component.mjs +5 -4
  34. package/esm2022/object-details/lib/retention-badge/retention-badge.component.mjs +27 -0
  35. package/esm2022/object-flavor/lib/object-flavor/object-flavor.component.mjs +2 -2
  36. package/esm2022/object-flavor/lib/object-flavor-picker/object-flavor-picker.component.mjs +2 -2
  37. package/esm2022/object-form/index.mjs +1 -1
  38. package/esm2022/object-form/lib/object-form.component.mjs +2 -1
  39. package/esm2022/object-form/lib/object-form.service.mjs +5 -2
  40. package/esm2022/object-summary/lib/object-summary/object-summary.component.mjs +15 -13
  41. package/esm2022/pagination/lib/pagination.component.mjs +4 -6
  42. package/esm2022/sequence-list/index.mjs +1 -3
  43. package/esm2022/sequence-list/lib/sequence-list.component.mjs +11 -16
  44. package/esm2022/sequence-list/lib/sequence-list.interface.mjs +1 -1
  45. package/esm2022/tile-list/lib/tile/tile.component.mjs +3 -3
  46. package/esm2022/tile-list/lib/tile-config/tile-config.component.mjs +2 -2
  47. package/esm2022/tile-list/lib/tile-extension/extensions/email.extension.mjs +1 -1
  48. package/fesm2022/yuuvis-client-framework-actions.mjs +4 -10
  49. package/fesm2022/yuuvis-client-framework-actions.mjs.map +1 -1
  50. package/fesm2022/yuuvis-client-framework-common.mjs +69 -4
  51. package/fesm2022/yuuvis-client-framework-common.mjs.map +1 -1
  52. package/fesm2022/yuuvis-client-framework-forms.mjs +1335 -755
  53. package/fesm2022/yuuvis-client-framework-forms.mjs.map +1 -1
  54. package/fesm2022/yuuvis-client-framework-icons.mjs +2 -1
  55. package/fesm2022/yuuvis-client-framework-icons.mjs.map +1 -1
  56. package/fesm2022/yuuvis-client-framework-list.mjs +5 -3
  57. package/fesm2022/yuuvis-client-framework-list.mjs.map +1 -1
  58. package/fesm2022/yuuvis-client-framework-metadata-form.mjs +12 -55
  59. package/fesm2022/yuuvis-client-framework-metadata-form.mjs.map +1 -1
  60. package/fesm2022/yuuvis-client-framework-object-details.mjs +28 -7
  61. package/fesm2022/yuuvis-client-framework-object-details.mjs.map +1 -1
  62. package/fesm2022/yuuvis-client-framework-object-flavor.mjs +2 -2
  63. package/fesm2022/yuuvis-client-framework-object-flavor.mjs.map +1 -1
  64. package/fesm2022/yuuvis-client-framework-object-form.mjs +5 -1
  65. package/fesm2022/yuuvis-client-framework-object-form.mjs.map +1 -1
  66. package/fesm2022/yuuvis-client-framework-object-summary.mjs +14 -12
  67. package/fesm2022/yuuvis-client-framework-object-summary.mjs.map +1 -1
  68. package/fesm2022/yuuvis-client-framework-pagination.mjs +3 -5
  69. package/fesm2022/yuuvis-client-framework-pagination.mjs.map +1 -1
  70. package/fesm2022/yuuvis-client-framework-sequence-list.mjs +17 -296
  71. package/fesm2022/yuuvis-client-framework-sequence-list.mjs.map +1 -1
  72. package/fesm2022/yuuvis-client-framework-tile-list.mjs +3 -3
  73. package/fesm2022/yuuvis-client-framework-tile-list.mjs.map +1 -1
  74. package/forms/index.d.ts +5 -7
  75. package/forms/lib/elements/data-grid/data-grid/data-grid.component.d.ts +38 -0
  76. package/forms/lib/elements/data-grid/edit-table-data/edit-data.component.d.ts +21 -0
  77. package/forms/lib/elements/data-grid/model/data-grid.interface.d.ts +14 -0
  78. package/forms/lib/elements/datetime-range/datetime-range.component.d.ts +2 -1
  79. package/forms/lib/elements/index.d.ts +10 -0
  80. package/forms/lib/elements/organization/organization.component.d.ts +13 -4
  81. package/forms/lib/elements/range-select-date/date-range-picker/date-range-picker.component.d.ts +13 -0
  82. package/forms/lib/elements/range-select-date/range-select-date.component.d.ts +33 -0
  83. package/forms/lib/elements/range-select-date/range-select-date.interface.d.ts +5 -0
  84. package/forms/lib/elements/range-select-filesize/range-select-filesize.component.d.ts +28 -0
  85. package/forms/lib/elements/range-select-filesize/range-select-filesize.interface.d.ts +5 -0
  86. package/list/lib/list.component.d.ts +2 -1
  87. package/metadata-form/lib/metadata-form-field/metadata-form-field.component.d.ts +1 -1
  88. package/object-details/index.d.ts +1 -0
  89. package/object-details/lib/retention-badge/retention-badge.component.d.ts +12 -0
  90. package/package.json +10 -10
  91. package/sequence-list/index.d.ts +0 -2
  92. package/sequence-list/lib/sequence-list.component.d.ts +2 -2
  93. package/sequence-list/lib/sequence-list.interface.d.ts +5 -4
  94. package/styles/client-framework.scss +55 -18
  95. package/esm2022/sequence-list/lib/sequence-list-template-manage/sequence-list-template-manage.component.mjs +0 -183
  96. package/esm2022/sequence-list/lib/sequence-list-templates/sequence-list-templates.component.mjs +0 -114
  97. package/sequence-list/lib/sequence-list-template-manage/sequence-list-template-manage.component.d.ts +0 -52
  98. package/sequence-list/lib/sequence-list-templates/sequence-list-templates.component.d.ts +0 -36
@@ -1,29 +1,119 @@
1
+ import * as i1$2 from '@angular/common';
2
+ import { CommonModule, DecimalPipe, NgClass } from '@angular/common';
1
3
  import * as i0 from '@angular/core';
2
- import { forwardRef, Component, Input, inject, input, EventEmitter, ViewChild, HostListener, HostBinding, Output, ElementRef, Renderer2, ViewEncapsulation, NgModule } from '@angular/core';
4
+ import { inject, Renderer2, Component, ViewEncapsulation, ViewChild, Input, HostBinding, forwardRef, ElementRef, signal, input, ChangeDetectionStrategy, computed, effect, untracked, EventEmitter, HostListener, Output, output, NgModule } from '@angular/core';
5
+ import { FocusWithinDirective, ErrorMessagesService } from '@yuuvis/client-framework/common';
3
6
  import * as i2 from '@angular/forms';
4
- import { NG_VALUE_ACCESSOR, FormsModule, FormBuilder, Validators, NG_VALIDATORS, ReactiveFormsModule, UntypedFormGroup, UntypedFormControl } from '@angular/forms';
7
+ import { NG_VALUE_ACCESSOR, FormsModule, NG_VALIDATORS, FormBuilder, Validators, ReactiveFormsModule, UntypedFormGroup, UntypedFormControl } from '@angular/forms';
5
8
  import * as i1 from '@yuuvis/client-core';
6
- import { Classification, OperatorLabel, Operator, FileSizePipe, LocaleNumberPipe, Utils, SystemService, UserService, YuvUser, TranslateModule, ClassificationPrefix, Situation } from '@yuuvis/client-core';
7
- import * as i3 from '@yuuvis/components/dropdown';
9
+ import { Classification, FileSizePipe, LocaleNumberPipe, Utils, ClassificationPrefix, Situation, TranslateModule, ClipboardService, TranslateService, OperatorLabel, Operator, SystemService, UserService, YuvUser, SearchUtils, LocaleDatePipe } from '@yuuvis/client-core';
10
+ import * as i1$1 from '@yuuvis/components/dropdown';
8
11
  import { YvcDropdownModule } from '@yuuvis/components/dropdown';
9
- import { TranslateService, TranslateModule as TranslateModule$1 } from '@ngx-translate/core';
10
- import * as i2$1 from '@yuuvis/components/datepicker';
11
- import { YvcDatepickerModule } from '@yuuvis/components/datepicker';
12
- import * as i1$1 from '@angular/common';
13
- import { CommonModule } from '@angular/common';
14
- import { YUV_ICONS, IconService } from '@yuuvis/client-framework/icons';
15
- import * as i2$2 from '@yuuvis/components/autocomplete';
16
- import { YvcAutocompleteModule } from '@yuuvis/components/autocomplete';
17
- import * as i3$1 from '@yuuvis/components/icon';
12
+ import { CdkMenu, CdkMenuTrigger, CdkMenuItem } from '@angular/cdk/menu';
13
+ import * as i4 from '@angular/cdk/table';
14
+ import { CdkTableModule } from '@angular/cdk/table';
15
+ import { IconService, YUV_ICONS } from '@yuuvis/client-framework/icons';
16
+ import * as i3 from '@yuuvis/components/icon';
18
17
  import { YvcIconModule } from '@yuuvis/components/icon';
19
- import { of, forkJoin } from 'rxjs';
20
- import { catchError } from 'rxjs/operators';
21
- import * as i2$3 from '@yuuvis/components/chips';
18
+ import { YvcOverlayRef, YvcOverlayService } from '@yuuvis/components/overlay';
19
+ import { map, of, forkJoin } from 'rxjs';
20
+ import * as i2$1 from '@yuuvis/components/chips';
22
21
  import { YvcChipsModule } from '@yuuvis/components/chips';
23
- import { FocusWithinDirective } from '@yuuvis/client-framework/common';
22
+ import { TranslateService as TranslateService$1, TranslateModule as TranslateModule$1 } from '@ngx-translate/core';
23
+ import * as i2$2 from '@yuuvis/components/datepicker';
24
+ import { YvcDatepickerModule } from '@yuuvis/components/datepicker';
25
+ import * as i3$1 from '@yuuvis/components/autocomplete';
26
+ import { YvcAutocompleteModule } from '@yuuvis/components/autocomplete';
27
+ import { map as map$1, catchError } from 'rxjs/operators';
28
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
29
+ import { marker } from '@colsen1991/ngx-translate-extract-marker';
24
30
  import { YvcCheckboxModule } from '@yuuvis/components/checkbox';
25
31
  import { YvcFocusWithin } from '@yuuvis/components/common';
26
32
 
33
+ /**
34
+ * Component for wrapping a form element. Provides a label and focus behaviour.
35
+ *
36
+ * @example
37
+ * <yuv-form-input [label]="'my form element'">
38
+ * <!-- form element to be wrapped -->
39
+ * </yuv-form-input>
40
+ */
41
+ class FormInputComponent {
42
+ constructor() {
43
+ this.renderer = inject(Renderer2);
44
+ this.isDisabled = false;
45
+ this.isInvalid = false;
46
+ this.isRequired = false;
47
+ }
48
+ /**
49
+ * A label string for the wrapped form element
50
+ */
51
+ set label(val) {
52
+ this._label = val;
53
+ }
54
+ /**
55
+ * Indicator that the wrapped form element is invalid. Will then render appropriate styles.
56
+ * You may also provide an array of error messages.
57
+ */
58
+ set invalid(iv) {
59
+ if (iv === null || iv === undefined) {
60
+ this.isInvalid = false;
61
+ this.renderer.removeAttribute(this.labelEl.nativeElement, 'title');
62
+ }
63
+ else if (Array.isArray(iv)) {
64
+ this.isInvalid = iv.length > 0;
65
+ if (this.isInvalid) {
66
+ this.renderer.setAttribute(this.labelEl.nativeElement, 'title', iv.join(';'));
67
+ }
68
+ }
69
+ else {
70
+ this.isInvalid = iv;
71
+ }
72
+ }
73
+ /**
74
+ * Indicator that the wrapped form element is disabled. Will then render appropriate styles.
75
+ */
76
+ set disabled(d) {
77
+ this.isDisabled = d;
78
+ }
79
+ /**
80
+ * Indicator that the wrapped form element is mandatory. Will then render appropriate styles.
81
+ */
82
+ set required(d) {
83
+ this.isRequired = d;
84
+ }
85
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FormInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
86
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: FormInputComponent, isStandalone: true, selector: "yuv-form-input", inputs: { label: "label", tag: "tag", description: "description", invalid: "invalid", disabled: "disabled", required: "required" }, host: { properties: { "class.disabled": "this.isDisabled", "class.invalid": "this.isInvalid", "class.required": "this.isRequired" } }, viewQueries: [{ propertyName: "labelEl", first: true, predicate: ["label"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"fe-wrapper\" yuvFocusWithin>\n @if (tag) {\n <div class=\"tag\" title=\"{{ tag.title }}\">{{ tag.label }}</div>\n }\n <label class=\"form-input__label\" #label>{{ _label }}</label>\n <div class=\"control\">\n <ng-content></ng-content>\n </div>\n</div>\n@if (description) {\n <div class=\"description\">{{ description }}</div>\n}\n", styles: ["yuv-form-input .yvc-form-element{--yvc-form-element-border-color: transparent;--yvc-form-element-focus-border-color: transparent;--yvc-form-element-focus-outline-color: transparent}yuv-form-input .fe-wrapper{display:flex;transition:all .2s ease-in-out;flex-flow:row nowrap;align-items:center;padding:calc(var(--app-pane-padding) / 4) 0;border-bottom:1px solid var(--text-color-hint)}yuv-form-input .fe-wrapper.focusWithin{border-color:var(--color-accent)}yuv-form-input .fe-wrapper.focusWithin>.form-input__label{color:var(--color-accent)}yuv-form-input .fe-wrapper>div.control{flex:1 1 auto;padding:0 calc(var(--app-pane-padding) / 4);order:1;min-height:20px}yuv-form-input .fe-wrapper>div.control>span{display:inline-block;border-radius:2px;font-size:var(--font-body);line-height:1.5em;background-color:var(--color-accent);padding:0 calc(var(--app-pane-padding) / 4);color:#fff}yuv-form-input .fe-wrapper>.triggers{order:3;display:none}yuv-form-input .fe-wrapper>.triggers.visible{order:2}yuv-form-input .fe-wrapper>.triggers.visible,yuv-form-input .fe-wrapper>.triggers:hover{display:flex}yuv-form-input .fe-wrapper>.form-input__label{text-align:end;transition:all .2s ease-in-out;-webkit-user-select:none;user-select:none;order:4;flex:0 1 auto;padding:2px calc(var(--app-pane-padding) / 4);margin-right:3px;color:var(--text-color-caption);border-radius:2px;font-size:var(--font-caption)}yuv-form-input .fe-wrapper>.form-input__label:hover+.triggers{display:flex}yuv-form-input .fe-wrapper>.tag{order:5;flex:0 0 auto;border-radius:2px;font-size:var(--font-body);display:inline-block;line-height:1.5em;padding:2px;cursor:default;background-color:rgba(var(--color-accent-rgb),.2);color:var(--color-accent);font-family:monospace}yuv-form-input.checkbox{position:relative}yuv-form-input.checkbox .fe-wrapper>.form-input__label{text-align:start}yuv-form-input .description{font-size:var(--font-hint);font-style:italic;padding:calc(var(--app-pane-padding) / 8) calc(var(--app-pane-padding) / 8) 0 calc(var(--app-pane-padding) / 8);color:var(--text-color-caption)}yuv-form-input.required .fe-wrapper>.form-input__label{font-weight:700}yuv-form-input.required .fe-wrapper>.form-input__label:after{content:\"*\";padding:0 4px}yuv-form-input.invalid .fe-wrapper{background:rgba(var(--color-error),.15);border-color:var(--color-error)}yuv-form-input.invalid .fe-wrapper>.form-input__label{background-color:var(--color-error);color:#fff;margin:0 4px}yuv-form-input.invalid .fe-wrapper>.form-input__label:after{content:\"!\";margin-left:calc(var(--app-pane-padding) / 2)}yuv-form-input.disabled .fe-wrapper{opacity:.7;background-color:var(--item-focus-background-color)}yuv-form-input.checkbox .fe-wrapper{border-color:transparent!important}yuv-form-input.checkbox .fe-wrapper>div.control{flex:0 0 auto}yuv-form-input.checkbox .fe-wrapper>.form-input__label{flex:0 1 auto}yuv-form-input:not(.skipToggle) .form-input__label{cursor:pointer}.yuv-form-input .fe-wrapper .fe-wrapper{background:transparent;padding:0}.yuv-form-input input:not([type=checkbox]),.yuv-form-input .p-inputtext{padding:0;border:0!important;display:flex;flex-wrap:wrap;align-items:center;width:100%}.yuv-form-input input{background-color:transparent}.yuv-form-input button.p-button{background:transparent;border:0;border-radius:2px;color:var(--text-color-caption);cursor:pointer;width:20px;height:20px;padding:0;min-width:20px}.yuv-form-input button.p-button:enabled:active,.yuv-form-input button.p-button:enabled:focus{border:0;box-shadow:none;background:var(--color-accent);color:#fff}.yuv-form-input button.p-button:enabled:active,.yuv-form-input button.p-button:enabled:hover{border:0;background:var(--color-accent);color:#fff}.yuv-form-input button.p-button .fa{color:currentColor!important}.yuv-form-input button.p-button yuv-icon{width:16px;height:16px;margin:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: FocusWithinDirective, selector: "[yuvFocusWithin]", outputs: ["yuvFocusWithin", "yuvFocusWithinBlur"] }], encapsulation: i0.ViewEncapsulation.None }); }
87
+ }
88
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FormInputComponent, decorators: [{
89
+ type: Component,
90
+ args: [{ selector: 'yuv-form-input', standalone: true, imports: [CommonModule, FocusWithinDirective], encapsulation: ViewEncapsulation.None, template: "<div class=\"fe-wrapper\" yuvFocusWithin>\n @if (tag) {\n <div class=\"tag\" title=\"{{ tag.title }}\">{{ tag.label }}</div>\n }\n <label class=\"form-input__label\" #label>{{ _label }}</label>\n <div class=\"control\">\n <ng-content></ng-content>\n </div>\n</div>\n@if (description) {\n <div class=\"description\">{{ description }}</div>\n}\n", styles: ["yuv-form-input .yvc-form-element{--yvc-form-element-border-color: transparent;--yvc-form-element-focus-border-color: transparent;--yvc-form-element-focus-outline-color: transparent}yuv-form-input .fe-wrapper{display:flex;transition:all .2s ease-in-out;flex-flow:row nowrap;align-items:center;padding:calc(var(--app-pane-padding) / 4) 0;border-bottom:1px solid var(--text-color-hint)}yuv-form-input .fe-wrapper.focusWithin{border-color:var(--color-accent)}yuv-form-input .fe-wrapper.focusWithin>.form-input__label{color:var(--color-accent)}yuv-form-input .fe-wrapper>div.control{flex:1 1 auto;padding:0 calc(var(--app-pane-padding) / 4);order:1;min-height:20px}yuv-form-input .fe-wrapper>div.control>span{display:inline-block;border-radius:2px;font-size:var(--font-body);line-height:1.5em;background-color:var(--color-accent);padding:0 calc(var(--app-pane-padding) / 4);color:#fff}yuv-form-input .fe-wrapper>.triggers{order:3;display:none}yuv-form-input .fe-wrapper>.triggers.visible{order:2}yuv-form-input .fe-wrapper>.triggers.visible,yuv-form-input .fe-wrapper>.triggers:hover{display:flex}yuv-form-input .fe-wrapper>.form-input__label{text-align:end;transition:all .2s ease-in-out;-webkit-user-select:none;user-select:none;order:4;flex:0 1 auto;padding:2px calc(var(--app-pane-padding) / 4);margin-right:3px;color:var(--text-color-caption);border-radius:2px;font-size:var(--font-caption)}yuv-form-input .fe-wrapper>.form-input__label:hover+.triggers{display:flex}yuv-form-input .fe-wrapper>.tag{order:5;flex:0 0 auto;border-radius:2px;font-size:var(--font-body);display:inline-block;line-height:1.5em;padding:2px;cursor:default;background-color:rgba(var(--color-accent-rgb),.2);color:var(--color-accent);font-family:monospace}yuv-form-input.checkbox{position:relative}yuv-form-input.checkbox .fe-wrapper>.form-input__label{text-align:start}yuv-form-input .description{font-size:var(--font-hint);font-style:italic;padding:calc(var(--app-pane-padding) / 8) calc(var(--app-pane-padding) / 8) 0 calc(var(--app-pane-padding) / 8);color:var(--text-color-caption)}yuv-form-input.required .fe-wrapper>.form-input__label{font-weight:700}yuv-form-input.required .fe-wrapper>.form-input__label:after{content:\"*\";padding:0 4px}yuv-form-input.invalid .fe-wrapper{background:rgba(var(--color-error),.15);border-color:var(--color-error)}yuv-form-input.invalid .fe-wrapper>.form-input__label{background-color:var(--color-error);color:#fff;margin:0 4px}yuv-form-input.invalid .fe-wrapper>.form-input__label:after{content:\"!\";margin-left:calc(var(--app-pane-padding) / 2)}yuv-form-input.disabled .fe-wrapper{opacity:.7;background-color:var(--item-focus-background-color)}yuv-form-input.checkbox .fe-wrapper{border-color:transparent!important}yuv-form-input.checkbox .fe-wrapper>div.control{flex:0 0 auto}yuv-form-input.checkbox .fe-wrapper>.form-input__label{flex:0 1 auto}yuv-form-input:not(.skipToggle) .form-input__label{cursor:pointer}.yuv-form-input .fe-wrapper .fe-wrapper{background:transparent;padding:0}.yuv-form-input input:not([type=checkbox]),.yuv-form-input .p-inputtext{padding:0;border:0!important;display:flex;flex-wrap:wrap;align-items:center;width:100%}.yuv-form-input input{background-color:transparent}.yuv-form-input button.p-button{background:transparent;border:0;border-radius:2px;color:var(--text-color-caption);cursor:pointer;width:20px;height:20px;padding:0;min-width:20px}.yuv-form-input button.p-button:enabled:active,.yuv-form-input button.p-button:enabled:focus{border:0;box-shadow:none;background:var(--color-accent);color:#fff}.yuv-form-input button.p-button:enabled:active,.yuv-form-input button.p-button:enabled:hover{border:0;background:var(--color-accent);color:#fff}.yuv-form-input button.p-button .fa{color:currentColor!important}.yuv-form-input button.p-button yuv-icon{width:16px;height:16px;margin:auto}\n"] }]
91
+ }], propDecorators: { labelEl: [{
92
+ type: ViewChild,
93
+ args: ['label', { static: true }]
94
+ }], label: [{
95
+ type: Input
96
+ }], tag: [{
97
+ type: Input
98
+ }], description: [{
99
+ type: Input
100
+ }], invalid: [{
101
+ type: Input
102
+ }], disabled: [{
103
+ type: Input
104
+ }], required: [{
105
+ type: Input
106
+ }], isDisabled: [{
107
+ type: HostBinding,
108
+ args: ['class.disabled']
109
+ }], isInvalid: [{
110
+ type: HostBinding,
111
+ args: ['class.invalid']
112
+ }], isRequired: [{
113
+ type: HostBinding,
114
+ args: ['class.required']
115
+ }] } });
116
+
27
117
  /**
28
118
  * Component rendering a simple catalog as form element.
29
119
  * There are two ways how to use this component. One is to add options as an array
@@ -105,7 +195,7 @@ class CatalogComponent {
105
195
  useExisting: forwardRef(() => CatalogComponent),
106
196
  multi: true
107
197
  }
108
- ], ngImport: i0, template: "<yvc-dropdown [multiple]=\"multiselect\" [options]=\"_options\" [(ngModel)]=\"value\" (ngModelChange)=\"onChange($event)\" [filter]=\"filter\"\n [disabled]=\"readonly\"></yvc-dropdown>\n", styles: [":host{display:block}:host ::ng-deep .p-checkbox{flex-shrink:0}:host ::ng-deep .p-multiselect-item{white-space:normal;min-width:33ch}:host ::ng-deep .p-overlay{max-width:300px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: YvcDropdownModule }, { kind: "component", type: i3.Dropdown, selector: "yvc-dropdown", inputs: ["options", "filter", "disabled", "multiple", "disableClearButton"], outputs: ["onDropdownOptionsClose"] }] }); }
198
+ ], ngImport: i0, template: "<yvc-dropdown [multiple]=\"multiselect\" [options]=\"_options\" [(ngModel)]=\"value\" (ngModelChange)=\"onChange($event)\" [filter]=\"filter\"\n [disabled]=\"readonly\"></yvc-dropdown>\n", styles: [":host{display:block}:host ::ng-deep .p-checkbox{flex-shrink:0}:host ::ng-deep .p-multiselect-item{white-space:normal;min-width:33ch}:host ::ng-deep .p-overlay{max-width:300px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: YvcDropdownModule }, { kind: "component", type: i1$1.Dropdown, selector: "yvc-dropdown", inputs: ["options", "filter", "disabled", "multiple", "disableClearButton"], outputs: ["onDropdownOptionsClose"] }] }); }
109
199
  }
110
200
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CatalogComponent, decorators: [{
111
201
  type: Component,
@@ -134,314 +224,82 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
134
224
  type: Input
135
225
  }] } });
136
226
 
137
- class DatetimeComponent {
138
- constructor() {
139
- this.translate = inject(TranslateService);
140
- this.value = null;
141
- this.locale = this.translate.currentLang;
142
- /**
143
- * Whether or not to allow only values in the future (default: false)
144
- */
145
- this.onlyFutureDates = false;
146
- /**
147
- * Will prevent the input from being changed (default: false)
148
- */
149
- this.readonly = false;
150
- /**
151
- * Enables setting time as well (default: false)
152
- */
153
- this.withTime = false;
154
- // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
155
- this.propagateChange = (fn) => { };
156
- // eslint-disable-next-line @typescript-eslint/no-empty-function
157
- this.validationChange = () => { };
158
- this._setLabels();
159
- this.translate.onLangChange.subscribe((e) => (this.locale = e.lang));
227
+ /**
228
+ * Creates form input for number values.
229
+ *
230
+ * Implements `ControlValueAccessor` so it can be used within Angular forms.
231
+ *
232
+ * @example
233
+ * <yuv-number [scale]="2"></yuv-number>
234
+ *
235
+ */
236
+ class NumberComponent {
237
+ /**
238
+ * Number of decimal places
239
+ */
240
+ set scale(val) {
241
+ this._scale = Math.min(val || 0, 30);
160
242
  }
161
- _setLabels() {
162
- this.labels = {
163
- calendarApply: this.translate.instant('yuv.form.element.datetime.calendar.select'),
164
- calendarCancel: this.translate.instant('yuv.form.element.datetime.calendar.cancel'),
165
- shortcut: { today: this.translate.instant('yuv.form.element.datetime.calendar.today') }
166
- };
243
+ get scale() {
244
+ return this._scale;
167
245
  }
168
- writeValue(value) {
169
- if (typeof value === 'string') {
170
- value = new Date(value);
171
- this.propagateChange(value);
172
- }
173
- this.value = value || null;
246
+ /**
247
+ * Overall amount of digits allowed (including decimal places)
248
+ */
249
+ set precision(val) {
250
+ this._precision = Math.min(val || 100, 100);
174
251
  }
175
- registerOnChange(fn) {
176
- this.propagateChange = fn;
252
+ get precision() {
253
+ return this._precision;
177
254
  }
178
- registerOnValidatorChange(fn) {
179
- this.validationChange = fn;
255
+ /**
256
+ * Set to true to group number by pattern
257
+ */
258
+ set grouping(val) {
259
+ this._grouping = val ?? true;
180
260
  }
181
- // eslint-disable-next-line @typescript-eslint/no-empty-function
182
- registerOnTouched() { }
183
- onValueChange(e) {
184
- this.propagateChange(e);
261
+ get grouping() {
262
+ return this._grouping;
185
263
  }
186
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatetimeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
187
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DatetimeComponent, isStandalone: true, selector: "yuv-datetime", inputs: { onlyFutureDates: "onlyFutureDates", readonly: "readonly", withTime: "withTime" }, providers: [
188
- {
189
- provide: NG_VALUE_ACCESSOR,
190
- useExisting: forwardRef(() => DatetimeComponent),
191
- multi: true
192
- }
193
- ], ngImport: i0, template: "<yvc-datepicker #picker [calendar]=\"true\" [disabled]=\"readonly\" [locale]=\"locale\" [withTime]=\"withTime\" [labels]=\"labels!\"\n [onlyFutureDates]=\"onlyFutureDates\"\n [ngModelOptions]=\"{standalone: true}\" [(ngModel)]=\"value\"\n (ngModelChange)=\"onValueChange($event)\"></yvc-datepicker>", styles: [":host{display:flex}:host yvc-datepicker{flex:1}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: YvcDatepickerModule }, { kind: "component", type: i2$1.Datepicker, selector: "yvc-datepicker", inputs: ["calendar", "readonly", "hour12", "locale", "labels", "withTime", "onlyFutureDates", "minDate", "maxDate", "disabled"] }] }); }
194
- }
195
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatetimeComponent, decorators: [{
196
- type: Component,
197
- args: [{ selector: 'yuv-datetime', standalone: true, imports: [FormsModule, YvcDatepickerModule, DatetimeComponent], providers: [
198
- {
199
- provide: NG_VALUE_ACCESSOR,
200
- useExisting: forwardRef(() => DatetimeComponent),
201
- multi: true
202
- }
203
- ], template: "<yvc-datepicker #picker [calendar]=\"true\" [disabled]=\"readonly\" [locale]=\"locale\" [withTime]=\"withTime\" [labels]=\"labels!\"\n [onlyFutureDates]=\"onlyFutureDates\"\n [ngModelOptions]=\"{standalone: true}\" [(ngModel)]=\"value\"\n (ngModelChange)=\"onValueChange($event)\"></yvc-datepicker>", styles: [":host{display:flex}:host yvc-datepicker{flex:1}\n"] }]
204
- }], ctorParameters: () => [], propDecorators: { onlyFutureDates: [{
205
- type: Input
206
- }], readonly: [{
207
- type: Input
208
- }], withTime: [{
209
- type: Input
210
- }] } });
211
-
212
- class DatetimeRangeComponent {
213
- constructor() {
214
- this.fb = inject(FormBuilder);
215
- /**
216
- * Enables setting time as well (default: false)
217
- */
218
- this.withTime = false;
264
+ /**
265
+ * The pattern to group number value by
266
+ */
267
+ set groupPattern(val) {
268
+ this._pattern = val;
269
+ }
270
+ get groupPattern() {
271
+ return this._pattern;
272
+ }
273
+ /**
274
+ * classification property adds some semantics to the value of this component.
275
+ * If you provide a value of `filesize` numbers typed into the control will be
276
+ * handled like file sizes (calculates differnt units)
277
+ */
278
+ set classifications(classifications) {
279
+ this.numberPipe =
280
+ classifications && classifications.includes(Classification.NUMBER_FILESIZE) ? new FileSizePipe(this.translate) : new LocaleNumberPipe(this.translate);
281
+ }
282
+ static betweenTwoNumbers(val, minVal, maxVal) {
283
+ const min = !Utils.isEmpty(minVal) ? minVal : -Infinity;
284
+ const max = !Utils.isEmpty(maxVal) ? maxVal : Infinity;
285
+ return val >= min && val <= max;
286
+ }
287
+ constructor(translate) {
288
+ this.translate = translate;
289
+ this.innerValue = null;
290
+ this._grouping = false;
291
+ this.validationErrors = [];
219
292
  /**
220
293
  * Will prevent the input from being changed (default: false)
221
294
  */
222
295
  this.readonly = false;
223
- this.operator = 'eq';
224
- this.rangeForm = this.fb.group({
225
- dateValue: [undefined, Validators.required],
226
- dateValueFrom: []
227
- });
228
- this._isValid = true;
229
- // options for search situation
230
- this.availableSearchOptions = [
231
- { label: OperatorLabel.EQUAL, value: Operator.EQUAL },
232
- { label: OperatorLabel.GREATER_OR_EQUAL, value: Operator.GREATER_OR_EQUAL },
233
- { label: OperatorLabel.LESS_OR_EQUAL, value: Operator.LESS_OR_EQUAL },
234
- { label: OperatorLabel.INTERVAL_INCLUDE_BOTH, value: Operator.INTERVAL_INCLUDE_BOTH }
235
- ];
236
- // the selected search option
237
- this.searchOption = this.availableSearchOptions[1].value;
238
296
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
239
297
  this.propagateChange = (_) => { };
298
+ this.numberPipe = new LocaleNumberPipe(this.translate);
240
299
  }
241
300
  writeValue(value) {
242
- if (value && (value.firstValue || value.secondValue)) {
243
- const match = this.availableSearchOptions.find((o) => o.value === value.operator);
244
- this.searchOption = match ? match.value : this.availableSearchOptions[0].value;
245
- this.value = value;
246
- this.rangeForm.patchValue({
247
- dateValueFrom: value.secondValue && value.firstValue,
248
- dateValue: value.secondValue || value.firstValue
249
- });
250
- }
251
- else {
252
- this.searchOption = this.availableSearchOptions[0].value;
253
- this.value = undefined;
254
- this.rangeForm.reset();
255
- }
256
- }
257
- registerOnChange(fn) {
258
- this.propagateChange = fn;
259
- }
260
- // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
261
- registerOnTouched(fn) { }
262
- onValueChange() {
263
- const dateValue = this.rangeForm.value.dateValue || undefined;
264
- if (this.searchOption === Operator.INTERVAL_INCLUDE_BOTH) {
265
- const dateValueFrom = this.rangeForm.value.dateValueFrom || undefined;
266
- if (dateValueFrom || dateValue) {
267
- this._isValid = this.rangeForm.valid && !!dateValueFrom && !!dateValue;
268
- this.value = !this._isValid ?
269
- // {
270
- // operator: this.searchOption,
271
- // firstValue: undefined,
272
- // secondValue: undefined
273
- // }
274
- undefined
275
- :
276
- {
277
- operator: this.searchOption,
278
- firstValue: dateValueFrom,
279
- secondValue: dateValue
280
- };
281
- }
282
- }
283
- else {
284
- this._isValid = this.rangeForm.valid;
285
- this.value = !this._isValid ?
286
- // {
287
- // operator: this.searchOption,
288
- // firstValue: undefined,
289
- // secondValue: undefined
290
- // }
291
- undefined
292
- :
293
- {
294
- operator: this.searchOption,
295
- firstValue: dateValue,
296
- secondValue: undefined
297
- };
298
- }
299
- this.propagateChange(this.value);
300
- }
301
- validate() {
302
- let err;
303
- if (this.searchOption === Operator.EQUAL) {
304
- err = {
305
- datecontrol: {
306
- valid: false
307
- }
308
- };
309
- }
310
- else {
311
- // make sure that on ranges, the first value is earlier than the last
312
- if (this.searchOption === Operator.INTERVAL_INCLUDE_BOTH && this.value && this.value.firstValue && this.value.secondValue) {
313
- this._isValid = new Date(this.value.firstValue).getTime() < new Date(this.value.secondValue).getTime();
314
- err = {
315
- daterangeorder: {
316
- valid: false
317
- }
318
- };
319
- }
320
- else {
321
- err = {
322
- daterange: {
323
- valid: false
324
- }
325
- };
326
- }
327
- }
328
- return this._isValid ? null : err;
329
- }
330
- ngOnInit() {
331
- this.rangeForm.valueChanges.subscribe(() => this.onValueChange());
332
- }
333
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatetimeRangeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
334
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: DatetimeRangeComponent, isStandalone: true, selector: "yuv-datetime-range", inputs: { withTime: "withTime", readonly: "readonly", operator: "operator" }, providers: [
335
- {
336
- provide: NG_VALUE_ACCESSOR,
337
- useExisting: forwardRef(() => DatetimeRangeComponent),
338
- multi: true
339
- },
340
- {
341
- provide: NG_VALIDATORS,
342
- useExisting: forwardRef(() => DatetimeRangeComponent),
343
- multi: true
344
- }
345
- ], ngImport: i0, template: "<form class=\"eo-datetime-range\" [formGroup]=\"rangeForm\">\n @if (searchOption === 'gtelte') {\n <yuv-datetime [withTime]=\"withTime\" formControlName=\"dateValueFrom\"></yuv-datetime>\n }\n <yvc-dropdown\n [disableClearButton]=\"true\"\n [(ngModel)]=\"searchOption\"\n (ngModelChange)=\"onValueChange()\"\n [ngModelOptions]=\"{ standalone: true }\"\n [options]=\"availableSearchOptions\"\n ></yvc-dropdown>\n\n <yuv-datetime [withTime]=\"withTime\" formControlName=\"dateValue\"></yuv-datetime>\n</form>\n", styles: [":host form{display:flex;flex-flow:row nowrap;align-items:center}:host form yuv-datetime{flex:1 1 auto}:host form yvc-dropdown{--yvc-form-element-border-color: var(--text-color-hint);--yvc-form-element-focus-border-color: var(--color-accent);padding:0;min-width:auto;border-radius:2px;background-color:var(--list-item-hover-background)}:host form yvc-dropdown:hover{background-color:var(--list-item-selected-background)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: YvcDropdownModule }, { kind: "component", type: i3.Dropdown, selector: "yvc-dropdown", inputs: ["options", "filter", "disabled", "multiple", "disableClearButton"], outputs: ["onDropdownOptionsClose"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: DatetimeComponent, selector: "yuv-datetime", inputs: ["onlyFutureDates", "readonly", "withTime"] }] }); }
346
- }
347
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatetimeRangeComponent, decorators: [{
348
- type: Component,
349
- args: [{ selector: 'yuv-datetime-range', standalone: true, imports: [CommonModule, FormsModule, YvcDropdownModule, ReactiveFormsModule, DatetimeComponent], providers: [
350
- {
351
- provide: NG_VALUE_ACCESSOR,
352
- useExisting: forwardRef(() => DatetimeRangeComponent),
353
- multi: true
354
- },
355
- {
356
- provide: NG_VALIDATORS,
357
- useExisting: forwardRef(() => DatetimeRangeComponent),
358
- multi: true
359
- }
360
- ], template: "<form class=\"eo-datetime-range\" [formGroup]=\"rangeForm\">\n @if (searchOption === 'gtelte') {\n <yuv-datetime [withTime]=\"withTime\" formControlName=\"dateValueFrom\"></yuv-datetime>\n }\n <yvc-dropdown\n [disableClearButton]=\"true\"\n [(ngModel)]=\"searchOption\"\n (ngModelChange)=\"onValueChange()\"\n [ngModelOptions]=\"{ standalone: true }\"\n [options]=\"availableSearchOptions\"\n ></yvc-dropdown>\n\n <yuv-datetime [withTime]=\"withTime\" formControlName=\"dateValue\"></yuv-datetime>\n</form>\n", styles: [":host form{display:flex;flex-flow:row nowrap;align-items:center}:host form yuv-datetime{flex:1 1 auto}:host form yvc-dropdown{--yvc-form-element-border-color: var(--text-color-hint);--yvc-form-element-focus-border-color: var(--color-accent);padding:0;min-width:auto;border-radius:2px;background-color:var(--list-item-hover-background)}:host form yvc-dropdown:hover{background-color:var(--list-item-selected-background)}\n"] }]
361
- }], propDecorators: { withTime: [{
362
- type: Input
363
- }], readonly: [{
364
- type: Input
365
- }], operator: [{
366
- type: Input
367
- }] } });
368
-
369
- /**
370
- * Creates form input for number values.
371
- *
372
- * Implements `ControlValueAccessor` so it can be used within Angular forms.
373
- *
374
- * @example
375
- * <yuv-number [scale]="2"></yuv-number>
376
- *
377
- */
378
- class NumberComponent {
379
- /**
380
- * Number of decimal places
381
- */
382
- set scale(val) {
383
- this._scale = Math.min(val || 0, 30);
384
- }
385
- get scale() {
386
- return this._scale;
387
- }
388
- /**
389
- * Overall amount of digits allowed (including decimal places)
390
- */
391
- set precision(val) {
392
- this._precision = Math.min(val || 100, 100);
393
- }
394
- get precision() {
395
- return this._precision;
396
- }
397
- /**
398
- * Set to true to group number by pattern
399
- */
400
- set grouping(val) {
401
- this._grouping = val ?? true;
402
- }
403
- get grouping() {
404
- return this._grouping;
405
- }
406
- /**
407
- * The pattern to group number value by
408
- */
409
- set groupPattern(val) {
410
- this._pattern = val;
411
- }
412
- get groupPattern() {
413
- return this._pattern;
414
- }
415
- /**
416
- * classification property adds some semantics to the value of this component.
417
- * If you provide a value of `filesize` numbers typed into the control will be
418
- * handled like file sizes (calculates differnt units)
419
- */
420
- set classifications(classifications) {
421
- this.numberPipe =
422
- classifications && classifications.includes(Classification.NUMBER_FILESIZE) ? new FileSizePipe(this.translate) : new LocaleNumberPipe(this.translate);
423
- }
424
- static betweenTwoNumbers(val, minVal, maxVal) {
425
- const min = !Utils.isEmpty(minVal) ? minVal : -Infinity;
426
- const max = !Utils.isEmpty(maxVal) ? maxVal : Infinity;
427
- return val >= min && val <= max;
428
- }
429
- constructor(translate) {
430
- this.translate = translate;
431
- this.innerValue = null;
432
- this._grouping = false;
433
- this.validationErrors = [];
434
- /**
435
- * Will prevent the input from being changed (default: false)
436
- */
437
- this.readonly = false;
438
- // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
439
- this.propagateChange = (_) => { };
440
- this.numberPipe = new LocaleNumberPipe(this.translate);
441
- }
442
- writeValue(value) {
443
- this.value = value != null ? value : null;
444
- this.innerValue = value != null ? this.numberPipe.numberToString(value, this.grouping, this.groupPattern, this.scale) : null;
301
+ this.value = value != null ? value : null;
302
+ this.innerValue = value != null ? this.numberPipe.numberToString(value, this.grouping, this.groupPattern, this.scale) : null;
445
303
  }
446
304
  registerOnChange(fn) {
447
305
  this.propagateChange = fn;
@@ -520,7 +378,7 @@ class NumberComponent {
520
378
  useExisting: forwardRef(() => NumberComponent),
521
379
  multi: true
522
380
  }
523
- ], ngImport: i0, template: "<input type=\"string\" [(ngModel)]=\"innerValue\" (focus)=\"unformat()\" (blur)=\"format()\" class=\"input-number\"\n [readonly]=\"readonly\" (ngModelChange)=\"onValueChange($event)\" />\n", styles: [":host{display:block}:host input{width:100%;border:0;background-color:transparent}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
381
+ ], ngImport: i0, template: "<input type=\"string\" [(ngModel)]=\"innerValue\" (focus)=\"unformat()\" (blur)=\"format()\" class=\"input-number\"\n [readonly]=\"readonly\" (ngModelChange)=\"onValueChange($event)\" />\n", styles: [":host{display:flex}:host input{width:100%;border:0;background-color:transparent}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
524
382
  }
525
383
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NumberComponent, decorators: [{
526
384
  type: Component,
@@ -535,7 +393,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
535
393
  useExisting: forwardRef(() => NumberComponent),
536
394
  multi: true
537
395
  }
538
- ], template: "<input type=\"string\" [(ngModel)]=\"innerValue\" (focus)=\"unformat()\" (blur)=\"format()\" class=\"input-number\"\n [readonly]=\"readonly\" (ngModelChange)=\"onValueChange($event)\" />\n", styles: [":host{display:block}:host input{width:100%;border:0;background-color:transparent}\n"] }]
396
+ ], template: "<input type=\"string\" [(ngModel)]=\"innerValue\" (focus)=\"unformat()\" (blur)=\"format()\" class=\"input-number\"\n [readonly]=\"readonly\" (ngModelChange)=\"onValueChange($event)\" />\n", styles: [":host{display:flex}:host input{width:100%;border:0;background-color:transparent}\n"] }]
539
397
  }], ctorParameters: () => [{ type: i1.TranslateService }], propDecorators: { scale: [{
540
398
  type: Input
541
399
  }], precision: [{
@@ -555,72 +413,800 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
555
413
  }] } });
556
414
 
557
415
  /**
558
- * Creates form input for ranges of numeric values.
416
+ * Creates form input for strings. Based on the input values different kinds of inputs will be generated.
559
417
  *
560
418
  * Implements `ControlValueAccessor` so it can be used within Angular forms.
561
419
  *
562
420
  * @example
563
- * <yuv-number-range [scale]="2"></yuv-number-range>
421
+ * <!-- string input validating input to be between 5 and 10 characters -->
422
+ * <yuv-string [minLength]="5" [maxLength]="10"></yuv-string>
423
+ *
424
+ * <!-- string input that only allow digits -->
425
+ * <yuv-string [regex]="[0-9]*"></yuv-string>
426
+ *
427
+ * <!-- string input rendering a large textarea -->
428
+ * <yuv-string [rows]="10"></yuv-string>
564
429
  *
565
430
  */
566
- class NumberRangeComponent {
431
+ class StringComponent {
567
432
  constructor() {
433
+ this.iconsService = inject(IconService);
434
+ this.elementRef = inject(ElementRef);
435
+ this.classifiytionIcons = {
436
+ email: this.iconsService.getIcon(ClassificationPrefix.EMAIL_ICON) || '',
437
+ url: this.iconsService.getIcon(ClassificationPrefix.URL_ICON) || '',
438
+ phone: this.iconsService.getIcon(ClassificationPrefix.PHONE_ICON) || ''
439
+ };
440
+ // provides all css variables defined by |yuuvis/comonents
441
+ this.fe = true;
568
442
  /**
569
- * Set to true to group number by pattern
443
+ * Indicator that multiple strings could be inserted, they will be rendered as chips (default: false).
570
444
  */
571
- this.grouping = false;
445
+ this.multiselect = false;
572
446
  /**
573
447
  * Will prevent the input from being changed (default: false)
574
448
  */
575
449
  this.readonly = false;
576
450
  /**
577
- * classification property adds some semantics to the value of this component.
578
- * If you provide a value of `filesize` numbers typed into the control will be
579
- * handled like file sizes (calculates differnt units)
451
+ * Enable autofucus for the input (default: false)
580
452
  */
581
- this.classifications = [];
582
- this.rangeForm = new UntypedFormGroup({
583
- numberValue: new UntypedFormControl(),
584
- numberValueFrom: new UntypedFormControl()
585
- });
586
- this.isValid = true;
587
- // options for search situation
588
- this.availableSearchOptions = [
589
- { label: OperatorLabel.EQUAL, value: Operator.EQUAL },
590
- { label: OperatorLabel.GREATER_OR_EQUAL, value: Operator.GREATER_OR_EQUAL },
591
- { label: OperatorLabel.LESS_OR_EQUAL, value: Operator.LESS_OR_EQUAL },
592
- { label: OperatorLabel.INTERVAL_INCLUDE_BOTH, value: Operator.INTERVAL_INCLUDE_BOTH }
593
- ];
594
- // the selected search option
595
- this.searchOption = this.availableSearchOptions[1].value;
596
- // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
453
+ this.autofocus = false;
454
+ this.valid = false;
455
+ this.validationErrors = [];
456
+ this._classifications = [];
597
457
  this.propagateChange = (_) => { };
598
- this.rangeForm.valueChanges.forEach(() => {
599
- this.onValueChange();
600
- });
601
458
  }
602
- writeValue(value) {
603
- if (value && (value.firstValue != null || value.secondValue != null)) {
604
- const match = this.availableSearchOptions.find((o) => o.value === value.operator);
605
- this.searchOption = match ? match.value : this.availableSearchOptions[0].value;
606
- this.value = value;
607
- if (value.secondValue == null) {
608
- this.rangeForm.setValue({
609
- numberValueFrom: null,
610
- numberValue: value.firstValue != null ? value.firstValue : null
611
- });
459
+ /**
460
+ * Additional semantics for the form element. Possible values are
461
+ * `email` (validates and creates a link to send an email once there
462
+ * is a valid email address) and `url` (validates and creates a link
463
+ * to an URL typed into the form element).
464
+ */
465
+ set classifications(c) {
466
+ this._classifications = c;
467
+ if (c && c.length) {
468
+ if (c.includes(Classification.STRING_EMAIL)) {
469
+ this.classify = {
470
+ hrefPrefix: ClassificationPrefix.EMAIL,
471
+ icon: this.classifiytionIcons.email
472
+ };
612
473
  }
613
- else {
614
- this.rangeForm.setValue({
615
- numberValueFrom: value.firstValue != null ? value.firstValue : null,
616
- numberValue: value.secondValue
617
- });
474
+ else if (c.includes(Classification.STRING_URL)) {
475
+ this.classify = {
476
+ hrefPrefix: ClassificationPrefix.URL,
477
+ icon: this.classifiytionIcons.url
478
+ };
618
479
  }
619
- }
620
- else {
621
- this.searchOption = this.availableSearchOptions[0].value;
622
- this.value = undefined;
623
- this.rangeForm.reset();
480
+ else if (c.includes(Classification.STRING_PHONE)) {
481
+ this.classify = {
482
+ hrefPrefix: ClassificationPrefix.PHONE,
483
+ icon: this.classifiytionIcons.phone
484
+ };
485
+ }
486
+ }
487
+ }
488
+ get classifications() {
489
+ return this._classifications;
490
+ }
491
+ propagate() {
492
+ this.propagateChange(this.value);
493
+ }
494
+ writeValue(value) {
495
+ if (Array.isArray(value)) {
496
+ value = value.filter((v) => typeof v === 'string' && v.trim().length > 0);
497
+ }
498
+ this.formatedValue = Utils.formatMailTo(value, this.classify?.hrefPrefix === ClassificationPrefix.EMAIL);
499
+ this.value = value || null;
500
+ }
501
+ registerOnChange(fn) {
502
+ this.propagateChange = fn;
503
+ }
504
+ registerOnTouched() { }
505
+ onValueChange(val) {
506
+ this.maxEntryCountIfInvalid = undefined;
507
+ this.validationErrors = [];
508
+ if (Utils.isEmpty(val)) {
509
+ this.value = null;
510
+ this.propagate();
511
+ return;
512
+ }
513
+ const multiCheck = (check) => !!(this.multiselect ? val : [val]).find((v) => check(v));
514
+ // validate regular expression
515
+ if (this.regex && multiCheck((v) => !RegExp(this.regex).test(v))) {
516
+ this.validationErrors.push({ key: 'regex' });
517
+ }
518
+ // validate classification settings
519
+ if (this.classifications && this.classifications.length) {
520
+ this.classifications.forEach((c) => {
521
+ if (multiCheck((v) => !this.validateClassification(v, c))) {
522
+ this.validationErrors.push({ key: 'classification' + c });
523
+ }
524
+ });
525
+ }
526
+ // validate min length
527
+ if (!Utils.isEmpty(this.minLength) && multiCheck((v) => v.length < this.minLength)) {
528
+ this.validationErrors.push({ key: 'minlength', params: { minLength: this.minLength } });
529
+ }
530
+ // validate max length
531
+ if (!Utils.isEmpty(this.maxLength) && multiCheck((v) => v.length > this.maxLength)) {
532
+ this.validationErrors.push({ key: 'maxlength', params: { maxLength: this.maxLength } });
533
+ }
534
+ // validate invalid if only whitespaces
535
+ if (multiCheck((v) => v.length > 0 && !v.trim().length)) {
536
+ this.validationErrors.push({ key: 'onlyWhitespaces' });
537
+ }
538
+ if (this.validationErrors.length && this.multiselect && this.value) {
539
+ // Setting maxEntryCountIfInvalid to the actual length of the value array to prevent the user to add more entries.
540
+ this.maxEntryCountIfInvalid = this.value.length;
541
+ }
542
+ this.formatedValue = Utils.formatMailTo(val, this.classify?.hrefPrefix === ClassificationPrefix.EMAIL);
543
+ this.propagate();
544
+ }
545
+ onBlur() {
546
+ if (this.multiselect) {
547
+ // add on blur
548
+ this.value.push('');
549
+ }
550
+ if (this.trimValue()) {
551
+ this.propagate();
552
+ }
553
+ }
554
+ /**
555
+ * Trims the current value and returns wether or not it has been trimmed
556
+ */
557
+ trimValue() {
558
+ if (this.value) {
559
+ if (this.multiselect) {
560
+ const lengthBefore = this.value.join('').length;
561
+ this.value = this.value.map((v) => v.trim());
562
+ return this.value.join('').length !== lengthBefore;
563
+ }
564
+ else {
565
+ const lengthBefore = this.value.length;
566
+ this.value = this.value.trim();
567
+ return this.value.length !== lengthBefore;
568
+ }
569
+ }
570
+ return false;
571
+ }
572
+ validateClassification(string, classification) {
573
+ if (this.situation === Situation.SEARCH) {
574
+ return true;
575
+ }
576
+ else {
577
+ let pattern;
578
+ if (classification === Classification.STRING_EMAIL) {
579
+ pattern =
580
+ /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
581
+ }
582
+ else if (classification === Classification.STRING_URL) {
583
+ pattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)?([\w.,@?^=%&amp;:\/~+#-]*[\w@?^=%&amp;\/~+#-])?/;
584
+ }
585
+ else if (classification === Classification.STRING_PHONE) {
586
+ pattern = /^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-x\s\./0-9]*$/g;
587
+ }
588
+ return pattern ? pattern.test(string) : true;
589
+ }
590
+ }
591
+ /**
592
+ * returns null when valid else the validation object
593
+ */
594
+ validate() {
595
+ if (this.validationErrors.length) {
596
+ this.valid = false;
597
+ return Utils.arrayToObject(this.validationErrors, 'key', (err) => ({ valid: false, ...err }));
598
+ }
599
+ else {
600
+ this.valid = true;
601
+ return null;
602
+ }
603
+ }
604
+ ngAfterViewInit() {
605
+ if (this.autofocus) {
606
+ if (!this.multiselect) {
607
+ const el = this.elementRef.nativeElement.querySelector(this.rows && this.rows > 1 ? 'textarea' : 'input');
608
+ if (el)
609
+ el.focus();
610
+ }
611
+ }
612
+ }
613
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StringComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
614
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: StringComponent, isStandalone: true, selector: "yuv-string", inputs: { multiselect: "multiselect", rows: "rows", readonly: "readonly", autofocus: "autofocus", classifications: "classifications", situation: "situation", regex: "regex", minLength: "minLength", maxLength: "maxLength" }, host: { properties: { "class.yvc-form-element": "this.fe" } }, providers: [
615
+ {
616
+ provide: NG_VALUE_ACCESSOR,
617
+ useExisting: forwardRef(() => StringComponent),
618
+ multi: true
619
+ },
620
+ {
621
+ provide: NG_VALIDATORS,
622
+ useExisting: forwardRef(() => StringComponent),
623
+ multi: true
624
+ }
625
+ ], ngImport: i0, template: "@if ((!rows || rows <= 1) && !multiselect) {\n <input type=\"text\" (blur)=\"onBlur()\" [readonly]=\"readonly\" [(ngModel)]=\"value\" (ngModelChange)=\"onValueChange($event)\" />\n}\n@else if ((!rows || rows <= 1) && multiselect) {\n <!-- single line input with multiselect-->\n <yvc-chips\n [(ngModel)]=\"value\"\n [disabled]=\"readonly\"\n [max]=\"maxEntryCountIfInvalid\"\n [addOnBlur]=\"true\"\n (onBlur)=\"onBlur()\"\n (ngModelChange)=\"onValueChange($event)\"\n [ngClass]=\"{ invalid: validationErrors.length }\"\n >\n <ng-template let-item #chipTemplate>\n <span class=\"p-autocomplete-token-label\">\n @if (classify && !validationErrors.length) {\n <div class=\"classify inchip\">\n <a href=\"{{ classify.hrefPrefix + item }}\">\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n </a>\n </div>\n }\n <div class=\"label\">\n {{ item }}\n </div>\n </span>\n </ng-template>\n </yvc-chips>\n} @else if (rows && rows > 1) {\n <!-- multi line text inputs -->\n <textarea\n class=\"input-textarea\"\n pInputTextarea\n (blur)=\"onBlur()\"\n [(ngModel)]=\"value\"\n [rows]=\"rows\"\n [readonly]=\"readonly\"\n (ngModelChange)=\"onValueChange($event)\"\n ></textarea>\n}\n\n@if (classify) {\n <div class=\"classify\">\n @if (value && !validationErrors.length && (classify.hrefPrefix !== '' || !multiselect || value.length <= 1)) {\n <a href=\"{{ classify.hrefPrefix + formatedValue }}\">\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n </a>\n } @else {\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n }\n </div>\n}\n", styles: [":host{display:flex;flex-flow:row nowrap;align-items:center}:host .yvc-chips-list li.chip{--yvc-form-element-border-color: var(--text-color-hint)}:host .classify{color:var(--text-color-hint)}:host .classify a{color:var(--text-color-hint);display:block;border-radius:2px}:host .classify a:hover,:host .classify a:focus{background-color:var(--color-accent);color:#fff}:host .classify yvc-icon{width:18px;height:18px;padding:calc(var(--app-pane-padding) / 8)}:host textarea.input-textarea{width:100%;resize:vertical;background-color:transparent;color:var(--text-color-body);border:1px solid var(--yvc-form-element-border-color)}:host yvc-chips{width:100%}:host input{color:var(--text-color-body);padding:0;border:1px solid var(--yvc-form-element-border-color);display:flex;flex-wrap:wrap;align-items:center;width:100%;background:transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: YvcChipsModule }, { kind: "component", type: i2$1.Chips, selector: "yvc-chips", inputs: ["field", "placeholder", "max", "disabled", "addOnBlur"] }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i3.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
626
+ }
627
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StringComponent, decorators: [{
628
+ type: Component,
629
+ args: [{ selector: 'yuv-string', standalone: true, imports: [CommonModule, YvcChipsModule, YvcIconModule, FormsModule], providers: [
630
+ {
631
+ provide: NG_VALUE_ACCESSOR,
632
+ useExisting: forwardRef(() => StringComponent),
633
+ multi: true
634
+ },
635
+ {
636
+ provide: NG_VALIDATORS,
637
+ useExisting: forwardRef(() => StringComponent),
638
+ multi: true
639
+ }
640
+ ], template: "@if ((!rows || rows <= 1) && !multiselect) {\n <input type=\"text\" (blur)=\"onBlur()\" [readonly]=\"readonly\" [(ngModel)]=\"value\" (ngModelChange)=\"onValueChange($event)\" />\n}\n@else if ((!rows || rows <= 1) && multiselect) {\n <!-- single line input with multiselect-->\n <yvc-chips\n [(ngModel)]=\"value\"\n [disabled]=\"readonly\"\n [max]=\"maxEntryCountIfInvalid\"\n [addOnBlur]=\"true\"\n (onBlur)=\"onBlur()\"\n (ngModelChange)=\"onValueChange($event)\"\n [ngClass]=\"{ invalid: validationErrors.length }\"\n >\n <ng-template let-item #chipTemplate>\n <span class=\"p-autocomplete-token-label\">\n @if (classify && !validationErrors.length) {\n <div class=\"classify inchip\">\n <a href=\"{{ classify.hrefPrefix + item }}\">\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n </a>\n </div>\n }\n <div class=\"label\">\n {{ item }}\n </div>\n </span>\n </ng-template>\n </yvc-chips>\n} @else if (rows && rows > 1) {\n <!-- multi line text inputs -->\n <textarea\n class=\"input-textarea\"\n pInputTextarea\n (blur)=\"onBlur()\"\n [(ngModel)]=\"value\"\n [rows]=\"rows\"\n [readonly]=\"readonly\"\n (ngModelChange)=\"onValueChange($event)\"\n ></textarea>\n}\n\n@if (classify) {\n <div class=\"classify\">\n @if (value && !validationErrors.length && (classify.hrefPrefix !== '' || !multiselect || value.length <= 1)) {\n <a href=\"{{ classify.hrefPrefix + formatedValue }}\">\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n </a>\n } @else {\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n }\n </div>\n}\n", styles: [":host{display:flex;flex-flow:row nowrap;align-items:center}:host .yvc-chips-list li.chip{--yvc-form-element-border-color: var(--text-color-hint)}:host .classify{color:var(--text-color-hint)}:host .classify a{color:var(--text-color-hint);display:block;border-radius:2px}:host .classify a:hover,:host .classify a:focus{background-color:var(--color-accent);color:#fff}:host .classify yvc-icon{width:18px;height:18px;padding:calc(var(--app-pane-padding) / 8)}:host textarea.input-textarea{width:100%;resize:vertical;background-color:transparent;color:var(--text-color-body);border:1px solid var(--yvc-form-element-border-color)}:host yvc-chips{width:100%}:host input{color:var(--text-color-body);padding:0;border:1px solid var(--yvc-form-element-border-color);display:flex;flex-wrap:wrap;align-items:center;width:100%;background:transparent}\n"] }]
641
+ }], propDecorators: { fe: [{
642
+ type: HostBinding,
643
+ args: ['class.yvc-form-element']
644
+ }], multiselect: [{
645
+ type: Input
646
+ }], rows: [{
647
+ type: Input
648
+ }], readonly: [{
649
+ type: Input
650
+ }], autofocus: [{
651
+ type: Input
652
+ }], classifications: [{
653
+ type: Input
654
+ }], situation: [{
655
+ type: Input
656
+ }], regex: [{
657
+ type: Input
658
+ }], minLength: [{
659
+ type: Input
660
+ }], maxLength: [{
661
+ type: Input
662
+ }] } });
663
+
664
+ class EditTableDataComponent {
665
+ constructor() {
666
+ this.#oRef = inject((YvcOverlayRef));
667
+ this.#fb = inject(FormBuilder);
668
+ this.#errorMassge = inject(ErrorMessagesService);
669
+ this.errorMassage = signal(null);
670
+ this.tableForm = this.#fb.group({});
671
+ this.isInnerTableForm = input(true);
672
+ this.formElement = this.#oRef.data?.formElement || {};
673
+ this.#elementData = this.#oRef.data?.elementData || {};
674
+ this.situation = this.#oRef.data?.situation || Situation.EDIT;
675
+ this.header = this.#oRef.data?.label || '';
676
+ this.adding = this.#oRef.data?.adding;
677
+ }
678
+ #oRef;
679
+ #fb;
680
+ #errorMassge;
681
+ #elementData;
682
+ cancel() {
683
+ if (this.#oRef)
684
+ this.#oRef.close();
685
+ }
686
+ submit() {
687
+ if (this.tableForm.valid && this.#oRef)
688
+ this.#oRef.close(this.tableForm.getRawValue());
689
+ }
690
+ ngOnInit() {
691
+ Object.values(this.formElement['elements']).forEach((element) => {
692
+ return this.tableForm.addControl(element.name, this.#fb.control({ value: '', disabled: element.readonly }, element.required ? Validators.required : null));
693
+ });
694
+ this.tableForm.setValidators(this.#globalErrorValidator());
695
+ this.#elementData && this.tableForm.patchValue(this.#elementData);
696
+ this.tableForm.valueChanges.subscribe((v) => {
697
+ this.errorMassage.set(this.tableForm.errors
698
+ ? Object.keys(this.tableForm.errors).map((key) => this.tableForm.errors && this.tableForm.errors[key]
699
+ ? Object.keys(this.tableForm.errors[key]).map((k) => ({ [key]: this.#errorMassge.getErrorLabel(k, key) }))
700
+ : null)
701
+ : null);
702
+ });
703
+ }
704
+ #globalErrorValidator() {
705
+ return (control) => {
706
+ const formGroup = control;
707
+ const errors = {};
708
+ Object.keys(formGroup.controls).forEach((key) => {
709
+ const control = formGroup.get(key);
710
+ if (control && control.invalid && control.dirty) {
711
+ const controlErrors = control.errors;
712
+ if (controlErrors) {
713
+ // Ignore 'required' error if there are more errors
714
+ if (Object.keys(controlErrors).length > 1 && controlErrors['required']) {
715
+ const { required, ...otherErrors } = controlErrors;
716
+ errors[key] = otherErrors;
717
+ }
718
+ else {
719
+ errors[key] = controlErrors;
720
+ }
721
+ }
722
+ }
723
+ });
724
+ return Object.keys(errors).length ? errors : null;
725
+ };
726
+ }
727
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditTableDataComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
728
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: EditTableDataComponent, isStandalone: true, selector: "yuv-edit-table-data", inputs: { isInnerTableForm: { classPropertyName: "isInnerTableForm", publicName: "isInnerTableForm", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
729
+ {
730
+ provide: NG_VALUE_ACCESSOR,
731
+ useExisting: forwardRef(() => EditTableDataComponent),
732
+ multi: true
733
+ }
734
+ ], ngImport: i0, template: "<header>\n <h2>{{ 'yuv.form.element.data.grid.edit.headline' | translate: { headline: header } }}</h2>\n</header>\n\n<div [formGroup]=\"tableForm\">\n @for (element of formElement['elements']; track $index) {\n <div [attr.data-name]=\"element.name\" class=\"form-field\">\n <yuv-form-input\n [label]=\"element.label\"\n [required]=\"element.required\"\n [invalid]=\"false\"\n [disabled]=\"element.readonly\"\n [invalid]=\"!tableForm.get(element.label)?.valid && tableForm.get(element.label)?.dirty\"\n >\n @switch (element.type) {\n @case ('string') {\n <yuv-string\n [situation]=\"situation\"\n [formControlName]=\"element.name\"\n [attr.data-name]=\"element.name\"\n [multiselect]=\"element.cardinality === 'multi' || situation === 'SEARCH'\"\n [rows]=\"element.rows\"\n [classifications]=\"element.classifications\"\n [regex]=\"element.regex\"\n [readonly]=\"element.readonly\"\n [minLength]=\"element.minLength\"\n [maxLength]=\"element.maxLength\"\n >\n </yuv-string>\n }\n @case ('decimal') {\n <yuv-number\n [readonly]=\"element.readonly\"\n [precision]=\"element.precision\"\n [scale]=\"element.scale\"\n [pattern]=\"element.pattern\"\n [grouping]=\"element.grouping\"\n [minValue]=\"element.minValue\"\n [maxValue]=\"element.maxValue\"\n [formControlName]=\"element.name\"\n [attr.data-name]=\"element.name\"\n ></yuv-number>\n }\n @default {\n <input [type]=\"element.type\" [id]=\"element.name\" [name]=\"element.name\" [readonly]=\"element.readonly\" [required]=\"element.required\" />\n }\n }\n <!-- <input [type]=\"element.type\" [id]=\"element.name\" [name]=\"element.name\" [readonly]=\"element.readonly\" [required]=\"element.required\" /> -->\n </yuv-form-input>\n @let errorsGroup = errorMassage();\n @if (errorsGroup && tableForm.errors) {\n <div class=\"err-msg\">\n @for (errors of errorsGroup; track $index) {\n @for (error of errors; track $index) {\n {{ error[element.label] }}\n }\n }\n </div>\n }\n </div>\n }\n <footer>\n <button (click)=\"cancel()\">{{ 'yuv.form.element.data.grid.edit.cancel' | translate }}</button>\n <button class=\"primary\" (click)=\"submit()\" [disabled]=\"!tableForm.dirty && !tableForm.valid\">\n @if (adding) {\n {{ 'yuv.form.element.data.grid.edit.add' | translate }}\n } @else {\n {{ 'yuv.form.element.data.grid.edit' | translate }}\n }\n </button>\n </footer>\n</div>\n", styles: [":host{display:flex;flex-direction:column;padding:var(--app-pane-padding)}:host header h2{padding:0;font-weight:400;font-size:var(--font-headline);margin:0 0 var(--app-pane-padding) 0}:host .err-msg{font-size:var(--font-hint);color:var(--color-error);padding:calc(var(--app-pane-padding) / 4) 0;border:0}:host footer{display:flex;justify-content:end;gap:var(--app-pane-padding);margin-block-start:var(--app-pane-padding)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: FormInputComponent, selector: "yuv-form-input", inputs: ["label", "tag", "description", "invalid", "disabled", "required"] }, { kind: "component", type: StringComponent, selector: "yuv-string", inputs: ["multiselect", "rows", "readonly", "autofocus", "classifications", "situation", "regex", "minLength", "maxLength"] }, { kind: "component", type: NumberComponent, selector: "yuv-number", inputs: ["scale", "precision", "grouping", "groupPattern", "readonly", "minValue", "maxValue", "classifications"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
735
+ }
736
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditTableDataComponent, decorators: [{
737
+ type: Component,
738
+ args: [{ selector: 'yuv-edit-table-data', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormInputComponent, StringComponent, NumberComponent, TranslateModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
739
+ {
740
+ provide: NG_VALUE_ACCESSOR,
741
+ useExisting: forwardRef(() => EditTableDataComponent),
742
+ multi: true
743
+ }
744
+ ], template: "<header>\n <h2>{{ 'yuv.form.element.data.grid.edit.headline' | translate: { headline: header } }}</h2>\n</header>\n\n<div [formGroup]=\"tableForm\">\n @for (element of formElement['elements']; track $index) {\n <div [attr.data-name]=\"element.name\" class=\"form-field\">\n <yuv-form-input\n [label]=\"element.label\"\n [required]=\"element.required\"\n [invalid]=\"false\"\n [disabled]=\"element.readonly\"\n [invalid]=\"!tableForm.get(element.label)?.valid && tableForm.get(element.label)?.dirty\"\n >\n @switch (element.type) {\n @case ('string') {\n <yuv-string\n [situation]=\"situation\"\n [formControlName]=\"element.name\"\n [attr.data-name]=\"element.name\"\n [multiselect]=\"element.cardinality === 'multi' || situation === 'SEARCH'\"\n [rows]=\"element.rows\"\n [classifications]=\"element.classifications\"\n [regex]=\"element.regex\"\n [readonly]=\"element.readonly\"\n [minLength]=\"element.minLength\"\n [maxLength]=\"element.maxLength\"\n >\n </yuv-string>\n }\n @case ('decimal') {\n <yuv-number\n [readonly]=\"element.readonly\"\n [precision]=\"element.precision\"\n [scale]=\"element.scale\"\n [pattern]=\"element.pattern\"\n [grouping]=\"element.grouping\"\n [minValue]=\"element.minValue\"\n [maxValue]=\"element.maxValue\"\n [formControlName]=\"element.name\"\n [attr.data-name]=\"element.name\"\n ></yuv-number>\n }\n @default {\n <input [type]=\"element.type\" [id]=\"element.name\" [name]=\"element.name\" [readonly]=\"element.readonly\" [required]=\"element.required\" />\n }\n }\n <!-- <input [type]=\"element.type\" [id]=\"element.name\" [name]=\"element.name\" [readonly]=\"element.readonly\" [required]=\"element.required\" /> -->\n </yuv-form-input>\n @let errorsGroup = errorMassage();\n @if (errorsGroup && tableForm.errors) {\n <div class=\"err-msg\">\n @for (errors of errorsGroup; track $index) {\n @for (error of errors; track $index) {\n {{ error[element.label] }}\n }\n }\n </div>\n }\n </div>\n }\n <footer>\n <button (click)=\"cancel()\">{{ 'yuv.form.element.data.grid.edit.cancel' | translate }}</button>\n <button class=\"primary\" (click)=\"submit()\" [disabled]=\"!tableForm.dirty && !tableForm.valid\">\n @if (adding) {\n {{ 'yuv.form.element.data.grid.edit.add' | translate }}\n } @else {\n {{ 'yuv.form.element.data.grid.edit' | translate }}\n }\n </button>\n </footer>\n</div>\n", styles: [":host{display:flex;flex-direction:column;padding:var(--app-pane-padding)}:host header h2{padding:0;font-weight:400;font-size:var(--font-headline);margin:0 0 var(--app-pane-padding) 0}:host .err-msg{font-size:var(--font-hint);color:var(--color-error);padding:calc(var(--app-pane-padding) / 4) 0;border:0}:host footer{display:flex;justify-content:end;gap:var(--app-pane-padding);margin-block-start:var(--app-pane-padding)}\n"] }]
745
+ }] });
746
+
747
+ var DataGridSizeType;
748
+ (function (DataGridSizeType) {
749
+ DataGridSizeType["SMALL"] = "small";
750
+ DataGridSizeType["MEDIUM"] = "medium";
751
+ DataGridSizeType["LARGE"] = "large";
752
+ DataGridSizeType["XLARGE"] = "extra-large";
753
+ DataGridSizeType["AUTO"] = "auto";
754
+ })(DataGridSizeType || (DataGridSizeType = {}));
755
+
756
+ const CDK_IMPORT = [CdkMenu, CdkTableModule, CdkMenuTrigger, CdkMenuItem];
757
+ class DataGridComponent {
758
+ constructor() {
759
+ this.#overlay = inject(YvcOverlayService);
760
+ this.#clipboardService = inject(ClipboardService);
761
+ this.#decimalPipe = inject(DecimalPipe);
762
+ this.trnaslate = inject(TranslateService);
763
+ this.situation = input(Situation.EDIT);
764
+ this.formElement = input(undefined);
765
+ this.formControl = input(undefined);
766
+ this.classifications = input([]);
767
+ this.readonly = input(false);
768
+ this.size = input(DataGridSizeType.AUTO);
769
+ this.displayedColumns = signal([]);
770
+ this.displayedColumnsWithActions = signal([]);
771
+ this.dataSource = signal([]);
772
+ this.tableLabel = computed(() => this.formElement()?.['label'] ?? '');
773
+ this.selectedRow = signal(null);
774
+ this.initalTableUpdate = true;
775
+ this.icons = {
776
+ add: YUV_ICONS.add,
777
+ more: YUV_ICONS.more
778
+ };
779
+ this.#loadData = effect(() => {
780
+ const formElement = this.formElement();
781
+ untracked(() => formElement && this.#updateTable(formElement['elements'], formElement['value'] || []));
782
+ });
783
+ this.#sourceData = effect(() => {
784
+ const dataSource = this.dataSource();
785
+ !this.initalTableUpdate && this.writeValue(dataSource.filter((row) => !row.isAddRow));
786
+ this.initalTableUpdate = false;
787
+ });
788
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
789
+ this.propagateChange = (fn) => { };
790
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
791
+ this.validationChange = () => { };
792
+ }
793
+ #overlay;
794
+ #clipboardService;
795
+ #decimalPipe;
796
+ #loadData;
797
+ #sourceData;
798
+ #openEditOverlay(elementData, adding = false) {
799
+ return this.#overlay
800
+ .open(EditTableDataComponent, {
801
+ formElement: {
802
+ ...this.formElement()
803
+ },
804
+ elementData,
805
+ situation: this.situation(),
806
+ adding,
807
+ label: this.tableLabel()
808
+ })
809
+ .afterClosed$.pipe(map((result) => result.data));
810
+ }
811
+ copyLine(element) {
812
+ this.#clipboardService.addToNavigatorClipBoard(JSON.stringify(element));
813
+ }
814
+ onMenuTriggert(element) {
815
+ this.selectedRow.set(element);
816
+ }
817
+ editRow(element) {
818
+ this.selectedRow.set(element);
819
+ this.#openEditOverlay(element).subscribe((result) => {
820
+ if (result) {
821
+ const updatedData = this.dataSource().map((item) => (JSON.stringify(item) === JSON.stringify(element) ? result : item));
822
+ const formElement = this.formElement();
823
+ formElement && this.#updateTable(formElement['elements'], [...updatedData]);
824
+ }
825
+ this.selectedRow.set(null);
826
+ });
827
+ }
828
+ addRow() {
829
+ this.#openEditOverlay(null, true).subscribe((result) => {
830
+ const currentData = this.dataSource();
831
+ const data = [...currentData];
832
+ result && data.push(result);
833
+ const formElement = this.formElement();
834
+ formElement && this.#updateTable(formElement['elements'], data);
835
+ });
836
+ }
837
+ removeRow(element) {
838
+ const updatedData = this.dataSource().filter((item) => JSON.stringify(item) !== JSON.stringify(element));
839
+ const formElement = this.formElement();
840
+ formElement && this.#updateTable(formElement['elements'], updatedData);
841
+ }
842
+ #cellor(element, value) {
843
+ switch (element.type) {
844
+ case 'string':
845
+ return value;
846
+ break;
847
+ case 'decimal':
848
+ return this.#decimalPipe.transform(value, '1.2-4', this.trnaslate.currentLang);
849
+ break;
850
+ default:
851
+ return value;
852
+ break;
853
+ }
854
+ }
855
+ #updateTable(elements, data = []) {
856
+ if (elements.length > 0) {
857
+ this.displayedColumns.set(elements.reduce((acc, el) => {
858
+ acc.push({
859
+ columnDef: el.label,
860
+ header: el.label,
861
+ cell: (element) => (element.isAddRow ? '' : this.#cellor(el, element[el.label]))
862
+ });
863
+ return acc;
864
+ }, []));
865
+ }
866
+ else {
867
+ this.displayedColumns.set([]);
868
+ }
869
+ this.displayedColumnsWithActions.set([...this.displayedColumns().map((col) => col.columnDef), 'actions']);
870
+ this.dataSource.set(data);
871
+ }
872
+ writeValue(obj) {
873
+ this.propagateChange(obj);
874
+ }
875
+ registerOnChange(fn) {
876
+ this.propagateChange = fn;
877
+ }
878
+ registerOnTouched(fn) {
879
+ this.validationChange = fn;
880
+ }
881
+ setDisabledState(isDisabled) {
882
+ // console.log('setDisabledState: ', isDisabled);
883
+ }
884
+ onValueChange(e) {
885
+ this.propagateChange(e);
886
+ }
887
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DataGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
888
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: DataGridComponent, isStandalone: true, selector: "yuv-data-grid", inputs: { situation: { classPropertyName: "situation", publicName: "situation", isSignal: true, isRequired: false, transformFunction: null }, formElement: { classPropertyName: "formElement", publicName: "formElement", isSignal: true, isRequired: false, transformFunction: null }, formControl: { classPropertyName: "formControl", publicName: "formControl", isSignal: true, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "yuv-data-grid" }, providers: [
889
+ {
890
+ provide: NG_VALUE_ACCESSOR,
891
+ useExisting: forwardRef(() => DataGridComponent),
892
+ multi: true
893
+ },
894
+ DecimalPipe
895
+ ], ngImport: i0, template: "<header>\n <h3>{{ tableLabel() }}</h3>\n @if (!readonly()) {\n <button (click)=\"addRow()\" aria-label=\"Add Row\" class=\"table-options-add-row\">\n <yvc-icon [svg]=\"icons.add\"></yvc-icon>\n </button>\n }\n</header>\n@let displayedCol = displayedColumns();\n@let displayedColActions = displayedColumnsWithActions();\n<div class=\"table-wrapper\" [ngClass]=\"size()\">\n <table cdk-table [dataSource]=\"dataSource()\">\n <!-- Dynamic Columns -->\n @for (column of displayedCol; track $index) {\n <ng-container [cdkColumnDef]=\"column.columnDef\">\n <th class=\"sticky-column\" cdk-header-cell *cdkHeaderCellDef>{{ column.header }}</th>\n <td cdk-cell *cdkCellDef=\"let element\">{{ column.cell(element) }}</td>\n </ng-container>\n }\n\n <!-- Actions Column (Not in displayedColumns) -->\n <ng-container cdkColumnDef=\"actions\">\n <th class=\"actions-header sticky-column\" cdk-header-cell *cdkHeaderCellDef></th>\n <td class=\"actions-row sticky\" cdk-cell *cdkCellDef=\"let element\">\n <!-- Only show the button in the last (empty) row -->\n @if (!readonly()) {\n <button\n aria-label=\"Edit Row\"\n class=\"table-options-menu-bar-item\"\n cdkMenuItem\n (cdkMenuOpened)=\"onMenuTriggert(element)\"\n (cdkMenuClosed)=\"onMenuTriggert(null)\"\n [cdkMenuTriggerFor]=\"options\"\n [cdkMenuTriggerData]=\"{ element: element }\"\n >\n <yvc-icon [svg]=\"icons.more\"></yvc-icon>\n </button>\n }\n </td>\n </ng-container>\n\n <tr cdk-header-row *cdkHeaderRowDef=\"displayedColActions\"></tr>\n @if (!readonly()) {\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" cdk-row *cdkRowDef=\"let row; columns: displayedColActions\"></tr>\n } @else {\n <tr cdk-row *cdkRowDef=\"let row; columns: displayedColActions\"></tr>\n }\n </table>\n</div>\n<ng-template #options let-element=\"element\">\n <div class=\"table-options-menu\" cdkMenu>\n <button class=\"table-options-menu-item\" (click)=\"copyLine(element)\" cdkMenuItem>{{ 'yuv.form.element.data.grid.copy' | translate }}</button>\n <button class=\"table-options-menu-item\" cdkMenuItem (click)=\"editRow(element)\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button class=\"table-options-menu-item\" cdkMenuItem (click)=\"removeRow(element)\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n </div>\n</ng-template>\n", styles: [":root{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px}:host{border:1px solid var(--panel-divider-color)}:host header{display:flex;justify-content:space-between;background-color:var(--panel-background-grey)}:host header h3{text-align:start;-webkit-user-select:none;user-select:none;flex:0 1 auto;padding:1rem;margin:0;color:var(--text-color-caption);border-radius:2px;font-size:var(--font-caption);font-weight:400}:host.yuv-data-grid{display:block}:host.yuv-data-grid .table-wrapper{overflow:auto;position:relative;white-space:nowrap}:host.yuv-data-grid .table-wrapper.small{height:var(--table-size-small)}:host.yuv-data-grid .table-wrapper.medium{height:var(--table-size-medium)}:host.yuv-data-grid .table-wrapper.large{height:var(--table-size-large)}:host.yuv-data-grid .table-wrapper.extra-large{height:var(--table-size-extra-large)}:host.yuv-data-grid ::ng-deep .cdk-header-cell:not(:last-child){padding:.5rem 1rem}:host.yuv-data-grid ::ng-deep table{border-spacing:0}:host.yuv-data-grid ::ng-deep th{border-bottom:1px solid var(--panel-divider-color);border-right:1px solid var(--panel-divider-color);padding:.5rem 0}:host.yuv-data-grid ::ng-deep thead{background-color:var(--panel-background-grey)}:host.yuv-data-grid ::ng-deep tr.cdk-row{cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease-in-out}:host.yuv-data-grid ::ng-deep tr.cdk-row:hover td{border-top:1px solid var(--panel-background-grey);border-bottom:1px solid var(--panel-background-grey)}:host.yuv-data-grid ::ng-deep tr.cdk-row:hover:has(.actions-row) td.cdk-cell.actions-row.sticky{opacity:1}:host.yuv-data-grid ::ng-deep tr.cdk-row.selected-row{color:var(--text-color-hint)}:host.yuv-data-grid ::ng-deep tr.cdk-row td{border-bottom:1px solid transparent;border-top:1px solid transparent}:host.yuv-data-grid ::ng-deep tr.cdk-row td:not(:last-child){padding:.5rem 1rem}:host.yuv-data-grid ::ng-deep .cdk-table .cdk-header-row th[role=columnheader]{font-weight:500}:host.yuv-data-grid th.cdk-header-cell.sticky-column{position:sticky;top:0;z-index:1;background-color:var(--panel-background-grey)}:host.yuv-data-grid td.cdk-cell.actions-row.sticky{position:sticky;right:0;opacity:0;background-color:var(--panel-background);transition:opacity .2s ease-in-out}:host .table-options-menu-bar-item,:host .table-options-add-row{cursor:pointer;border:none;-webkit-user-select:none;user-select:none;min-width:34px;line-height:26px;padding:0;display:flex;align-items:center;justify-content:center}.table-options-menu{display:inline-flex;flex-direction:column;max-width:280px;background-color:var(--panel-background);border:1px solid var(--panel-divider-color);padding:calc(var(--app-pane-padding) / 6) 0}.table-options-menu .table-options-menu-item{background-color:transparent;cursor:pointer;border:none;border-radius:0;-webkit-user-select:none;user-select:none;display:flex;align-items:center;flex-direction:row;flex:1}.table-options-menu .table-options-menu-item:not(:last-child){border-block-end:1px solid var(--panel-divider-color)}.table-options-menu .table-options-menu-item>span{display:flex;flex-direction:row;flex:1;justify-content:flex-end}.table-options-menu .table-options-menu-item:active{background-color:var(--item-focus-border-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i3.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "directive", type: CdkMenu, selector: "[cdkMenu]", outputs: ["closed"], exportAs: ["cdkMenu"] }, { kind: "ngmodule", type: CdkTableModule }, { kind: "component", type: i4.CdkTable, selector: "cdk-table, table[cdk-table]", inputs: ["trackBy", "dataSource", "multiTemplateDataRows", "fixedLayout"], outputs: ["contentChanged"], exportAs: ["cdkTable"] }, { kind: "directive", type: i4.CdkRowDef, selector: "[cdkRowDef]", inputs: ["cdkRowDefColumns", "cdkRowDefWhen"] }, { kind: "directive", type: i4.CdkCellDef, selector: "[cdkCellDef]" }, { kind: "directive", type: i4.CdkHeaderCellDef, selector: "[cdkHeaderCellDef]" }, { kind: "directive", type: i4.CdkColumnDef, selector: "[cdkColumnDef]", inputs: ["cdkColumnDef", "sticky", "stickyEnd"] }, { kind: "directive", type: i4.CdkCell, selector: "cdk-cell, td[cdk-cell]" }, { kind: "component", type: i4.CdkRow, selector: "cdk-row, tr[cdk-row]" }, { kind: "directive", type: i4.CdkHeaderCell, selector: "cdk-header-cell, th[cdk-header-cell]" }, { kind: "component", type: i4.CdkHeaderRow, selector: "cdk-header-row, tr[cdk-header-row]" }, { kind: "directive", type: i4.CdkHeaderRowDef, selector: "[cdkHeaderRowDef]", inputs: ["cdkHeaderRowDef", "cdkHeaderRowDefSticky"] }, { kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "directive", type: CdkMenuItem, selector: "[cdkMenuItem]", inputs: ["cdkMenuItemDisabled", "cdkMenuitemTypeaheadLabel"], outputs: ["cdkMenuItemTriggered"], exportAs: ["cdkMenuItem"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
896
+ }
897
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DataGridComponent, decorators: [{
898
+ type: Component,
899
+ args: [{ selector: 'yuv-data-grid', standalone: true, imports: [CommonModule, NgClass, TranslateModule, YvcIconModule, ...CDK_IMPORT], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
900
+ {
901
+ provide: NG_VALUE_ACCESSOR,
902
+ useExisting: forwardRef(() => DataGridComponent),
903
+ multi: true
904
+ },
905
+ DecimalPipe
906
+ ], host: {
907
+ class: 'yuv-data-grid'
908
+ }, template: "<header>\n <h3>{{ tableLabel() }}</h3>\n @if (!readonly()) {\n <button (click)=\"addRow()\" aria-label=\"Add Row\" class=\"table-options-add-row\">\n <yvc-icon [svg]=\"icons.add\"></yvc-icon>\n </button>\n }\n</header>\n@let displayedCol = displayedColumns();\n@let displayedColActions = displayedColumnsWithActions();\n<div class=\"table-wrapper\" [ngClass]=\"size()\">\n <table cdk-table [dataSource]=\"dataSource()\">\n <!-- Dynamic Columns -->\n @for (column of displayedCol; track $index) {\n <ng-container [cdkColumnDef]=\"column.columnDef\">\n <th class=\"sticky-column\" cdk-header-cell *cdkHeaderCellDef>{{ column.header }}</th>\n <td cdk-cell *cdkCellDef=\"let element\">{{ column.cell(element) }}</td>\n </ng-container>\n }\n\n <!-- Actions Column (Not in displayedColumns) -->\n <ng-container cdkColumnDef=\"actions\">\n <th class=\"actions-header sticky-column\" cdk-header-cell *cdkHeaderCellDef></th>\n <td class=\"actions-row sticky\" cdk-cell *cdkCellDef=\"let element\">\n <!-- Only show the button in the last (empty) row -->\n @if (!readonly()) {\n <button\n aria-label=\"Edit Row\"\n class=\"table-options-menu-bar-item\"\n cdkMenuItem\n (cdkMenuOpened)=\"onMenuTriggert(element)\"\n (cdkMenuClosed)=\"onMenuTriggert(null)\"\n [cdkMenuTriggerFor]=\"options\"\n [cdkMenuTriggerData]=\"{ element: element }\"\n >\n <yvc-icon [svg]=\"icons.more\"></yvc-icon>\n </button>\n }\n </td>\n </ng-container>\n\n <tr cdk-header-row *cdkHeaderRowDef=\"displayedColActions\"></tr>\n @if (!readonly()) {\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" cdk-row *cdkRowDef=\"let row; columns: displayedColActions\"></tr>\n } @else {\n <tr cdk-row *cdkRowDef=\"let row; columns: displayedColActions\"></tr>\n }\n </table>\n</div>\n<ng-template #options let-element=\"element\">\n <div class=\"table-options-menu\" cdkMenu>\n <button class=\"table-options-menu-item\" (click)=\"copyLine(element)\" cdkMenuItem>{{ 'yuv.form.element.data.grid.copy' | translate }}</button>\n <button class=\"table-options-menu-item\" cdkMenuItem (click)=\"editRow(element)\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button class=\"table-options-menu-item\" cdkMenuItem (click)=\"removeRow(element)\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n </div>\n</ng-template>\n", styles: [":root{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px}:host{border:1px solid var(--panel-divider-color)}:host header{display:flex;justify-content:space-between;background-color:var(--panel-background-grey)}:host header h3{text-align:start;-webkit-user-select:none;user-select:none;flex:0 1 auto;padding:1rem;margin:0;color:var(--text-color-caption);border-radius:2px;font-size:var(--font-caption);font-weight:400}:host.yuv-data-grid{display:block}:host.yuv-data-grid .table-wrapper{overflow:auto;position:relative;white-space:nowrap}:host.yuv-data-grid .table-wrapper.small{height:var(--table-size-small)}:host.yuv-data-grid .table-wrapper.medium{height:var(--table-size-medium)}:host.yuv-data-grid .table-wrapper.large{height:var(--table-size-large)}:host.yuv-data-grid .table-wrapper.extra-large{height:var(--table-size-extra-large)}:host.yuv-data-grid ::ng-deep .cdk-header-cell:not(:last-child){padding:.5rem 1rem}:host.yuv-data-grid ::ng-deep table{border-spacing:0}:host.yuv-data-grid ::ng-deep th{border-bottom:1px solid var(--panel-divider-color);border-right:1px solid var(--panel-divider-color);padding:.5rem 0}:host.yuv-data-grid ::ng-deep thead{background-color:var(--panel-background-grey)}:host.yuv-data-grid ::ng-deep tr.cdk-row{cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease-in-out}:host.yuv-data-grid ::ng-deep tr.cdk-row:hover td{border-top:1px solid var(--panel-background-grey);border-bottom:1px solid var(--panel-background-grey)}:host.yuv-data-grid ::ng-deep tr.cdk-row:hover:has(.actions-row) td.cdk-cell.actions-row.sticky{opacity:1}:host.yuv-data-grid ::ng-deep tr.cdk-row.selected-row{color:var(--text-color-hint)}:host.yuv-data-grid ::ng-deep tr.cdk-row td{border-bottom:1px solid transparent;border-top:1px solid transparent}:host.yuv-data-grid ::ng-deep tr.cdk-row td:not(:last-child){padding:.5rem 1rem}:host.yuv-data-grid ::ng-deep .cdk-table .cdk-header-row th[role=columnheader]{font-weight:500}:host.yuv-data-grid th.cdk-header-cell.sticky-column{position:sticky;top:0;z-index:1;background-color:var(--panel-background-grey)}:host.yuv-data-grid td.cdk-cell.actions-row.sticky{position:sticky;right:0;opacity:0;background-color:var(--panel-background);transition:opacity .2s ease-in-out}:host .table-options-menu-bar-item,:host .table-options-add-row{cursor:pointer;border:none;-webkit-user-select:none;user-select:none;min-width:34px;line-height:26px;padding:0;display:flex;align-items:center;justify-content:center}.table-options-menu{display:inline-flex;flex-direction:column;max-width:280px;background-color:var(--panel-background);border:1px solid var(--panel-divider-color);padding:calc(var(--app-pane-padding) / 6) 0}.table-options-menu .table-options-menu-item{background-color:transparent;cursor:pointer;border:none;border-radius:0;-webkit-user-select:none;user-select:none;display:flex;align-items:center;flex-direction:row;flex:1}.table-options-menu .table-options-menu-item:not(:last-child){border-block-end:1px solid var(--panel-divider-color)}.table-options-menu .table-options-menu-item>span{display:flex;flex-direction:row;flex:1;justify-content:flex-end}.table-options-menu .table-options-menu-item:active{background-color:var(--item-focus-border-color)}\n"] }]
909
+ }] });
910
+
911
+ class DatetimeComponent {
912
+ constructor() {
913
+ this.translate = inject(TranslateService$1);
914
+ this.value = null;
915
+ this.locale = this.translate.currentLang;
916
+ /**
917
+ * Whether or not to allow only values in the future (default: false)
918
+ */
919
+ this.onlyFutureDates = false;
920
+ /**
921
+ * Will prevent the input from being changed (default: false)
922
+ */
923
+ this.readonly = false;
924
+ /**
925
+ * Enables setting time as well (default: false)
926
+ */
927
+ this.withTime = false;
928
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
929
+ this.propagateChange = (fn) => { };
930
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
931
+ this.validationChange = () => { };
932
+ this._setLabels();
933
+ this.translate.onLangChange.subscribe((e) => (this.locale = e.lang));
934
+ }
935
+ _setLabels() {
936
+ this.labels = {
937
+ calendarApply: this.translate.instant('yuv.form.element.datetime.calendar.select'),
938
+ calendarCancel: this.translate.instant('yuv.form.element.datetime.calendar.cancel'),
939
+ shortcut: { today: this.translate.instant('yuv.form.element.datetime.calendar.today') }
940
+ };
941
+ }
942
+ writeValue(value) {
943
+ if (typeof value === 'string') {
944
+ value = new Date(value);
945
+ this.propagateChange(value);
946
+ }
947
+ this.value = value || null;
948
+ }
949
+ registerOnChange(fn) {
950
+ this.propagateChange = fn;
951
+ }
952
+ registerOnValidatorChange(fn) {
953
+ this.validationChange = fn;
954
+ }
955
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
956
+ registerOnTouched() { }
957
+ onValueChange(e) {
958
+ this.propagateChange(e);
959
+ }
960
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatetimeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
961
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DatetimeComponent, isStandalone: true, selector: "yuv-datetime", inputs: { onlyFutureDates: "onlyFutureDates", readonly: "readonly", withTime: "withTime" }, providers: [
962
+ {
963
+ provide: NG_VALUE_ACCESSOR,
964
+ useExisting: forwardRef(() => DatetimeComponent),
965
+ multi: true
966
+ }
967
+ ], ngImport: i0, template: "<yvc-datepicker #picker [calendar]=\"true\" [disabled]=\"readonly\" [locale]=\"locale\" [withTime]=\"withTime\" [labels]=\"labels!\"\n [onlyFutureDates]=\"onlyFutureDates\"\n [ngModelOptions]=\"{standalone: true}\" [(ngModel)]=\"value\"\n (ngModelChange)=\"onValueChange($event)\"></yvc-datepicker>", styles: [":host{display:flex}:host yvc-datepicker{flex:1}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: YvcDatepickerModule }, { kind: "component", type: i2$2.Datepicker, selector: "yvc-datepicker", inputs: ["calendar", "readonly", "hour12", "locale", "labels", "withTime", "onlyFutureDates", "minDate", "maxDate", "disabled"] }] }); }
968
+ }
969
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatetimeComponent, decorators: [{
970
+ type: Component,
971
+ args: [{ selector: 'yuv-datetime', standalone: true, imports: [FormsModule, YvcDatepickerModule, DatetimeComponent], providers: [
972
+ {
973
+ provide: NG_VALUE_ACCESSOR,
974
+ useExisting: forwardRef(() => DatetimeComponent),
975
+ multi: true
976
+ }
977
+ ], template: "<yvc-datepicker #picker [calendar]=\"true\" [disabled]=\"readonly\" [locale]=\"locale\" [withTime]=\"withTime\" [labels]=\"labels!\"\n [onlyFutureDates]=\"onlyFutureDates\"\n [ngModelOptions]=\"{standalone: true}\" [(ngModel)]=\"value\"\n (ngModelChange)=\"onValueChange($event)\"></yvc-datepicker>", styles: [":host{display:flex}:host yvc-datepicker{flex:1}\n"] }]
978
+ }], ctorParameters: () => [], propDecorators: { onlyFutureDates: [{
979
+ type: Input
980
+ }], readonly: [{
981
+ type: Input
982
+ }], withTime: [{
983
+ type: Input
984
+ }] } });
985
+
986
+ class DatetimeRangeComponent {
987
+ constructor() {
988
+ this.fb = inject(FormBuilder);
989
+ /**
990
+ * Enables setting time as well (default: false)
991
+ */
992
+ this.withTime = false;
993
+ /**
994
+ * Will prevent the input from being changed (default: false)
995
+ */
996
+ this.readonly = false;
997
+ this.operator = 'eq';
998
+ this.rangeForm = this.fb.group({
999
+ dateValue: [undefined, Validators.required],
1000
+ dateValueFrom: []
1001
+ });
1002
+ this._isValid = true;
1003
+ // options for search situation
1004
+ this.availableSearchOptions = [
1005
+ { label: OperatorLabel.EQUAL, value: Operator.EQUAL },
1006
+ { label: OperatorLabel.GREATER_OR_EQUAL, value: Operator.GREATER_OR_EQUAL },
1007
+ { label: OperatorLabel.LESS_OR_EQUAL, value: Operator.LESS_OR_EQUAL },
1008
+ { label: OperatorLabel.INTERVAL_INCLUDE_BOTH, value: Operator.INTERVAL_INCLUDE_BOTH }
1009
+ ];
1010
+ // the selected search option
1011
+ this.searchOption = this.availableSearchOptions[1].value;
1012
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
1013
+ this.propagateChange = (_) => { };
1014
+ }
1015
+ writeValue(value) {
1016
+ if (value && (value.firstValue || value.secondValue)) {
1017
+ const match = this.availableSearchOptions.find((o) => o.value === value.operator);
1018
+ this.searchOption = match ? match.value : this.availableSearchOptions[0].value;
1019
+ this.value = value;
1020
+ this.rangeForm.patchValue({
1021
+ dateValueFrom: value.secondValue && value.firstValue,
1022
+ dateValue: value.secondValue || value.firstValue
1023
+ });
1024
+ }
1025
+ else {
1026
+ this.searchOption = this.availableSearchOptions[0].value;
1027
+ this.value = undefined;
1028
+ this.rangeForm.reset();
1029
+ }
1030
+ }
1031
+ registerOnChange(fn) {
1032
+ this.propagateChange = fn;
1033
+ }
1034
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
1035
+ registerOnTouched(fn) { }
1036
+ onValueChange() {
1037
+ const dateValue = this.rangeForm.value.dateValue || undefined;
1038
+ if (this.searchOption === Operator.INTERVAL_INCLUDE_BOTH) {
1039
+ const dateValueFrom = this.rangeForm.value.dateValueFrom || undefined;
1040
+ if (dateValueFrom || dateValue) {
1041
+ this._isValid = this.rangeForm.valid && !!dateValueFrom && !!dateValue;
1042
+ this.value = !this._isValid
1043
+ ? // {
1044
+ // operator: this.searchOption,
1045
+ // firstValue: undefined,
1046
+ // secondValue: undefined
1047
+ // }
1048
+ undefined
1049
+ : {
1050
+ operator: this.searchOption,
1051
+ firstValue: dateValueFrom,
1052
+ secondValue: dateValue
1053
+ };
1054
+ }
1055
+ }
1056
+ else {
1057
+ this._isValid = this.rangeForm.valid;
1058
+ this.value = !this._isValid
1059
+ ? // {
1060
+ // operator: this.searchOption,
1061
+ // firstValue: undefined,
1062
+ // secondValue: undefined
1063
+ // }
1064
+ undefined
1065
+ : {
1066
+ operator: this.searchOption,
1067
+ firstValue: dateValue,
1068
+ secondValue: undefined
1069
+ };
1070
+ }
1071
+ this.propagateChange(this.value);
1072
+ }
1073
+ validate() {
1074
+ let err;
1075
+ if (this.searchOption === Operator.EQUAL) {
1076
+ err = {
1077
+ datecontrol: {
1078
+ valid: false
1079
+ }
1080
+ };
1081
+ }
1082
+ else {
1083
+ // make sure that on ranges, the first value is earlier than the last
1084
+ if (this.searchOption === Operator.INTERVAL_INCLUDE_BOTH && this.value && this.value.firstValue && this.value.secondValue) {
1085
+ this._isValid = new Date(this.value.firstValue).getTime() < new Date(this.value.secondValue).getTime();
1086
+ err = {
1087
+ daterangeorder: {
1088
+ valid: false
1089
+ }
1090
+ };
1091
+ }
1092
+ else {
1093
+ err = {
1094
+ daterange: {
1095
+ valid: false
1096
+ }
1097
+ };
1098
+ }
1099
+ }
1100
+ return this.situation === Situation.SEARCH || this._isValid ? null : err;
1101
+ }
1102
+ ngOnInit() {
1103
+ this.rangeForm.valueChanges.subscribe(() => this.onValueChange());
1104
+ }
1105
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatetimeRangeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1106
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: DatetimeRangeComponent, isStandalone: true, selector: "yuv-datetime-range", inputs: { withTime: "withTime", readonly: "readonly", operator: "operator", situation: "situation" }, providers: [
1107
+ {
1108
+ provide: NG_VALUE_ACCESSOR,
1109
+ useExisting: forwardRef(() => DatetimeRangeComponent),
1110
+ multi: true
1111
+ },
1112
+ {
1113
+ provide: NG_VALIDATORS,
1114
+ useExisting: forwardRef(() => DatetimeRangeComponent),
1115
+ multi: true
1116
+ }
1117
+ ], ngImport: i0, template: "<form class=\"eo-datetime-range\" [formGroup]=\"rangeForm\">\n @if (searchOption === 'gtelte') {\n <yuv-datetime [withTime]=\"withTime\" formControlName=\"dateValueFrom\"></yuv-datetime>\n }\n <yvc-dropdown\n [disableClearButton]=\"true\"\n [(ngModel)]=\"searchOption\"\n (ngModelChange)=\"onValueChange()\"\n [ngModelOptions]=\"{ standalone: true }\"\n [options]=\"availableSearchOptions\"\n ></yvc-dropdown>\n\n <yuv-datetime [withTime]=\"withTime\" formControlName=\"dateValue\"></yuv-datetime>\n</form>\n", styles: [":host form{display:flex;flex-flow:row nowrap;gap:3px}:host form yuv-datetime{flex:1 1 auto}:host form yvc-dropdown{--yvc-form-element-border-color: var(--text-color-hint);--yvc-form-element-focus-border-color: var(--color-accent);padding:0;min-width:auto;border-radius:2px;background-color:var(--list-item-hover-background)}:host form yvc-dropdown:hover{background-color:var(--list-item-selected-background)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: YvcDropdownModule }, { kind: "component", type: i1$1.Dropdown, selector: "yvc-dropdown", inputs: ["options", "filter", "disabled", "multiple", "disableClearButton"], outputs: ["onDropdownOptionsClose"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: DatetimeComponent, selector: "yuv-datetime", inputs: ["onlyFutureDates", "readonly", "withTime"] }] }); }
1118
+ }
1119
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatetimeRangeComponent, decorators: [{
1120
+ type: Component,
1121
+ args: [{ selector: 'yuv-datetime-range', standalone: true, imports: [CommonModule, FormsModule, YvcDropdownModule, ReactiveFormsModule, DatetimeComponent], providers: [
1122
+ {
1123
+ provide: NG_VALUE_ACCESSOR,
1124
+ useExisting: forwardRef(() => DatetimeRangeComponent),
1125
+ multi: true
1126
+ },
1127
+ {
1128
+ provide: NG_VALIDATORS,
1129
+ useExisting: forwardRef(() => DatetimeRangeComponent),
1130
+ multi: true
1131
+ }
1132
+ ], template: "<form class=\"eo-datetime-range\" [formGroup]=\"rangeForm\">\n @if (searchOption === 'gtelte') {\n <yuv-datetime [withTime]=\"withTime\" formControlName=\"dateValueFrom\"></yuv-datetime>\n }\n <yvc-dropdown\n [disableClearButton]=\"true\"\n [(ngModel)]=\"searchOption\"\n (ngModelChange)=\"onValueChange()\"\n [ngModelOptions]=\"{ standalone: true }\"\n [options]=\"availableSearchOptions\"\n ></yvc-dropdown>\n\n <yuv-datetime [withTime]=\"withTime\" formControlName=\"dateValue\"></yuv-datetime>\n</form>\n", styles: [":host form{display:flex;flex-flow:row nowrap;gap:3px}:host form yuv-datetime{flex:1 1 auto}:host form yvc-dropdown{--yvc-form-element-border-color: var(--text-color-hint);--yvc-form-element-focus-border-color: var(--color-accent);padding:0;min-width:auto;border-radius:2px;background-color:var(--list-item-hover-background)}:host form yvc-dropdown:hover{background-color:var(--list-item-selected-background)}\n"] }]
1133
+ }], propDecorators: { withTime: [{
1134
+ type: Input
1135
+ }], readonly: [{
1136
+ type: Input
1137
+ }], operator: [{
1138
+ type: Input
1139
+ }], situation: [{
1140
+ type: Input
1141
+ }] } });
1142
+
1143
+ /**
1144
+ * Creates form input for ranges of numeric values.
1145
+ *
1146
+ * Implements `ControlValueAccessor` so it can be used within Angular forms.
1147
+ *
1148
+ * @example
1149
+ * <yuv-number-range [scale]="2"></yuv-number-range>
1150
+ *
1151
+ */
1152
+ class NumberRangeComponent {
1153
+ constructor() {
1154
+ /**
1155
+ * Set to true to group number by pattern
1156
+ */
1157
+ this.grouping = false;
1158
+ /**
1159
+ * Will prevent the input from being changed (default: false)
1160
+ */
1161
+ this.readonly = false;
1162
+ /**
1163
+ * classification property adds some semantics to the value of this component.
1164
+ * If you provide a value of `filesize` numbers typed into the control will be
1165
+ * handled like file sizes (calculates differnt units)
1166
+ */
1167
+ this.classifications = [];
1168
+ this.rangeForm = new UntypedFormGroup({
1169
+ numberValue: new UntypedFormControl(),
1170
+ numberValueFrom: new UntypedFormControl()
1171
+ });
1172
+ this.isValid = true;
1173
+ // options for search situation
1174
+ this.availableSearchOptions = [
1175
+ { label: OperatorLabel.EQUAL, value: Operator.EQUAL },
1176
+ { label: OperatorLabel.GREATER_OR_EQUAL, value: Operator.GREATER_OR_EQUAL },
1177
+ { label: OperatorLabel.LESS_OR_EQUAL, value: Operator.LESS_OR_EQUAL },
1178
+ { label: OperatorLabel.INTERVAL_INCLUDE_BOTH, value: Operator.INTERVAL_INCLUDE_BOTH }
1179
+ ];
1180
+ // the selected search option
1181
+ this.searchOption = this.availableSearchOptions[1].value;
1182
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
1183
+ this.propagateChange = (_) => { };
1184
+ this.rangeForm.valueChanges.forEach(() => {
1185
+ this.onValueChange();
1186
+ });
1187
+ }
1188
+ writeValue(value) {
1189
+ if (value && (value.firstValue != null || value.secondValue != null)) {
1190
+ const match = this.availableSearchOptions.find((o) => o.value === value.operator);
1191
+ this.searchOption = match ? match.value : this.availableSearchOptions[0].value;
1192
+ this.value = value;
1193
+ if (value.secondValue == null) {
1194
+ this.rangeForm.setValue({
1195
+ numberValueFrom: null,
1196
+ numberValue: value.firstValue != null ? value.firstValue : null
1197
+ });
1198
+ }
1199
+ else {
1200
+ this.rangeForm.setValue({
1201
+ numberValueFrom: value.firstValue != null ? value.firstValue : null,
1202
+ numberValue: value.secondValue
1203
+ });
1204
+ }
1205
+ }
1206
+ else {
1207
+ this.searchOption = this.availableSearchOptions[0].value;
1208
+ this.value = undefined;
1209
+ this.rangeForm.reset();
624
1210
  }
625
1211
  }
626
1212
  registerOnChange(fn) {
@@ -687,7 +1273,7 @@ class NumberRangeComponent {
687
1273
  useExisting: forwardRef(() => NumberRangeComponent),
688
1274
  multi: true
689
1275
  }
690
- ], ngImport: i0, template: "<form class=\"yuv-number-range\" [formGroup]=\"rangeForm\">\n @if(searchOption === 'gtelte'){\n <yuv-number\n class=\"first\"\n [readonly]=\"readonly\"\n [scale]=\"scale\"\n [precision]=\"precision\"\n [grouping]=\"grouping\"\n [groupPattern]=\"pattern\"\n formControlName=\"numberValueFrom\"\n [classifications]=\"classifications\"\n [minValue]=\"minValue\"\n [maxValue]=\"maxValue\"\n ></yuv-number>}\n\n <yvc-dropdown\n class=\"no-trigger\"\n [(ngModel)]=\"searchOption\"\n (ngModelChange)=\"onValueChange()\"\n [disabled]=\"readonly\"\n [disableClearButton]=\"true\"\n [ngModelOptions]=\"{ standalone: true }\"\n [options]=\"availableSearchOptions\"\n ></yvc-dropdown>\n\n <yuv-number\n [scale]=\"scale\"\n [readonly]=\"readonly\"\n [precision]=\"precision\"\n [grouping]=\"grouping\"\n [groupPattern]=\"pattern\"\n formControlName=\"numberValue\"\n [classifications]=\"classifications\"\n [minValue]=\"minValue\"\n [maxValue]=\"maxValue\"\n >\n </yuv-number>\n</form>\n", styles: [":host{display:block}:host>form{display:flex;align-items:center}:host>form yuv-number{flex:1 1 auto}:host>form yuv-number.first ::ng-deep .input-number{text-align:right}:host>form yvc-dropdown{--yvc-form-element-border-color: var(--text-color-hint);--yvc-form-element-focus-border-color: var(--color-accent);padding:0;min-width:auto;border-radius:2px;background-color:var(--list-item-hover-background)}:host>form yvc-dropdown:hover{background-color:var(--list-item-selected-background)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: NumberComponent, selector: "yuv-number", inputs: ["scale", "precision", "grouping", "groupPattern", "readonly", "minValue", "maxValue", "classifications"] }, { kind: "ngmodule", type: YvcDropdownModule }, { kind: "component", type: i3.Dropdown, selector: "yvc-dropdown", inputs: ["options", "filter", "disabled", "multiple", "disableClearButton"], outputs: ["onDropdownOptionsClose"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
1276
+ ], ngImport: i0, template: "<form class=\"yuv-number-range\" [formGroup]=\"rangeForm\">\n @if(searchOption === 'gtelte'){\n <yuv-number\n class=\"first\"\n [readonly]=\"readonly\"\n [scale]=\"scale\"\n [precision]=\"precision\"\n [grouping]=\"grouping\"\n [groupPattern]=\"pattern\"\n formControlName=\"numberValueFrom\"\n [classifications]=\"classifications\"\n [minValue]=\"minValue\"\n [maxValue]=\"maxValue\"\n ></yuv-number>}\n\n <yvc-dropdown\n class=\"no-trigger\"\n [(ngModel)]=\"searchOption\"\n (ngModelChange)=\"onValueChange()\"\n [disabled]=\"readonly\"\n [disableClearButton]=\"true\"\n [ngModelOptions]=\"{ standalone: true }\"\n [options]=\"availableSearchOptions\"\n ></yvc-dropdown>\n\n <yuv-number\n [scale]=\"scale\"\n [readonly]=\"readonly\"\n [precision]=\"precision\"\n [grouping]=\"grouping\"\n [groupPattern]=\"pattern\"\n formControlName=\"numberValue\"\n [classifications]=\"classifications\"\n [minValue]=\"minValue\"\n [maxValue]=\"maxValue\"\n >\n </yuv-number>\n</form>\n", styles: [":host>form{display:flex;flex-flow:row nowrap;gap:3px}:host>form yuv-number{flex:1 1 auto}:host>form yvc-dropdown{--yvc-form-element-border-color: var(--text-color-hint);--yvc-form-element-focus-border-color: var(--color-accent);padding:0;min-width:auto;border-radius:2px;background-color:var(--list-item-hover-background)}:host>form yvc-dropdown:hover{background-color:var(--list-item-selected-background)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: NumberComponent, selector: "yuv-number", inputs: ["scale", "precision", "grouping", "groupPattern", "readonly", "minValue", "maxValue", "classifications"] }, { kind: "ngmodule", type: YvcDropdownModule }, { kind: "component", type: i1$1.Dropdown, selector: "yvc-dropdown", inputs: ["options", "filter", "disabled", "multiple", "disableClearButton"], outputs: ["onDropdownOptionsClose"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
691
1277
  }
692
1278
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NumberRangeComponent, decorators: [{
693
1279
  type: Component,
@@ -702,7 +1288,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
702
1288
  useExisting: forwardRef(() => NumberRangeComponent),
703
1289
  multi: true
704
1290
  }
705
- ], template: "<form class=\"yuv-number-range\" [formGroup]=\"rangeForm\">\n @if(searchOption === 'gtelte'){\n <yuv-number\n class=\"first\"\n [readonly]=\"readonly\"\n [scale]=\"scale\"\n [precision]=\"precision\"\n [grouping]=\"grouping\"\n [groupPattern]=\"pattern\"\n formControlName=\"numberValueFrom\"\n [classifications]=\"classifications\"\n [minValue]=\"minValue\"\n [maxValue]=\"maxValue\"\n ></yuv-number>}\n\n <yvc-dropdown\n class=\"no-trigger\"\n [(ngModel)]=\"searchOption\"\n (ngModelChange)=\"onValueChange()\"\n [disabled]=\"readonly\"\n [disableClearButton]=\"true\"\n [ngModelOptions]=\"{ standalone: true }\"\n [options]=\"availableSearchOptions\"\n ></yvc-dropdown>\n\n <yuv-number\n [scale]=\"scale\"\n [readonly]=\"readonly\"\n [precision]=\"precision\"\n [grouping]=\"grouping\"\n [groupPattern]=\"pattern\"\n formControlName=\"numberValue\"\n [classifications]=\"classifications\"\n [minValue]=\"minValue\"\n [maxValue]=\"maxValue\"\n >\n </yuv-number>\n</form>\n", styles: [":host{display:block}:host>form{display:flex;align-items:center}:host>form yuv-number{flex:1 1 auto}:host>form yuv-number.first ::ng-deep .input-number{text-align:right}:host>form yvc-dropdown{--yvc-form-element-border-color: var(--text-color-hint);--yvc-form-element-focus-border-color: var(--color-accent);padding:0;min-width:auto;border-radius:2px;background-color:var(--list-item-hover-background)}:host>form yvc-dropdown:hover{background-color:var(--list-item-selected-background)}\n"] }]
1291
+ ], template: "<form class=\"yuv-number-range\" [formGroup]=\"rangeForm\">\n @if(searchOption === 'gtelte'){\n <yuv-number\n class=\"first\"\n [readonly]=\"readonly\"\n [scale]=\"scale\"\n [precision]=\"precision\"\n [grouping]=\"grouping\"\n [groupPattern]=\"pattern\"\n formControlName=\"numberValueFrom\"\n [classifications]=\"classifications\"\n [minValue]=\"minValue\"\n [maxValue]=\"maxValue\"\n ></yuv-number>}\n\n <yvc-dropdown\n class=\"no-trigger\"\n [(ngModel)]=\"searchOption\"\n (ngModelChange)=\"onValueChange()\"\n [disabled]=\"readonly\"\n [disableClearButton]=\"true\"\n [ngModelOptions]=\"{ standalone: true }\"\n [options]=\"availableSearchOptions\"\n ></yvc-dropdown>\n\n <yuv-number\n [scale]=\"scale\"\n [readonly]=\"readonly\"\n [precision]=\"precision\"\n [grouping]=\"grouping\"\n [groupPattern]=\"pattern\"\n formControlName=\"numberValue\"\n [classifications]=\"classifications\"\n [minValue]=\"minValue\"\n [maxValue]=\"maxValue\"\n >\n </yuv-number>\n</form>\n", styles: [":host>form{display:flex;flex-flow:row nowrap;gap:3px}:host>form yuv-number{flex:1 1 auto}:host>form yvc-dropdown{--yvc-form-element-border-color: var(--text-color-hint);--yvc-form-element-focus-border-color: var(--color-accent);padding:0;min-width:auto;border-radius:2px;background-color:var(--list-item-hover-background)}:host>form yvc-dropdown:hover{background-color:var(--list-item-selected-background)}\n"] }]
706
1292
  }], ctorParameters: () => [], propDecorators: { scale: [{
707
1293
  type: Input
708
1294
  }], precision: [{
@@ -734,6 +1320,7 @@ class OrganizationComponent {
734
1320
  constructor() {
735
1321
  this.system = inject(SystemService);
736
1322
  this.userService = inject(UserService);
1323
+ this.translate = inject(TranslateService);
737
1324
  this.minLength = 2;
738
1325
  this.icons = {
739
1326
  organizationMulti: YUV_ICONS['group'],
@@ -772,12 +1359,12 @@ class OrganizationComponent {
772
1359
  */
773
1360
  this.withMetadata = input(false);
774
1361
  this.userSelect = new EventEmitter();
775
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1362
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
776
1363
  this.propagateChange = (_) => { };
777
1364
  }
778
1365
  set innerValue(iv) {
779
1366
  this._innerValue = iv || [];
780
- this.userSelect.emit(this._innerValue);
1367
+ this.userSelect.emit(this._innerValue.map((v) => v.user));
781
1368
  }
782
1369
  get innerValue() {
783
1370
  return this._innerValue;
@@ -819,7 +1406,7 @@ class OrganizationComponent {
819
1406
  registerOnChange(fn) {
820
1407
  this.propagateChange = fn;
821
1408
  }
822
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1409
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
823
1410
  registerOnTouched(fn) { }
824
1411
  propagate() {
825
1412
  this.propagateChange(this.#getPropagateValue());
@@ -829,16 +1416,16 @@ class OrganizationComponent {
829
1416
  ? this.withMetadata()
830
1417
  ? this.value
831
1418
  ? this._innerValue.map((v) => ({
832
- id: v.id,
833
- title: v.title
1419
+ id: v.user.id,
1420
+ title: v.user.title
834
1421
  }))
835
1422
  : this.value
836
1423
  : this.value
837
1424
  : this.withMetadata()
838
1425
  ? this.value
839
1426
  ? {
840
- id: this._innerValue[0].id,
841
- title: this._innerValue[0].title
1427
+ id: this._innerValue[0].user.id,
1428
+ title: this._innerValue[0].user.title
842
1429
  }
843
1430
  : this.value
844
1431
  : this.value;
@@ -847,17 +1434,29 @@ class OrganizationComponent {
847
1434
  this.autoCompleteInput.focusInput();
848
1435
  }
849
1436
  resolveFn(value) {
850
- const map = (value instanceof Array ? value : [value]).map((v) => {
851
- const match = this.innerValue.find((iv) => iv.id === v);
1437
+ const obs = (value instanceof Array ? value : [value]).map((v) => {
1438
+ const valueID = typeof v === 'string' ? v : v.id;
1439
+ const match = this.innerValue.find((iv) => iv.user.id === valueID);
852
1440
  return match
853
1441
  ? of(match)
854
- : this.userService.getUserById(v).pipe(catchError(() => of(new YuvUser({
855
- id: v,
856
- title: v,
857
- image: null
858
- }, undefined))));
1442
+ : this.userService.getUserById(valueID).pipe(map$1((res) => ({
1443
+ user: res,
1444
+ state: {}
1445
+ })), catchError((e) => {
1446
+ const user = new YuvUser({
1447
+ id: typeof v === 'string' ? v : v.id
1448
+ });
1449
+ user.title = typeof v === 'string' ? v : v.title;
1450
+ return of({
1451
+ user,
1452
+ state: {
1453
+ notFound: e.status === 404
1454
+ },
1455
+ titleString: e.status === 404 ? this.translate.instant('yuv.form.element.organization.user.not-found') : undefined
1456
+ });
1457
+ }));
859
1458
  });
860
- return forkJoin(map).subscribe((data) => {
1459
+ return forkJoin(obs).subscribe((data) => {
861
1460
  this.innerValue = data;
862
1461
  // setTimeout(() => this.autoCompleteInput.cd.markForCheck());
863
1462
  });
@@ -866,440 +1465,404 @@ class OrganizationComponent {
866
1465
  if (query.length >= this.minLength) {
867
1466
  this.userService.queryUser(query, this.excludeMe, this.filterRoles).subscribe({
868
1467
  next: (users) => {
869
- this.autocompleteRes = users.filter((user) => !this.innerValue.some((value) => value.id === user.id));
1468
+ this.autocompleteRes = users
1469
+ .filter((user) => !this.innerValue.some((value) => value.user.id === user.id))
1470
+ .map((user) => ({
1471
+ user: user,
1472
+ state: {}
1473
+ }));
870
1474
  this.propagateValidity(this.autocompleteRes.length > 0);
871
1475
  },
872
- error: () => {
873
- this.autocompleteRes = [];
874
- this.propagateValidity(this.autocompleteRes.length > 0);
875
- }
876
- });
877
- }
878
- else {
879
- this.autocompleteRes = [];
880
- }
881
- }
882
- // returns null when valid else the validation object
883
- validate() {
884
- return this.isValidInput ? null : { empty: { valid: false } };
885
- }
886
- propagateValidity(valid = true) {
887
- if (this.isValidInput !== valid) {
888
- this.isValidInput = valid;
889
- this.propagate();
890
- }
891
- }
892
- // handle selection changes to the model
893
- onSelect() {
894
- if (this.multiselect) {
895
- this.value = this.innerValue.map((v) => v.id);
896
- }
897
- else {
898
- // internal autocomplete control is always set to multiselect
899
- // so the resolved value is always an array
900
- this.innerValue = this.innerValue.slice(-1);
901
- this.value = this.innerValue[0].id;
902
- }
903
- this.propagate();
904
- }
905
- // handle selection changes to the model
906
- onUnselect(value) {
907
- this.innerValue = this.innerValue.filter((v) => v.id !== value.id);
908
- const _value = this.innerValue.map((v) => v.id);
909
- this.value = this.multiselect ? _value : null;
910
- if (!this.multiselect) {
911
- this.clearInnerInput();
912
- }
913
- this.propagate();
914
- }
915
- onAutoCompleteBlur() {
916
- this.clearInnerInput();
917
- }
918
- clearInnerInput() {
919
- this.autoCompleteInput.clearInput();
920
- }
921
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OrganizationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
922
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: OrganizationComponent, isStandalone: true, selector: "yuv-organization", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null }, situation: { classPropertyName: "situation", publicName: "situation", isSignal: false, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: false, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: false, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: false, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: false, isRequired: false, transformFunction: null }, appendTo: { classPropertyName: "appendTo", publicName: "appendTo", isSignal: false, isRequired: false, transformFunction: null }, excludeMe: { classPropertyName: "excludeMe", publicName: "excludeMe", isSignal: false, isRequired: false, transformFunction: null }, withMetadata: { classPropertyName: "withMetadata", publicName: "withMetadata", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { userSelect: "userSelect" }, host: { listeners: { "keydown.enter": "onKeydownHandler($event)" }, properties: { "class.inputDisabled": "this._inputDisabled" } }, providers: [
923
- {
924
- provide: NG_VALUE_ACCESSOR,
925
- useExisting: forwardRef(() => OrganizationComponent),
926
- multi: true
927
- },
928
- {
929
- provide: NG_VALIDATORS,
930
- useExisting: forwardRef(() => OrganizationComponent),
931
- multi: true
932
- }
933
- ], viewQueries: [{ propertyName: "autoCompleteInput", first: true, predicate: ["autocomplete"], descendants: true }], ngImport: i0, template: "<yvc-autocomplete\n [(ngModel)]=\"innerValue\"\n #autocomplete\n (suggestionSelect)=\"onSelect()\"\n [placeholder]=\"placeholder\"\n (suggestionUnselect)=\"onUnselect($event)\"\n (blur)=\"onAutoCompleteBlur()\"\n [disabled]=\"readonly\"\n [autocompleteValues]=\"autocompleteRes\"\n field=\"id\"\n [forceSelection]=\"true\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #autocompleteOptionTemplate let-item>\n <span class=\"chip\">{{ item.title }}</span>\n </ng-template>\n \n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n <span class=\"chip\">{{ item.title }}</span>\n </ng-template>\n</yvc-autocomplete>\n\n<yvc-icon\n class=\"classify\"\n [title]=\"'yuv.form.element.organization.classify.icon.title' | translate\"\n [svg]=\"multiselect ? icons.organizationMulti : icons.organization\"\n (click)=\"focusInput()\"\n></yvc-icon>\n", styles: [":host{display:flex;align-items:center}:host ::ng-deep .chip{--yvc-form-element-border-color: var(--text-color-hint)}:host yvc-autocomplete{flex:1;--yvc-form-element-focus-border-color: transparent;--yvc-form-element-focus-outline-color: transparent}:host yvc-icon.classify{width:18px;height:18px;padding:calc(var(--app-pane-padding) / 8);color:var(--text-color-hint)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: YvcAutocompleteModule }, { kind: "component", type: i2$2.AutoComplete, selector: "yvc-autocomplete", inputs: ["field", "placeholder", "minLength", "multiple", "typeahead", "distinctValues", "forceSelection", "autocompleteValues", "disabled"], outputs: ["autocompleteFnc", "blur", "focus", "suggestionUnselect", "suggestionSelect"] }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i3$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] }); }
934
- }
935
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OrganizationComponent, decorators: [{
936
- type: Component,
937
- args: [{ selector: 'yuv-organization', standalone: true, imports: [CommonModule, FormsModule, YvcAutocompleteModule, YvcIconModule, TranslateModule], providers: [
938
- {
939
- provide: NG_VALUE_ACCESSOR,
940
- useExisting: forwardRef(() => OrganizationComponent),
941
- multi: true
942
- },
943
- {
944
- provide: NG_VALIDATORS,
945
- useExisting: forwardRef(() => OrganizationComponent),
946
- multi: true
947
- }
948
- ], template: "<yvc-autocomplete\n [(ngModel)]=\"innerValue\"\n #autocomplete\n (suggestionSelect)=\"onSelect()\"\n [placeholder]=\"placeholder\"\n (suggestionUnselect)=\"onUnselect($event)\"\n (blur)=\"onAutoCompleteBlur()\"\n [disabled]=\"readonly\"\n [autocompleteValues]=\"autocompleteRes\"\n field=\"id\"\n [forceSelection]=\"true\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #autocompleteOptionTemplate let-item>\n <span class=\"chip\">{{ item.title }}</span>\n </ng-template>\n \n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n <span class=\"chip\">{{ item.title }}</span>\n </ng-template>\n</yvc-autocomplete>\n\n<yvc-icon\n class=\"classify\"\n [title]=\"'yuv.form.element.organization.classify.icon.title' | translate\"\n [svg]=\"multiselect ? icons.organizationMulti : icons.organization\"\n (click)=\"focusInput()\"\n></yvc-icon>\n", styles: [":host{display:flex;align-items:center}:host ::ng-deep .chip{--yvc-form-element-border-color: var(--text-color-hint)}:host yvc-autocomplete{flex:1;--yvc-form-element-focus-border-color: transparent;--yvc-form-element-focus-outline-color: transparent}:host yvc-icon.classify{width:18px;height:18px;padding:calc(var(--app-pane-padding) / 8);color:var(--text-color-hint)}\n"] }]
949
- }], propDecorators: { autoCompleteInput: [{
950
- type: ViewChild,
951
- args: ['autocomplete']
952
- }], onKeydownHandler: [{
953
- type: HostListener,
954
- args: ['keydown.enter', ['$event']]
955
- }], _inputDisabled: [{
956
- type: HostBinding,
957
- args: ['class.inputDisabled']
958
- }], placeholder: [{
959
- type: Input
960
- }], situation: [{
961
- type: Input
962
- }], multiselect: [{
963
- type: Input
964
- }], classifications: [{
965
- type: Input
966
- }], readonly: [{
967
- type: Input
968
- }], autofocus: [{
969
- type: Input
970
- }], appendTo: [{
971
- type: Input
972
- }], excludeMe: [{
973
- type: Input
974
- }], userSelect: [{
975
- type: Output
976
- }] } });
977
-
978
- /**
979
- * Creates form input for strings. Based on the input values different kinds of inputs will be generated.
980
- *
981
- * Implements `ControlValueAccessor` so it can be used within Angular forms.
982
- *
983
- * @example
984
- * <!-- string input validating input to be between 5 and 10 characters -->
985
- * <yuv-string [minLength]="5" [maxLength]="10"></yuv-string>
986
- *
987
- * <!-- string input that only allow digits -->
988
- * <yuv-string [regex]="[0-9]*"></yuv-string>
989
- *
990
- * <!-- string input rendering a large textarea -->
991
- * <yuv-string [rows]="10"></yuv-string>
992
- *
993
- */
994
- class StringComponent {
995
- constructor() {
996
- this.iconsService = inject(IconService);
997
- this.elementRef = inject(ElementRef);
998
- this.classifiytionIcons = {
999
- email: this.iconsService.getIcon(ClassificationPrefix.EMAIL_ICON) || '',
1000
- url: this.iconsService.getIcon(ClassificationPrefix.URL_ICON) || '',
1001
- phone: this.iconsService.getIcon(ClassificationPrefix.PHONE_ICON) || ''
1002
- };
1003
- // provides all css variables defined by |yuuvis/comonents
1004
- this.fe = true;
1005
- /**
1006
- * Indicator that multiple strings could be inserted, they will be rendered as chips (default: false).
1007
- */
1008
- this.multiselect = false;
1009
- /**
1010
- * Will prevent the input from being changed (default: false)
1011
- */
1012
- this.readonly = false;
1013
- /**
1014
- * Enable autofucus for the input (default: false)
1015
- */
1016
- this.autofocus = false;
1017
- this.valid = false;
1018
- this.validationErrors = [];
1019
- this._classifications = [];
1020
- this.propagateChange = (_) => { };
1021
- }
1022
- /**
1023
- * Additional semantics for the form element. Possible values are
1024
- * `email` (validates and creates a link to send an email once there
1025
- * is a valid email address) and `url` (validates and creates a link
1026
- * to an URL typed into the form element).
1027
- */
1028
- set classifications(c) {
1029
- this._classifications = c;
1030
- if (c && c.length) {
1031
- if (c.includes(Classification.STRING_EMAIL)) {
1032
- this.classify = {
1033
- hrefPrefix: ClassificationPrefix.EMAIL,
1034
- icon: this.classifiytionIcons.email
1035
- };
1036
- }
1037
- else if (c.includes(Classification.STRING_URL)) {
1038
- this.classify = {
1039
- hrefPrefix: ClassificationPrefix.URL,
1040
- icon: this.classifiytionIcons.url
1041
- };
1042
- }
1043
- else if (c.includes(Classification.STRING_PHONE)) {
1044
- this.classify = {
1045
- hrefPrefix: ClassificationPrefix.PHONE,
1046
- icon: this.classifiytionIcons.phone
1047
- };
1048
- }
1049
- }
1050
- }
1051
- get classifications() {
1052
- return this._classifications;
1053
- }
1054
- propagate() {
1055
- this.propagateChange(this.value);
1056
- }
1057
- writeValue(value) {
1058
- this.formatedValue = Utils.formatMailTo(value, this.classify?.hrefPrefix === ClassificationPrefix.EMAIL);
1059
- this.value = value || null;
1060
- }
1061
- registerOnChange(fn) {
1062
- this.propagateChange = fn;
1063
- }
1064
- registerOnTouched() { }
1065
- onValueChange(val) {
1066
- this.maxEntryCountIfInvalid = undefined;
1067
- this.validationErrors = [];
1068
- if (Utils.isEmpty(val)) {
1069
- this.value = null;
1070
- this.propagate();
1071
- return;
1072
- }
1073
- const multiCheck = (check) => !!(this.multiselect ? val : [val]).find((v) => check(v));
1074
- // validate regular expression
1075
- if (this.regex && multiCheck((v) => !RegExp(this.regex).test(v))) {
1076
- this.validationErrors.push({ key: 'regex' });
1077
- }
1078
- // validate classification settings
1079
- if (this.classifications && this.classifications.length) {
1080
- this.classifications.forEach((c) => {
1081
- if (multiCheck((v) => !this.validateClassification(v, c))) {
1082
- this.validationErrors.push({ key: 'classification' + c });
1083
- }
1084
- });
1085
- }
1086
- // validate min length
1087
- if (!Utils.isEmpty(this.minLength) && multiCheck((v) => v.length < this.minLength)) {
1088
- this.validationErrors.push({ key: 'minlength', params: { minLength: this.minLength } });
1089
- }
1090
- // validate max length
1091
- if (!Utils.isEmpty(this.maxLength) && multiCheck((v) => v.length > this.maxLength)) {
1092
- this.validationErrors.push({ key: 'maxlength', params: { maxLength: this.maxLength } });
1093
- }
1094
- // validate invalid if only whitespaces
1095
- if (multiCheck((v) => v.length > 0 && !v.trim().length)) {
1096
- this.validationErrors.push({ key: 'onlyWhitespaces' });
1097
- }
1098
- if (this.validationErrors.length && this.multiselect && this.value) {
1099
- // Setting maxEntryCountIfInvalid to the actual length of the value array to prevent the user to add more entries.
1100
- this.maxEntryCountIfInvalid = this.value.length;
1101
- }
1102
- this.formatedValue = Utils.formatMailTo(val, this.classify?.hrefPrefix === ClassificationPrefix.EMAIL);
1103
- this.propagate();
1104
- }
1105
- onBlur() {
1106
- if (this.trimValue()) {
1107
- this.propagate();
1108
- }
1109
- }
1110
- /**
1111
- * Trims the current value and returns wether or not it has been trimmed
1112
- */
1113
- trimValue() {
1114
- if (this.value) {
1115
- if (this.multiselect) {
1116
- const lengthBefore = this.value.join('').length;
1117
- this.value = this.value.map((v) => v.trim());
1118
- return this.value.join('').length !== lengthBefore;
1119
- }
1120
- else {
1121
- const lengthBefore = this.value.length;
1122
- this.value = this.value.trim();
1123
- return this.value.length !== lengthBefore;
1124
- }
1125
- }
1126
- return false;
1127
- }
1128
- validateClassification(string, classification) {
1129
- if (this.situation === Situation.SEARCH) {
1130
- return true;
1476
+ error: () => {
1477
+ this.autocompleteRes = [];
1478
+ this.propagateValidity(this.autocompleteRes.length > 0);
1479
+ }
1480
+ });
1131
1481
  }
1132
1482
  else {
1133
- let pattern;
1134
- if (classification === Classification.STRING_EMAIL) {
1135
- pattern =
1136
- /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
1137
- }
1138
- else if (classification === Classification.STRING_URL) {
1139
- pattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)?([\w.,@?^=%&amp;:\/~+#-]*[\w@?^=%&amp;\/~+#-])?/;
1140
- }
1141
- else if (classification === Classification.STRING_PHONE) {
1142
- pattern = /^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-x\s\./0-9]*$/g;
1143
- }
1144
- return pattern ? pattern.test(string) : true;
1483
+ this.autocompleteRes = [];
1145
1484
  }
1146
1485
  }
1147
- /**
1148
- * returns null when valid else the validation object
1149
- */
1486
+ // returns null when valid else the validation object
1150
1487
  validate() {
1151
- if (this.validationErrors.length) {
1152
- this.valid = false;
1153
- return Utils.arrayToObject(this.validationErrors, 'key', (err) => ({ valid: false, ...err }));
1488
+ return this.isValidInput ? null : { empty: { valid: false } };
1489
+ }
1490
+ propagateValidity(valid = true) {
1491
+ if (this.isValidInput !== valid) {
1492
+ this.isValidInput = valid;
1493
+ this.propagate();
1494
+ }
1495
+ }
1496
+ // handle selection changes to the model
1497
+ onSelect() {
1498
+ if (this.multiselect) {
1499
+ this.value = this.innerValue.map((v) => v.user.id);
1154
1500
  }
1155
1501
  else {
1156
- this.valid = true;
1157
- return null;
1502
+ // internal autocomplete control is always set to multiselect
1503
+ // so the resolved value is always an array
1504
+ this.innerValue = this.innerValue.slice(-1);
1505
+ this.value = this.innerValue[0].user.id;
1158
1506
  }
1507
+ this.propagate();
1159
1508
  }
1160
- ngAfterViewInit() {
1161
- if (this.autofocus) {
1162
- if (!this.multiselect) {
1163
- const el = this.elementRef.nativeElement.querySelector(this.rows && this.rows > 1 ? 'textarea' : 'input');
1164
- if (el)
1165
- el.focus();
1166
- }
1509
+ // handle selection changes to the model
1510
+ onUnselect(value) {
1511
+ this.innerValue = this.innerValue.filter((v) => v.user.id !== value.id);
1512
+ const _value = this.innerValue.map((v) => v.user.id);
1513
+ this.value = this.multiselect ? _value : null;
1514
+ if (!this.multiselect) {
1515
+ this.clearInnerInput();
1167
1516
  }
1517
+ this.propagate();
1168
1518
  }
1169
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StringComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1170
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: StringComponent, isStandalone: true, selector: "yuv-string", inputs: { multiselect: "multiselect", rows: "rows", readonly: "readonly", autofocus: "autofocus", classifications: "classifications", situation: "situation", regex: "regex", minLength: "minLength", maxLength: "maxLength" }, host: { properties: { "class.yvc-form-element": "this.fe" } }, providers: [
1519
+ onAutoCompleteBlur() {
1520
+ this.clearInnerInput();
1521
+ }
1522
+ clearInnerInput() {
1523
+ this.autoCompleteInput.clearInput();
1524
+ }
1525
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OrganizationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1526
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: OrganizationComponent, isStandalone: true, selector: "yuv-organization", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null }, situation: { classPropertyName: "situation", publicName: "situation", isSignal: false, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: false, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: false, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: false, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: false, isRequired: false, transformFunction: null }, appendTo: { classPropertyName: "appendTo", publicName: "appendTo", isSignal: false, isRequired: false, transformFunction: null }, excludeMe: { classPropertyName: "excludeMe", publicName: "excludeMe", isSignal: false, isRequired: false, transformFunction: null }, withMetadata: { classPropertyName: "withMetadata", publicName: "withMetadata", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { userSelect: "userSelect" }, host: { listeners: { "keydown.enter": "onKeydownHandler($event)" }, properties: { "class.inputDisabled": "this._inputDisabled" } }, providers: [
1171
1527
  {
1172
1528
  provide: NG_VALUE_ACCESSOR,
1173
- useExisting: forwardRef(() => StringComponent),
1529
+ useExisting: forwardRef(() => OrganizationComponent),
1174
1530
  multi: true
1175
1531
  },
1176
1532
  {
1177
1533
  provide: NG_VALIDATORS,
1178
- useExisting: forwardRef(() => StringComponent),
1534
+ useExisting: forwardRef(() => OrganizationComponent),
1179
1535
  multi: true
1180
1536
  }
1181
- ], ngImport: i0, template: "@if ((!rows || rows <= 1) && !multiselect) {\n <input type=\"text\" (blur)=\"onBlur()\" [readonly]=\"readonly\" [(ngModel)]=\"value\" (ngModelChange)=\"onValueChange($event)\" />\n}\n@else if ((!rows || rows <= 1) && multiselect) {\n <!-- single line input with multiselect-->\n <yvc-chips\n [(ngModel)]=\"value\"\n [disabled]=\"readonly\"\n [max]=\"maxEntryCountIfInvalid\"\n (onBlur)=\"onBlur()\"\n (ngModelChange)=\"onValueChange($event)\"\n [ngClass]=\"{ invalid: validationErrors.length }\"\n >\n <ng-template let-item #chipTemplate>\n <span class=\"p-autocomplete-token-label\">\n @if (classify && !validationErrors.length) {\n <div class=\"classify inchip\">\n <a href=\"{{ classify.hrefPrefix + item }}\">\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n </a>\n </div>\n }\n <div class=\"label\">\n {{ item }}\n </div>\n </span>\n </ng-template>\n </yvc-chips>\n} @else if (rows && rows > 1) {\n <!-- multi line text inputs -->\n <textarea\n class=\"input-textarea\"\n pInputTextarea\n (blur)=\"onBlur()\"\n [(ngModel)]=\"value\"\n [rows]=\"rows\"\n [readonly]=\"readonly\"\n (ngModelChange)=\"onValueChange($event)\"\n ></textarea>\n}\n\n@if (classify) {\n <div class=\"classify\">\n @if (value && !validationErrors.length && (classify.hrefPrefix !== '' || !multiselect || value.length <= 1)) {\n <a href=\"{{ classify.hrefPrefix + formatedValue }}\">\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n </a>\n } @else {\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n }\n </div>\n}\n", styles: [":host{font-family:Roboto;display:flex;flex-flow:row nowrap;align-items:center}:host .p-autocomplete-token-label{display:flex;align-items:center;-webkit-user-select:text;user-select:text}:host .p-autocomplete-token-label .label{padding:0 calc(var(--app-pane-padding) / 4);word-break:break-word}:host .classify{color:var(--text-color-hint)}:host .classify a{color:var(--text-color-hint);display:block;border-radius:2px}:host .classify a:hover,:host .classify a:focus{background-color:var(--color-accent);color:#fff}:host .classify yvc-icon{width:18px;height:18px;padding:calc(var(--app-pane-padding) / 8)}:host textarea.input-textarea{width:100%;resize:vertical;background-color:transparent;color:var(--text-color-body);border:1px solid var(--yvc-form-element-border-color)}:host yvc-chips{width:100%}:host input{color:var(--text-color-body);padding:0;border:1px solid var(--yvc-form-element-border-color);display:flex;flex-wrap:wrap;align-items:center;width:100%;background:transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: YvcChipsModule }, { kind: "component", type: i2$3.Chips, selector: "yvc-chips", inputs: ["field", "placeholder", "max", "disabled"] }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i3$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
1537
+ ], viewQueries: [{ propertyName: "autoCompleteInput", first: true, predicate: ["autocomplete"], descendants: true }], ngImport: i0, template: "<yvc-autocomplete\n [(ngModel)]=\"innerValue\"\n #autocomplete\n (suggestionSelect)=\"onSelect()\"\n [placeholder]=\"placeholder\"\n (suggestionUnselect)=\"onUnselect($event)\"\n (blur)=\"onAutoCompleteBlur()\"\n [disabled]=\"readonly\"\n [autocompleteValues]=\"autocompleteRes\"\n field=\"id\"\n [forceSelection]=\"true\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #autocompleteOptionTemplate let-item>\n <span class=\"chip\">{{ item.user.title }}</span>\n </ng-template>\n\n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n <span class=\"chip\" [ngClass]=\"{ notFound: item.state.notFound }\" [title]=\"item.titleString\">\n {{ item.user.title }}\n </span>\n </ng-template>\n</yvc-autocomplete>\n\n<yvc-icon class=\"classify\" aria-hidden=\"true\" [svg]=\"multiselect ? icons.organizationMulti : icons.organization\" (click)=\"focusInput()\"></yvc-icon>\n", styles: [":host{display:flex;align-items:center}:host .chip.notFound{color:var(--color-error);text-decoration:line-through}:host .chip.notFound:before{content:\"!\";display:inline-block;background-color:var(--color-error);color:#fff;border-radius:2px;padding-inline:.3em;text-decoration:none;margin-inline-end:.75em}:host yvc-autocomplete{flex:1;--yvc-form-element-focus-border-color: transparent;--yvc-form-element-focus-outline-color: transparent}:host yvc-icon.classify{width:18px;height:18px;padding:calc(var(--app-pane-padding) / 8);color:var(--text-color-hint)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: YvcAutocompleteModule }, { kind: "component", type: i3$1.AutoComplete, selector: "yvc-autocomplete", inputs: ["field", "placeholder", "minLength", "multiple", "typeahead", "distinctValues", "forceSelection", "autocompleteValues", "disabled"], outputs: ["autocompleteFnc", "blur", "focus", "suggestionUnselect", "suggestionSelect"] }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i3.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "ngmodule", type: TranslateModule }] }); }
1182
1538
  }
1183
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StringComponent, decorators: [{
1539
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OrganizationComponent, decorators: [{
1184
1540
  type: Component,
1185
- args: [{ selector: 'yuv-string', standalone: true, imports: [CommonModule, YvcChipsModule, YvcIconModule, FormsModule], providers: [
1541
+ args: [{ selector: 'yuv-organization', standalone: true, imports: [CommonModule, FormsModule, YvcAutocompleteModule, YvcIconModule, TranslateModule], providers: [
1186
1542
  {
1187
1543
  provide: NG_VALUE_ACCESSOR,
1188
- useExisting: forwardRef(() => StringComponent),
1544
+ useExisting: forwardRef(() => OrganizationComponent),
1189
1545
  multi: true
1190
1546
  },
1191
1547
  {
1192
1548
  provide: NG_VALIDATORS,
1193
- useExisting: forwardRef(() => StringComponent),
1549
+ useExisting: forwardRef(() => OrganizationComponent),
1194
1550
  multi: true
1195
1551
  }
1196
- ], template: "@if ((!rows || rows <= 1) && !multiselect) {\n <input type=\"text\" (blur)=\"onBlur()\" [readonly]=\"readonly\" [(ngModel)]=\"value\" (ngModelChange)=\"onValueChange($event)\" />\n}\n@else if ((!rows || rows <= 1) && multiselect) {\n <!-- single line input with multiselect-->\n <yvc-chips\n [(ngModel)]=\"value\"\n [disabled]=\"readonly\"\n [max]=\"maxEntryCountIfInvalid\"\n (onBlur)=\"onBlur()\"\n (ngModelChange)=\"onValueChange($event)\"\n [ngClass]=\"{ invalid: validationErrors.length }\"\n >\n <ng-template let-item #chipTemplate>\n <span class=\"p-autocomplete-token-label\">\n @if (classify && !validationErrors.length) {\n <div class=\"classify inchip\">\n <a href=\"{{ classify.hrefPrefix + item }}\">\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n </a>\n </div>\n }\n <div class=\"label\">\n {{ item }}\n </div>\n </span>\n </ng-template>\n </yvc-chips>\n} @else if (rows && rows > 1) {\n <!-- multi line text inputs -->\n <textarea\n class=\"input-textarea\"\n pInputTextarea\n (blur)=\"onBlur()\"\n [(ngModel)]=\"value\"\n [rows]=\"rows\"\n [readonly]=\"readonly\"\n (ngModelChange)=\"onValueChange($event)\"\n ></textarea>\n}\n\n@if (classify) {\n <div class=\"classify\">\n @if (value && !validationErrors.length && (classify.hrefPrefix !== '' || !multiselect || value.length <= 1)) {\n <a href=\"{{ classify.hrefPrefix + formatedValue }}\">\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n </a>\n } @else {\n <yvc-icon [svg]=\"classify.icon!\"></yvc-icon>\n }\n </div>\n}\n", styles: [":host{font-family:Roboto;display:flex;flex-flow:row nowrap;align-items:center}:host .p-autocomplete-token-label{display:flex;align-items:center;-webkit-user-select:text;user-select:text}:host .p-autocomplete-token-label .label{padding:0 calc(var(--app-pane-padding) / 4);word-break:break-word}:host .classify{color:var(--text-color-hint)}:host .classify a{color:var(--text-color-hint);display:block;border-radius:2px}:host .classify a:hover,:host .classify a:focus{background-color:var(--color-accent);color:#fff}:host .classify yvc-icon{width:18px;height:18px;padding:calc(var(--app-pane-padding) / 8)}:host textarea.input-textarea{width:100%;resize:vertical;background-color:transparent;color:var(--text-color-body);border:1px solid var(--yvc-form-element-border-color)}:host yvc-chips{width:100%}:host input{color:var(--text-color-body);padding:0;border:1px solid var(--yvc-form-element-border-color);display:flex;flex-wrap:wrap;align-items:center;width:100%;background:transparent}\n"] }]
1197
- }], propDecorators: { fe: [{
1552
+ ], template: "<yvc-autocomplete\n [(ngModel)]=\"innerValue\"\n #autocomplete\n (suggestionSelect)=\"onSelect()\"\n [placeholder]=\"placeholder\"\n (suggestionUnselect)=\"onUnselect($event)\"\n (blur)=\"onAutoCompleteBlur()\"\n [disabled]=\"readonly\"\n [autocompleteValues]=\"autocompleteRes\"\n field=\"id\"\n [forceSelection]=\"true\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #autocompleteOptionTemplate let-item>\n <span class=\"chip\">{{ item.user.title }}</span>\n </ng-template>\n\n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n <span class=\"chip\" [ngClass]=\"{ notFound: item.state.notFound }\" [title]=\"item.titleString\">\n {{ item.user.title }}\n </span>\n </ng-template>\n</yvc-autocomplete>\n\n<yvc-icon class=\"classify\" aria-hidden=\"true\" [svg]=\"multiselect ? icons.organizationMulti : icons.organization\" (click)=\"focusInput()\"></yvc-icon>\n", styles: [":host{display:flex;align-items:center}:host .chip.notFound{color:var(--color-error);text-decoration:line-through}:host .chip.notFound:before{content:\"!\";display:inline-block;background-color:var(--color-error);color:#fff;border-radius:2px;padding-inline:.3em;text-decoration:none;margin-inline-end:.75em}:host yvc-autocomplete{flex:1;--yvc-form-element-focus-border-color: transparent;--yvc-form-element-focus-outline-color: transparent}:host yvc-icon.classify{width:18px;height:18px;padding:calc(var(--app-pane-padding) / 8);color:var(--text-color-hint)}\n"] }]
1553
+ }], propDecorators: { autoCompleteInput: [{
1554
+ type: ViewChild,
1555
+ args: ['autocomplete']
1556
+ }], onKeydownHandler: [{
1557
+ type: HostListener,
1558
+ args: ['keydown.enter', ['$event']]
1559
+ }], _inputDisabled: [{
1198
1560
  type: HostBinding,
1199
- args: ['class.yvc-form-element']
1200
- }], multiselect: [{
1201
- type: Input
1202
- }], rows: [{
1561
+ args: ['class.inputDisabled']
1562
+ }], placeholder: [{
1203
1563
  type: Input
1204
- }], readonly: [{
1564
+ }], situation: [{
1205
1565
  type: Input
1206
- }], autofocus: [{
1566
+ }], multiselect: [{
1207
1567
  type: Input
1208
1568
  }], classifications: [{
1209
1569
  type: Input
1210
- }], situation: [{
1570
+ }], readonly: [{
1211
1571
  type: Input
1212
- }], regex: [{
1572
+ }], autofocus: [{
1213
1573
  type: Input
1214
- }], minLength: [{
1574
+ }], appendTo: [{
1215
1575
  type: Input
1216
- }], maxLength: [{
1576
+ }], excludeMe: [{
1217
1577
  type: Input
1578
+ }], userSelect: [{
1579
+ type: Output
1218
1580
  }] } });
1219
1581
 
1582
+ class DateRangePickerComponent {
1583
+ constructor() {
1584
+ this.#oRef = inject(YvcOverlayRef);
1585
+ this.#fb = inject(FormBuilder);
1586
+ this.form = this.#fb.group({
1587
+ range: this.#fb.control(this.#oRef.data.range, Validators.required)
1588
+ });
1589
+ this.range = input(this.#oRef.data.range);
1590
+ this.rangeChange = output();
1591
+ this.#rangeEffect = effect(() => {
1592
+ const range = this.range();
1593
+ this.form.patchValue({ range });
1594
+ });
1595
+ }
1596
+ #oRef;
1597
+ #fb;
1598
+ #rangeEffect;
1599
+ apply() {
1600
+ this.rangeChange.emit(this.form.value.range || undefined);
1601
+ this.#oRef?.close(this.form.value.range);
1602
+ }
1603
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DateRangePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1604
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: DateRangePickerComponent, isStandalone: true, selector: "yuv-date-range-picker", inputs: { range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rangeChange: "rangeChange" }, ngImport: i0, template: "<form [formGroup]=\"form\" (ngSubmit)=\"apply()\">\n <h2>{{ 'yuv.form.element.range-select-date.custom.overlay.title' | translate }}</h2>\n <yuv-datetime-range [withTime]=\"false\" formControlName=\"range\"></yuv-datetime-range>\n <button class=\"primary\" [disabled]=\"form.invalid\">{{ 'yuv.form.element.range-select-date.custom.overlay.button.apply' | translate }}</button>\n</form>\n", styles: [":host{--form-element-border-color: transparent;--yvc-form-element-border-color: transparent}:host form{display:grid;grid-template-columns:1fr auto;grid-template-rows:repeat(3,auto);grid-template-areas:\"title title\" \"input input\" \". button\";gap:var(--app-pane-padding);padding:var(--app-pane-padding)}:host form h2{grid-area:title;margin:0}:host form yuv-datetime-range{grid-area:input;border:1px solid var(--text-color-hint);padding:1px 2px;border-radius:2px}:host form button{grid-area:button}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "component", type: DatetimeRangeComponent, selector: "yuv-datetime-range", inputs: ["withTime", "readonly", "operator", "situation"] }] }); }
1605
+ }
1606
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DateRangePickerComponent, decorators: [{
1607
+ type: Component,
1608
+ args: [{ selector: 'yuv-date-range-picker', standalone: true, imports: [CommonModule, ReactiveFormsModule, TranslateModule, DatetimeRangeComponent], template: "<form [formGroup]=\"form\" (ngSubmit)=\"apply()\">\n <h2>{{ 'yuv.form.element.range-select-date.custom.overlay.title' | translate }}</h2>\n <yuv-datetime-range [withTime]=\"false\" formControlName=\"range\"></yuv-datetime-range>\n <button class=\"primary\" [disabled]=\"form.invalid\">{{ 'yuv.form.element.range-select-date.custom.overlay.button.apply' | translate }}</button>\n</form>\n", styles: [":host{--form-element-border-color: transparent;--yvc-form-element-border-color: transparent}:host form{display:grid;grid-template-columns:1fr auto;grid-template-rows:repeat(3,auto);grid-template-areas:\"title title\" \"input input\" \". button\";gap:var(--app-pane-padding);padding:var(--app-pane-padding)}:host form h2{grid-area:title;margin:0}:host form yuv-datetime-range{grid-area:input;border:1px solid var(--text-color-hint);padding:1px 2px;border-radius:2px}:host form button{grid-area:button}\n"] }]
1609
+ }] });
1610
+
1611
+ // marker for extracting translations for the available date range options
1612
+ marker('yuv.form.element.range-select-date.option.any');
1613
+ marker('yuv.form.element.range-select-date.option.today');
1614
+ marker('yuv.form.element.range-select-date.option.yesterday');
1615
+ marker('yuv.form.element.range-select-date.option.thisWeek');
1616
+ marker('yuv.form.element.range-select-date.option.lastWeek');
1617
+ marker('yuv.form.element.range-select-date.option.thisMonth');
1618
+ marker('yuv.form.element.range-select-date.option.lastMonth');
1619
+ marker('yuv.form.element.range-select-date.option.thisYear');
1620
+ marker('yuv.form.element.range-select-date.option.lastYear');
1621
+ marker('yuv.form.element.range-select-date.option.custom');
1220
1622
  /**
1221
- * Component for wrapping a form element. Provides a label and focus behaviour.
1222
- *
1223
- * @example
1224
- * <yuv-form-input [label]="'my form element'">
1225
- * <!-- form element to be wrapped -->
1226
- * </yuv-form-input>
1623
+ * Component for selecting a date range based on pre-defined ranges like
1624
+ * 'today', 'this week', 'this month', etc.
1625
+ * It also allows to pick a custom date range.
1227
1626
  */
1228
- class FormInputComponent {
1627
+ class RangeSelectDateComponent {
1628
+ #overlay;
1629
+ #fb;
1630
+ #ANY_OPTION;
1631
+ #CUSTOM_OPTION;
1632
+ #customDateRange;
1229
1633
  constructor() {
1230
- this.renderer = inject(Renderer2);
1231
- this.isDisabled = false;
1232
- this.isInvalid = false;
1233
- this.isRequired = false;
1634
+ this.translate = inject(TranslateService);
1635
+ this.#overlay = inject(YvcOverlayService);
1636
+ this.#fb = inject(FormBuilder);
1637
+ this.#ANY_OPTION = 'any';
1638
+ this.#CUSTOM_OPTION = 'custom';
1639
+ this.dateOptions = signal([]);
1640
+ this.innerForm = this.#fb.nonNullable.group({
1641
+ range: [this.#ANY_OPTION]
1642
+ });
1643
+ /**
1644
+ * Range values to be used in the dropdown.
1645
+ */
1646
+ this.ranges = input(['today', 'yesterday', 'thisWeek', 'thisMonth', 'thisYear']);
1647
+ /**
1648
+ * Whether to show the custom date range option.
1649
+ */
1650
+ this.customRange = input(true);
1651
+ // ControlValueAccessor implementation
1652
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1653
+ this.propagateChange = (_) => { };
1654
+ this.translate.onLangChange.pipe(takeUntilDestroyed()).subscribe((_) => this.#setupOptions());
1655
+ this.#setupOptions();
1656
+ this.innerForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((v) => this.#onFormValueChange(v));
1657
+ }
1658
+ #onFormValueChange(v) {
1659
+ if (v.range === this.#CUSTOM_OPTION) {
1660
+ if (!this.#customDateRange || this.dateOptions().find((o) => o.value === this.#CUSTOM_OPTION)?.label === this.#customDateRangeToString())
1661
+ this.#openCustomRangeDialog();
1662
+ else
1663
+ this.propagateChange({
1664
+ rangeValue: this.#customDateRange,
1665
+ label: this.#customDateRangeToString()
1666
+ });
1667
+ }
1668
+ else {
1669
+ const { start, end } = SearchUtils.dateRangeStartEnd(v.range);
1670
+ this.propagateChange(v.range !== this.#ANY_OPTION
1671
+ ? {
1672
+ rangeValue: { operator: Operator.INTERVAL_INCLUDE_BOTH, firstValue: start, secondValue: end },
1673
+ label: this.translate.instant(`yuv.form.element.range-select-date.option.${v.range}`)
1674
+ }
1675
+ : undefined);
1676
+ this.#customDateRange = undefined;
1677
+ this.#setupOptions();
1678
+ }
1234
1679
  }
1235
- /**
1236
- * A label string for the wrapped form element
1237
- */
1238
- set label(val) {
1239
- this._label = val;
1680
+ #openCustomRangeDialog() {
1681
+ // open date range picker
1682
+ const o = this.#overlay.open(DateRangePickerComponent, {
1683
+ range: this.#customDateRange
1684
+ });
1685
+ o.afterClosed$.subscribe((res) => {
1686
+ this.#customDateRange = res.data;
1687
+ if (!res.data) {
1688
+ this.innerForm.patchValue({ range: this.#ANY_OPTION });
1689
+ this.#setupOptions();
1690
+ }
1691
+ else {
1692
+ this.#onFormValueChange(this.innerForm.value);
1693
+ this.#setupOptions(this.#customDateRangeToString());
1694
+ setTimeout(() => {
1695
+ this.innerForm.patchValue({ range: this.#CUSTOM_OPTION }, {
1696
+ emitEvent: false
1697
+ });
1698
+ });
1699
+ }
1700
+ });
1240
1701
  }
1241
- /**
1242
- * Indicator that the wrapped form element is invalid. Will then render appropriate styles.
1243
- * You may also provide an array of error messages.
1244
- */
1245
- set invalid(iv) {
1246
- if (iv === null || iv === undefined) {
1247
- this.isInvalid = false;
1248
- this.renderer.removeAttribute(this.labelEl.nativeElement, 'title');
1702
+ #setupOptions(custom) {
1703
+ const options = this.ranges().map((value) => ({
1704
+ label: this.translate.instant(`yuv.form.element.range-select-date.option.${value}`),
1705
+ value
1706
+ }));
1707
+ if (this.customRange())
1708
+ options.push({
1709
+ label: custom || this.translate.instant('yuv.form.element.range-select-date.option.custom'),
1710
+ value: this.#CUSTOM_OPTION
1711
+ });
1712
+ this.dateOptions.set([
1713
+ {
1714
+ label: this.translate.instant('yuv.form.element.range-select-date.option.any'),
1715
+ value: this.#ANY_OPTION
1716
+ },
1717
+ ...options
1718
+ ]);
1719
+ }
1720
+ #customDateRangeToString() {
1721
+ if (!this.#customDateRange)
1722
+ return undefined;
1723
+ const dp = new LocaleDatePipe(this.translate);
1724
+ switch (this.#customDateRange.operator) {
1725
+ case Operator.EQUAL: {
1726
+ return dp.transform(this.#customDateRange.firstValue, 'shortDate');
1727
+ }
1728
+ case Operator.GREATER_OR_EQUAL: {
1729
+ return `${OperatorLabel.GREATER_OR_EQUAL} ${dp.transform(this.#customDateRange.firstValue, 'shortDate')}`;
1730
+ }
1731
+ case Operator.LESS_OR_EQUAL: {
1732
+ return `${OperatorLabel.LESS_OR_EQUAL} ${dp.transform(this.#customDateRange.firstValue, 'shortDate')}`;
1733
+ }
1734
+ case Operator.INTERVAL_INCLUDE_BOTH: {
1735
+ return `${dp.transform(this.#customDateRange.firstValue, 'shortDate')} ${OperatorLabel.INTERVAL_INCLUDE_BOTH} ${dp.transform(this.#customDateRange.secondValue, 'shortDate')}`;
1736
+ }
1249
1737
  }
1250
- else if (Array.isArray(iv)) {
1251
- this.isInvalid = iv.length > 0;
1252
- if (this.isInvalid) {
1253
- this.renderer.setAttribute(this.labelEl.nativeElement, 'title', iv.join(';'));
1738
+ return undefined;
1739
+ }
1740
+ writeValue(value) {
1741
+ if (value?.rangeValue?.operator && value?.rangeValue?.firstValue) {
1742
+ const dr = SearchUtils.getMatchingDateRange(value.rangeValue);
1743
+ if (dr) {
1744
+ this.innerForm.patchValue({ range: dr });
1745
+ }
1746
+ else {
1747
+ this.#customDateRange = value.rangeValue;
1748
+ this.innerForm.patchValue({ range: this.#CUSTOM_OPTION });
1254
1749
  }
1255
1750
  }
1256
1751
  else {
1257
- this.isInvalid = iv;
1752
+ this.innerForm.patchValue({ range: this.#ANY_OPTION });
1258
1753
  }
1259
1754
  }
1260
- /**
1261
- * Indicator that the wrapped form element is disabled. Will then render appropriate styles.
1262
- */
1263
- set disabled(d) {
1264
- this.isDisabled = d;
1755
+ registerOnChange(fn) {
1756
+ this.propagateChange = fn;
1265
1757
  }
1266
- /**
1267
- * Indicator that the wrapped form element is mandatory. Will then render appropriate styles.
1268
- */
1269
- set required(d) {
1270
- this.isRequired = d;
1758
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1759
+ registerOnTouched(fn) { }
1760
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RangeSelectDateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1761
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: RangeSelectDateComponent, isStandalone: true, selector: "yuv-range-select-date", inputs: { ranges: { classPropertyName: "ranges", publicName: "ranges", isSignal: true, isRequired: false, transformFunction: null }, customRange: { classPropertyName: "customRange", publicName: "customRange", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
1762
+ {
1763
+ provide: NG_VALUE_ACCESSOR,
1764
+ useExisting: forwardRef(() => RangeSelectDateComponent),
1765
+ multi: true
1766
+ }
1767
+ ], ngImport: i0, template: "<form [formGroup]=\"innerForm\">\n <yvc-dropdown formControlName=\"range\" [options]=\"dateOptions()\" [disableClearButton]=\"true\"></yvc-dropdown>\n</form>", styles: [":host form{display:flex}:host form yvc-dropdown{flex:1;outline-offset:0px;color:currentColor}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: YvcDropdownModule }, { kind: "component", type: i1$1.Dropdown, selector: "yvc-dropdown", inputs: ["options", "filter", "disabled", "multiple", "disableClearButton"], outputs: ["onDropdownOptionsClose"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
1768
+ }
1769
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RangeSelectDateComponent, decorators: [{
1770
+ type: Component,
1771
+ args: [{ selector: 'yuv-range-select-date', standalone: true, imports: [CommonModule, YvcDropdownModule, ReactiveFormsModule], providers: [
1772
+ {
1773
+ provide: NG_VALUE_ACCESSOR,
1774
+ useExisting: forwardRef(() => RangeSelectDateComponent),
1775
+ multi: true
1776
+ }
1777
+ ], template: "<form [formGroup]=\"innerForm\">\n <yvc-dropdown formControlName=\"range\" [options]=\"dateOptions()\" [disableClearButton]=\"true\"></yvc-dropdown>\n</form>", styles: [":host form{display:flex}:host form yvc-dropdown{flex:1;outline-offset:0px;color:currentColor}\n"] }]
1778
+ }], ctorParameters: () => [] });
1779
+
1780
+ // marker for extracting translations for the available filesize range options
1781
+ marker('yuv.form.element.range-select-filesize.option.any');
1782
+ marker('yuv.form.element.range-select-filesize.option.small');
1783
+ marker('yuv.form.element.range-select-filesize.option.medium');
1784
+ marker('yuv.form.element.range-select-filesize.option.large');
1785
+ marker('yuv.form.element.range-select-filesize.option.verylarge');
1786
+ /**
1787
+ * Component for selecting a range of filesizes based on pre-defined ranges like
1788
+ * 'today', 'this week', 'this month', etc.
1789
+ */
1790
+ class RangeSelectFilesizeComponent {
1791
+ #fb;
1792
+ #ANY_OPTION;
1793
+ constructor() {
1794
+ this.translate = inject(TranslateService$1);
1795
+ this.#fb = inject(FormBuilder);
1796
+ this.#ANY_OPTION = 'any';
1797
+ this.options = signal([]);
1798
+ this.innerForm = this.#fb.nonNullable.group({
1799
+ range: [this.#ANY_OPTION]
1800
+ });
1801
+ /**
1802
+ * Range values to be used in the dropdown.
1803
+ */
1804
+ this.ranges = input(['small', 'medium', 'large', 'verylarge']);
1805
+ // ControlValueAccessor implementation
1806
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1807
+ this.propagateChange = (_) => { };
1808
+ this.translate.onLangChange.pipe(takeUntilDestroyed()).subscribe((_) => this.#setupOptions());
1809
+ this.#setupOptions();
1810
+ this.innerForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((v) => this.#onFormValueChange(v));
1811
+ }
1812
+ #onFormValueChange(v) {
1813
+ const rangeValue = v.range !== this.#ANY_OPTION ? SearchUtils.filesizeRangeToRangeValue(v.range) : undefined;
1814
+ const res = rangeValue && {
1815
+ rangeValue,
1816
+ label: this.translate.instant(`yuv.form.element.range-select-filesize.option.${v.range}`)
1817
+ };
1818
+ this.propagateChange(res);
1819
+ }
1820
+ #setupOptions() {
1821
+ const options = this.ranges().map((value) => ({
1822
+ label: this.translate.instant(`yuv.form.element.range-select-filesize.option.${value}`),
1823
+ value
1824
+ }));
1825
+ this.options.set([
1826
+ {
1827
+ label: this.translate.instant('yuv.form.element.range-select-filesize.option.any'),
1828
+ value: this.#ANY_OPTION
1829
+ },
1830
+ ...options
1831
+ ]);
1271
1832
  }
1272
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FormInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1273
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: FormInputComponent, isStandalone: true, selector: "yuv-form-input", inputs: { label: "label", tag: "tag", description: "description", invalid: "invalid", disabled: "disabled", required: "required" }, host: { properties: { "class.disabled": "this.isDisabled", "class.invalid": "this.isInvalid", "class.required": "this.isRequired" } }, viewQueries: [{ propertyName: "labelEl", first: true, predicate: ["label"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"fe-wrapper\" yuvFocusWithin>\n @if (tag) {\n <div class=\"tag\" title=\"{{ tag.title }}\">{{ tag.label }}</div>\n }\n <label class=\"form-input__label\" #label>{{ _label }}</label>\n <div class=\"control\">\n <ng-content></ng-content>\n </div>\n</div>\n@if (description) {\n <div class=\"description\">{{ description }}</div>\n}\n", styles: ["yuv-form-input .yvc-form-element{--yvc-form-element-border-color: transparent;--yvc-form-element-focus-border-color: transparent;--yvc-form-element-focus-outline-color: transparent}yuv-form-input .fe-wrapper{display:flex;transition:all .2s ease-in-out;flex-flow:row nowrap;align-items:center;padding:calc(var(--app-pane-padding) / 4) 0;border-bottom:1px solid var(--text-color-hint)}yuv-form-input .fe-wrapper.focusWithin{border-color:var(--color-accent)}yuv-form-input .fe-wrapper.focusWithin>.form-input__label{color:var(--color-accent)}yuv-form-input .fe-wrapper>div.control{flex:1 1 auto;padding:0 calc(var(--app-pane-padding) / 4);order:1;min-height:20px}yuv-form-input .fe-wrapper>div.control>span{display:inline-block;border-radius:2px;font-size:var(--font-body);line-height:1.5em;background-color:var(--color-accent);padding:0 calc(var(--app-pane-padding) / 4);color:#fff}yuv-form-input .fe-wrapper>.triggers{order:3;display:none}yuv-form-input .fe-wrapper>.triggers.visible{order:2}yuv-form-input .fe-wrapper>.triggers.visible,yuv-form-input .fe-wrapper>.triggers:hover{display:flex}yuv-form-input .fe-wrapper>.form-input__label{text-align:end;transition:all .2s ease-in-out;-webkit-user-select:none;user-select:none;order:4;flex:0 1 auto;padding:2px calc(var(--app-pane-padding) / 4);margin-right:3px;color:var(--text-color-caption);border-radius:2px;font-size:var(--font-caption)}yuv-form-input .fe-wrapper>.form-input__label:hover+.triggers{display:flex}yuv-form-input .fe-wrapper>.tag{order:5;flex:0 0 auto;border-radius:2px;font-size:var(--font-body);display:inline-block;line-height:1.5em;padding:2px;cursor:default;background-color:rgba(var(--color-accent-rgb),.2);color:var(--color-accent);font-family:monospace}yuv-form-input.checkbox{position:relative}yuv-form-input.checkbox .fe-wrapper>.form-input__label{text-align:start}yuv-form-input .description{font-size:var(--font-hint);font-style:italic;padding:calc(var(--app-pane-padding) / 8) calc(var(--app-pane-padding) / 8) 0 calc(var(--app-pane-padding) / 8);color:var(--text-color-caption)}yuv-form-input.required .fe-wrapper>.form-input__label{font-weight:700}yuv-form-input.required .fe-wrapper>.form-input__label:after{content:\"*\";padding:0 4px}yuv-form-input.invalid .fe-wrapper{background:rgba(var(--color-error),.15);border-color:var(--color-error)}yuv-form-input.invalid .fe-wrapper>.form-input__label{background-color:var(--color-error);color:#fff;margin:0 4px}yuv-form-input.invalid .fe-wrapper>.form-input__label:after{content:\"!\";margin-left:calc(var(--app-pane-padding) / 2)}yuv-form-input.disabled .fe-wrapper{opacity:.7;background-color:var(--item-focus-background-color)}yuv-form-input.checkbox .fe-wrapper{border-color:transparent!important}yuv-form-input.checkbox .fe-wrapper>div.control{flex:0 0 auto}yuv-form-input.checkbox .fe-wrapper>.form-input__label{flex:0 1 auto}yuv-form-input:not(.skipToggle) .form-input__label{cursor:pointer}.yuv-form-input .fe-wrapper .fe-wrapper{background:transparent;padding:0}.yuv-form-input input:not([type=checkbox]),.yuv-form-input .p-inputtext{padding:0;border:0!important;display:flex;flex-wrap:wrap;align-items:center;width:100%}.yuv-form-input input{background-color:transparent}.yuv-form-input button.p-button{background:transparent;border:0;border-radius:2px;color:var(--text-color-caption);cursor:pointer;width:20px;height:20px;padding:0;min-width:20px}.yuv-form-input button.p-button:enabled:active,.yuv-form-input button.p-button:enabled:focus{border:0;box-shadow:none;background:var(--color-accent);color:#fff}.yuv-form-input button.p-button:enabled:active,.yuv-form-input button.p-button:enabled:hover{border:0;background:var(--color-accent);color:#fff}.yuv-form-input button.p-button .fa{color:currentColor!important}.yuv-form-input button.p-button yuv-icon{width:16px;height:16px;margin:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: FocusWithinDirective, selector: "[yuvFocusWithin]", outputs: ["yuvFocusWithin", "yuvFocusWithinBlur"] }], encapsulation: i0.ViewEncapsulation.None }); }
1833
+ writeValue(value) {
1834
+ const patch = { range: this.#ANY_OPTION };
1835
+ if (value?.rangeValue?.operator && value?.rangeValue?.firstValue) {
1836
+ const range = SearchUtils.getMatchingFilesizeRange(value.rangeValue);
1837
+ if (range)
1838
+ patch.range = range;
1839
+ }
1840
+ this.innerForm.patchValue(patch);
1841
+ }
1842
+ registerOnChange(fn) {
1843
+ this.propagateChange = fn;
1844
+ }
1845
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1846
+ registerOnTouched(fn) { }
1847
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RangeSelectFilesizeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1848
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: RangeSelectFilesizeComponent, isStandalone: true, selector: "yuv-range-select-filesize", inputs: { ranges: { classPropertyName: "ranges", publicName: "ranges", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
1849
+ {
1850
+ provide: NG_VALUE_ACCESSOR,
1851
+ useExisting: forwardRef(() => RangeSelectFilesizeComponent),
1852
+ multi: true
1853
+ }
1854
+ ], ngImport: i0, template: "<form [formGroup]=\"innerForm\">\n <yvc-dropdown formControlName=\"range\" [options]=\"options()\" [disableClearButton]=\"true\"></yvc-dropdown>\n</form>\n", styles: [":host form{display:flex}:host form yvc-dropdown{flex:1;outline-offset:0px;color:currentColor}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: YvcDropdownModule }, { kind: "component", type: i1$1.Dropdown, selector: "yvc-dropdown", inputs: ["options", "filter", "disabled", "multiple", "disableClearButton"], outputs: ["onDropdownOptionsClose"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
1274
1855
  }
1275
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FormInputComponent, decorators: [{
1856
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RangeSelectFilesizeComponent, decorators: [{
1276
1857
  type: Component,
1277
- args: [{ selector: 'yuv-form-input', standalone: true, imports: [CommonModule, FocusWithinDirective], encapsulation: ViewEncapsulation.None, template: "<div class=\"fe-wrapper\" yuvFocusWithin>\n @if (tag) {\n <div class=\"tag\" title=\"{{ tag.title }}\">{{ tag.label }}</div>\n }\n <label class=\"form-input__label\" #label>{{ _label }}</label>\n <div class=\"control\">\n <ng-content></ng-content>\n </div>\n</div>\n@if (description) {\n <div class=\"description\">{{ description }}</div>\n}\n", styles: ["yuv-form-input .yvc-form-element{--yvc-form-element-border-color: transparent;--yvc-form-element-focus-border-color: transparent;--yvc-form-element-focus-outline-color: transparent}yuv-form-input .fe-wrapper{display:flex;transition:all .2s ease-in-out;flex-flow:row nowrap;align-items:center;padding:calc(var(--app-pane-padding) / 4) 0;border-bottom:1px solid var(--text-color-hint)}yuv-form-input .fe-wrapper.focusWithin{border-color:var(--color-accent)}yuv-form-input .fe-wrapper.focusWithin>.form-input__label{color:var(--color-accent)}yuv-form-input .fe-wrapper>div.control{flex:1 1 auto;padding:0 calc(var(--app-pane-padding) / 4);order:1;min-height:20px}yuv-form-input .fe-wrapper>div.control>span{display:inline-block;border-radius:2px;font-size:var(--font-body);line-height:1.5em;background-color:var(--color-accent);padding:0 calc(var(--app-pane-padding) / 4);color:#fff}yuv-form-input .fe-wrapper>.triggers{order:3;display:none}yuv-form-input .fe-wrapper>.triggers.visible{order:2}yuv-form-input .fe-wrapper>.triggers.visible,yuv-form-input .fe-wrapper>.triggers:hover{display:flex}yuv-form-input .fe-wrapper>.form-input__label{text-align:end;transition:all .2s ease-in-out;-webkit-user-select:none;user-select:none;order:4;flex:0 1 auto;padding:2px calc(var(--app-pane-padding) / 4);margin-right:3px;color:var(--text-color-caption);border-radius:2px;font-size:var(--font-caption)}yuv-form-input .fe-wrapper>.form-input__label:hover+.triggers{display:flex}yuv-form-input .fe-wrapper>.tag{order:5;flex:0 0 auto;border-radius:2px;font-size:var(--font-body);display:inline-block;line-height:1.5em;padding:2px;cursor:default;background-color:rgba(var(--color-accent-rgb),.2);color:var(--color-accent);font-family:monospace}yuv-form-input.checkbox{position:relative}yuv-form-input.checkbox .fe-wrapper>.form-input__label{text-align:start}yuv-form-input .description{font-size:var(--font-hint);font-style:italic;padding:calc(var(--app-pane-padding) / 8) calc(var(--app-pane-padding) / 8) 0 calc(var(--app-pane-padding) / 8);color:var(--text-color-caption)}yuv-form-input.required .fe-wrapper>.form-input__label{font-weight:700}yuv-form-input.required .fe-wrapper>.form-input__label:after{content:\"*\";padding:0 4px}yuv-form-input.invalid .fe-wrapper{background:rgba(var(--color-error),.15);border-color:var(--color-error)}yuv-form-input.invalid .fe-wrapper>.form-input__label{background-color:var(--color-error);color:#fff;margin:0 4px}yuv-form-input.invalid .fe-wrapper>.form-input__label:after{content:\"!\";margin-left:calc(var(--app-pane-padding) / 2)}yuv-form-input.disabled .fe-wrapper{opacity:.7;background-color:var(--item-focus-background-color)}yuv-form-input.checkbox .fe-wrapper{border-color:transparent!important}yuv-form-input.checkbox .fe-wrapper>div.control{flex:0 0 auto}yuv-form-input.checkbox .fe-wrapper>.form-input__label{flex:0 1 auto}yuv-form-input:not(.skipToggle) .form-input__label{cursor:pointer}.yuv-form-input .fe-wrapper .fe-wrapper{background:transparent;padding:0}.yuv-form-input input:not([type=checkbox]),.yuv-form-input .p-inputtext{padding:0;border:0!important;display:flex;flex-wrap:wrap;align-items:center;width:100%}.yuv-form-input input{background-color:transparent}.yuv-form-input button.p-button{background:transparent;border:0;border-radius:2px;color:var(--text-color-caption);cursor:pointer;width:20px;height:20px;padding:0;min-width:20px}.yuv-form-input button.p-button:enabled:active,.yuv-form-input button.p-button:enabled:focus{border:0;box-shadow:none;background:var(--color-accent);color:#fff}.yuv-form-input button.p-button:enabled:active,.yuv-form-input button.p-button:enabled:hover{border:0;background:var(--color-accent);color:#fff}.yuv-form-input button.p-button .fa{color:currentColor!important}.yuv-form-input button.p-button yuv-icon{width:16px;height:16px;margin:auto}\n"] }]
1278
- }], propDecorators: { labelEl: [{
1279
- type: ViewChild,
1280
- args: ['label', { static: true }]
1281
- }], label: [{
1282
- type: Input
1283
- }], tag: [{
1284
- type: Input
1285
- }], description: [{
1286
- type: Input
1287
- }], invalid: [{
1288
- type: Input
1289
- }], disabled: [{
1290
- type: Input
1291
- }], required: [{
1292
- type: Input
1293
- }], isDisabled: [{
1294
- type: HostBinding,
1295
- args: ['class.disabled']
1296
- }], isInvalid: [{
1297
- type: HostBinding,
1298
- args: ['class.invalid']
1299
- }], isRequired: [{
1300
- type: HostBinding,
1301
- args: ['class.required']
1302
- }] } });
1858
+ args: [{ selector: 'yuv-range-select-filesize', standalone: true, imports: [CommonModule, YvcDropdownModule, ReactiveFormsModule], providers: [
1859
+ {
1860
+ provide: NG_VALUE_ACCESSOR,
1861
+ useExisting: forwardRef(() => RangeSelectFilesizeComponent),
1862
+ multi: true
1863
+ }
1864
+ ], template: "<form [formGroup]=\"innerForm\">\n <yvc-dropdown formControlName=\"range\" [options]=\"options()\" [disableClearButton]=\"true\"></yvc-dropdown>\n</form>\n", styles: [":host form{display:flex}:host form yvc-dropdown{flex:1;outline-offset:0px;color:currentColor}\n"] }]
1865
+ }], ctorParameters: () => [] });
1303
1866
 
1304
1867
  class YuvFormsModule {
1305
1868
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: YuvFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
@@ -1347,9 +1910,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
1347
1910
  }]
1348
1911
  }] });
1349
1912
 
1913
+ // export { CatalogComponent } from './lib/elements/catalog/catalog.component';
1914
+ // export { CheckboxComponent } from './lib/elements/checkbox/checkbox.component';
1915
+ // export { DatetimeRangeComponent } from './lib/elements/datetime-range/datetime-range.component';
1916
+ // export { DatepickerComponent } from './lib/elements/datetime/datepicker/datepicker.component';
1917
+ // export { DatetimeComponent } from './lib/elements/datetime/datetime.component';
1918
+ // export { YearRangeDirective } from './lib/elements/datetime/year-range/year-range.directive';
1919
+ // export { DynamicCatalogManagementComponent } from './lib/elements/dynamic-catalog/dynamic-catalog-management/dynamic-catalog-management.component';
1920
+ // export { DynamicCatalogComponent } from './lib/elements/dynamic-catalog/dynamic-catalog.component';
1921
+ // export { NumberRangeComponent } from './lib/elements/number-range/number-range.component';
1922
+ // export { NumberComponent } from './lib/elements/number/number.component';
1923
+ // export { OrganizationSetComponent } from './lib/elements/organization-set/organization-set.component';
1924
+ // export { OrganizationComponent } from './lib/elements/organization/organization.component';
1925
+ // export { ReferenceItemComponent } from './lib/elements/reference/reference-item/reference-item.component';
1926
+ // export { ReferenceComponent } from './lib/elements/reference/reference.component';
1927
+ // export * from './lib/elements/reference/reference.interface';
1928
+ // export { StringComponent } from './lib/elements/string/string.component';
1929
+
1350
1930
  /**
1351
1931
  * Generated bundle index. Do not edit.
1352
1932
  */
1353
1933
 
1354
- export { CatalogComponent, DatetimeComponent, DatetimeRangeComponent, FormInputComponent, NumberComponent, NumberRangeComponent, OrganizationComponent, StringComponent, YuvFormsModule };
1934
+ export { CatalogComponent, DataGridComponent, DatetimeComponent, DatetimeRangeComponent, FormInputComponent, NumberComponent, NumberRangeComponent, OrganizationComponent, RangeSelectDateComponent, RangeSelectFilesizeComponent, StringComponent, YuvFormsModule };
1355
1935
  //# sourceMappingURL=yuuvis-client-framework-forms.mjs.map