@jvsoft/mat-form-controls 1.0.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +184 -0
  2. package/base/index.d.ts +5 -0
  3. package/base/jvs-mat-form-control-base.d.ts +51 -0
  4. package/base/public-api.d.ts +1 -0
  5. package/fesm2022/jvsoft-mat-form-controls-base.mjs +145 -0
  6. package/fesm2022/jvsoft-mat-form-controls-base.mjs.map +1 -0
  7. package/fesm2022/jvsoft-mat-form-controls-jvs-autocomplete.mjs +101 -0
  8. package/fesm2022/jvsoft-mat-form-controls-jvs-autocomplete.mjs.map +1 -0
  9. package/fesm2022/jvsoft-mat-form-controls-jvs-file-upload.mjs +624 -0
  10. package/fesm2022/jvsoft-mat-form-controls-jvs-file-upload.mjs.map +1 -0
  11. package/fesm2022/jvsoft-mat-form-controls.mjs +145 -0
  12. package/fesm2022/jvsoft-mat-form-controls.mjs.map +1 -0
  13. package/index.d.ts +5 -0
  14. package/jvs-autocomplete/index.d.ts +5 -0
  15. package/jvs-autocomplete/jvs-autocomplete.component.d.ts +26 -0
  16. package/jvs-autocomplete/jvs-autocomplete.component.scss +58 -0
  17. package/jvs-autocomplete/public-api.d.ts +1 -0
  18. package/jvs-file-upload/README.md +613 -0
  19. package/jvs-file-upload/index.d.ts +5 -0
  20. package/jvs-file-upload/jvs-file-upload-item/jvs-file-upload-item.component.d.ts +29 -0
  21. package/jvs-file-upload/jvs-file-upload-item/jvs-file-upload-item.component.scss +118 -0
  22. package/jvs-file-upload/jvs-file-upload.component.d.ts +140 -0
  23. package/jvs-file-upload/jvs-file-upload.component.scss +163 -0
  24. package/jvs-file-upload/jvs-file-upload.directive.d.ts +42 -0
  25. package/jvs-file-upload/jvs-file-upload.interfaces.d.ts +77 -0
  26. package/jvs-file-upload/public-api.d.ts +4 -0
  27. package/package.json +39 -0
  28. package/public-api.d.ts +1 -0
  29. package/src/lib/mat-form-controls/mat-form-controls.component.css +0 -0
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # mat-form-controls
2
+
3
+ Librería de componentes personalizados (Custom Form Controls) basados en Angular Material para proyectos de @jvsoft.
4
+
5
+ ## JvsAutocompleteComponent
6
+
7
+ Un componente unificado de autocompletado que cumple con la interfaz `MatFormFieldControl`, permitiendo su uso tanto dentro de un `mat-form-field` como de forma independiente.
8
+
9
+ ### Características
10
+ - **Soporte Nativo para Angular 19+**: Basado íntegramente en Angular Signals para máxima eficiencia.
11
+ - **Doble Modo de Visualización**:
12
+ - **Integrado**: Se adapta automáticamente al estilo de un `mat-form-field` (outline, fill, etc.).
13
+ - **Standalone (Plano)**: Muestra un borde y estilo de input estándar cuando se usa fuera de un form-field.
14
+ - **Búsqueda Local y Remota**: Soporta arrays estáticos y servicios que implementan `getData`.
15
+ - **Botón de Búsqueda/Limpiar**: Incluye un sufijo integrado para acciones rápidas.
16
+
17
+ ---
18
+
19
+ ### Instalación y Uso
20
+
21
+ #### 1. Importar el componente
22
+ El componente es standalone y se encuentra en su propio entry point para mejorar el tree-shaking:
23
+
24
+ ```typescript
25
+ import { JvsAutocompleteComponent } from '@jvsoft/mat-form-controls/jvs-autocomplete';
26
+
27
+ @Component({
28
+ standalone: true,
29
+ imports: [JvsAutocompleteComponent, ReactiveFormsModule, ...],
30
+ // ...
31
+ })
32
+ ```
33
+
34
+ #### 2. Uso dentro de Mat-Form-Field (Recomendado)
35
+ Aprovecha todas las funcionalidades de Material (labels, hints, errors, prefixes/suffixes):
36
+
37
+ ```html
38
+ <mat-form-field appearance="outline" class="w-full">
39
+ <mat-label>Seleccionar Usuario</mat-label>
40
+ <jvs-autocomplete
41
+ [formControl]="miControl"
42
+ [data]="listaUsuarios"
43
+ [fields]="['nombre', 'apellido', 'codigo']"
44
+ idField="id"
45
+ displayField="nombreCompleto"
46
+ ></jvs-autocomplete>
47
+ <mat-hint>Busca por nombre o código</mat-hint>
48
+ </mat-form-field>
49
+ ```
50
+
51
+ #### 3. Uso Standalone (Plano)
52
+ Ideal para filtros rápidos o áreas sin espacio para labels flotantes:
53
+
54
+ ```html
55
+ <jvs-autocomplete
56
+ [formControl]="miControl"
57
+ [data]="listaUsuarios"
58
+ [fields]="['nombre']"
59
+ placeholder="Escribe para buscar..."
60
+ ></jvs-autocomplete>
61
+ ```
62
+
63
+ #### 4. Búsqueda Remota (Service-based)
64
+ Si necesitas realizar búsquedas contra una API:
65
+
66
+ ```html
67
+ <jvs-autocomplete
68
+ [formControl]="miControl"
69
+ [queryService]="miServicioData"
70
+ [fields]="['nombre']"
71
+ ></jvs-autocomplete>
72
+ ```
73
+ *Nota: El `queryService` debe tener un método `getData(filtro: string)` que devuelva un `Observable` de resultados.*
74
+
75
+ ---
76
+
77
+ ### API del Componente
78
+
79
+ #### Entry Point: `@jvsoft/mat-form-controls/jvs-autocomplete`
80
+
81
+ #### Inputs
82
+ | Propiedad | Tipo | Por defecto | Descripción |
83
+ | :--- | :--- | :--- | :--- |
84
+ | `data` | `any[]` | `null` | Array de datos para búsqueda local. |
85
+ | `fields` | `string \| string[]` | `''` | Campos sobre los que se realizará el filtro. |
86
+ | `idField` | `string` | `'id'` | Campo que se usará como valor identificador. |
87
+ | `displayField`| `string` | `'display'` | Campo que se mostrará en el input tras seleccionar. |
88
+ | `queryService`| `any` | `null` | Servicio para búsqueda remota. |
89
+ | `showSearchButton`| `boolean`| `true` | Muestra/oculta el ícono de búsqueda/limpiar. |
90
+ | `placeholder` | `string` | `''` | Texto de ayuda en el input. |
91
+ | `required` | `boolean` | `false` | Indica si el campo es obligatorio. |
92
+
93
+ ---
94
+
95
+ ### Verificación en Storybook
96
+ Para ver todos los escenarios de uso de forma interactiva, ejecuta:
97
+ ```bash
98
+ npx nx run mat-form-controls:storybook
99
+ ```
100
+ Navega a la sección `JvsAutocomplete` para probar los modos **InsideFormField**, **StandalonePlano** y **RemoteSearch**.
101
+
102
+ ---
103
+
104
+ ## JvsFileUploadComponent
105
+
106
+ Componente de subida de archivos reutilizable con soporte de drag-and-drop, validación, barra de progreso y firma electrónica delegada. Construido con el estándar Angular 19+ (signals, `input()`, `output()`).
107
+
108
+ ### Características
109
+ - **Signals nativos**: `input()`, `output()`, `signal()`, `computed()` — sin decoradores legacy.
110
+ - **Dos modos**: subida manual (pre-form) y subida inmediata (temporal) con barra de progreso.
111
+ - **Drag & Drop** integrado con directiva interna `jvsFileUpload`.
112
+ - **Validación flexible**: por extensión, tamaño máximo, partes del nombre y nombres exclusivos.
113
+ - **Inversión de dependencias**: las funciones de `upload` y `remove` se pasan como `input()`.
114
+ - **Firma delegada**: emite `(firmarArchivo)` para que el padre gestione la firma electrónica.
115
+ - **Modo readonly**: solo muestra la lista, sin zona de drop.
116
+
117
+ ### Instalación y uso rápido
118
+
119
+ ```typescript
120
+ import { JvsFileUploadComponent } from '@jvsoft/mat-form-controls/jvs-file-upload';
121
+ ```
122
+
123
+ #### Modo manual (pre-form)
124
+
125
+ ```html
126
+ <jvs-file-upload
127
+ [extensionesPermitidas]="['pdf', 'docx']"
128
+ [tamanoMaximoMB]="10"
129
+ formControlName="archivos"
130
+ />
131
+ ```
132
+
133
+ ```typescript
134
+ // Antes de guardar el formulario:
135
+ const archivos = await this.fileUpload.uploadFilesPreForm('documentos/2024');
136
+ ```
137
+
138
+ #### Modo temporal (subida inmediata)
139
+
140
+ ```html
141
+ <jvs-file-upload
142
+ [temporal]="true"
143
+ [extensionesPermitidas]="['pdf']"
144
+ [uploadFn]="uploadFn"
145
+ [removeFn]="removeFn"
146
+ (archivoDescarga)="onDescargar($event)"
147
+ (firmarArchivo)="onFirmar($event)"
148
+ formControlName="archivos"
149
+ />
150
+ ```
151
+
152
+ ### API resumida
153
+
154
+ #### Entry Point: `@jvsoft/mat-form-controls/jvs-file-upload`
155
+
156
+ #### Inputs principales
157
+ | Propiedad | Tipo | Por defecto | Descripción |
158
+ | :--- | :--- | :--- | :--- |
159
+ | `temporal` | `boolean` | `false` | Subida inmediata al seleccionar. |
160
+ | `permitirEliminar` | `boolean` | `true` | Muestra botón eliminar. |
161
+ | `readonly` | `boolean` | `false` | Solo vista, sin edición. |
162
+ | `multiple` | `boolean` | `true` | Permite múltiples archivos. |
163
+ | `extensionesPermitidas` | `string[]` | `[]` | Extensiones válidas (sin punto). |
164
+ | `tamanoMaximoMB` | `number \| null` | `null` | Límite de tamaño en MB. |
165
+ | `uploadFn` | `JvsUploadFn \| null` | `null` | Función de subida al servidor. |
166
+ | `removeFn` | `JvsRemoveFn \| null` | `null` | Función de eliminación del servidor. |
167
+ | `carpetaSubida` | `string \| null` | `null` | Carpeta destino en el servidor. |
168
+ | `diskSubida` | `string \| null` | `null` | Disk de almacenamiento. |
169
+
170
+ #### Outputs
171
+ | Evento | Emite | Descripción |
172
+ | :--- | :--- | :--- |
173
+ | `resultadoEliminado` | `JvsArchivoServidor[]` | Lista actualizada tras eliminar. |
174
+ | `archivoDescarga` | `JvsFileEntry` | Usuario solicita descarga. |
175
+ | `firmarArchivo` | `JvsArchivoServidor` | Usuario solicita firma. |
176
+
177
+ #### Métodos públicos (via `ViewChild`)
178
+ | Método | Descripción |
179
+ | :--- | :--- |
180
+ | `uploadFilesPreForm(carpeta?, anonimo?, disk?)` | Sube archivos pendientes, retorna `Promise<JvsArchivoServidor[]>`. |
181
+ | `reset()` | Limpia la lista y notifica al `FormControl`. |
182
+
183
+ > 📖 **Documentación completa**: ver [`jvs-file-upload/README.md`](./jvs-file-upload/README.md)
184
+
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="@jvsoft/mat-form-controls/base" />
5
+ export * from './public-api';
@@ -0,0 +1,51 @@
1
+ import { FocusMonitor } from '@angular/cdk/a11y';
2
+ import { BooleanInput } from '@angular/cdk/coercion';
3
+ import { ElementRef, OnDestroy, OnInit } from '@angular/core';
4
+ import { ControlValueAccessor, NgControl } from '@angular/forms';
5
+ import { MatFormField, MatFormFieldControl } from '@angular/material/form-field';
6
+ import { Subject } from 'rxjs';
7
+ import * as i0 from "@angular/core";
8
+ export declare abstract class JvsMatFormControlBase<T> implements MatFormFieldControl<T>, ControlValueAccessor, OnInit, OnDestroy {
9
+ static nextId: number;
10
+ inputElement: ElementRef<HTMLInputElement>;
11
+ protected _focusMonitor: FocusMonitor;
12
+ protected _elementRef: ElementRef<any>;
13
+ _formField: MatFormField | null;
14
+ ngControl: NgControl | null;
15
+ private injector;
16
+ readonly stateChanges: Subject<void>;
17
+ readonly controlType = "jvs-mat-form-control";
18
+ readonly id: string;
19
+ protected readonly _focused: import("@angular/core").WritableSignal<boolean>;
20
+ get focused(): boolean;
21
+ protected readonly _touched: import("@angular/core").WritableSignal<boolean>;
22
+ get touched(): boolean;
23
+ get placeholder(): string;
24
+ set placeholder(value: string);
25
+ private readonly _placeholder;
26
+ get required(): boolean;
27
+ set required(value: BooleanInput);
28
+ private readonly _required;
29
+ get disabled(): boolean;
30
+ set disabled(value: BooleanInput);
31
+ private readonly _disabled;
32
+ get value(): T | null;
33
+ set value(value: T | null);
34
+ protected readonly _value: import("@angular/core").WritableSignal<T | null>;
35
+ get empty(): boolean;
36
+ get shouldLabelFloat(): boolean;
37
+ get errorState(): boolean;
38
+ onContainerClick(event: MouseEvent): void;
39
+ setDescribedByIds(ids: string[]): void;
40
+ onChange: (_: any) => void;
41
+ onTouched: () => void;
42
+ writeValue(value: T | null): void;
43
+ registerOnChange(fn: any): void;
44
+ registerOnTouched(fn: any): void;
45
+ setDisabledState(isDisabled: boolean): void;
46
+ constructor();
47
+ ngOnInit(): void;
48
+ ngOnDestroy(): void;
49
+ static ɵfac: i0.ɵɵFactoryDeclaration<JvsMatFormControlBase<any>, never>;
50
+ static ɵcmp: i0.ɵɵComponentDeclaration<JvsMatFormControlBase<any>, "ng-component", never, { "placeholder": { "alias": "placeholder"; "required": false; }; "required": { "alias": "required"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "value": { "alias": "value"; "required": false; }; }, {}, never, never, true, never>;
51
+ }
@@ -0,0 +1 @@
1
+ export * from './jvs-mat-form-control-base';
@@ -0,0 +1,145 @@
1
+ import { FocusMonitor } from '@angular/cdk/a11y';
2
+ import { coerceBooleanProperty } from '@angular/cdk/coercion';
3
+ import * as i0 from '@angular/core';
4
+ import { inject, ElementRef, Injector, signal, Input, ViewChild, Component } from '@angular/core';
5
+ import { NgControl } from '@angular/forms';
6
+ import { MAT_FORM_FIELD } from '@angular/material/form-field';
7
+ import { Subject } from 'rxjs';
8
+
9
+ class JvsMatFormControlBase {
10
+ static nextId = 0;
11
+ inputElement;
12
+ _focusMonitor = inject(FocusMonitor);
13
+ _elementRef = inject(ElementRef);
14
+ _formField = null;
15
+ ngControl = inject(NgControl, { optional: true, self: true });
16
+ injector = inject(Injector);
17
+ stateChanges = new Subject();
18
+ controlType = 'jvs-mat-form-control';
19
+ id = `jvs-mat-form-control-${JvsMatFormControlBase.nextId++}`;
20
+ _focused = signal(false);
21
+ get focused() {
22
+ return this._focused();
23
+ }
24
+ _touched = signal(false);
25
+ get touched() {
26
+ return this._touched();
27
+ }
28
+ get placeholder() {
29
+ return this._placeholder();
30
+ }
31
+ set placeholder(value) {
32
+ this._placeholder.set(value);
33
+ this.stateChanges.next();
34
+ }
35
+ _placeholder = signal('');
36
+ get required() {
37
+ return this._required();
38
+ }
39
+ set required(value) {
40
+ this._required.set(coerceBooleanProperty(value));
41
+ this.stateChanges.next();
42
+ }
43
+ _required = signal(false);
44
+ get disabled() {
45
+ return this._disabled();
46
+ }
47
+ set disabled(value) {
48
+ this._disabled.set(coerceBooleanProperty(value));
49
+ this.stateChanges.next();
50
+ }
51
+ _disabled = signal(false);
52
+ get value() {
53
+ return this._value();
54
+ }
55
+ set value(value) {
56
+ this._value.set(value);
57
+ this.onChange(value);
58
+ this.stateChanges.next();
59
+ }
60
+ _value = signal(null);
61
+ get empty() {
62
+ const value = this._value();
63
+ return (value === null ||
64
+ value === undefined ||
65
+ (typeof value === 'string' && value.length === 0));
66
+ }
67
+ get shouldLabelFloat() {
68
+ return this.focused || !this.empty;
69
+ }
70
+ get errorState() {
71
+ return !!(this.ngControl?.invalid && this.touched);
72
+ }
73
+ onContainerClick(event) {
74
+ if (event.target.tagName.toLowerCase() !== 'input') {
75
+ this.inputElement?.nativeElement.focus();
76
+ }
77
+ }
78
+ setDescribedByIds(ids) {
79
+ // Implementación opcional si se necesita aria-describedby
80
+ }
81
+ // ControlValueAccessor implementation
82
+ onChange = (_) => { };
83
+ onTouched = () => { };
84
+ writeValue(value) {
85
+ this._value.set(value);
86
+ this.stateChanges.next();
87
+ }
88
+ registerOnChange(fn) {
89
+ this.onChange = fn;
90
+ }
91
+ registerOnTouched(fn) {
92
+ this.onTouched = fn;
93
+ }
94
+ setDisabledState(isDisabled) {
95
+ this._disabled.set(isDisabled);
96
+ this.stateChanges.next();
97
+ }
98
+ constructor() {
99
+ if (this.ngControl != null) {
100
+ this.ngControl.valueAccessor = this;
101
+ }
102
+ }
103
+ ngOnInit() {
104
+ this._formField = this.injector.get(MAT_FORM_FIELD, null, { optional: true });
105
+ this._focusMonitor.monitor(this._elementRef, true).subscribe((origin) => {
106
+ this._focused.set(!!origin);
107
+ if (!origin) {
108
+ this._touched.set(true);
109
+ this.onTouched();
110
+ }
111
+ this.stateChanges.next();
112
+ });
113
+ }
114
+ ngOnDestroy() {
115
+ this.stateChanges.complete();
116
+ this._focusMonitor.stopMonitoring(this._elementRef);
117
+ }
118
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsMatFormControlBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
119
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: JvsMatFormControlBase, isStandalone: true, selector: "ng-component", inputs: { placeholder: "placeholder", required: "required", disabled: "disabled", value: "value" }, viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["input"], descendants: true }], ngImport: i0, template: '', isInline: true });
120
+ }
121
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsMatFormControlBase, decorators: [{
122
+ type: Component,
123
+ args: [{
124
+ template: '',
125
+ standalone: true,
126
+ }]
127
+ }], ctorParameters: () => [], propDecorators: { inputElement: [{
128
+ type: ViewChild,
129
+ args: ['input']
130
+ }], placeholder: [{
131
+ type: Input
132
+ }], required: [{
133
+ type: Input
134
+ }], disabled: [{
135
+ type: Input
136
+ }], value: [{
137
+ type: Input
138
+ }] } });
139
+
140
+ /**
141
+ * Generated bundle index. Do not edit.
142
+ */
143
+
144
+ export { JvsMatFormControlBase };
145
+ //# sourceMappingURL=jvsoft-mat-form-controls-base.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jvsoft-mat-form-controls-base.mjs","sources":["../../../projects/mat-form-controls/base/jvs-mat-form-control-base.ts","../../../projects/mat-form-controls/base/jvsoft-mat-form-controls-base.ts"],"sourcesContent":["import {FocusMonitor} from '@angular/cdk/a11y';\nimport {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';\nimport {Component, ElementRef, inject, Injector, Input, OnDestroy, OnInit, signal, ViewChild} from '@angular/core';\nimport {ControlValueAccessor, NgControl} from '@angular/forms';\nimport {MAT_FORM_FIELD, MatFormField, MatFormFieldControl} from '@angular/material/form-field';\nimport {Subject} from 'rxjs';\n\n@Component({\n template: '',\n standalone: true,\n})\nexport abstract class JvsMatFormControlBase<T>\n implements MatFormFieldControl<T>, ControlValueAccessor, OnInit, OnDestroy\n{\n static nextId = 0;\n\n @ViewChild('input') inputElement!: ElementRef<HTMLInputElement>;\n\n protected _focusMonitor = inject(FocusMonitor);\n protected _elementRef = inject(ElementRef);\n public _formField: MatFormField | null = null;\n public ngControl = inject(NgControl, { optional: true, self: true });\n private injector = inject(Injector);\n\n readonly stateChanges = new Subject<void>();\n readonly controlType = 'jvs-mat-form-control';\n readonly id = `jvs-mat-form-control-${JvsMatFormControlBase.nextId++}`;\n\n protected readonly _focused = signal(false);\n get focused(): boolean {\n return this._focused();\n }\n\n protected readonly _touched = signal(false);\n get touched(): boolean {\n return this._touched();\n }\n @Input()\n get placeholder(): string {\n return this._placeholder();\n }\n set placeholder(value: string) {\n this._placeholder.set(value);\n this.stateChanges.next();\n }\n private readonly _placeholder = signal('');\n\n @Input()\n get required(): boolean {\n return this._required();\n }\n set required(value: BooleanInput) {\n this._required.set(coerceBooleanProperty(value));\n this.stateChanges.next();\n }\n private readonly _required = signal(false);\n\n @Input()\n get disabled(): boolean {\n return this._disabled();\n }\n set disabled(value: BooleanInput) {\n this._disabled.set(coerceBooleanProperty(value));\n this.stateChanges.next();\n }\n private readonly _disabled = signal(false);\n\n @Input()\n get value(): T | null {\n return this._value();\n }\n set value(value: T | null) {\n this._value.set(value);\n this.onChange(value);\n this.stateChanges.next();\n }\n protected readonly _value = signal<T | null>(null);\n\n get empty(): boolean {\n const value = this._value();\n return (\n value === null ||\n value === undefined ||\n (typeof value === 'string' && value.length === 0)\n );\n }\n\n get shouldLabelFloat(): boolean {\n return this.focused || !this.empty;\n }\n\n get errorState(): boolean {\n return !!(this.ngControl?.invalid && this.touched);\n }\n\n onContainerClick(event: MouseEvent): void {\n if ((event.target as Element).tagName.toLowerCase() !== 'input') {\n this.inputElement?.nativeElement.focus();\n }\n }\n\n setDescribedByIds(ids: string[]): void {\n // Implementación opcional si se necesita aria-describedby\n }\n\n // ControlValueAccessor implementation\n onChange = (_: any) => {};\n onTouched = () => {};\n\n writeValue(value: T | null): void {\n this._value.set(value);\n this.stateChanges.next();\n }\n\n registerOnChange(fn: any): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: any): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this._disabled.set(isDisabled);\n this.stateChanges.next();\n }\n\n constructor() {\n if (this.ngControl != null) {\n this.ngControl.valueAccessor = this;\n }\n }\n\n ngOnInit(): void {\n this._formField = this.injector.get(MAT_FORM_FIELD, null, { optional: true });\n\n this._focusMonitor.monitor(this._elementRef, true).subscribe((origin) => {\n this._focused.set(!!origin);\n if (!origin) {\n this._touched.set(true);\n this.onTouched();\n }\n this.stateChanges.next();\n });\n }\n\n ngOnDestroy(): void {\n this.stateChanges.complete();\n this._focusMonitor.stopMonitoring(this._elementRef);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, DestroyRef, input, signal, forwardRef, Component } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import * as i1 from '@angular/forms';
5
+ import { FormControl, ReactiveFormsModule } from '@angular/forms';
6
+ import * as i2 from '@angular/material/autocomplete';
7
+ import { MatAutocompleteModule } from '@angular/material/autocomplete';
8
+ import * as i3 from '@angular/material/form-field';
9
+ import { MatFormFieldModule, MatFormFieldControl } from '@angular/material/form-field';
10
+ import { MatInputModule } from '@angular/material/input';
11
+ import { MatIconModule } from '@angular/material/icon';
12
+ import { MatRippleModule } from '@angular/material/core';
13
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
14
+ import { distinctUntilChanged } from 'rxjs';
15
+ import { JvsAutocompleteDirective, JvsDisplayWithPipe } from '@jvsoft/utils';
16
+ import { MatSuffixSearchButtonComponent } from '@jvsoft/components';
17
+ import { JvsMatFormControlBase } from '@jvsoft/mat-form-controls/base';
18
+
19
+ class JvsAutocompleteComponent extends JvsMatFormControlBase {
20
+ destroyRef = inject(DestroyRef);
21
+ // Inputs específicos de Autocomplete
22
+ data = input(null);
23
+ fields = input('');
24
+ idField = input('id');
25
+ displayField = input('name');
26
+ queryService = input(null);
27
+ showSearchButton = input(true);
28
+ // Estado interno
29
+ internalControl = new FormControl();
30
+ filteredOptions = signal([]);
31
+ isLoading = signal(false);
32
+ ngOnInit() {
33
+ super.ngOnInit();
34
+ // Sincronizar cambios del control interno (el input) hacia el valor del componente
35
+ this.internalControl.valueChanges
36
+ .pipe(takeUntilDestroyed(this.destroyRef), distinctUntilChanged())
37
+ .subscribe((value) => {
38
+ this.value = value;
39
+ });
40
+ }
41
+ writeValue(value) {
42
+ super.writeValue(value);
43
+ this.internalControl.setValue(value, { emitEvent: false });
44
+ }
45
+ onFiltered(data) {
46
+ this.filteredOptions.set(data);
47
+ }
48
+ onLoading(loading) {
49
+ this.isLoading.set(loading);
50
+ }
51
+ onSearchClick() {
52
+ // Lógica para disparar búsqueda manual si fuera necesario
53
+ }
54
+ limpiar() {
55
+ this.internalControl.reset();
56
+ }
57
+ _onInputFocus() {
58
+ this._focused.set(true);
59
+ this.stateChanges.next();
60
+ }
61
+ _onInputBlur() {
62
+ this._focused.set(false);
63
+ this._touched.set(true);
64
+ this.onTouched();
65
+ this.stateChanges.next();
66
+ }
67
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsAutocompleteComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
68
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: JvsAutocompleteComponent, isStandalone: true, selector: "jvs-autocomplete", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null }, idField: { classPropertyName: "idField", publicName: "idField", isSignal: true, isRequired: false, transformFunction: null }, displayField: { classPropertyName: "displayField", publicName: "displayField", isSignal: true, isRequired: false, transformFunction: null }, queryService: { classPropertyName: "queryService", publicName: "queryService", isSignal: true, isRequired: false, transformFunction: null }, showSearchButton: { classPropertyName: "showSearchButton", publicName: "showSearchButton", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
69
+ {
70
+ provide: MatFormFieldControl,
71
+ useExisting: forwardRef(() => JvsAutocompleteComponent),
72
+ },
73
+ ], usesInheritance: true, ngImport: i0, template: "<div class=\"jvs-autocomplete-container\" \n [class.jvs-autocomplete-standalone]=\"!_formField\"\n [class.jvs-autocomplete-focused]=\"focused\">\n \n <input\n #input\n type=\"text\"\n [placeholder]=\"placeholder || ''\"\n [matAutocomplete]=\"auto\"\n [formControl]=\"internalControl\"\n [required]=\"required\"\n (focus)=\"_onInputFocus()\"\n (blur)=\"_onInputBlur()\"\n jvsAutocomplete\n [data]=\"data()\"\n [queryService]=\"queryService()\"\n [fields]=\"fields()\"\n (filtered)=\"onFiltered($event)\"\n (loading)=\"onLoading($event)\"\n class=\"jvs-autocomplete-input\"\n />\n\n @if (showSearchButton()) {\n <div matSuffix matSuffixSearchButton\n class=\"jvs-autocomplete-suffix\"\n [fControl]=\"internalControl\"\n (eventLimpiar)=\"limpiar()\"\n (eventBuscar)=\"onSearchClick()\">\n </div>\n }\n\n <mat-autocomplete #auto=\"matAutocomplete\" [displayWith]=\"data() | jvsDisplayWith:idField():displayField()\">\n @for (option of filteredOptions(); track option[idField()]) {\n <mat-option [value]=\"option\">\n {{ option[displayField()] }}\n </mat-option>\n }\n </mat-autocomplete>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.jvs-autocomplete-container{display:flex;align-items:center;position:relative;width:100%;box-sizing:border-box}.jvs-autocomplete-input{flex:1;width:100%;border:none;background:transparent;outline:none;font:inherit;color:inherit;padding:0;margin:0;min-width:0}.jvs-autocomplete-standalone{border:1px solid #d1d5db;border-radius:.375rem;padding:.5rem .75rem;background-color:#fff;transition:border-color .2s,box-shadow .2s}.jvs-autocomplete-standalone.jvs-autocomplete-focused{border-color:#3b82f6;box-shadow:0 0 0 2px #3b82f633}.jvs-autocomplete-suffix{margin-left:.5rem;flex-shrink:0}:host-context(mat-form-field) .jvs-autocomplete-container{padding:0;border:none;box-shadow:none}:host-context(mat-form-field) .jvs-autocomplete-input{height:1.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { 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: MatFormFieldModule }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: JvsAutocompleteDirective, selector: "[jvsAutocomplete]", inputs: ["data", "fields", "typeReq", "queryService", "minLength", "dataExtra", "anonimo", "debounce"], outputs: ["filtered", "loading"] }, { kind: "pipe", type: JvsDisplayWithPipe, name: "jvsDisplayWith" }, { kind: "component", type: MatSuffixSearchButtonComponent, selector: "div[matSuffix][matSuffixSearchButton]", inputs: ["fControl"], outputs: ["eventLimpiar", "eventBuscar"] }] });
74
+ }
75
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsAutocompleteComponent, decorators: [{
76
+ type: Component,
77
+ args: [{ selector: 'jvs-autocomplete', standalone: true, imports: [
78
+ CommonModule,
79
+ ReactiveFormsModule,
80
+ MatAutocompleteModule,
81
+ MatFormFieldModule,
82
+ MatInputModule,
83
+ MatIconModule,
84
+ MatRippleModule,
85
+ JvsAutocompleteDirective,
86
+ JvsDisplayWithPipe,
87
+ MatSuffixSearchButtonComponent,
88
+ ], providers: [
89
+ {
90
+ provide: MatFormFieldControl,
91
+ useExisting: forwardRef(() => JvsAutocompleteComponent),
92
+ },
93
+ ], template: "<div class=\"jvs-autocomplete-container\" \n [class.jvs-autocomplete-standalone]=\"!_formField\"\n [class.jvs-autocomplete-focused]=\"focused\">\n \n <input\n #input\n type=\"text\"\n [placeholder]=\"placeholder || ''\"\n [matAutocomplete]=\"auto\"\n [formControl]=\"internalControl\"\n [required]=\"required\"\n (focus)=\"_onInputFocus()\"\n (blur)=\"_onInputBlur()\"\n jvsAutocomplete\n [data]=\"data()\"\n [queryService]=\"queryService()\"\n [fields]=\"fields()\"\n (filtered)=\"onFiltered($event)\"\n (loading)=\"onLoading($event)\"\n class=\"jvs-autocomplete-input\"\n />\n\n @if (showSearchButton()) {\n <div matSuffix matSuffixSearchButton\n class=\"jvs-autocomplete-suffix\"\n [fControl]=\"internalControl\"\n (eventLimpiar)=\"limpiar()\"\n (eventBuscar)=\"onSearchClick()\">\n </div>\n }\n\n <mat-autocomplete #auto=\"matAutocomplete\" [displayWith]=\"data() | jvsDisplayWith:idField():displayField()\">\n @for (option of filteredOptions(); track option[idField()]) {\n <mat-option [value]=\"option\">\n {{ option[displayField()] }}\n </mat-option>\n }\n </mat-autocomplete>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.jvs-autocomplete-container{display:flex;align-items:center;position:relative;width:100%;box-sizing:border-box}.jvs-autocomplete-input{flex:1;width:100%;border:none;background:transparent;outline:none;font:inherit;color:inherit;padding:0;margin:0;min-width:0}.jvs-autocomplete-standalone{border:1px solid #d1d5db;border-radius:.375rem;padding:.5rem .75rem;background-color:#fff;transition:border-color .2s,box-shadow .2s}.jvs-autocomplete-standalone.jvs-autocomplete-focused{border-color:#3b82f6;box-shadow:0 0 0 2px #3b82f633}.jvs-autocomplete-suffix{margin-left:.5rem;flex-shrink:0}:host-context(mat-form-field) .jvs-autocomplete-container{padding:0;border:none;box-shadow:none}:host-context(mat-form-field) .jvs-autocomplete-input{height:1.5rem}\n"] }]
94
+ }] });
95
+
96
+ /**
97
+ * Generated bundle index. Do not edit.
98
+ */
99
+
100
+ export { JvsAutocompleteComponent };
101
+ //# sourceMappingURL=jvsoft-mat-form-controls-jvs-autocomplete.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jvsoft-mat-form-controls-jvs-autocomplete.mjs","sources":["../../../projects/mat-form-controls/jvs-autocomplete/jvs-autocomplete.component.ts","../../../projects/mat-form-controls/jvs-autocomplete/jvs-autocomplete.component.html","../../../projects/mat-form-controls/jvs-autocomplete/jvsoft-mat-form-controls-jvs-autocomplete.ts"],"sourcesContent":["import {\n Component,\n DestroyRef,\n forwardRef,\n inject,\n input,\n OnInit,\n signal,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n FormControl,\n ReactiveFormsModule,\n} from '@angular/forms';\nimport { MatAutocompleteModule } from '@angular/material/autocomplete';\nimport { MatFormFieldModule, MatFormFieldControl } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatRippleModule } from '@angular/material/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { distinctUntilChanged } from 'rxjs';\n\nimport { JvsAutocompleteDirective, JvsDisplayWithPipe } from '@jvsoft/utils';\nimport { MatSuffixSearchButtonComponent } from '@jvsoft/components';\nimport { JvsMatFormControlBase } from '@jvsoft/mat-form-controls/base';\n\n@Component({\n selector: 'jvs-autocomplete',\n standalone: true,\n imports: [\n CommonModule,\n ReactiveFormsModule,\n MatAutocompleteModule,\n MatFormFieldModule,\n MatInputModule,\n MatIconModule,\n MatRippleModule,\n JvsAutocompleteDirective,\n JvsDisplayWithPipe,\n MatSuffixSearchButtonComponent,\n ],\n templateUrl: './jvs-autocomplete.component.html',\n styleUrl: './jvs-autocomplete.component.scss',\n providers: [\n {\n provide: MatFormFieldControl,\n useExisting: forwardRef(() => JvsAutocompleteComponent),\n },\n ],\n})\nexport class JvsAutocompleteComponent\n extends JvsMatFormControlBase<any>\n implements OnInit\n{\n private readonly destroyRef = inject(DestroyRef);\n\n // Inputs específicos de Autocomplete\n data = input<any[] | null>(null);\n fields = input<string | string[]>('');\n idField = input<string>('id');\n displayField = input<string>('name');\n queryService = input<any>(null);\n showSearchButton = input<boolean>(true);\n\n // Estado interno\n internalControl = new FormControl();\n filteredOptions = signal<any[]>([]);\n isLoading = signal<boolean>(false);\n\n override ngOnInit(): void {\n super.ngOnInit();\n\n // Sincronizar cambios del control interno (el input) hacia el valor del componente\n this.internalControl.valueChanges\n .pipe(takeUntilDestroyed(this.destroyRef), distinctUntilChanged())\n .subscribe((value) => {\n this.value = value;\n });\n }\n\n override writeValue(value: any): void {\n super.writeValue(value);\n this.internalControl.setValue(value, { emitEvent: false });\n }\n\n onFiltered(data: any[]): void {\n this.filteredOptions.set(data);\n }\n\n onLoading(loading: boolean): void {\n this.isLoading.set(loading);\n }\n\n onSearchClick(): void {\n // Lógica para disparar búsqueda manual si fuera necesario\n }\n\n limpiar(): void {\n this.internalControl.reset();\n }\n\n _onInputFocus() {\n this._focused.set(true);\n this.stateChanges.next();\n }\n\n _onInputBlur() {\n this._focused.set(false);\n this._touched.set(true);\n this.onTouched();\n this.stateChanges.next();\n }\n}\n","<div class=\"jvs-autocomplete-container\" \n [class.jvs-autocomplete-standalone]=\"!_formField\"\n [class.jvs-autocomplete-focused]=\"focused\">\n \n <input\n #input\n type=\"text\"\n [placeholder]=\"placeholder || ''\"\n [matAutocomplete]=\"auto\"\n [formControl]=\"internalControl\"\n [required]=\"required\"\n (focus)=\"_onInputFocus()\"\n (blur)=\"_onInputBlur()\"\n jvsAutocomplete\n [data]=\"data()\"\n [queryService]=\"queryService()\"\n [fields]=\"fields()\"\n (filtered)=\"onFiltered($event)\"\n (loading)=\"onLoading($event)\"\n class=\"jvs-autocomplete-input\"\n />\n\n @if (showSearchButton()) {\n <div matSuffix matSuffixSearchButton\n class=\"jvs-autocomplete-suffix\"\n [fControl]=\"internalControl\"\n (eventLimpiar)=\"limpiar()\"\n (eventBuscar)=\"onSearchClick()\">\n </div>\n }\n\n <mat-autocomplete #auto=\"matAutocomplete\" [displayWith]=\"data() | jvsDisplayWith:idField():displayField()\">\n @for (option of filteredOptions(); track option[idField()]) {\n <mat-option [value]=\"option\">\n {{ option[displayField()] }}\n </mat-option>\n }\n </mat-autocomplete>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}