@webilix/ngx-form-m3 0.0.42 → 0.0.43

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 { HostBinding, Directive, Input, HostListener, Optional, Pipe, InjectionToken, inject, Component, Injector, EventEmitter, Output, makeEnvironmentProviders, ViewChild, Inject } from '@angular/core';
2
+ import { HostBinding, Directive, Input, HostListener, Optional, Pipe, InjectionToken, inject, Component, Injector, EventEmitter, Output, model, computed, makeEnvironmentProviders, ViewChild, Inject } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { ReactiveFormsModule, FormControl, Validators, FormsModule, FormGroup } from '@angular/forms';
5
5
  import { MatIconButton, MatButton } from '@angular/material/button';
@@ -24,6 +24,9 @@ import * as i3$1 from '@angular/material/menu';
24
24
  import { MatMenuModule } from '@angular/material/menu';
25
25
  import * as i4 from '@angular/material/select';
26
26
  import { MatSelectModule } from '@angular/material/select';
27
+ import { ENTER, COMMA } from '@angular/cdk/keycodes';
28
+ import * as i3$2 from '@angular/material/chips';
29
+ import { MatChipsModule } from '@angular/material/chips';
27
30
  import * as i1$5 from '@angular/router';
28
31
 
29
32
  class AutoCompleteDirective {
@@ -1752,6 +1755,93 @@ class InputSelectMethods extends InputMethods {
1752
1755
  }
1753
1756
  }
1754
1757
 
1758
+ class InputTagComponent {
1759
+ formControl = inject(INPUT_CONTROL);
1760
+ input = inject(INPUT_TYPE);
1761
+ config = inject(INPUT_CONFIG);
1762
+ values;
1763
+ isButtonDisabled;
1764
+ separatorKeysCodes = [ENTER, COMMA];
1765
+ inputValue = model('', ...(ngDevMode ? [{ debugName: "inputValue" }] : []));
1766
+ tags = Array.isArray(this.formControl.value) ? this.formControl.value : [];
1767
+ filteredTags = computed(() => {
1768
+ const value = this.inputValue().toLowerCase();
1769
+ const options = this.input.tags
1770
+ .filter((tag) => !this.tags.includes(tag))
1771
+ .filter((t, i, a) => a.indexOf(t) === i)
1772
+ .sort((t1, t2) => t1.localeCompare(t2));
1773
+ return value ? options.filter((option) => option.toLowerCase().includes(value)) : options;
1774
+ }, ...(ngDevMode ? [{ debugName: "filteredTags" }] : []));
1775
+ setValues() {
1776
+ this.tags = this.tags.sort((t1, t2) => t1.localeCompare(t2));
1777
+ this.formControl.setValue(this.tags.length === 0 ? null : this.tags);
1778
+ this.formControl.markAsTouched();
1779
+ this.inputValue.set('');
1780
+ }
1781
+ addTag(event) {
1782
+ const value = (event.value || '').trim();
1783
+ if (!value || this.tags.includes(value))
1784
+ return;
1785
+ this.tags.push(value);
1786
+ this.setValues();
1787
+ }
1788
+ removeTag(tag) {
1789
+ if (!this.tags.includes(tag))
1790
+ return;
1791
+ this.tags = this.tags.filter((t) => t !== tag);
1792
+ this.setValues();
1793
+ }
1794
+ selectTag(event) {
1795
+ const value = event.option.viewValue;
1796
+ if (!value || this.tags.includes(value))
1797
+ return;
1798
+ this.tags.push(value);
1799
+ this.setValues();
1800
+ event.option.deselect();
1801
+ }
1802
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: InputTagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1803
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: InputTagComponent, isStandalone: true, selector: "ng-component", inputs: { values: { classPropertyName: "values", publicName: "values", isSignal: false, isRequired: true, transformFunction: null }, isButtonDisabled: { classPropertyName: "isButtonDisabled", publicName: "isButtonDisabled", isSignal: false, isRequired: true, transformFunction: null }, inputValue: { classPropertyName: "inputValue", publicName: "inputValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { inputValue: "inputValueChange" }, host: { attributes: { "selector": "input-tag" } }, ngImport: i0, template: "<mat-form-field [appearance]=\"input.appearance || config.appearance\" [floatLabel]=\"tags.length === 0 ? 'auto' : 'always'\">\n <mat-label>{{ input.title || '\u062A\u06AF' }}</mat-label>\n @if (formControl.invalid) { <mat-error>{{ formControl.errors | InputErrorPipe : input.type }}</mat-error> }\n\n <!-- HINT -->\n @if (input.hint) { <mat-hint>{{ input.hint }}</mat-hint> }\n\n <!-- BUTTON -->\n @if (input.button) {\n <span matIconSuffix>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"isButtonDisabled\"\n (click)=\"input.button.onClick(values)\"\n [tabIndex]=\"-1\"\n >\n <mat-icon [style.color]=\"isButtonDisabled ? undefined : input.button.color\">\n {{ input.button.icon }}\n </mat-icon>\n </button>\n </span>\n }\n\n <mat-chip-grid #chipGrid [formControl]=\"formControl\" class=\"ngx-helper-form-m3-tag-input\">\n @for (tag of tags; track $index) {\n <mat-chip-row (removed)=\"removeTag(tag); tagInput.value = ''\">\n <span class=\"tag\">{{ tag }}</span>\n <button matChipRemove type=\"button\"><mat-icon>cancel</mat-icon></button>\n </mat-chip-row>\n }\n </mat-chip-grid>\n <input\n type=\"text\"\n name=\"inputValue\"\n [(ngModel)]=\"inputValue\"\n [AutoFocusDirective]=\"config.autoFocus === input.name\"\n [matChipInputFor]=\"chipGrid\"\n [matAutocomplete]=\"auto\"\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\n (matChipInputTokenEnd)=\"addTag($event); tagInput.value = ''\"\n #tagInput\n />\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selectTag($event); tagInput.value = ''\">\n @for (option of filteredTags(); track $index) {\n <mat-option [value]=\"option\">{{ option }}</mat-option>\n }\n </mat-autocomplete>\n\n <!-- DESCRIPTION -->\n @if (input.description) {\n <div\n class=\"ngx-form-m3-input-description\"\n [class.ngx-form-m3-disabled-input]=\"formControl.disabled\"\n [innerHTML]=\"input.description | MultiLinePipe\"\n ></div>\n }\n</mat-form-field>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i3$2.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i3$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "directive", type: i3$2.MatChipRemove, selector: "[matChipRemove]" }, { kind: "component", type: i3$2.MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i2$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i2$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i2$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: AutoCompleteDirective, selector: "input[type=\"text\"]" }, { kind: "directive", type: AutoFocusDirective, selector: "[AutoFocusDirective]", inputs: ["AutoFocusDirective"] }, { kind: "pipe", type: InputErrorPipe, name: "InputErrorPipe" }, { kind: "pipe", type: MultiLinePipe, name: "MultiLinePipe" }] });
1804
+ }
1805
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: InputTagComponent, decorators: [{
1806
+ type: Component,
1807
+ args: [{ host: { selector: 'input-tag' }, imports: [
1808
+ ReactiveFormsModule,
1809
+ FormsModule,
1810
+ MatAutocompleteModule,
1811
+ MatChipsModule,
1812
+ MatFormField,
1813
+ MatIcon,
1814
+ MatIconButton,
1815
+ MatInputModule,
1816
+ AutoCompleteDirective,
1817
+ AutoFocusDirective,
1818
+ InputErrorPipe,
1819
+ MultiLinePipe,
1820
+ ], template: "<mat-form-field [appearance]=\"input.appearance || config.appearance\" [floatLabel]=\"tags.length === 0 ? 'auto' : 'always'\">\n <mat-label>{{ input.title || '\u062A\u06AF' }}</mat-label>\n @if (formControl.invalid) { <mat-error>{{ formControl.errors | InputErrorPipe : input.type }}</mat-error> }\n\n <!-- HINT -->\n @if (input.hint) { <mat-hint>{{ input.hint }}</mat-hint> }\n\n <!-- BUTTON -->\n @if (input.button) {\n <span matIconSuffix>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"isButtonDisabled\"\n (click)=\"input.button.onClick(values)\"\n [tabIndex]=\"-1\"\n >\n <mat-icon [style.color]=\"isButtonDisabled ? undefined : input.button.color\">\n {{ input.button.icon }}\n </mat-icon>\n </button>\n </span>\n }\n\n <mat-chip-grid #chipGrid [formControl]=\"formControl\" class=\"ngx-helper-form-m3-tag-input\">\n @for (tag of tags; track $index) {\n <mat-chip-row (removed)=\"removeTag(tag); tagInput.value = ''\">\n <span class=\"tag\">{{ tag }}</span>\n <button matChipRemove type=\"button\"><mat-icon>cancel</mat-icon></button>\n </mat-chip-row>\n }\n </mat-chip-grid>\n <input\n type=\"text\"\n name=\"inputValue\"\n [(ngModel)]=\"inputValue\"\n [AutoFocusDirective]=\"config.autoFocus === input.name\"\n [matChipInputFor]=\"chipGrid\"\n [matAutocomplete]=\"auto\"\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\n (matChipInputTokenEnd)=\"addTag($event); tagInput.value = ''\"\n #tagInput\n />\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selectTag($event); tagInput.value = ''\">\n @for (option of filteredTags(); track $index) {\n <mat-option [value]=\"option\">{{ option }}</mat-option>\n }\n </mat-autocomplete>\n\n <!-- DESCRIPTION -->\n @if (input.description) {\n <div\n class=\"ngx-form-m3-input-description\"\n [class.ngx-form-m3-disabled-input]=\"formControl.disabled\"\n [innerHTML]=\"input.description | MultiLinePipe\"\n ></div>\n }\n</mat-form-field>\n" }]
1821
+ }], propDecorators: { values: [{
1822
+ type: Input,
1823
+ args: [{ required: true }]
1824
+ }], isButtonDisabled: [{
1825
+ type: Input,
1826
+ args: [{ required: true }]
1827
+ }] } });
1828
+
1829
+ class InputTagMethods extends InputMethods {
1830
+ control(input, validators) {
1831
+ if (input.minCount)
1832
+ validators.push(MinCountValidator(input.minCount));
1833
+ if (input.maxCount)
1834
+ validators.push(MaxCountValidator(input.maxCount));
1835
+ const value = (Array.isArray(input.value) ? input.value : [])
1836
+ .filter((value) => Helper.IS.string(value) && value !== '')
1837
+ .filter((value, index, arr) => arr.indexOf(value) === index);
1838
+ return new FormControl(value, validators);
1839
+ }
1840
+ value(value, input) {
1841
+ return Array.isArray(value) && value.length > 0 ? value : null;
1842
+ }
1843
+ }
1844
+
1755
1845
  class InputTextComponent {
1756
1846
  formControl = inject(INPUT_CONTROL);
1757
1847
  input = inject(INPUT_TYPE);
@@ -1961,6 +2051,7 @@ const InputInfo = {
1961
2051
  PRICE: { title: 'قیمت', methods: new InputPriceMethods(), component: InputPriceComponent },
1962
2052
  ROUTE: { title: 'مسیر', methods: new InputRouteMethods(), component: InputRouteComponent },
1963
2053
  SELECT: { title: 'لیست کشویی', methods: new InputSelectMethods(), component: InputSelectComponent },
2054
+ TAG: { title: 'تگ', methods: new InputTagMethods(), component: InputTagComponent },
1964
2055
  TEXT: { title: 'متن یک خطی', methods: new InputTextMethods(), component: InputTextComponent },
1965
2056
  TEXTAREA: { title: 'متن چند خطی', methods: new InputTextareaMethods(), component: InputTextareaComponent },
1966
2057
  URL: { title: 'آدرس سایت', methods: new InputUrlMethods(), component: InputUrlComponent },
@@ -2170,6 +2261,7 @@ class NgxFormComponent {
2170
2261
  input.type === 'ITEM-LIST' ||
2171
2262
  input.type === 'MULTI-SELECT' ||
2172
2263
  input.type === 'OPTION-LIST' ||
2264
+ input.type === 'TAG' ||
2173
2265
  input.optional ||
2174
2266
  readonly
2175
2267
  ? []