@maro-tech/form 0.1.6 → 0.1.8

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.
@@ -219,6 +219,7 @@ class InputBarcodeControlComponent {
219
219
  cameraStream = null;
220
220
  scanLoopId = null;
221
221
  autoOpenQueued = false;
222
+ autoOpenAttempted = false;
222
223
  openToken = 0;
223
224
  ngOnChanges(changes) {
224
225
  if (changes['disabled']?.currentValue === true) {
@@ -245,6 +246,10 @@ class InputBarcodeControlComponent {
245
246
  if (this.disabled() || this.isCameraStarting() || this.isCameraOpen()) {
246
247
  return;
247
248
  }
249
+ // The value emitted by a successful scan updates the parent form and
250
+ // triggers ngOnChanges. Do not treat that value update as a request to
251
+ // start the camera again after it has already been opened once.
252
+ this.autoOpenAttempted = true;
248
253
  this.cameraError.set('');
249
254
  this.cameraStatus.set('Запускаємо камеру…');
250
255
  this.isCameraStarting.set(true);
@@ -297,13 +302,13 @@ class InputBarcodeControlComponent {
297
302
  this.stopCamera();
298
303
  }
299
304
  scheduleAutoOpen() {
300
- if (typeof window === 'undefined' || this.disabled() || this.isCameraOpen() || this.isCameraStarting() || this.autoOpenQueued) {
305
+ if (typeof window === 'undefined' || this.disabled() || this.autoOpenAttempted || this.isCameraOpen() || this.isCameraStarting() || this.autoOpenQueued) {
301
306
  return;
302
307
  }
303
308
  this.autoOpenQueued = true;
304
309
  window.requestAnimationFrame(() => {
305
310
  this.autoOpenQueued = false;
306
- if (this.disabled() || this.isCameraOpen() || this.isCameraStarting()) {
311
+ if (this.disabled() || this.autoOpenAttempted || this.isCameraOpen() || this.isCameraStarting()) {
307
312
  return;
308
313
  }
309
314
  void this.openCamera();
@@ -2476,8 +2481,6 @@ class InputSelectControlComponent {
2476
2481
  required = false;
2477
2482
  disabled = false;
2478
2483
  multiple = false;
2479
- includeBlankOption = false;
2480
- blankOptionLabel = 'Оберіть…';
2481
2484
  emptyStateLabel = 'Немає варіантів для вибору';
2482
2485
  searchable = true;
2483
2486
  _options = [];
@@ -2636,11 +2639,11 @@ class InputSelectControlComponent {
2636
2639
  get displayLabel() {
2637
2640
  if (this.multiple) {
2638
2641
  if (!this.selectedOptions.length) {
2639
- return this.placeholder ?? this.blankOptionLabel;
2642
+ return this.placeholder ?? 'Оберіть…';
2640
2643
  }
2641
2644
  return `${this.selectedOptions.length}`;
2642
2645
  }
2643
- return this.selectedOptions[0]?.label ?? this.placeholder ?? this.blankOptionLabel;
2646
+ return this.selectedOptions[0]?.label ?? this.placeholder ?? 'Оберіть…';
2644
2647
  }
2645
2648
  isSelected(option) {
2646
2649
  const value = this.getOptionValue(option);
@@ -2662,9 +2665,6 @@ class InputSelectControlComponent {
2662
2665
  }
2663
2666
  const search = this.searchTerm.trim().toLowerCase();
2664
2667
  return options.filter((option) => {
2665
- if (this.includeBlankOption && !this.multiple && this.isBlankOption(option)) {
2666
- return true;
2667
- }
2668
2668
  return String(option.label ?? '').toLowerCase().includes(search);
2669
2669
  });
2670
2670
  }
@@ -2683,6 +2683,18 @@ class InputSelectControlComponent {
2683
2683
  this.updateSelectionFromValue();
2684
2684
  }
2685
2685
  }
2686
+ clearValue(event) {
2687
+ event.stopPropagation();
2688
+ if (this.disabled)
2689
+ return;
2690
+ const nextValue = this.multiple ? [] : null;
2691
+ this.value = '';
2692
+ this.multiValue = [];
2693
+ this.onChange(nextValue);
2694
+ this.valueChange.emit(nextValue);
2695
+ this.updateSelectionFromValue();
2696
+ this.cdr.markForCheck();
2697
+ }
2686
2698
  updateSelectionFromValue() {
2687
2699
  const options = this.getRenderOptions();
2688
2700
  if (this.multiple) {
@@ -2694,10 +2706,7 @@ class InputSelectControlComponent {
2694
2706
  }
2695
2707
  getRenderOptions() {
2696
2708
  const merged = this.mergeOptions(this.options, this.dictionaryOptions);
2697
- if (!this.includeBlankOption || this.multiple) {
2698
- return merged;
2699
- }
2700
- return [{ label: this.blankOptionLabel, value: '' }, ...merged];
2709
+ return merged;
2701
2710
  }
2702
2711
  mergeOptions(...optionSets) {
2703
2712
  const merged = new Map();
@@ -2828,14 +2837,14 @@ class InputSelectControlComponent {
2828
2837
  return this.http.get(`/api/suggest/${encodeURIComponent(name)}/${encodeURIComponent(key)}`);
2829
2838
  }
2830
2839
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: InputSelectControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2831
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: InputSelectControlComponent, isStandalone: true, selector: "input-select-control", inputs: { label: "label", placeholder: "placeholder", name: "name", data: "data", dataParams: "dataParams", required: "required", disabled: "disabled", multiple: ["multiple", "multiple", booleanAttribute], includeBlankOption: "includeBlankOption", blankOptionLabel: "blankOptionLabel", emptyStateLabel: "emptyStateLabel", searchable: "searchable", options: "options", error: "error", hint: "hint", triggerClass: "triggerClass", panelClass: "panelClass" }, outputs: { valueChange: "valueChange", searchChange: "searchChange" }, host: { listeners: { "document:click": "onDocumentClick()", "document:keydown.escape": "onEscape()" } }, providers: [
2840
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: InputSelectControlComponent, isStandalone: true, selector: "input-select-control", inputs: { label: "label", placeholder: "placeholder", name: "name", data: "data", dataParams: "dataParams", required: "required", disabled: "disabled", multiple: ["multiple", "multiple", booleanAttribute], emptyStateLabel: "emptyStateLabel", searchable: "searchable", options: "options", error: "error", hint: "hint", triggerClass: "triggerClass", panelClass: "panelClass" }, outputs: { valueChange: "valueChange", searchChange: "searchChange" }, host: { listeners: { "document:click": "onDocumentClick()", "document:keydown.escape": "onEscape()" } }, providers: [
2832
2841
  {
2833
2842
  provide: NG_VALUE_ACCESSOR,
2834
2843
  useExisting: forwardRef(() => InputSelectControlComponent),
2835
2844
  multi: true,
2836
2845
  },
2837
2846
  { provide: NG_VALIDATORS, useExisting: forwardRef(() => InputSelectControlComponent), multi: true },
2838
- ], viewQueries: [{ propertyName: "dropdownTrigger", first: true, predicate: ["dropdownTrigger"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: " <div class=\"relative w-full\">\n\n <button\n data-field-control\n cdkOverlayOrigin\n #dropdownTrigger=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"flex min-h-10 w-full flex-nowrap items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 transition hover:border-slate-300 focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [class]=\"triggerClass\"\n [class.opacity-50]=\"disabled\"\n [disabled]=\"disabled\"\n (click)=\"toggleDropdown($event)\"\n >\n\n <span class=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\" [class.-ml-2]=\"multiple\">\n <!-- MULTIPLE MODE -->\n @if (multiple) {\n\n @if (selectedOptions.length) {\n\n @for (option of selectedOptions; track option.value) {\n <span\n class=\"inline-flex h-6 shrink-0 items-center gap-1 rounded-md bg-slate-100 px-2 text-xs font-medium text-slate-700\"\n >\n {{ option.label }}\n\n <span\n role=\"button\"\n tabindex=\"0\"\n class=\"text-slate-400 hover:text-rose-500 transition-colors\"\n (click)=\"removeOption(option, $event)\"\n (keydown.enter)=\"removeOption(option, $event)\"\n (keydown.space)=\"$event.preventDefault(); removeOption(option, $event)\"\n >\n <lucide-icon [img]=\"closeIcon\" class=\"h-4 w-4 shrink-0\"></lucide-icon>\n </span>\n </span>\n }\n\n } @else {\n <span class=\"text-slate-400\">\n {{ placeholder ?? blankOptionLabel }}\n </span>\n }\n\n } @else {\n\n <!-- SINGLE MODE -->\n @if (selectedOptions[0]?.imageUrl) {\n <img [src]=\"selectedOptions[0]?.imageUrl\" alt=\"\" class=\"h-7 w-7 rounded object-cover\" />\n }\n <span class=\"min-w-0 truncate\">\n {{ selectedOptions[0]?.label ?? placeholder ?? blankOptionLabel }}\n </span>\n\n }\n </span>\n\n <lucide-icon [img]=\"chevronDownIcon\" class=\"shrink-0 text-xs text-slate-400\"></lucide-icon>\n\n </button>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"dropdownTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPositions]=\"dropdownPositions\"\n [cdkConnectedOverlayViewportMargin]=\"popupViewportMargin\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n (detach)=\"closeDropdown()\"\n >\n <!-- DROPDOWN -->\n <div\n class=\"z-50 w-full max-w-[calc(100vw-2rem)] rounded-xl border border-slate-200 bg-white shadow-lg\"\n [style.width.px]=\"popupWidth\"\n [style.max-width]=\"'calc(100vw - 2rem)'\"\n [class]=\"panelClass\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (searchable) {\n <div class=\"border-b border-slate-100 p-2\">\n <input\n type=\"text\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none transition focus:border-slate-900 focus:ring-2 focus:ring-slate-200\"\n placeholder=\"\u041F\u043E\u0448\u0443\u043A...\"\n [ngModel]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange($event)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div class=\"max-h-60 overflow-auto\">\n @if (!visibleOptions.length) {\n <div class=\"px-4 py-3 text-sm text-slate-500\">\n @if (isDictionaryLoading && data) {\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...\n } @else {\n {{ emptyStateLabel }}\n }\n </div>\n } @else {\n @for (option of visibleOptions; track trackOption($index, option)) {\n <button\n type=\"button\"\n class=\"flex w-full items-start justify-between gap-3 whitespace-normal break-words px-4 py-2 text-left text-sm hover:bg-slate-50\"\n [class.bg-slate-100]=\"isSelected(option)\"\n (click)=\"selectOption(option, $event)\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (option.imageUrl) {\n <img [src]=\"option.imageUrl\" alt=\"\" class=\"h-8 w-8 shrink-0 rounded object-cover\" />\n }\n <span class=\"whitespace-normal break-words\">{{ option.label }}</span>\n </span>\n\n @if (isSelected(option)) {\n <lucide-icon [img]=\"checkIcon\" class=\"text-xs text-sky-500\"></lucide-icon>\n }\n </button>\n }\n }\n </div>\n\n </div>\n </ng-template>\n\n </div>\n", dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: CommonModule }, { 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"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2847
+ ], viewQueries: [{ propertyName: "dropdownTrigger", first: true, predicate: ["dropdownTrigger"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: " <div class=\"relative w-full\">\n\n <button\n data-field-control\n cdkOverlayOrigin\n #dropdownTrigger=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"relative flex min-h-10 w-full flex-nowrap items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 pr-14 text-sm text-slate-900 transition hover:border-slate-300 focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [class]=\"triggerClass\"\n [class.opacity-50]=\"disabled\"\n [disabled]=\"disabled\"\n (click)=\"toggleDropdown($event)\"\n >\n\n <span class=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\" [class.-ml-2]=\"multiple\">\n <!-- MULTIPLE MODE -->\n @if (multiple) {\n\n @if (selectedOptions.length) {\n\n @for (option of selectedOptions; track option.value) {\n <span\n class=\"inline-flex h-6 shrink-0 items-center gap-1 rounded-md bg-slate-100 px-2 text-xs font-medium text-slate-700\"\n >\n {{ option.label }}\n\n <span\n role=\"button\"\n tabindex=\"0\"\n class=\"text-slate-400 hover:text-rose-500 transition-colors\"\n (click)=\"removeOption(option, $event)\"\n (keydown.enter)=\"removeOption(option, $event)\"\n (keydown.space)=\"$event.preventDefault(); removeOption(option, $event)\"\n >\n <lucide-icon [img]=\"closeIcon\" class=\"h-4 w-4 shrink-0\"></lucide-icon>\n </span>\n </span>\n }\n\n } @else {\n <span class=\"text-slate-400\">\n {{ placeholder ?? '\u041E\u0431\u0435\u0440\u0456\u0442\u044C\u2026' }}\n </span>\n }\n\n } @else {\n\n <!-- SINGLE MODE -->\n @if (selectedOptions[0]?.imageUrl) {\n <img [src]=\"selectedOptions[0]?.imageUrl\" alt=\"\" class=\"h-7 w-7 rounded object-cover\" />\n }\n <span class=\"min-w-0 truncate\">\n {{ selectedOptions[0]?.label ?? placeholder ?? '\u041E\u0431\u0435\u0440\u0456\u0442\u044C\u2026' }}\n </span>\n\n }\n </span>\n\n <span class=\"absolute right-3 top-1/2 flex -translate-y-1/2 items-center gap-0\">\n <lucide-icon [img]=\"chevronDownIcon\" class=\"h-4 w-4 shrink-0 text-slate-400\"></lucide-icon>\n\n @if (selectedOptions.length && !disabled) {\n <span\n role=\"button\"\n tabindex=\"0\"\n class=\"inline-flex h-5 w-5 items-center justify-center rounded-md text-slate-400 transition-colors hover:bg-slate-100 hover:text-rose-500\"\n aria-label=\"\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u0438\"\n (click)=\"clearValue($event)\"\n (keydown.enter)=\"clearValue($event)\"\n (keydown.space)=\"$event.preventDefault(); clearValue($event)\"\n >\n <lucide-icon [img]=\"closeIcon\" class=\"h-4 w-4 shrink-0\"></lucide-icon>\n </span>\n }\n </span>\n\n </button>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"dropdownTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPositions]=\"dropdownPositions\"\n [cdkConnectedOverlayViewportMargin]=\"popupViewportMargin\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n (detach)=\"closeDropdown()\"\n >\n <!-- DROPDOWN -->\n <div\n class=\"z-50 w-full max-w-[calc(100vw-2rem)] rounded-xl border border-slate-200 bg-white shadow-lg\"\n [style.width.px]=\"popupWidth\"\n [style.max-width]=\"'calc(100vw - 2rem)'\"\n [class]=\"panelClass\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (searchable) {\n <div class=\"border-b border-slate-100 p-2\">\n <input\n type=\"text\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none transition focus:border-slate-900 focus:ring-2 focus:ring-slate-200\"\n placeholder=\"\u041F\u043E\u0448\u0443\u043A...\"\n [ngModel]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange($event)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div class=\"max-h-60 overflow-auto\">\n @if (!visibleOptions.length) {\n <div class=\"px-4 py-3 text-sm text-slate-500\">\n @if (isDictionaryLoading && data) {\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...\n } @else {\n {{ emptyStateLabel }}\n }\n </div>\n } @else {\n @for (option of visibleOptions; track trackOption($index, option)) {\n <button\n type=\"button\"\n class=\"flex w-full items-start justify-between gap-3 whitespace-normal break-words px-4 py-2 text-left text-sm hover:bg-slate-50\"\n [class.bg-slate-100]=\"isSelected(option)\"\n (click)=\"selectOption(option, $event)\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (option.imageUrl) {\n <img [src]=\"option.imageUrl\" alt=\"\" class=\"h-8 w-8 shrink-0 rounded object-cover\" />\n }\n <span class=\"whitespace-normal break-words\">{{ option.label }}</span>\n </span>\n\n @if (isSelected(option)) {\n <lucide-icon [img]=\"checkIcon\" class=\"text-xs text-sky-500\"></lucide-icon>\n }\n </button>\n }\n }\n </div>\n\n </div>\n </ng-template>\n\n </div>\n", dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: CommonModule }, { 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"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2839
2848
  }
2840
2849
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: InputSelectControlComponent, decorators: [{
2841
2850
  type: Component,
@@ -2846,7 +2855,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2846
2855
  multi: true,
2847
2856
  },
2848
2857
  { provide: NG_VALIDATORS, useExisting: forwardRef(() => InputSelectControlComponent), multi: true },
2849
- ], template: " <div class=\"relative w-full\">\n\n <button\n data-field-control\n cdkOverlayOrigin\n #dropdownTrigger=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"flex min-h-10 w-full flex-nowrap items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-900 transition hover:border-slate-300 focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [class]=\"triggerClass\"\n [class.opacity-50]=\"disabled\"\n [disabled]=\"disabled\"\n (click)=\"toggleDropdown($event)\"\n >\n\n <span class=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\" [class.-ml-2]=\"multiple\">\n <!-- MULTIPLE MODE -->\n @if (multiple) {\n\n @if (selectedOptions.length) {\n\n @for (option of selectedOptions; track option.value) {\n <span\n class=\"inline-flex h-6 shrink-0 items-center gap-1 rounded-md bg-slate-100 px-2 text-xs font-medium text-slate-700\"\n >\n {{ option.label }}\n\n <span\n role=\"button\"\n tabindex=\"0\"\n class=\"text-slate-400 hover:text-rose-500 transition-colors\"\n (click)=\"removeOption(option, $event)\"\n (keydown.enter)=\"removeOption(option, $event)\"\n (keydown.space)=\"$event.preventDefault(); removeOption(option, $event)\"\n >\n <lucide-icon [img]=\"closeIcon\" class=\"h-4 w-4 shrink-0\"></lucide-icon>\n </span>\n </span>\n }\n\n } @else {\n <span class=\"text-slate-400\">\n {{ placeholder ?? blankOptionLabel }}\n </span>\n }\n\n } @else {\n\n <!-- SINGLE MODE -->\n @if (selectedOptions[0]?.imageUrl) {\n <img [src]=\"selectedOptions[0]?.imageUrl\" alt=\"\" class=\"h-7 w-7 rounded object-cover\" />\n }\n <span class=\"min-w-0 truncate\">\n {{ selectedOptions[0]?.label ?? placeholder ?? blankOptionLabel }}\n </span>\n\n }\n </span>\n\n <lucide-icon [img]=\"chevronDownIcon\" class=\"shrink-0 text-xs text-slate-400\"></lucide-icon>\n\n </button>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"dropdownTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPositions]=\"dropdownPositions\"\n [cdkConnectedOverlayViewportMargin]=\"popupViewportMargin\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n (detach)=\"closeDropdown()\"\n >\n <!-- DROPDOWN -->\n <div\n class=\"z-50 w-full max-w-[calc(100vw-2rem)] rounded-xl border border-slate-200 bg-white shadow-lg\"\n [style.width.px]=\"popupWidth\"\n [style.max-width]=\"'calc(100vw - 2rem)'\"\n [class]=\"panelClass\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (searchable) {\n <div class=\"border-b border-slate-100 p-2\">\n <input\n type=\"text\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none transition focus:border-slate-900 focus:ring-2 focus:ring-slate-200\"\n placeholder=\"\u041F\u043E\u0448\u0443\u043A...\"\n [ngModel]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange($event)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div class=\"max-h-60 overflow-auto\">\n @if (!visibleOptions.length) {\n <div class=\"px-4 py-3 text-sm text-slate-500\">\n @if (isDictionaryLoading && data) {\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...\n } @else {\n {{ emptyStateLabel }}\n }\n </div>\n } @else {\n @for (option of visibleOptions; track trackOption($index, option)) {\n <button\n type=\"button\"\n class=\"flex w-full items-start justify-between gap-3 whitespace-normal break-words px-4 py-2 text-left text-sm hover:bg-slate-50\"\n [class.bg-slate-100]=\"isSelected(option)\"\n (click)=\"selectOption(option, $event)\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (option.imageUrl) {\n <img [src]=\"option.imageUrl\" alt=\"\" class=\"h-8 w-8 shrink-0 rounded object-cover\" />\n }\n <span class=\"whitespace-normal break-words\">{{ option.label }}</span>\n </span>\n\n @if (isSelected(option)) {\n <lucide-icon [img]=\"checkIcon\" class=\"text-xs text-sky-500\"></lucide-icon>\n }\n </button>\n }\n }\n </div>\n\n </div>\n </ng-template>\n\n </div>\n" }]
2858
+ ], template: " <div class=\"relative w-full\">\n\n <button\n data-field-control\n cdkOverlayOrigin\n #dropdownTrigger=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"relative flex min-h-10 w-full flex-nowrap items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 pr-14 text-sm text-slate-900 transition hover:border-slate-300 focus:border-slate-900 focus:outline-none focus:ring-2 focus:ring-slate-200\"\n [class]=\"triggerClass\"\n [class.opacity-50]=\"disabled\"\n [disabled]=\"disabled\"\n (click)=\"toggleDropdown($event)\"\n >\n\n <span class=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\" [class.-ml-2]=\"multiple\">\n <!-- MULTIPLE MODE -->\n @if (multiple) {\n\n @if (selectedOptions.length) {\n\n @for (option of selectedOptions; track option.value) {\n <span\n class=\"inline-flex h-6 shrink-0 items-center gap-1 rounded-md bg-slate-100 px-2 text-xs font-medium text-slate-700\"\n >\n {{ option.label }}\n\n <span\n role=\"button\"\n tabindex=\"0\"\n class=\"text-slate-400 hover:text-rose-500 transition-colors\"\n (click)=\"removeOption(option, $event)\"\n (keydown.enter)=\"removeOption(option, $event)\"\n (keydown.space)=\"$event.preventDefault(); removeOption(option, $event)\"\n >\n <lucide-icon [img]=\"closeIcon\" class=\"h-4 w-4 shrink-0\"></lucide-icon>\n </span>\n </span>\n }\n\n } @else {\n <span class=\"text-slate-400\">\n {{ placeholder ?? '\u041E\u0431\u0435\u0440\u0456\u0442\u044C\u2026' }}\n </span>\n }\n\n } @else {\n\n <!-- SINGLE MODE -->\n @if (selectedOptions[0]?.imageUrl) {\n <img [src]=\"selectedOptions[0]?.imageUrl\" alt=\"\" class=\"h-7 w-7 rounded object-cover\" />\n }\n <span class=\"min-w-0 truncate\">\n {{ selectedOptions[0]?.label ?? placeholder ?? '\u041E\u0431\u0435\u0440\u0456\u0442\u044C\u2026' }}\n </span>\n\n }\n </span>\n\n <span class=\"absolute right-3 top-1/2 flex -translate-y-1/2 items-center gap-0\">\n <lucide-icon [img]=\"chevronDownIcon\" class=\"h-4 w-4 shrink-0 text-slate-400\"></lucide-icon>\n\n @if (selectedOptions.length && !disabled) {\n <span\n role=\"button\"\n tabindex=\"0\"\n class=\"inline-flex h-5 w-5 items-center justify-center rounded-md text-slate-400 transition-colors hover:bg-slate-100 hover:text-rose-500\"\n aria-label=\"\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u0438\"\n (click)=\"clearValue($event)\"\n (keydown.enter)=\"clearValue($event)\"\n (keydown.space)=\"$event.preventDefault(); clearValue($event)\"\n >\n <lucide-icon [img]=\"closeIcon\" class=\"h-4 w-4 shrink-0\"></lucide-icon>\n </span>\n }\n </span>\n\n </button>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"dropdownTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPositions]=\"dropdownPositions\"\n [cdkConnectedOverlayViewportMargin]=\"popupViewportMargin\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n (detach)=\"closeDropdown()\"\n >\n <!-- DROPDOWN -->\n <div\n class=\"z-50 w-full max-w-[calc(100vw-2rem)] rounded-xl border border-slate-200 bg-white shadow-lg\"\n [style.width.px]=\"popupWidth\"\n [style.max-width]=\"'calc(100vw - 2rem)'\"\n [class]=\"panelClass\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (searchable) {\n <div class=\"border-b border-slate-100 p-2\">\n <input\n type=\"text\"\n class=\"w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none transition focus:border-slate-900 focus:ring-2 focus:ring-slate-200\"\n placeholder=\"\u041F\u043E\u0448\u0443\u043A...\"\n [ngModel]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange($event)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div class=\"max-h-60 overflow-auto\">\n @if (!visibleOptions.length) {\n <div class=\"px-4 py-3 text-sm text-slate-500\">\n @if (isDictionaryLoading && data) {\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...\n } @else {\n {{ emptyStateLabel }}\n }\n </div>\n } @else {\n @for (option of visibleOptions; track trackOption($index, option)) {\n <button\n type=\"button\"\n class=\"flex w-full items-start justify-between gap-3 whitespace-normal break-words px-4 py-2 text-left text-sm hover:bg-slate-50\"\n [class.bg-slate-100]=\"isSelected(option)\"\n (click)=\"selectOption(option, $event)\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (option.imageUrl) {\n <img [src]=\"option.imageUrl\" alt=\"\" class=\"h-8 w-8 shrink-0 rounded object-cover\" />\n }\n <span class=\"whitespace-normal break-words\">{{ option.label }}</span>\n </span>\n\n @if (isSelected(option)) {\n <lucide-icon [img]=\"checkIcon\" class=\"text-xs text-sky-500\"></lucide-icon>\n }\n </button>\n }\n }\n </div>\n\n </div>\n </ng-template>\n\n </div>\n" }]
2850
2859
  }], ctorParameters: () => [], propDecorators: { label: [{
2851
2860
  type: Input
2852
2861
  }], placeholder: [{
@@ -2864,10 +2873,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2864
2873
  }], multiple: [{
2865
2874
  type: Input,
2866
2875
  args: [{ transform: booleanAttribute }]
2867
- }], includeBlankOption: [{
2868
- type: Input
2869
- }], blankOptionLabel: [{
2870
- type: Input
2871
2876
  }], emptyStateLabel: [{
2872
2877
  type: Input
2873
2878
  }], searchable: [{
@@ -2909,8 +2914,6 @@ class InputSelectComponent {
2909
2914
  required = false;
2910
2915
  disabled = false;
2911
2916
  multiple = false;
2912
- includeBlankOption = false;
2913
- blankOptionLabel = 'Оберіть…';
2914
2917
  emptyStateLabel = 'Немає варіантів для вибору';
2915
2918
  searchable = true;
2916
2919
  options = [];
@@ -2938,17 +2941,17 @@ class InputSelectComponent {
2938
2941
  setDisabledState(isDisabled) { this.disabled = isDisabled; }
2939
2942
  validate(control) { return validateFormControl(control, this.required); }
2940
2943
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: InputSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2941
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "21.2.19", type: InputSelectComponent, isStandalone: true, selector: "input-select", inputs: { label: "label", hint: "hint", error: "error", placeholder: "placeholder", name: "name", data: "data", dataParams: "dataParams", required: "required", disabled: "disabled", multiple: ["multiple", "multiple", booleanAttribute], includeBlankOption: "includeBlankOption", blankOptionLabel: "blankOptionLabel", emptyStateLabel: "emptyStateLabel", searchable: "searchable", options: "options", triggerClass: "triggerClass", panelClass: "panelClass" }, outputs: { valueChange: "valueChange", searchChange: "searchChange" }, providers: [
2944
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "21.2.19", type: InputSelectComponent, isStandalone: true, selector: "input-select", inputs: { label: "label", hint: "hint", error: "error", placeholder: "placeholder", name: "name", data: "data", dataParams: "dataParams", required: "required", disabled: "disabled", multiple: ["multiple", "multiple", booleanAttribute], emptyStateLabel: "emptyStateLabel", searchable: "searchable", options: "options", triggerClass: "triggerClass", panelClass: "panelClass" }, outputs: { valueChange: "valueChange", searchChange: "searchChange" }, providers: [
2942
2945
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputSelectComponent), multi: true },
2943
2946
  { provide: NG_VALIDATORS, useExisting: forwardRef(() => InputSelectComponent), multi: true },
2944
- ], viewQueries: [{ propertyName: "control", first: true, predicate: InputSelectControlComponent, descendants: true }], ngImport: i0, template: "<field-frame [label]=\"label\" [hint]=\"hint\" [error]=\"error\" [required]=\"required\" [disabled]=\"disabled\">\n <input-select-control\n [placeholder]=\"placeholder\"\n [name]=\"name\"\n [data]=\"data\"\n [dataParams]=\"dataParams\"\n [required]=\"required\"\n [disabled]=\"disabled\"\n [multiple]=\"multiple\"\n [includeBlankOption]=\"includeBlankOption\"\n [blankOptionLabel]=\"blankOptionLabel\"\n [emptyStateLabel]=\"emptyStateLabel\"\n [searchable]=\"searchable\"\n [options]=\"options\"\n [triggerClass]=\"triggerClass\"\n [panelClass]=\"panelClass\"\n (valueChange)=\"valueChange.emit($event)\"\n (searchChange)=\"searchChange.emit($event)\"\n />\n</field-frame>\n", dependencies: [{ kind: "component", type: FieldFrameComponent, selector: "field-frame", inputs: ["label", "hint", "error", "required", "forId", "disabled", "actions"], outputs: ["actionTriggered"] }, { kind: "component", type: InputSelectControlComponent, selector: "input-select-control", inputs: ["label", "placeholder", "name", "data", "dataParams", "required", "disabled", "multiple", "includeBlankOption", "blankOptionLabel", "emptyStateLabel", "searchable", "options", "error", "hint", "triggerClass", "panelClass"], outputs: ["valueChange", "searchChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2947
+ ], viewQueries: [{ propertyName: "control", first: true, predicate: InputSelectControlComponent, descendants: true }], ngImport: i0, template: "<field-frame [label]=\"label\" [hint]=\"hint\" [error]=\"error\" [required]=\"required\" [disabled]=\"disabled\">\n <input-select-control\n [placeholder]=\"placeholder\"\n [name]=\"name\"\n [data]=\"data\"\n [dataParams]=\"dataParams\"\n [required]=\"required\"\n [disabled]=\"disabled\"\n [multiple]=\"multiple\"\n [emptyStateLabel]=\"emptyStateLabel\"\n [searchable]=\"searchable\"\n [options]=\"options\"\n [triggerClass]=\"triggerClass\"\n [panelClass]=\"panelClass\"\n (valueChange)=\"valueChange.emit($event)\"\n (searchChange)=\"searchChange.emit($event)\"\n />\n</field-frame>\n", dependencies: [{ kind: "component", type: FieldFrameComponent, selector: "field-frame", inputs: ["label", "hint", "error", "required", "forId", "disabled", "actions"], outputs: ["actionTriggered"] }, { kind: "component", type: InputSelectControlComponent, selector: "input-select-control", inputs: ["label", "placeholder", "name", "data", "dataParams", "required", "disabled", "multiple", "emptyStateLabel", "searchable", "options", "error", "hint", "triggerClass", "panelClass"], outputs: ["valueChange", "searchChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2945
2948
  }
2946
2949
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: InputSelectComponent, decorators: [{
2947
2950
  type: Component,
2948
2951
  args: [{ selector: 'input-select', standalone: true, imports: [FieldFrameComponent, InputSelectControlComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2949
2952
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputSelectComponent), multi: true },
2950
2953
  { provide: NG_VALIDATORS, useExisting: forwardRef(() => InputSelectComponent), multi: true },
2951
- ], template: "<field-frame [label]=\"label\" [hint]=\"hint\" [error]=\"error\" [required]=\"required\" [disabled]=\"disabled\">\n <input-select-control\n [placeholder]=\"placeholder\"\n [name]=\"name\"\n [data]=\"data\"\n [dataParams]=\"dataParams\"\n [required]=\"required\"\n [disabled]=\"disabled\"\n [multiple]=\"multiple\"\n [includeBlankOption]=\"includeBlankOption\"\n [blankOptionLabel]=\"blankOptionLabel\"\n [emptyStateLabel]=\"emptyStateLabel\"\n [searchable]=\"searchable\"\n [options]=\"options\"\n [triggerClass]=\"triggerClass\"\n [panelClass]=\"panelClass\"\n (valueChange)=\"valueChange.emit($event)\"\n (searchChange)=\"searchChange.emit($event)\"\n />\n</field-frame>\n" }]
2954
+ ], template: "<field-frame [label]=\"label\" [hint]=\"hint\" [error]=\"error\" [required]=\"required\" [disabled]=\"disabled\">\n <input-select-control\n [placeholder]=\"placeholder\"\n [name]=\"name\"\n [data]=\"data\"\n [dataParams]=\"dataParams\"\n [required]=\"required\"\n [disabled]=\"disabled\"\n [multiple]=\"multiple\"\n [emptyStateLabel]=\"emptyStateLabel\"\n [searchable]=\"searchable\"\n [options]=\"options\"\n [triggerClass]=\"triggerClass\"\n [panelClass]=\"panelClass\"\n (valueChange)=\"valueChange.emit($event)\"\n (searchChange)=\"searchChange.emit($event)\"\n />\n</field-frame>\n" }]
2952
2955
  }], propDecorators: { control: [{
2953
2956
  type: ViewChild,
2954
2957
  args: [InputSelectControlComponent]
@@ -2973,10 +2976,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2973
2976
  }], multiple: [{
2974
2977
  type: Input,
2975
2978
  args: [{ transform: booleanAttribute }]
2976
- }], includeBlankOption: [{
2977
- type: Input
2978
- }], blankOptionLabel: [{
2979
- type: Input
2980
2979
  }], emptyStateLabel: [{
2981
2980
  type: Input
2982
2981
  }], searchable: [{