@masterteam/components 0.0.182 → 0.0.183

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, signal, inject, viewChild, effect, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { input, signal, computed, inject, viewChild, effect, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { Validators, NgControl, FormsModule } from '@angular/forms';
5
5
  import * as i2 from 'primeng/autocomplete';
@@ -39,6 +39,17 @@ class UserSearchField {
39
39
  size = input(...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
40
40
  filteredUsers = signal([], ...(ngDevMode ? [{ debugName: "filteredUsers" }] : /* istanbul ignore next */ []));
41
41
  searchTerms = new Subject();
42
+ /**
43
+ * In single-select mode, `true` when the currently selected user is no
44
+ * longer linked to the application. Drives the inline info badge/tooltip.
45
+ * Multiple-select mode handles this per-chip via the `selecteditem` template.
46
+ */
47
+ unlinkedSingleUser = computed(() => {
48
+ if (this.isMultiple())
49
+ return false;
50
+ const current = this.value();
51
+ return !!current && current.isLinkedToCurrentApplication === false;
52
+ }, ...(ngDevMode ? [{ debugName: "unlinkedSingleUser" }] : /* istanbul ignore next */ []));
42
53
  translocoService = inject(TranslocoService);
43
54
  autocomplete = viewChild('autocomplete', ...(ngDevMode ? [{ debugName: "autocomplete" }] : /* istanbul ignore next */ []));
44
55
  onTouched = () => { };
@@ -197,7 +208,7 @@ class UserSearchField {
197
208
  null);
198
209
  }
199
210
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserSearchField, deps: [], target: i0.ɵɵFactoryTarget.Component });
200
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UserSearchField, isStandalone: true, selector: "mt-user-search-field", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, isMultiple: { classPropertyName: "isMultiple", publicName: "isMultiple", isSignal: true, isRequired: false, transformFunction: null }, apiUrl: { classPropertyName: "apiUrl", publicName: "apiUrl", isSignal: true, isRequired: true, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, paramName: { classPropertyName: "paramName", publicName: "paramName", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.styleClass" }, classAttribute: "grid gap-1" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (label()) {\n <label\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\n [for]=\"ngControl?.name || label()\"\n >\n {{ label() }}\n </label>\n}\n<div class=\"relative\">\n <p-inputgroup>\n <p-autoComplete\n #autocomplete=\"\"\n [suggestions]=\"filteredUsers()\"\n (completeMethod)=\"search($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onClear)=\"onClear()\"\n (onFocus)=\"onFocus()\"\n (onBlur)=\"onBlur()\"\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\n [disabled]=\"disabled() || readonly()\"\n [id]=\"ngControl?.name || label()\"\n [invalid]=\"isInvalid(ngControl?.control)\"\n [placeholder]=\"'components.userSearchField.search' | transloco\"\n [multiple]=\"isMultiple()\"\n [optionLabel]=\"'displayName'\"\n class=\"w-full\"\n appendTo=\"body\"\n styleClass=\"w-full\"\n [dropdown]=\"false\"\n [size]=\"size()\"\n >\n <ng-template let-user pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template>\n\n <!-- <ng-template let-user #pTemplate=\"selecteditem\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template> -->\n </p-autoComplete>\n @if (hint()) {\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\n <mt-icon icon=\"general.help-circle\" />\n </p-inputgroup-addon>\n } @else {\n <p-inputgroup-addon tooltipPosition=\"top\">\n <mt-icon icon=\"user.user-03\" />\n </p-inputgroup-addon>\n }\n </p-inputgroup>\n\n @if (loading()) {\n <mt-icon\n icon=\"general.loading-01\"\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\n />\n }\n</div>\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\n", styles: [":host ::ng-deep .p-autocomplete-input-multiple{border-start-end-radius:0;border-end-end-radius:0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i2.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: Tooltip, selector: "[mtTooltip]" }, { kind: "ngmodule", type: InputGroupModule }, { kind: "component", type: i4.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "ngmodule", type: InputGroupAddonModule }, { kind: "component", type: i5.InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "component", type: FieldValidation, selector: "mt-field-validation", inputs: ["control", "touched"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
211
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UserSearchField, isStandalone: true, selector: "mt-user-search-field", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, isMultiple: { classPropertyName: "isMultiple", publicName: "isMultiple", isSignal: true, isRequired: false, transformFunction: null }, apiUrl: { classPropertyName: "apiUrl", publicName: "apiUrl", isSignal: true, isRequired: true, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, paramName: { classPropertyName: "paramName", publicName: "paramName", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.styleClass" }, classAttribute: "grid gap-1" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (label()) {\r\n <label\r\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\r\n [for]=\"ngControl?.name || label()\"\r\n >\r\n {{ label() }}\r\n </label>\r\n}\r\n<div class=\"relative\">\r\n <p-inputgroup>\r\n @if (unlinkedSingleUser()) {\r\n <p-inputgroup-addon\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n >\r\n <mt-icon icon=\"general.info-circle\" class=\"text-amber-500\" />\r\n </p-inputgroup-addon>\r\n }\r\n <p-autoComplete\r\n #autocomplete=\"\"\r\n [suggestions]=\"filteredUsers()\"\r\n (completeMethod)=\"search($event)\"\r\n (onSelect)=\"onSelect($event)\"\r\n (onUnselect)=\"onUnselect($event)\"\r\n (onClear)=\"onClear()\"\r\n (onFocus)=\"onFocus()\"\r\n (onBlur)=\"onBlur()\"\r\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\r\n [disabled]=\"disabled() || readonly()\"\r\n [id]=\"ngControl?.name || label()\"\r\n [invalid]=\"isInvalid(ngControl?.control)\"\r\n [placeholder]=\"'components.userSearchField.search' | transloco\"\r\n [multiple]=\"isMultiple()\"\r\n [optionLabel]=\"'displayName'\"\r\n class=\"w-full\"\r\n appendTo=\"body\"\r\n styleClass=\"w-full\"\r\n [dropdown]=\"false\"\r\n [size]=\"size()\"\r\n >\r\n <ng-template let-user pTemplate=\"item\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\r\n <div class=\"flex align-items-center gap-3\">\r\n <span class=\"font-medium\">{{ user.displayName }}</span>\r\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template let-user pTemplate=\"selecteditem\">\r\n <span class=\"inline-flex items-center gap-1\">\r\n <span>{{ user.displayName }}</span>\r\n @if (user.isLinkedToCurrentApplication === false) {\r\n <mt-icon\r\n icon=\"general.info-circle\"\r\n class=\"text-amber-500 text-sm shrink-0\"\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </span>\r\n </ng-template>\r\n </p-autoComplete>\r\n @if (hint()) {\r\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\r\n <mt-icon icon=\"general.help-circle\" />\r\n </p-inputgroup-addon>\r\n } @else {\r\n <p-inputgroup-addon tooltipPosition=\"top\">\r\n <mt-icon icon=\"user.user-03\" />\r\n </p-inputgroup-addon>\r\n }\r\n </p-inputgroup>\r\n\r\n @if (loading()) {\r\n <mt-icon\r\n icon=\"general.loading-01\"\r\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\r\n />\r\n }\r\n</div>\r\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\r\n", styles: [":host ::ng-deep .p-autocomplete-input-multiple{border-start-end-radius:0;border-end-end-radius:0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i2.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: Tooltip, selector: "[mtTooltip]" }, { kind: "ngmodule", type: InputGroupModule }, { kind: "component", type: i4.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "ngmodule", type: InputGroupAddonModule }, { kind: "component", type: i5.InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "component", type: FieldValidation, selector: "mt-field-validation", inputs: ["control", "touched"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
201
212
  }
202
213
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserSearchField, decorators: [{
203
214
  type: Component,
@@ -213,7 +224,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
213
224
  TranslocoPipe,
214
225
  ], changeDetection: ChangeDetectionStrategy.OnPush, host: {
215
226
  class: 'grid gap-1',
216
- }, template: "@if (label()) {\n <label\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\n [for]=\"ngControl?.name || label()\"\n >\n {{ label() }}\n </label>\n}\n<div class=\"relative\">\n <p-inputgroup>\n <p-autoComplete\n #autocomplete=\"\"\n [suggestions]=\"filteredUsers()\"\n (completeMethod)=\"search($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onClear)=\"onClear()\"\n (onFocus)=\"onFocus()\"\n (onBlur)=\"onBlur()\"\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\n [disabled]=\"disabled() || readonly()\"\n [id]=\"ngControl?.name || label()\"\n [invalid]=\"isInvalid(ngControl?.control)\"\n [placeholder]=\"'components.userSearchField.search' | transloco\"\n [multiple]=\"isMultiple()\"\n [optionLabel]=\"'displayName'\"\n class=\"w-full\"\n appendTo=\"body\"\n styleClass=\"w-full\"\n [dropdown]=\"false\"\n [size]=\"size()\"\n >\n <ng-template let-user pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template>\n\n <!-- <ng-template let-user #pTemplate=\"selecteditem\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template> -->\n </p-autoComplete>\n @if (hint()) {\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\n <mt-icon icon=\"general.help-circle\" />\n </p-inputgroup-addon>\n } @else {\n <p-inputgroup-addon tooltipPosition=\"top\">\n <mt-icon icon=\"user.user-03\" />\n </p-inputgroup-addon>\n }\n </p-inputgroup>\n\n @if (loading()) {\n <mt-icon\n icon=\"general.loading-01\"\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\n />\n }\n</div>\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\n", styles: [":host ::ng-deep .p-autocomplete-input-multiple{border-start-end-radius:0;border-end-end-radius:0}\n"] }]
227
+ }, template: "@if (label()) {\r\n <label\r\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\r\n [for]=\"ngControl?.name || label()\"\r\n >\r\n {{ label() }}\r\n </label>\r\n}\r\n<div class=\"relative\">\r\n <p-inputgroup>\r\n @if (unlinkedSingleUser()) {\r\n <p-inputgroup-addon\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n >\r\n <mt-icon icon=\"general.info-circle\" class=\"text-amber-500\" />\r\n </p-inputgroup-addon>\r\n }\r\n <p-autoComplete\r\n #autocomplete=\"\"\r\n [suggestions]=\"filteredUsers()\"\r\n (completeMethod)=\"search($event)\"\r\n (onSelect)=\"onSelect($event)\"\r\n (onUnselect)=\"onUnselect($event)\"\r\n (onClear)=\"onClear()\"\r\n (onFocus)=\"onFocus()\"\r\n (onBlur)=\"onBlur()\"\r\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\r\n [disabled]=\"disabled() || readonly()\"\r\n [id]=\"ngControl?.name || label()\"\r\n [invalid]=\"isInvalid(ngControl?.control)\"\r\n [placeholder]=\"'components.userSearchField.search' | transloco\"\r\n [multiple]=\"isMultiple()\"\r\n [optionLabel]=\"'displayName'\"\r\n class=\"w-full\"\r\n appendTo=\"body\"\r\n styleClass=\"w-full\"\r\n [dropdown]=\"false\"\r\n [size]=\"size()\"\r\n >\r\n <ng-template let-user pTemplate=\"item\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\r\n <div class=\"flex align-items-center gap-3\">\r\n <span class=\"font-medium\">{{ user.displayName }}</span>\r\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template let-user pTemplate=\"selecteditem\">\r\n <span class=\"inline-flex items-center gap-1\">\r\n <span>{{ user.displayName }}</span>\r\n @if (user.isLinkedToCurrentApplication === false) {\r\n <mt-icon\r\n icon=\"general.info-circle\"\r\n class=\"text-amber-500 text-sm shrink-0\"\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </span>\r\n </ng-template>\r\n </p-autoComplete>\r\n @if (hint()) {\r\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\r\n <mt-icon icon=\"general.help-circle\" />\r\n </p-inputgroup-addon>\r\n } @else {\r\n <p-inputgroup-addon tooltipPosition=\"top\">\r\n <mt-icon icon=\"user.user-03\" />\r\n </p-inputgroup-addon>\r\n }\r\n </p-inputgroup>\r\n\r\n @if (loading()) {\r\n <mt-icon\r\n icon=\"general.loading-01\"\r\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\r\n />\r\n }\r\n</div>\r\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\r\n", styles: [":host ::ng-deep .p-autocomplete-input-multiple{border-start-end-radius:0;border-end-end-radius:0}\n"] }]
217
228
  }], ctorParameters: () => [], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], isMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMultiple", required: false }] }], apiUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "apiUrl", required: true }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], paramName: [{ type: i0.Input, args: [{ isSignal: true, alias: "paramName", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], styleClass: [{
218
229
  type: HostBinding,
219
230
  args: ['class']
@@ -1 +1 @@
1
- {"version":3,"file":"masterteam-components-user-search-field.mjs","sources":["../../../../packages/masterteam/components/user-search-field/user-search-field.ts","../../../../packages/masterteam/components/user-search-field/user-search-field.html","../../../../packages/masterteam/components/user-search-field/masterteam-components-user-search-field.ts"],"sourcesContent":["import {\n Component,\n HostBinding,\n signal,\n input,\n OnInit,\n inject,\n ChangeDetectionStrategy,\n effect,\n viewChild,\n} from '@angular/core';\nimport {\n ControlValueAccessor,\n FormsModule,\n NgControl,\n Validators,\n} from '@angular/forms';\nimport { AutoComplete, AutoCompleteModule } from 'primeng/autocomplete';\nimport { InputGroupModule } from 'primeng/inputgroup';\nimport { InputGroupAddonModule } from 'primeng/inputgroupaddon';\nimport { Tooltip } from '@masterteam/components/tooltip';\nimport { FieldValidation } from '@masterteam/components/field-validation';\nimport { isInvalid } from '@masterteam/components';\nimport { Icon } from '@masterteam/icons';\nimport {\n Subject,\n debounceTime,\n switchMap,\n tap,\n of,\n finalize,\n catchError,\n} from 'rxjs';\nimport { HttpClient, HttpContext, HttpParams } from '@angular/common/http';\nimport { Avatar } from '@masterteam/components/avatar';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { TranslocoService, TranslocoPipe } from '@jsverse/transloco';\n\nexport interface User {\n isExternal: boolean;\n id: string;\n displayName: string;\n userName: string;\n photo: string;\n}\n\n@Component({\n selector: 'mt-user-search-field',\n standalone: true,\n imports: [\n FormsModule,\n AutoCompleteModule,\n Tooltip,\n InputGroupModule,\n InputGroupAddonModule,\n FieldValidation,\n Icon,\n Avatar,\n TranslocoPipe,\n ],\n templateUrl: './user-search-field.html',\n styleUrls: ['./user-search-field.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'grid gap-1',\n },\n})\nexport class UserSearchField implements ControlValueAccessor, OnInit {\n readonly hint = input<string>();\n readonly label = input<string>();\n readonly placeholder = input<string>();\n readonly class = input<string>('');\n readonly readonly = input<boolean>(false);\n readonly required = input<boolean>(false);\n readonly isMultiple = input<boolean>(false);\n readonly apiUrl = input.required<string>();\n readonly dataKey = input<string>('data');\n readonly paramName = input<string>('query');\n readonly context = input<HttpContext | undefined>(undefined);\n\n @HostBinding('class') styleClass: string;\n\n requiredValidator = Validators.required;\n value = signal<User | User[] | null>(null);\n disabled = signal<boolean>(false);\n loading = signal<boolean>(false);\n\n readonly size = input<'small' | 'large' | undefined>();\n\n filteredUsers = signal<User[]>([]);\n private searchTerms = new Subject<string>();\n\n private readonly translocoService = inject(TranslocoService);\n\n readonly autocomplete = viewChild<AutoComplete>('autocomplete');\n\n onTouched: () => void = () => {};\n onModelChange: (value: any) => void = () => {};\n\n public ngControl: NgControl | null = null;\n private http = inject(HttpClient);\n\n isInvalid = isInvalid;\n\n constructor() {\n this.ngControl = inject(NgControl, { self: true, optional: true });\n if (this.ngControl) {\n this.ngControl.valueAccessor = this;\n }\n effect(() => {\n if (this.ngControl?.control && this.required()) {\n this.ngControl.control.addValidators(Validators.required);\n this.ngControl.control.updateValueAndValidity();\n }\n });\n this.getUsers();\n }\n\n ngOnInit() {\n this.styleClass = this.class();\n }\n\n search(event: { query: string }) {\n this.searchTerms.next(event.query);\n }\n\n onFocus() {\n const autocomplete = this.autocomplete();\n if (!autocomplete) return;\n const inputEl = this.getInputElement(autocomplete);\n const typed = (inputEl?.value ?? '').trim();\n if (!typed) {\n this.filteredUsers.set([]);\n return;\n }\n if (this.filteredUsers().length > 0) {\n autocomplete.show();\n }\n }\n\n onBlur() {\n this.onTouched();\n\n const autocomplete = this.autocomplete();\n if (!autocomplete || this.filteredUsers().length > 0) return;\n\n const inputEl = this.getInputElement(autocomplete);\n const typed = (inputEl?.value ?? '').trim();\n if (!typed) return;\n\n if (!this.isMultiple()) {\n const value = this.value();\n const selectedLabel = Array.isArray(value)\n ? value[0]?.displayName\n : value?.displayName;\n\n if (selectedLabel?.trim() === typed) return;\n\n this.value.set(null);\n this.onModelChange(null);\n }\n\n if (inputEl) {\n inputEl.value = '';\n }\n this.filteredUsers.set([]);\n this.loading.set(false);\n autocomplete.hide();\n }\n\n onSelect(event: { originalEvent: Event; value: User }) {\n const selectedUser = event.value;\n if (this.isMultiple()) {\n const current = (this.value() as User[]) || [];\n const updated = [...current, selectedUser];\n this.value.set(updated);\n this.onModelChange(updated);\n const remaining = this.filteredUsers().filter(\n (u) => u.id !== selectedUser.id,\n );\n this.filteredUsers.set(remaining);\n if (remaining.length > 0) {\n queueMicrotask(() => this.autocomplete()?.show());\n }\n } else {\n this.value.set(selectedUser);\n this.onModelChange(selectedUser);\n this.filteredUsers.set([]);\n this.autocomplete()?.hide();\n }\n this.onTouched();\n this.loading.set(false);\n }\n\n onUnselect(event: { originalEvent: Event; value: User }) {\n const removedUser = event.value;\n const current = (this.value() as User[]) || [];\n const updated = current.filter((u) => u.id !== removedUser.id);\n this.value.set(updated);\n this.onModelChange(updated);\n this.onTouched();\n }\n\n onClear() {\n this.value.set(this.isMultiple() ? [] : null);\n this.onModelChange(this.isMultiple() ? [] : null);\n this.filteredUsers.set([]);\n this.loading.set(false);\n }\n\n writeValue(value: User | User[] | null): void {\n if (this.isMultiple()) {\n this.value.set(Array.isArray(value) ? value : value ? [value] : []);\n } else {\n this.value.set(Array.isArray(value) ? (value[0] ?? null) : value);\n }\n }\n\n registerOnChange(fn: (value: User | null) => void) {\n this.onModelChange = fn;\n }\n\n registerOnTouched(fn: any) {\n this.onTouched = fn;\n }\n\n setDisabledState(disabled: boolean) {\n this.disabled.set(disabled);\n }\n\n getUsers() {\n this.searchTerms\n .pipe(\n takeUntilDestroyed(),\n debounceTime(250),\n tap(() => this.loading.set(true)),\n switchMap((term: string) => {\n const trimmed = term?.trim();\n if (!trimmed) {\n this.filteredUsers.set([]);\n this.loading.set(false);\n return of({ [this.dataKey()]: [] } as Record<string, User[]>);\n }\n const params = new HttpParams().set(this.paramName(), trimmed);\n return this.http\n .get<Record<string, User[]>>(this.apiUrl(), {\n params,\n context: this.context(),\n })\n .pipe(\n finalize(() => this.loading.set(false)),\n catchError((err) => {\n console.error('API search failed:', err);\n return of({ [this.dataKey()]: [] } as Record<string, User[]>);\n }),\n );\n }),\n )\n .subscribe({\n next: (response) => {\n const users = (response?.[this.dataKey()] ?? []) as User[];\n if (this.isMultiple()) {\n const selectedIds = new Set(\n ((this.value() as User[]) ?? []).map((u) => u.id),\n );\n this.filteredUsers.set(users.filter((u) => !selectedIds.has(u.id)));\n } else {\n this.filteredUsers.set(users);\n }\n },\n });\n }\n\n private getInputElement(autocomplete: AutoComplete): HTMLInputElement | null {\n return (\n autocomplete.multiInputEl?.nativeElement ??\n autocomplete.inputEL?.nativeElement ??\n null\n );\n }\n}\n","@if (label()) {\n <label\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\n [for]=\"ngControl?.name || label()\"\n >\n {{ label() }}\n </label>\n}\n<div class=\"relative\">\n <p-inputgroup>\n <p-autoComplete\n #autocomplete=\"\"\n [suggestions]=\"filteredUsers()\"\n (completeMethod)=\"search($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onClear)=\"onClear()\"\n (onFocus)=\"onFocus()\"\n (onBlur)=\"onBlur()\"\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\n [disabled]=\"disabled() || readonly()\"\n [id]=\"ngControl?.name || label()\"\n [invalid]=\"isInvalid(ngControl?.control)\"\n [placeholder]=\"'components.userSearchField.search' | transloco\"\n [multiple]=\"isMultiple()\"\n [optionLabel]=\"'displayName'\"\n class=\"w-full\"\n appendTo=\"body\"\n styleClass=\"w-full\"\n [dropdown]=\"false\"\n [size]=\"size()\"\n >\n <ng-template let-user pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template>\n\n <!-- <ng-template let-user #pTemplate=\"selecteditem\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template> -->\n </p-autoComplete>\n @if (hint()) {\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\n <mt-icon icon=\"general.help-circle\" />\n </p-inputgroup-addon>\n } @else {\n <p-inputgroup-addon tooltipPosition=\"top\">\n <mt-icon icon=\"user.user-03\" />\n </p-inputgroup-addon>\n }\n </p-inputgroup>\n\n @if (loading()) {\n <mt-icon\n icon=\"general.loading-01\"\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\n />\n }\n</div>\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"masterteam-components-user-search-field.mjs","sources":["../../../../packages/masterteam/components/user-search-field/user-search-field.ts","../../../../packages/masterteam/components/user-search-field/user-search-field.html","../../../../packages/masterteam/components/user-search-field/masterteam-components-user-search-field.ts"],"sourcesContent":["import {\r\n Component,\r\n HostBinding,\r\n signal,\r\n computed,\r\n input,\r\n OnInit,\r\n inject,\r\n ChangeDetectionStrategy,\r\n effect,\r\n viewChild,\r\n} from '@angular/core';\r\nimport {\r\n ControlValueAccessor,\r\n FormsModule,\r\n NgControl,\r\n Validators,\r\n} from '@angular/forms';\r\nimport { AutoComplete, AutoCompleteModule } from 'primeng/autocomplete';\r\nimport { InputGroupModule } from 'primeng/inputgroup';\r\nimport { InputGroupAddonModule } from 'primeng/inputgroupaddon';\r\nimport { Tooltip } from '@masterteam/components/tooltip';\r\nimport { FieldValidation } from '@masterteam/components/field-validation';\r\nimport { isInvalid } from '@masterteam/components';\r\nimport { Icon } from '@masterteam/icons';\r\nimport {\r\n Subject,\r\n debounceTime,\r\n switchMap,\r\n tap,\r\n of,\r\n finalize,\r\n catchError,\r\n} from 'rxjs';\r\nimport { HttpClient, HttpContext, HttpParams } from '@angular/common/http';\r\nimport { Avatar } from '@masterteam/components/avatar';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { TranslocoService, TranslocoPipe } from '@jsverse/transloco';\r\n\r\nexport interface User {\r\n isExternal: boolean;\r\n id: string;\r\n displayName: string;\r\n userName: string;\r\n photo: string;\r\n /**\r\n * `false` when the user is no longer linked to the current application\r\n * (e.g. removed/deleted) but is still referenced by historical records.\r\n */\r\n isLinkedToCurrentApplication?: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'mt-user-search-field',\r\n standalone: true,\r\n imports: [\r\n FormsModule,\r\n AutoCompleteModule,\r\n Tooltip,\r\n InputGroupModule,\r\n InputGroupAddonModule,\r\n FieldValidation,\r\n Icon,\r\n Avatar,\r\n TranslocoPipe,\r\n ],\r\n templateUrl: './user-search-field.html',\r\n styleUrls: ['./user-search-field.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'grid gap-1',\r\n },\r\n})\r\nexport class UserSearchField implements ControlValueAccessor, OnInit {\r\n readonly hint = input<string>();\r\n readonly label = input<string>();\r\n readonly placeholder = input<string>();\r\n readonly class = input<string>('');\r\n readonly readonly = input<boolean>(false);\r\n readonly required = input<boolean>(false);\r\n readonly isMultiple = input<boolean>(false);\r\n readonly apiUrl = input.required<string>();\r\n readonly dataKey = input<string>('data');\r\n readonly paramName = input<string>('query');\r\n readonly context = input<HttpContext | undefined>(undefined);\r\n\r\n @HostBinding('class') styleClass: string;\r\n\r\n requiredValidator = Validators.required;\r\n value = signal<User | User[] | null>(null);\r\n disabled = signal<boolean>(false);\r\n loading = signal<boolean>(false);\r\n\r\n readonly size = input<'small' | 'large' | undefined>();\r\n\r\n filteredUsers = signal<User[]>([]);\r\n private searchTerms = new Subject<string>();\r\n\r\n /**\r\n * In single-select mode, `true` when the currently selected user is no\r\n * longer linked to the application. Drives the inline info badge/tooltip.\r\n * Multiple-select mode handles this per-chip via the `selecteditem` template.\r\n */\r\n readonly unlinkedSingleUser = computed<boolean>(() => {\r\n if (this.isMultiple()) return false;\r\n const current = this.value() as User | null;\r\n return !!current && current.isLinkedToCurrentApplication === false;\r\n });\r\n\r\n private readonly translocoService = inject(TranslocoService);\r\n\r\n readonly autocomplete = viewChild<AutoComplete>('autocomplete');\r\n\r\n onTouched: () => void = () => {};\r\n onModelChange: (value: any) => void = () => {};\r\n\r\n public ngControl: NgControl | null = null;\r\n private http = inject(HttpClient);\r\n\r\n isInvalid = isInvalid;\r\n\r\n constructor() {\r\n this.ngControl = inject(NgControl, { self: true, optional: true });\r\n if (this.ngControl) {\r\n this.ngControl.valueAccessor = this;\r\n }\r\n effect(() => {\r\n if (this.ngControl?.control && this.required()) {\r\n this.ngControl.control.addValidators(Validators.required);\r\n this.ngControl.control.updateValueAndValidity();\r\n }\r\n });\r\n this.getUsers();\r\n }\r\n\r\n ngOnInit() {\r\n this.styleClass = this.class();\r\n }\r\n\r\n search(event: { query: string }) {\r\n this.searchTerms.next(event.query);\r\n }\r\n\r\n onFocus() {\r\n const autocomplete = this.autocomplete();\r\n if (!autocomplete) return;\r\n const inputEl = this.getInputElement(autocomplete);\r\n const typed = (inputEl?.value ?? '').trim();\r\n if (!typed) {\r\n this.filteredUsers.set([]);\r\n return;\r\n }\r\n if (this.filteredUsers().length > 0) {\r\n autocomplete.show();\r\n }\r\n }\r\n\r\n onBlur() {\r\n this.onTouched();\r\n\r\n const autocomplete = this.autocomplete();\r\n if (!autocomplete || this.filteredUsers().length > 0) return;\r\n\r\n const inputEl = this.getInputElement(autocomplete);\r\n const typed = (inputEl?.value ?? '').trim();\r\n if (!typed) return;\r\n\r\n if (!this.isMultiple()) {\r\n const value = this.value();\r\n const selectedLabel = Array.isArray(value)\r\n ? value[0]?.displayName\r\n : value?.displayName;\r\n\r\n if (selectedLabel?.trim() === typed) return;\r\n\r\n this.value.set(null);\r\n this.onModelChange(null);\r\n }\r\n\r\n if (inputEl) {\r\n inputEl.value = '';\r\n }\r\n this.filteredUsers.set([]);\r\n this.loading.set(false);\r\n autocomplete.hide();\r\n }\r\n\r\n onSelect(event: { originalEvent: Event; value: User }) {\r\n const selectedUser = event.value;\r\n if (this.isMultiple()) {\r\n const current = (this.value() as User[]) || [];\r\n const updated = [...current, selectedUser];\r\n this.value.set(updated);\r\n this.onModelChange(updated);\r\n const remaining = this.filteredUsers().filter(\r\n (u) => u.id !== selectedUser.id,\r\n );\r\n this.filteredUsers.set(remaining);\r\n if (remaining.length > 0) {\r\n queueMicrotask(() => this.autocomplete()?.show());\r\n }\r\n } else {\r\n this.value.set(selectedUser);\r\n this.onModelChange(selectedUser);\r\n this.filteredUsers.set([]);\r\n this.autocomplete()?.hide();\r\n }\r\n this.onTouched();\r\n this.loading.set(false);\r\n }\r\n\r\n onUnselect(event: { originalEvent: Event; value: User }) {\r\n const removedUser = event.value;\r\n const current = (this.value() as User[]) || [];\r\n const updated = current.filter((u) => u.id !== removedUser.id);\r\n this.value.set(updated);\r\n this.onModelChange(updated);\r\n this.onTouched();\r\n }\r\n\r\n onClear() {\r\n this.value.set(this.isMultiple() ? [] : null);\r\n this.onModelChange(this.isMultiple() ? [] : null);\r\n this.filteredUsers.set([]);\r\n this.loading.set(false);\r\n }\r\n\r\n writeValue(value: User | User[] | null): void {\r\n if (this.isMultiple()) {\r\n this.value.set(Array.isArray(value) ? value : value ? [value] : []);\r\n } else {\r\n this.value.set(Array.isArray(value) ? (value[0] ?? null) : value);\r\n }\r\n }\r\n\r\n registerOnChange(fn: (value: User | null) => void) {\r\n this.onModelChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: any) {\r\n this.onTouched = fn;\r\n }\r\n\r\n setDisabledState(disabled: boolean) {\r\n this.disabled.set(disabled);\r\n }\r\n\r\n getUsers() {\r\n this.searchTerms\r\n .pipe(\r\n takeUntilDestroyed(),\r\n debounceTime(250),\r\n tap(() => this.loading.set(true)),\r\n switchMap((term: string) => {\r\n const trimmed = term?.trim();\r\n if (!trimmed) {\r\n this.filteredUsers.set([]);\r\n this.loading.set(false);\r\n return of({ [this.dataKey()]: [] } as Record<string, User[]>);\r\n }\r\n const params = new HttpParams().set(this.paramName(), trimmed);\r\n return this.http\r\n .get<Record<string, User[]>>(this.apiUrl(), {\r\n params,\r\n context: this.context(),\r\n })\r\n .pipe(\r\n finalize(() => this.loading.set(false)),\r\n catchError((err) => {\r\n console.error('API search failed:', err);\r\n return of({ [this.dataKey()]: [] } as Record<string, User[]>);\r\n }),\r\n );\r\n }),\r\n )\r\n .subscribe({\r\n next: (response) => {\r\n const users = (response?.[this.dataKey()] ?? []) as User[];\r\n if (this.isMultiple()) {\r\n const selectedIds = new Set(\r\n ((this.value() as User[]) ?? []).map((u) => u.id),\r\n );\r\n this.filteredUsers.set(users.filter((u) => !selectedIds.has(u.id)));\r\n } else {\r\n this.filteredUsers.set(users);\r\n }\r\n },\r\n });\r\n }\r\n\r\n private getInputElement(autocomplete: AutoComplete): HTMLInputElement | null {\r\n return (\r\n autocomplete.multiInputEl?.nativeElement ??\r\n autocomplete.inputEL?.nativeElement ??\r\n null\r\n );\r\n }\r\n}\r\n","@if (label()) {\r\n <label\r\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\r\n [for]=\"ngControl?.name || label()\"\r\n >\r\n {{ label() }}\r\n </label>\r\n}\r\n<div class=\"relative\">\r\n <p-inputgroup>\r\n @if (unlinkedSingleUser()) {\r\n <p-inputgroup-addon\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n >\r\n <mt-icon icon=\"general.info-circle\" class=\"text-amber-500\" />\r\n </p-inputgroup-addon>\r\n }\r\n <p-autoComplete\r\n #autocomplete=\"\"\r\n [suggestions]=\"filteredUsers()\"\r\n (completeMethod)=\"search($event)\"\r\n (onSelect)=\"onSelect($event)\"\r\n (onUnselect)=\"onUnselect($event)\"\r\n (onClear)=\"onClear()\"\r\n (onFocus)=\"onFocus()\"\r\n (onBlur)=\"onBlur()\"\r\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\r\n [disabled]=\"disabled() || readonly()\"\r\n [id]=\"ngControl?.name || label()\"\r\n [invalid]=\"isInvalid(ngControl?.control)\"\r\n [placeholder]=\"'components.userSearchField.search' | transloco\"\r\n [multiple]=\"isMultiple()\"\r\n [optionLabel]=\"'displayName'\"\r\n class=\"w-full\"\r\n appendTo=\"body\"\r\n styleClass=\"w-full\"\r\n [dropdown]=\"false\"\r\n [size]=\"size()\"\r\n >\r\n <ng-template let-user pTemplate=\"item\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\r\n <div class=\"flex align-items-center gap-3\">\r\n <span class=\"font-medium\">{{ user.displayName }}</span>\r\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template let-user pTemplate=\"selecteditem\">\r\n <span class=\"inline-flex items-center gap-1\">\r\n <span>{{ user.displayName }}</span>\r\n @if (user.isLinkedToCurrentApplication === false) {\r\n <mt-icon\r\n icon=\"general.info-circle\"\r\n class=\"text-amber-500 text-sm shrink-0\"\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </span>\r\n </ng-template>\r\n </p-autoComplete>\r\n @if (hint()) {\r\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\r\n <mt-icon icon=\"general.help-circle\" />\r\n </p-inputgroup-addon>\r\n } @else {\r\n <p-inputgroup-addon tooltipPosition=\"top\">\r\n <mt-icon icon=\"user.user-03\" />\r\n </p-inputgroup-addon>\r\n }\r\n </p-inputgroup>\r\n\r\n @if (loading()) {\r\n <mt-icon\r\n icon=\"general.loading-01\"\r\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\r\n />\r\n }\r\n</div>\r\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masterteam/components",
3
- "version": "0.0.182",
3
+ "version": "0.0.183",
4
4
  "publishConfig": {
5
5
  "directory": "../../../dist/masterteam/components",
6
6
  "linkDirectory": true,
@@ -97,6 +97,11 @@ interface EntityUserValue {
97
97
  photoUrl?: string;
98
98
  phoneNumber?: string;
99
99
  email?: string;
100
+ /**
101
+ * `false` when the user is no longer linked to the current application
102
+ * (e.g. removed/deleted) but is still referenced by historical records.
103
+ */
104
+ isLinkedToCurrentApplication?: boolean;
100
105
  }
101
106
  interface LeafDetailsStatusSummary {
102
107
  key: string;
@@ -265,6 +270,11 @@ declare class EntityUser {
265
270
  readonly userName: _angular_core.Signal<string>;
266
271
  readonly userPhoto: _angular_core.Signal<string>;
267
272
  readonly labelText: _angular_core.Signal<string>;
273
+ /**
274
+ * `true` when the referenced user is no longer linked to the application.
275
+ * Drives the inline info badge/tooltip next to the display name.
276
+ */
277
+ readonly isUnlinked: _angular_core.Signal<boolean>;
268
278
  private readonly config;
269
279
  readonly showDisplayName: _angular_core.Signal<boolean>;
270
280
  readonly showPhoneNumber: _angular_core.Signal<boolean>;
@@ -239,7 +239,7 @@ declare class Table {
239
239
  captionStartContent: _angular_core.Signal<TemplateRef<any> | undefined>;
240
240
  captionEndContent: _angular_core.Signal<TemplateRef<any> | undefined>;
241
241
  emptyContent: _angular_core.Signal<TemplateRef<any> | undefined>;
242
- paginatorPosition: _angular_core.InputSignal<"center" | "end" | "start">;
242
+ paginatorPosition: _angular_core.InputSignal<"end" | "start" | "center">;
243
243
  alwaysShowPaginator: _angular_core.InputSignalWithTransform<boolean, unknown>;
244
244
  rowsPerPageOptions: _angular_core.InputSignal<number[]>;
245
245
  pageSize: _angular_core.ModelSignal<number>;
@@ -248,7 +248,7 @@ declare class Table {
248
248
  filterTerm: _angular_core.ModelSignal<string>;
249
249
  groupBy: _angular_core.ModelSignal<string | null>;
250
250
  sortField: _angular_core.WritableSignal<string | null>;
251
- sortDirection: _angular_core.WritableSignal<"desc" | "asc" | null>;
251
+ sortDirection: _angular_core.WritableSignal<"asc" | "desc" | null>;
252
252
  confirmationService: ConfirmationService;
253
253
  private readonly exportService;
254
254
  private readonly transloco;
@@ -11,6 +11,11 @@ interface User {
11
11
  displayName: string;
12
12
  userName: string;
13
13
  photo: string;
14
+ /**
15
+ * `false` when the user is no longer linked to the current application
16
+ * (e.g. removed/deleted) but is still referenced by historical records.
17
+ */
18
+ isLinkedToCurrentApplication?: boolean;
14
19
  }
15
20
  declare class UserSearchField implements ControlValueAccessor, OnInit {
16
21
  readonly hint: _angular_core.InputSignal<string | undefined>;
@@ -32,6 +37,12 @@ declare class UserSearchField implements ControlValueAccessor, OnInit {
32
37
  readonly size: _angular_core.InputSignal<"small" | "large" | undefined>;
33
38
  filteredUsers: _angular_core.WritableSignal<User[]>;
34
39
  private searchTerms;
40
+ /**
41
+ * In single-select mode, `true` when the currently selected user is no
42
+ * longer linked to the application. Drives the inline info badge/tooltip.
43
+ * Multiple-select mode handles this per-chip via the `selecteditem` template.
44
+ */
45
+ readonly unlinkedSingleUser: _angular_core.Signal<boolean>;
35
46
  private readonly translocoService;
36
47
  readonly autocomplete: _angular_core.Signal<AutoComplete | undefined>;
37
48
  onTouched: () => void;