@ellie-software/ui 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, ViewChild, Output, Input, Component } from '@angular/core';
3
- import { NgClass } from '@angular/common';
2
+ import { EventEmitter, ViewChild, ContentChild, Output, Input, Component, Injectable } from '@angular/core';
3
+ import { NgClass, NgTemplateOutlet } from '@angular/common';
4
+ import { Subject } from 'rxjs';
4
5
 
5
6
  class EllieModal {
6
7
  title = '';
@@ -10,6 +11,7 @@ class EllieModal {
10
11
  buttons = [];
11
12
  buttonClick = new EventEmitter();
12
13
  closed = new EventEmitter();
14
+ customFooter;
13
15
  ellieModal;
14
16
  static instanceCount = 0;
15
17
  backdropId;
@@ -48,11 +50,11 @@ class EllieModal {
48
50
  this.closed.emit();
49
51
  }
50
52
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: EllieModal, deps: [], target: i0.ɵɵFactoryTarget.Component });
51
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: EllieModal, isStandalone: true, selector: "app-ellie-modal", inputs: { title: "title", titleIcon: "titleIcon", bannerClass: "bannerClass", size: "size", buttons: "buttons" }, outputs: { buttonClick: "buttonClick", closed: "closed" }, viewQueries: [{ propertyName: "ellieModal", first: true, predicate: ["ellieModal"], descendants: true }], ngImport: i0, template: "<div class=\"modal fade\" #ellieModal tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog modal-dialog-centered\" [ngClass]=\"sizeClass\" role=\"document\">\n <div class=\"modal-content\">\n\n <div class=\"modal-header text-white\" [ngClass]=\"bannerClass\">\n <h5 class=\"modal-title\">\n @if (titleIcon) {\n <i [class]=\"titleIcon\"></i>\n }\n {{ title }}\n </h5>\n <button type=\"button\" class=\"close text-white\" (click)=\"onCloseX()\">&times;</button>\n </div>\n\n <div class=\"modal-body\">\n <ng-content></ng-content>\n </div>\n\n <div class=\"modal-footer\">\n @for (btn of buttons; track btn.action) {\n <button\n type=\"button\"\n class=\"btn\"\n [ngClass]=\"btn.colorClass\"\n [disabled]=\"btn.disabled || btn.loading\"\n (click)=\"onButtonClick(btn)\">\n @if (btn.loading) {\n <span class=\"spinner-border spinner-border-sm\" role=\"status\"></span>\n {{ btn.loadingLabel || btn.label }}\n } @else {\n @if (btn.icon) {\n <i [class]=\"btn.icon\"></i>\n }\n {{ btn.label }}\n }\n </button>\n }\n </div>\n\n </div>\n </div>\n</div>\n", styles: [".modal-header .close{background:transparent;border:none;font-size:1.5rem;line-height:1;opacity:.8;cursor:pointer}.modal-header .close:hover{opacity:1}.modal-content{max-height:90vh;display:flex;flex-direction:column}.modal-body{overflow-y:auto;flex:1 1 auto}@media(max-width:576px){.modal-dialog{margin:.5rem}.modal-content{max-height:95vh}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
53
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: EllieModal, isStandalone: true, selector: "app-ellie-modal", inputs: { title: "title", titleIcon: "titleIcon", bannerClass: "bannerClass", size: "size", buttons: "buttons" }, outputs: { buttonClick: "buttonClick", closed: "closed" }, queries: [{ propertyName: "customFooter", first: true, predicate: ["modalFooter"], descendants: true }], viewQueries: [{ propertyName: "ellieModal", first: true, predicate: ["ellieModal"], descendants: true }], ngImport: i0, template: "<div class=\"modal fade\" #ellieModal tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog modal-dialog-centered\" [ngClass]=\"sizeClass\" role=\"document\">\n <div class=\"modal-content\">\n\n <div class=\"modal-header text-white\" [ngClass]=\"bannerClass\">\n <h5 class=\"modal-title\">\n @if (titleIcon) {\n <i [class]=\"titleIcon\"></i>\n }\n {{ title }}\n </h5>\n <button type=\"button\" class=\"close text-white\" (click)=\"onCloseX()\">&times;</button>\n </div>\n\n <div class=\"modal-body\">\n <ng-content></ng-content>\n </div>\n\n @if (customFooter) {\n <ng-container [ngTemplateOutlet]=\"customFooter\"></ng-container>\n } @else {\n <div class=\"modal-footer\">\n @for (btn of buttons; track btn.action) {\n <button\n type=\"button\"\n class=\"btn\"\n [ngClass]=\"btn.colorClass\"\n [disabled]=\"btn.disabled || btn.loading\"\n (click)=\"onButtonClick(btn)\">\n @if (btn.loading) {\n <span class=\"spinner-border spinner-border-sm\" role=\"status\"></span>\n {{ btn.loadingLabel || btn.label }}\n } @else {\n @if (btn.icon) {\n <i [class]=\"btn.icon\"></i>\n }\n {{ btn.label }}\n }\n </button>\n }\n </div>\n }\n\n </div>\n </div>\n</div>\n", styles: [".modal-header .close{background:transparent;border:none;font-size:1.5rem;line-height:1;opacity:.8;cursor:pointer}.modal-header .close:hover{opacity:1}.modal-content{max-height:90vh;display:flex;flex-direction:column}.modal-body{overflow-y:auto;flex:1 1 auto}@media(max-width:576px){.modal-dialog{margin:.5rem}.modal-content{max-height:95vh}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
52
54
  }
53
55
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: EllieModal, decorators: [{
54
56
  type: Component,
55
- args: [{ selector: 'app-ellie-modal', imports: [NgClass], template: "<div class=\"modal fade\" #ellieModal tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog modal-dialog-centered\" [ngClass]=\"sizeClass\" role=\"document\">\n <div class=\"modal-content\">\n\n <div class=\"modal-header text-white\" [ngClass]=\"bannerClass\">\n <h5 class=\"modal-title\">\n @if (titleIcon) {\n <i [class]=\"titleIcon\"></i>\n }\n {{ title }}\n </h5>\n <button type=\"button\" class=\"close text-white\" (click)=\"onCloseX()\">&times;</button>\n </div>\n\n <div class=\"modal-body\">\n <ng-content></ng-content>\n </div>\n\n <div class=\"modal-footer\">\n @for (btn of buttons; track btn.action) {\n <button\n type=\"button\"\n class=\"btn\"\n [ngClass]=\"btn.colorClass\"\n [disabled]=\"btn.disabled || btn.loading\"\n (click)=\"onButtonClick(btn)\">\n @if (btn.loading) {\n <span class=\"spinner-border spinner-border-sm\" role=\"status\"></span>\n {{ btn.loadingLabel || btn.label }}\n } @else {\n @if (btn.icon) {\n <i [class]=\"btn.icon\"></i>\n }\n {{ btn.label }}\n }\n </button>\n }\n </div>\n\n </div>\n </div>\n</div>\n", styles: [".modal-header .close{background:transparent;border:none;font-size:1.5rem;line-height:1;opacity:.8;cursor:pointer}.modal-header .close:hover{opacity:1}.modal-content{max-height:90vh;display:flex;flex-direction:column}.modal-body{overflow-y:auto;flex:1 1 auto}@media(max-width:576px){.modal-dialog{margin:.5rem}.modal-content{max-height:95vh}}\n"] }]
57
+ args: [{ selector: 'app-ellie-modal', imports: [NgClass, NgTemplateOutlet], template: "<div class=\"modal fade\" #ellieModal tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog modal-dialog-centered\" [ngClass]=\"sizeClass\" role=\"document\">\n <div class=\"modal-content\">\n\n <div class=\"modal-header text-white\" [ngClass]=\"bannerClass\">\n <h5 class=\"modal-title\">\n @if (titleIcon) {\n <i [class]=\"titleIcon\"></i>\n }\n {{ title }}\n </h5>\n <button type=\"button\" class=\"close text-white\" (click)=\"onCloseX()\">&times;</button>\n </div>\n\n <div class=\"modal-body\">\n <ng-content></ng-content>\n </div>\n\n @if (customFooter) {\n <ng-container [ngTemplateOutlet]=\"customFooter\"></ng-container>\n } @else {\n <div class=\"modal-footer\">\n @for (btn of buttons; track btn.action) {\n <button\n type=\"button\"\n class=\"btn\"\n [ngClass]=\"btn.colorClass\"\n [disabled]=\"btn.disabled || btn.loading\"\n (click)=\"onButtonClick(btn)\">\n @if (btn.loading) {\n <span class=\"spinner-border spinner-border-sm\" role=\"status\"></span>\n {{ btn.loadingLabel || btn.label }}\n } @else {\n @if (btn.icon) {\n <i [class]=\"btn.icon\"></i>\n }\n {{ btn.label }}\n }\n </button>\n }\n </div>\n }\n\n </div>\n </div>\n</div>\n", styles: [".modal-header .close{background:transparent;border:none;font-size:1.5rem;line-height:1;opacity:.8;cursor:pointer}.modal-header .close:hover{opacity:1}.modal-content{max-height:90vh;display:flex;flex-direction:column}.modal-body{overflow-y:auto;flex:1 1 auto}@media(max-width:576px){.modal-dialog{margin:.5rem}.modal-content{max-height:95vh}}\n"] }]
56
58
  }], ctorParameters: () => [], propDecorators: { title: [{
57
59
  type: Input
58
60
  }], titleIcon: [{
@@ -67,18 +69,158 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
67
69
  type: Output
68
70
  }], closed: [{
69
71
  type: Output
72
+ }], customFooter: [{
73
+ type: ContentChild,
74
+ args: ['modalFooter']
70
75
  }], ellieModal: [{
71
76
  type: ViewChild,
72
77
  args: ['ellieModal']
73
78
  }] } });
74
79
 
80
+ class Paginator {
81
+ totalCount = "0";
82
+ limit = "10";
83
+ pages = "0";
84
+ currentSkip = 1;
85
+ constructor(skip) {
86
+ this.currentSkip = skip ?? 1;
87
+ }
88
+ }
89
+
90
+ class ToastService {
91
+ toastSubject = new Subject();
92
+ toastState$ = this.toastSubject.asObservable();
93
+ timeoutId;
94
+ show(message, type = 'info', title) {
95
+ if (this.timeoutId)
96
+ clearTimeout(this.timeoutId);
97
+ this.toastSubject.next({ message, type, title });
98
+ this.timeoutId = setTimeout(() => {
99
+ this.close();
100
+ }, 20000);
101
+ }
102
+ close() {
103
+ this.toastSubject.next(null);
104
+ if (this.timeoutId)
105
+ clearTimeout(this.timeoutId);
106
+ }
107
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
108
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToastService, providedIn: 'root' });
109
+ }
110
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToastService, decorators: [{
111
+ type: Injectable,
112
+ args: [{
113
+ providedIn: 'root'
114
+ }]
115
+ }] });
116
+
117
+ class ToastMessages {
118
+ toastService;
119
+ options = null;
120
+ subscription;
121
+ constructor(toastService) {
122
+ this.toastService = toastService;
123
+ }
124
+ ngOnInit() {
125
+ this.subscription = this.toastService.toastState$.subscribe(state => {
126
+ this.options = state;
127
+ });
128
+ }
129
+ onClose() {
130
+ this.toastService.close();
131
+ }
132
+ ngOnDestroy() {
133
+ if (this.subscription) {
134
+ this.subscription.unsubscribe();
135
+ }
136
+ }
137
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToastMessages, deps: [{ token: ToastService }], target: i0.ɵɵFactoryTarget.Component });
138
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ToastMessages, isStandalone: true, selector: "app-toast-messages", ngImport: i0, template: "@if (options) {\n <div id=\"toast-container\">\n <div class=\"toast\" [class]=\"'toast-' + options.type\" role=\"alert\">\n\n @if (options.type === 'success') { <i class=\"fas fa-check-circle\"></i> }\n @else if (options.type === 'error') { <i class=\"fas fa-times-circle\"></i> }\n @else if (options.type === 'warning') { <i class=\"fas fa-exclamation-triangle\"></i> }\n @else { <i class=\"fas fa-info-circle\"></i> }\n\n <div class=\"toast-content\">\n @if (options.title) {\n <span class=\"toast-title\">{{ options.title }}</span>\n }\n <span class=\"toast-message\">{{ options.message }}</span>\n </div>\n\n <button type=\"button\" class=\"toast-close-button\" (click)=\"onClose()\">\n &times;\n </button>\n\n </div>\n </div>\n}\n", styles: ["#toast-container{position:fixed;bottom:20px;right:20px;left:auto!important;top:auto!important;z-index:9999999!important;pointer-events:none}#toast-container .toast{position:relative;pointer-events:auto;width:380px;min-height:64px;padding:15px 50px 15px 60px;margin-bottom:10px;border-radius:4px;color:#fff!important;box-shadow:0 8px 25px #00000080;border:1px solid rgba(255,255,255,.2);display:flex;flex-direction:column;justify-content:center;overflow:visible!important}#toast-container .toast i{position:absolute;left:18px;top:50%;transform:translateY(-50%);font-size:26px;opacity:.9}.toast-success{background-color:#28a745!important}.toast-error{background-color:#de4848!important}.toast-warning{background-color:#ffc107!important;color:#212529!important}.toast-info{background-color:#17a2b8!important}.toast-title{font-weight:700;font-size:15px;display:block;margin-bottom:2px}.toast-message{font-size:13.5px;line-height:1.4;display:block}.toast-close-button{position:absolute!important;top:50%!important;right:10px!important;transform:translateY(-50%)!important;background:none!important;border:none!important;outline:none!important;padding:0!important;margin:0!important;color:#fff!important;font-family:Arial,sans-serif!important;font-size:28px!important;font-weight:700!important;line-height:1!important;width:30px!important;height:30px!important;display:flex!important;align-items:center;justify-content:center;cursor:pointer!important;pointer-events:auto!important;z-index:1000!important;opacity:.8}.toast-warning .toast-close-button{color:#212529!important}.toast-close-button:hover{opacity:1;transform:translateY(-50%) scale(1.1)!important}@media(max-width:575px){#toast-container{right:10px;left:10px;width:calc(100% - 20px)}#toast-container .toast{width:100%}}\n"] });
139
+ }
140
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToastMessages, decorators: [{
141
+ type: Component,
142
+ args: [{ selector: 'app-toast-messages', template: "@if (options) {\n <div id=\"toast-container\">\n <div class=\"toast\" [class]=\"'toast-' + options.type\" role=\"alert\">\n\n @if (options.type === 'success') { <i class=\"fas fa-check-circle\"></i> }\n @else if (options.type === 'error') { <i class=\"fas fa-times-circle\"></i> }\n @else if (options.type === 'warning') { <i class=\"fas fa-exclamation-triangle\"></i> }\n @else { <i class=\"fas fa-info-circle\"></i> }\n\n <div class=\"toast-content\">\n @if (options.title) {\n <span class=\"toast-title\">{{ options.title }}</span>\n }\n <span class=\"toast-message\">{{ options.message }}</span>\n </div>\n\n <button type=\"button\" class=\"toast-close-button\" (click)=\"onClose()\">\n &times;\n </button>\n\n </div>\n </div>\n}\n", styles: ["#toast-container{position:fixed;bottom:20px;right:20px;left:auto!important;top:auto!important;z-index:9999999!important;pointer-events:none}#toast-container .toast{position:relative;pointer-events:auto;width:380px;min-height:64px;padding:15px 50px 15px 60px;margin-bottom:10px;border-radius:4px;color:#fff!important;box-shadow:0 8px 25px #00000080;border:1px solid rgba(255,255,255,.2);display:flex;flex-direction:column;justify-content:center;overflow:visible!important}#toast-container .toast i{position:absolute;left:18px;top:50%;transform:translateY(-50%);font-size:26px;opacity:.9}.toast-success{background-color:#28a745!important}.toast-error{background-color:#de4848!important}.toast-warning{background-color:#ffc107!important;color:#212529!important}.toast-info{background-color:#17a2b8!important}.toast-title{font-weight:700;font-size:15px;display:block;margin-bottom:2px}.toast-message{font-size:13.5px;line-height:1.4;display:block}.toast-close-button{position:absolute!important;top:50%!important;right:10px!important;transform:translateY(-50%)!important;background:none!important;border:none!important;outline:none!important;padding:0!important;margin:0!important;color:#fff!important;font-family:Arial,sans-serif!important;font-size:28px!important;font-weight:700!important;line-height:1!important;width:30px!important;height:30px!important;display:flex!important;align-items:center;justify-content:center;cursor:pointer!important;pointer-events:auto!important;z-index:1000!important;opacity:.8}.toast-warning .toast-close-button{color:#212529!important}.toast-close-button:hover{opacity:1;transform:translateY(-50%) scale(1.1)!important}@media(max-width:575px){#toast-container{right:10px;left:10px;width:calc(100% - 20px)}#toast-container .toast{width:100%}}\n"] }]
143
+ }], ctorParameters: () => [{ type: ToastService }] });
144
+
145
+ class EllieFileUpload {
146
+ accept = '.png,.jpg,.jpeg,.pdf';
147
+ acceptLabel = 'PNG, JPG, PDF';
148
+ maxSizeMb = 10;
149
+ fileSelected = new EventEmitter();
150
+ selectedFile = null;
151
+ errorMessage = '';
152
+ isDragOver = false;
153
+ onFileChange(event) {
154
+ const input = event.target;
155
+ this.handleFile(input.files?.[0] ?? null);
156
+ input.value = '';
157
+ }
158
+ onDragOver(event) {
159
+ event.preventDefault();
160
+ this.isDragOver = true;
161
+ }
162
+ onDragLeave() {
163
+ this.isDragOver = false;
164
+ }
165
+ onDrop(event) {
166
+ event.preventDefault();
167
+ this.isDragOver = false;
168
+ this.handleFile(event.dataTransfer?.files?.[0] ?? null);
169
+ }
170
+ remove() {
171
+ this.selectedFile = null;
172
+ this.errorMessage = '';
173
+ this.fileSelected.emit(null);
174
+ }
175
+ get fileSizeLabel() {
176
+ if (!this.selectedFile)
177
+ return '';
178
+ const kb = this.selectedFile.size / 1024;
179
+ return kb >= 1024
180
+ ? `${(kb / 1024).toFixed(1)} MB`
181
+ : `${Math.round(kb)} KB`;
182
+ }
183
+ handleFile(file) {
184
+ this.errorMessage = '';
185
+ if (!file)
186
+ return;
187
+ if (file.size > this.maxSizeMb * 1024 * 1024) {
188
+ this.errorMessage = `El archivo supera el límite de ${this.maxSizeMb} MB.`;
189
+ return;
190
+ }
191
+ const ext = '.' + (file.name.split('.').pop()?.toLowerCase() ?? '');
192
+ const allowed = this.accept.split(',').map(e => e.trim().toLowerCase());
193
+ if (!allowed.includes(ext)) {
194
+ this.errorMessage = `Tipo no permitido. Formatos aceptados: ${this.acceptLabel}.`;
195
+ return;
196
+ }
197
+ this.selectedFile = file;
198
+ this.fileSelected.emit(file);
199
+ }
200
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: EllieFileUpload, deps: [], target: i0.ɵɵFactoryTarget.Component });
201
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: EllieFileUpload, isStandalone: true, selector: "app-ellie-file-upload", inputs: { accept: "accept", acceptLabel: "acceptLabel", maxSizeMb: "maxSizeMb" }, outputs: { fileSelected: "fileSelected" }, ngImport: i0, template: "<div class=\"upload-zone\"\n [class.upload-zone--drag]=\"isDragOver\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave()\"\n (drop)=\"onDrop($event)\">\n <input type=\"file\"\n [accept]=\"accept\"\n (change)=\"onFileChange($event)\">\n <div class=\"upload-zone__icon\">&#128196;</div>\n <div class=\"upload-zone__title\">Arrastra tu archivo aqu&#237;</div>\n <div class=\"upload-zone__sub\">o haz clic para seleccionar desde tu dispositivo</div>\n <div class=\"upload-zone__types\">{{ acceptLabel }} &nbsp;&middot;&nbsp; M&#225;x. {{ maxSizeMb }} MB</div>\n</div>\n\n@if (errorMessage) {\n <div class=\"upload-error\">{{ errorMessage }}</div>\n}\n\n@if (selectedFile) {\n <div class=\"file-list\">\n <div class=\"file-item\">\n <div class=\"file-item__icon\">&#128196;</div>\n <div class=\"file-item__info\">\n <div class=\"file-item__name\">{{ selectedFile.name }}</div>\n <div class=\"file-item__size\">{{ fileSizeLabel }}</div>\n <div class=\"file-progress\">\n <div class=\"file-progress__bar\" style=\"width:100%\"></div>\n </div>\n </div>\n <button type=\"button\" class=\"file-item__remove\" (click)=\"remove()\">&#10005;</button>\n </div>\n </div>\n}\n", styles: [":host{--color-primary: #00C48C;--color-primary-dark: #00A376;--color-primary-light:#E6FAF4;--color-gray-100: #EFF1F5;--color-gray-200: #DDE1EA;--color-gray-300: #C8CEDB;--color-gray-400: #9AA3B5;--color-gray-800: #2C3347;--color-danger: #E53935;--color-danger-light: #FEECEC;--radius-sm: 6px;--radius-lg: 16px;--transition: .16s ease;display:block}.upload-zone{border:2px dashed var(--color-gray-300);border-radius:var(--radius-lg);padding:40px 24px;text-align:center;cursor:pointer;transition:border-color var(--transition),background var(--transition);position:relative}.upload-zone:hover,.upload-zone--drag{border-color:var(--color-primary);background:var(--color-primary-light)}.upload-zone input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%}.upload-zone__icon{font-size:40px;margin-bottom:12px}.upload-zone__title{font-size:16px;font-weight:700;color:var(--color-gray-800);margin-bottom:6px}.upload-zone__sub{font-size:13px;color:var(--color-gray-400);margin-bottom:14px}.upload-zone__types{font-size:11px;color:var(--color-gray-400)}.upload-error{margin-top:8px;font-size:12px;color:var(--color-danger)}.file-list{margin-top:16px;display:flex;flex-direction:column;gap:8px}.file-item{display:flex;align-items:center;gap:12px;padding:12px 14px;background:var(--color-gray-100);border:1.5px solid var(--color-gray-200);border-radius:var(--radius-sm)}.file-item__icon{font-size:22px;width:30px;text-align:center}.file-item__info{flex:1;min-width:0}.file-item__name{font-size:13px;font-weight:600;color:var(--color-gray-800);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.file-item__size{font-size:11px;color:var(--color-gray-400)}.file-item__remove{width:28px;height:28px;border:none;background:var(--color-danger-light);color:var(--color-danger);border-radius:6px;cursor:pointer;font-size:16px;display:flex;align-items:center;justify-content:center;transition:background var(--transition)}.file-item__remove:hover{background:var(--color-danger);color:#fff}.file-progress{height:3px;background:var(--color-gray-200);border-radius:2px;margin-top:6px;overflow:hidden}.file-progress__bar{height:100%;background:var(--color-primary);border-radius:2px}\n"] });
202
+ }
203
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: EllieFileUpload, decorators: [{
204
+ type: Component,
205
+ args: [{ selector: 'app-ellie-file-upload', imports: [], template: "<div class=\"upload-zone\"\n [class.upload-zone--drag]=\"isDragOver\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave()\"\n (drop)=\"onDrop($event)\">\n <input type=\"file\"\n [accept]=\"accept\"\n (change)=\"onFileChange($event)\">\n <div class=\"upload-zone__icon\">&#128196;</div>\n <div class=\"upload-zone__title\">Arrastra tu archivo aqu&#237;</div>\n <div class=\"upload-zone__sub\">o haz clic para seleccionar desde tu dispositivo</div>\n <div class=\"upload-zone__types\">{{ acceptLabel }} &nbsp;&middot;&nbsp; M&#225;x. {{ maxSizeMb }} MB</div>\n</div>\n\n@if (errorMessage) {\n <div class=\"upload-error\">{{ errorMessage }}</div>\n}\n\n@if (selectedFile) {\n <div class=\"file-list\">\n <div class=\"file-item\">\n <div class=\"file-item__icon\">&#128196;</div>\n <div class=\"file-item__info\">\n <div class=\"file-item__name\">{{ selectedFile.name }}</div>\n <div class=\"file-item__size\">{{ fileSizeLabel }}</div>\n <div class=\"file-progress\">\n <div class=\"file-progress__bar\" style=\"width:100%\"></div>\n </div>\n </div>\n <button type=\"button\" class=\"file-item__remove\" (click)=\"remove()\">&#10005;</button>\n </div>\n </div>\n}\n", styles: [":host{--color-primary: #00C48C;--color-primary-dark: #00A376;--color-primary-light:#E6FAF4;--color-gray-100: #EFF1F5;--color-gray-200: #DDE1EA;--color-gray-300: #C8CEDB;--color-gray-400: #9AA3B5;--color-gray-800: #2C3347;--color-danger: #E53935;--color-danger-light: #FEECEC;--radius-sm: 6px;--radius-lg: 16px;--transition: .16s ease;display:block}.upload-zone{border:2px dashed var(--color-gray-300);border-radius:var(--radius-lg);padding:40px 24px;text-align:center;cursor:pointer;transition:border-color var(--transition),background var(--transition);position:relative}.upload-zone:hover,.upload-zone--drag{border-color:var(--color-primary);background:var(--color-primary-light)}.upload-zone input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%}.upload-zone__icon{font-size:40px;margin-bottom:12px}.upload-zone__title{font-size:16px;font-weight:700;color:var(--color-gray-800);margin-bottom:6px}.upload-zone__sub{font-size:13px;color:var(--color-gray-400);margin-bottom:14px}.upload-zone__types{font-size:11px;color:var(--color-gray-400)}.upload-error{margin-top:8px;font-size:12px;color:var(--color-danger)}.file-list{margin-top:16px;display:flex;flex-direction:column;gap:8px}.file-item{display:flex;align-items:center;gap:12px;padding:12px 14px;background:var(--color-gray-100);border:1.5px solid var(--color-gray-200);border-radius:var(--radius-sm)}.file-item__icon{font-size:22px;width:30px;text-align:center}.file-item__info{flex:1;min-width:0}.file-item__name{font-size:13px;font-weight:600;color:var(--color-gray-800);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.file-item__size{font-size:11px;color:var(--color-gray-400)}.file-item__remove{width:28px;height:28px;border:none;background:var(--color-danger-light);color:var(--color-danger);border-radius:6px;cursor:pointer;font-size:16px;display:flex;align-items:center;justify-content:center;transition:background var(--transition)}.file-item__remove:hover{background:var(--color-danger);color:#fff}.file-progress{height:3px;background:var(--color-gray-200);border-radius:2px;margin-top:6px;overflow:hidden}.file-progress__bar{height:100%;background:var(--color-primary);border-radius:2px}\n"] }]
206
+ }], propDecorators: { accept: [{
207
+ type: Input
208
+ }], acceptLabel: [{
209
+ type: Input
210
+ }], maxSizeMb: [{
211
+ type: Input
212
+ }], fileSelected: [{
213
+ type: Output
214
+ }] } });
215
+
75
216
  /*
76
217
  * @ellie-software/ui — Public API Surface
77
218
  */
219
+ // Modal
78
220
 
79
221
  /**
80
222
  * Generated bundle index. Do not edit.
81
223
  */
82
224
 
83
- export { EllieModal };
225
+ export { EllieFileUpload, EllieModal, Paginator, ToastMessages, ToastService };
84
226
  //# sourceMappingURL=ellie-software-ui.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ellie-software-ui.mjs","sources":["../../../projects/ui/src/lib/ellie-modal/ellie-modal.ts","../../../projects/ui/src/lib/ellie-modal/ellie-modal.html","../../../projects/ui/src/public-api.ts","../../../projects/ui/src/ellie-software-ui.ts"],"sourcesContent":["import { Component, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core';\nimport { NgClass } from '@angular/common';\n\nexport interface EllieModalButton {\n label: string;\n colorClass: string; // 'btn-danger', 'btn-secondary', 'btn-success', etc.\n action: string; // identificador emitido al padre\n icon?: string; // 'fa fa-save', 'icon-trash', etc.\n loading?: boolean;\n loadingLabel?: string;\n disabled?: boolean;\n}\n\n@Component({\n selector: 'app-ellie-modal',\n imports: [NgClass],\n templateUrl: './ellie-modal.html',\n styleUrl: './ellie-modal.css'\n})\nexport class EllieModal {\n @Input() title: string = '';\n @Input() titleIcon: string = '';\n @Input() bannerClass: string = 'bg-primary';\n @Input() size: 'sm' | 'md' | 'lg' | 'xl' = 'md';\n @Input() buttons: EllieModalButton[] = [];\n\n @Output() buttonClick = new EventEmitter<string>();\n @Output() closed = new EventEmitter<void>();\n\n @ViewChild('ellieModal') ellieModal!: ElementRef;\n\n private static instanceCount = 0;\n private backdropId: string;\n\n constructor() {\n EllieModal.instanceCount++;\n this.backdropId = `ellie-modal-backdrop-${EllieModal.instanceCount}`;\n }\n\n get sizeClass(): string {\n const map: Record<string, string> = { sm: 'modal-sm', lg: 'modal-lg', xl: 'modal-xl', md: '' };\n return map[this.size] ?? '';\n }\n\n openModal(): void {\n const el = this.ellieModal.nativeElement;\n el.classList.add('show');\n el.style.display = 'block';\n document.body.classList.add('modal-open');\n const backdrop = document.createElement('div');\n backdrop.classList.add('modal-backdrop', 'fade', 'show');\n backdrop.id = this.backdropId;\n document.body.appendChild(backdrop);\n }\n\n closeModal(): void {\n const el = this.ellieModal.nativeElement;\n el.classList.remove('show');\n el.style.display = 'none';\n document.body.classList.remove('modal-open');\n const backdrop = document.getElementById(this.backdropId);\n if (backdrop) backdrop.remove();\n }\n\n onButtonClick(btn: EllieModalButton): void {\n this.buttonClick.emit(btn.action);\n }\n\n onCloseX(): void {\n this.closeModal();\n this.closed.emit();\n }\n}\n","<div class=\"modal fade\" #ellieModal tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog modal-dialog-centered\" [ngClass]=\"sizeClass\" role=\"document\">\n <div class=\"modal-content\">\n\n <div class=\"modal-header text-white\" [ngClass]=\"bannerClass\">\n <h5 class=\"modal-title\">\n @if (titleIcon) {\n <i [class]=\"titleIcon\"></i>\n }\n {{ title }}\n </h5>\n <button type=\"button\" class=\"close text-white\" (click)=\"onCloseX()\">&times;</button>\n </div>\n\n <div class=\"modal-body\">\n <ng-content></ng-content>\n </div>\n\n <div class=\"modal-footer\">\n @for (btn of buttons; track btn.action) {\n <button\n type=\"button\"\n class=\"btn\"\n [ngClass]=\"btn.colorClass\"\n [disabled]=\"btn.disabled || btn.loading\"\n (click)=\"onButtonClick(btn)\">\n @if (btn.loading) {\n <span class=\"spinner-border spinner-border-sm\" role=\"status\"></span>\n {{ btn.loadingLabel || btn.label }}\n } @else {\n @if (btn.icon) {\n <i [class]=\"btn.icon\"></i>\n }\n {{ btn.label }}\n }\n </button>\n }\n </div>\n\n </div>\n </div>\n</div>\n","/*\n * @ellie-software/ui — Public API Surface\n */\n\nexport { EllieModal, EllieModalButton } from './lib/ellie-modal/ellie-modal';\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":"ellie-software-ui.mjs","sources":["../../../projects/ui/src/lib/ellie-modal/ellie-modal.ts","../../../projects/ui/src/lib/ellie-modal/ellie-modal.html","../../../projects/ui/src/lib/paginator/paginator.ts","../../../projects/ui/src/lib/toast/toast.service.ts","../../../projects/ui/src/lib/toast/toast-messages.ts","../../../projects/ui/src/lib/toast/toast-messages.html","../../../projects/ui/src/lib/file-upload/ellie-file-upload.ts","../../../projects/ui/src/lib/file-upload/ellie-file-upload.html","../../../projects/ui/src/public-api.ts","../../../projects/ui/src/ellie-software-ui.ts"],"sourcesContent":["import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, ContentChild, TemplateRef } from '@angular/core';\nimport { NgClass, NgTemplateOutlet } from '@angular/common';\n\nexport interface EllieModalButton {\n label: string;\n colorClass: string; // 'btn-danger', 'btn-secondary', 'btn-success', etc.\n action: string; // identificador emitido al padre\n icon?: string; // 'fa fa-save', 'icon-trash', etc.\n loading?: boolean;\n loadingLabel?: string;\n disabled?: boolean;\n}\n\n@Component({\n selector: 'app-ellie-modal',\n imports: [NgClass, NgTemplateOutlet],\n templateUrl: './ellie-modal.html',\n styleUrl: './ellie-modal.css'\n})\nexport class EllieModal {\n @Input() title: string = '';\n @Input() titleIcon: string = '';\n @Input() bannerClass: string = 'bg-primary';\n @Input() size: 'sm' | 'md' | 'lg' | 'xl' = 'md';\n @Input() buttons: EllieModalButton[] = [];\n\n @Output() buttonClick = new EventEmitter<string>();\n @Output() closed = new EventEmitter<void>();\n\n @ContentChild('modalFooter') customFooter?: TemplateRef<unknown>;\n @ViewChild('ellieModal') ellieModal!: ElementRef;\n\n private static instanceCount = 0;\n private backdropId: string;\n\n constructor() {\n EllieModal.instanceCount++;\n this.backdropId = `ellie-modal-backdrop-${EllieModal.instanceCount}`;\n }\n\n get sizeClass(): string {\n const map: Record<string, string> = { sm: 'modal-sm', lg: 'modal-lg', xl: 'modal-xl', md: '' };\n return map[this.size] ?? '';\n }\n\n openModal(): void {\n const el = this.ellieModal.nativeElement;\n el.classList.add('show');\n el.style.display = 'block';\n document.body.classList.add('modal-open');\n const backdrop = document.createElement('div');\n backdrop.classList.add('modal-backdrop', 'fade', 'show');\n backdrop.id = this.backdropId;\n document.body.appendChild(backdrop);\n }\n\n closeModal(): void {\n const el = this.ellieModal.nativeElement;\n el.classList.remove('show');\n el.style.display = 'none';\n document.body.classList.remove('modal-open');\n const backdrop = document.getElementById(this.backdropId);\n if (backdrop) backdrop.remove();\n }\n\n onButtonClick(btn: EllieModalButton): void {\n this.buttonClick.emit(btn.action);\n }\n\n onCloseX(): void {\n this.closeModal();\n this.closed.emit();\n }\n}\n","<div class=\"modal fade\" #ellieModal tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog modal-dialog-centered\" [ngClass]=\"sizeClass\" role=\"document\">\n <div class=\"modal-content\">\n\n <div class=\"modal-header text-white\" [ngClass]=\"bannerClass\">\n <h5 class=\"modal-title\">\n @if (titleIcon) {\n <i [class]=\"titleIcon\"></i>\n }\n {{ title }}\n </h5>\n <button type=\"button\" class=\"close text-white\" (click)=\"onCloseX()\">&times;</button>\n </div>\n\n <div class=\"modal-body\">\n <ng-content></ng-content>\n </div>\n\n @if (customFooter) {\n <ng-container [ngTemplateOutlet]=\"customFooter\"></ng-container>\n } @else {\n <div class=\"modal-footer\">\n @for (btn of buttons; track btn.action) {\n <button\n type=\"button\"\n class=\"btn\"\n [ngClass]=\"btn.colorClass\"\n [disabled]=\"btn.disabled || btn.loading\"\n (click)=\"onButtonClick(btn)\">\n @if (btn.loading) {\n <span class=\"spinner-border spinner-border-sm\" role=\"status\"></span>\n {{ btn.loadingLabel || btn.label }}\n } @else {\n @if (btn.icon) {\n <i [class]=\"btn.icon\"></i>\n }\n {{ btn.label }}\n }\n </button>\n }\n </div>\n }\n\n </div>\n </div>\n</div>\n","export class Paginator {\n totalCount: string = \"0\";\n limit: string = \"10\";\n pages: string = \"0\";\n currentSkip: number = 1;\n\n constructor(skip?: number) {\n this.currentSkip = skip ?? 1;\n }\n}\n","import { Injectable } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nexport type ToastType = 'info' | 'success' | 'warning' | 'error';\n\nexport interface ToastOptions {\n message: string;\n type: ToastType;\n title?: string;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ToastService {\n private toastSubject = new Subject<ToastOptions | null>();\n public toastState$ = this.toastSubject.asObservable();\n private timeoutId: any;\n\n show(message: string, type: ToastType = 'info', title?: string) {\n if (this.timeoutId) clearTimeout(this.timeoutId);\n\n this.toastSubject.next({ message, type, title });\n\n this.timeoutId = setTimeout(() => {\n this.close();\n }, 20000);\n }\n\n close() {\n this.toastSubject.next(null);\n if (this.timeoutId) clearTimeout(this.timeoutId);\n }\n}\n","import { Component, OnInit, OnDestroy } from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { ToastOptions, ToastService } from './toast.service';\n\n@Component({\n selector: 'app-toast-messages',\n templateUrl: './toast-messages.html',\n styleUrl: './toast-messages.css'\n})\nexport class ToastMessages {\n public options: ToastOptions | null = null;\n private subscription!: Subscription;\n\n constructor(private toastService: ToastService) {}\n\n ngOnInit(): void {\n this.subscription = this.toastService.toastState$.subscribe(state => {\n this.options = state;\n });\n }\n\n onClose(): void {\n this.toastService.close();\n }\n\n ngOnDestroy(): void {\n if (this.subscription) {\n this.subscription.unsubscribe();\n }\n }\n}\n","@if (options) {\n <div id=\"toast-container\">\n <div class=\"toast\" [class]=\"'toast-' + options.type\" role=\"alert\">\n\n @if (options.type === 'success') { <i class=\"fas fa-check-circle\"></i> }\n @else if (options.type === 'error') { <i class=\"fas fa-times-circle\"></i> }\n @else if (options.type === 'warning') { <i class=\"fas fa-exclamation-triangle\"></i> }\n @else { <i class=\"fas fa-info-circle\"></i> }\n\n <div class=\"toast-content\">\n @if (options.title) {\n <span class=\"toast-title\">{{ options.title }}</span>\n }\n <span class=\"toast-message\">{{ options.message }}</span>\n </div>\n\n <button type=\"button\" class=\"toast-close-button\" (click)=\"onClose()\">\n &times;\n </button>\n\n </div>\n </div>\n}\n","import { Component, Input, Output, EventEmitter } from '@angular/core';\n\nexport interface EllieFileUploadAccept {\n extensions: string; // ej: '.png,.jpg,.jpeg,.pdf'\n label: string; // ej: 'PNG, JPG, PDF'\n}\n\n@Component({\n selector: 'app-ellie-file-upload',\n imports: [],\n templateUrl: './ellie-file-upload.html',\n styleUrl: './ellie-file-upload.css'\n})\nexport class EllieFileUpload {\n @Input() accept: string = '.png,.jpg,.jpeg,.pdf';\n @Input() acceptLabel: string = 'PNG, JPG, PDF';\n @Input() maxSizeMb: number = 10;\n @Output() fileSelected = new EventEmitter<File | null>();\n\n selectedFile: File | null = null;\n errorMessage: string = '';\n isDragOver: boolean = false;\n\n onFileChange(event: Event): void {\n const input = event.target as HTMLInputElement;\n this.handleFile(input.files?.[0] ?? null);\n input.value = '';\n }\n\n onDragOver(event: DragEvent): void {\n event.preventDefault();\n this.isDragOver = true;\n }\n\n onDragLeave(): void {\n this.isDragOver = false;\n }\n\n onDrop(event: DragEvent): void {\n event.preventDefault();\n this.isDragOver = false;\n this.handleFile(event.dataTransfer?.files?.[0] ?? null);\n }\n\n remove(): void {\n this.selectedFile = null;\n this.errorMessage = '';\n this.fileSelected.emit(null);\n }\n\n get fileSizeLabel(): string {\n if (!this.selectedFile) return '';\n const kb = this.selectedFile.size / 1024;\n return kb >= 1024\n ? `${(kb / 1024).toFixed(1)} MB`\n : `${Math.round(kb)} KB`;\n }\n\n private handleFile(file: File | null): void {\n this.errorMessage = '';\n if (!file) return;\n\n if (file.size > this.maxSizeMb * 1024 * 1024) {\n this.errorMessage = `El archivo supera el límite de ${this.maxSizeMb} MB.`;\n return;\n }\n\n const ext = '.' + (file.name.split('.').pop()?.toLowerCase() ?? '');\n const allowed = this.accept.split(',').map(e => e.trim().toLowerCase());\n if (!allowed.includes(ext)) {\n this.errorMessage = `Tipo no permitido. Formatos aceptados: ${this.acceptLabel}.`;\n return;\n }\n\n this.selectedFile = file;\n this.fileSelected.emit(file);\n }\n}\n","<div class=\"upload-zone\"\n [class.upload-zone--drag]=\"isDragOver\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave()\"\n (drop)=\"onDrop($event)\">\n <input type=\"file\"\n [accept]=\"accept\"\n (change)=\"onFileChange($event)\">\n <div class=\"upload-zone__icon\">&#128196;</div>\n <div class=\"upload-zone__title\">Arrastra tu archivo aqu&#237;</div>\n <div class=\"upload-zone__sub\">o haz clic para seleccionar desde tu dispositivo</div>\n <div class=\"upload-zone__types\">{{ acceptLabel }} &nbsp;&middot;&nbsp; M&#225;x. {{ maxSizeMb }} MB</div>\n</div>\n\n@if (errorMessage) {\n <div class=\"upload-error\">{{ errorMessage }}</div>\n}\n\n@if (selectedFile) {\n <div class=\"file-list\">\n <div class=\"file-item\">\n <div class=\"file-item__icon\">&#128196;</div>\n <div class=\"file-item__info\">\n <div class=\"file-item__name\">{{ selectedFile.name }}</div>\n <div class=\"file-item__size\">{{ fileSizeLabel }}</div>\n <div class=\"file-progress\">\n <div class=\"file-progress__bar\" style=\"width:100%\"></div>\n </div>\n </div>\n <button type=\"button\" class=\"file-item__remove\" (click)=\"remove()\">&#10005;</button>\n </div>\n </div>\n}\n","/*\n * @ellie-software/ui — Public API Surface\n */\n\n// Modal\nexport { EllieModal, EllieModalButton } from './lib/ellie-modal/ellie-modal';\n\n// Paginator\nexport { Paginator } from './lib/paginator/paginator';\n\n// Toast\nexport { ToastMessages } from './lib/toast/toast-messages';\nexport { ToastService, ToastType, ToastOptions } from './lib/toast/toast.service';\n\n// File Upload\nexport { EllieFileUpload, EllieFileUploadAccept } from './lib/file-upload/ellie-file-upload';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.ToastService"],"mappings":"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"}
package/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, ElementRef } from '@angular/core';
2
+ import { EventEmitter, TemplateRef, ElementRef } from '@angular/core';
3
+ import * as rxjs from 'rxjs';
3
4
 
4
5
  interface EllieModalButton {
5
6
  label: string;
@@ -18,6 +19,7 @@ declare class EllieModal {
18
19
  buttons: EllieModalButton[];
19
20
  buttonClick: EventEmitter<string>;
20
21
  closed: EventEmitter<void>;
22
+ customFooter?: TemplateRef<unknown>;
21
23
  ellieModal: ElementRef;
22
24
  private static instanceCount;
23
25
  private backdropId;
@@ -28,8 +30,67 @@ declare class EllieModal {
28
30
  onButtonClick(btn: EllieModalButton): void;
29
31
  onCloseX(): void;
30
32
  static ɵfac: i0.ɵɵFactoryDeclaration<EllieModal, never>;
31
- static ɵcmp: i0.ɵɵComponentDeclaration<EllieModal, "app-ellie-modal", never, { "title": { "alias": "title"; "required": false; }; "titleIcon": { "alias": "titleIcon"; "required": false; }; "bannerClass": { "alias": "bannerClass"; "required": false; }; "size": { "alias": "size"; "required": false; }; "buttons": { "alias": "buttons"; "required": false; }; }, { "buttonClick": "buttonClick"; "closed": "closed"; }, never, ["*"], true, never>;
33
+ static ɵcmp: i0.ɵɵComponentDeclaration<EllieModal, "app-ellie-modal", never, { "title": { "alias": "title"; "required": false; }; "titleIcon": { "alias": "titleIcon"; "required": false; }; "bannerClass": { "alias": "bannerClass"; "required": false; }; "size": { "alias": "size"; "required": false; }; "buttons": { "alias": "buttons"; "required": false; }; }, { "buttonClick": "buttonClick"; "closed": "closed"; }, ["customFooter"], ["*"], true, never>;
32
34
  }
33
35
 
34
- export { EllieModal };
35
- export type { EllieModalButton };
36
+ declare class Paginator {
37
+ totalCount: string;
38
+ limit: string;
39
+ pages: string;
40
+ currentSkip: number;
41
+ constructor(skip?: number);
42
+ }
43
+
44
+ type ToastType = 'info' | 'success' | 'warning' | 'error';
45
+ interface ToastOptions {
46
+ message: string;
47
+ type: ToastType;
48
+ title?: string;
49
+ }
50
+ declare class ToastService {
51
+ private toastSubject;
52
+ toastState$: rxjs.Observable<ToastOptions | null>;
53
+ private timeoutId;
54
+ show(message: string, type?: ToastType, title?: string): void;
55
+ close(): void;
56
+ static ɵfac: i0.ɵɵFactoryDeclaration<ToastService, never>;
57
+ static ɵprov: i0.ɵɵInjectableDeclaration<ToastService>;
58
+ }
59
+
60
+ declare class ToastMessages {
61
+ private toastService;
62
+ options: ToastOptions | null;
63
+ private subscription;
64
+ constructor(toastService: ToastService);
65
+ ngOnInit(): void;
66
+ onClose(): void;
67
+ ngOnDestroy(): void;
68
+ static ɵfac: i0.ɵɵFactoryDeclaration<ToastMessages, never>;
69
+ static ɵcmp: i0.ɵɵComponentDeclaration<ToastMessages, "app-toast-messages", never, {}, {}, never, never, true, never>;
70
+ }
71
+
72
+ interface EllieFileUploadAccept {
73
+ extensions: string;
74
+ label: string;
75
+ }
76
+ declare class EllieFileUpload {
77
+ accept: string;
78
+ acceptLabel: string;
79
+ maxSizeMb: number;
80
+ fileSelected: EventEmitter<File | null>;
81
+ selectedFile: File | null;
82
+ errorMessage: string;
83
+ isDragOver: boolean;
84
+ onFileChange(event: Event): void;
85
+ onDragOver(event: DragEvent): void;
86
+ onDragLeave(): void;
87
+ onDrop(event: DragEvent): void;
88
+ remove(): void;
89
+ get fileSizeLabel(): string;
90
+ private handleFile;
91
+ static ɵfac: i0.ɵɵFactoryDeclaration<EllieFileUpload, never>;
92
+ static ɵcmp: i0.ɵɵComponentDeclaration<EllieFileUpload, "app-ellie-file-upload", never, { "accept": { "alias": "accept"; "required": false; }; "acceptLabel": { "alias": "acceptLabel"; "required": false; }; "maxSizeMb": { "alias": "maxSizeMb"; "required": false; }; }, { "fileSelected": "fileSelected"; }, never, never, true, never>;
93
+ }
94
+
95
+ export { EllieFileUpload, EllieModal, Paginator, ToastMessages, ToastService };
96
+ export type { EllieFileUploadAccept, EllieModalButton, ToastOptions, ToastType };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ellie-software/ui",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Ellie shared UI components library",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "peerDependencies": {
11
11
  "@angular/common": "^20.0.0",
12
- "@angular/core": "^20.0.0"
12
+ "@angular/core": "^20.0.0",
13
+ "rxjs": "^7.0.0"
13
14
  },
14
15
  "sideEffects": false,
15
16
  "module": "fesm2022/ellie-software-ui.mjs",