sapenlinea-components 0.9.76 → 0.9.78
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.
- package/fesm2022/sapenlinea-components.mjs +600 -162
- package/fesm2022/sapenlinea-components.mjs.map +1 -1
- package/index.d.ts +73 -14
- package/package.json +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { model, input, signal, computed, Component, Injectable, inject, output, HostListener, ViewChildren, forwardRef, effect, ViewChild, ElementRef, booleanAttribute, DestroyRef, EventEmitter, Output, Input as Input$1, viewChildren, ChangeDetectionStrategy } from '@angular/core';
|
|
3
3
|
import * as i1$1 from '@angular/common';
|
|
4
|
-
import { CommonModule, UpperCasePipe } from '@angular/common';
|
|
4
|
+
import { CommonModule, UpperCasePipe, NgClass } from '@angular/common';
|
|
5
5
|
import * as i1 from '@angular/forms';
|
|
6
6
|
import { NG_VALUE_ACCESSOR, ReactiveFormsModule, FormsModule, FormGroup, FormControl, Validators } from '@angular/forms';
|
|
7
7
|
import PubSub from 'pubsub-js';
|
|
8
8
|
import { BarChart as BarChart$1, LineChart as LineChart$1, PieChart, HeatmapChart } from 'echarts/charts';
|
|
9
9
|
import * as echarts from 'echarts/core';
|
|
10
10
|
import { NgxEchartsDirective, provideEchartsCore } from 'ngx-echarts';
|
|
11
|
-
import { GridComponent, TooltipComponent, GraphicComponent, DataZoomComponent, VisualMapComponent, LegendComponent } from 'echarts/components';
|
|
11
|
+
import { GridComponent, TooltipComponent, GraphicComponent, DataZoomComponent, VisualMapComponent, LegendComponent, TitleComponent } from 'echarts/components';
|
|
12
12
|
import { CanvasRenderer } from 'echarts/renderers';
|
|
13
13
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
14
14
|
|
|
@@ -584,9 +584,10 @@ class DateTimePicker {
|
|
|
584
584
|
// Estado AM/PM
|
|
585
585
|
selectedAmPm = signal('AM', ...(ngDevMode ? [{ debugName: "selectedAmPm" }] : []));
|
|
586
586
|
documentClickListener;
|
|
587
|
+
resizeListener;
|
|
587
588
|
/**
|
|
588
589
|
* Valor que se muestra en el campo de texto.
|
|
589
|
-
*
|
|
590
|
+
* Modo 'date': DD/MM/YYYY. Modo 'datetime': DD/MM/YYYY HH:MM (24h).
|
|
590
591
|
*/
|
|
591
592
|
displayValue = computed(() => {
|
|
592
593
|
const text = this.inputTextValue().trim();
|
|
@@ -596,10 +597,7 @@ class DateTimePicker {
|
|
|
596
597
|
const date = this.selectedDate();
|
|
597
598
|
if (!date)
|
|
598
599
|
return '';
|
|
599
|
-
|
|
600
|
-
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
601
|
-
const year = date.getFullYear();
|
|
602
|
-
return `${day}/${month}/${year}`;
|
|
600
|
+
return this.formatDateForInput(date);
|
|
603
601
|
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
|
|
604
602
|
monthName = computed(() => {
|
|
605
603
|
const months = [
|
|
@@ -654,6 +652,7 @@ class DateTimePicker {
|
|
|
654
652
|
}
|
|
655
653
|
ngOnDestroy() {
|
|
656
654
|
this.removeDocumentListener();
|
|
655
|
+
this.removePositioningListeners();
|
|
657
656
|
}
|
|
658
657
|
writeValue(value) {
|
|
659
658
|
let date = null;
|
|
@@ -698,11 +697,10 @@ class DateTimePicker {
|
|
|
698
697
|
if (this.isBlocked())
|
|
699
698
|
return;
|
|
700
699
|
this.markAsTouched();
|
|
701
|
-
|
|
702
|
-
const spaceBelow = window.innerHeight - rect.bottom;
|
|
703
|
-
this.openUpward.set(spaceBelow < 420);
|
|
700
|
+
this.updatePosition();
|
|
704
701
|
this.isOpen.set(true);
|
|
705
702
|
this.addDocumentListener();
|
|
703
|
+
this.addPositioningListeners();
|
|
706
704
|
// Si hay fecha seleccionada, navegar a ese mes/año
|
|
707
705
|
const selected = this.selectedDate();
|
|
708
706
|
if (selected) {
|
|
@@ -712,9 +710,34 @@ class DateTimePicker {
|
|
|
712
710
|
}
|
|
713
711
|
close() {
|
|
714
712
|
this.isOpen.set(false);
|
|
713
|
+
this.openUpward.set(false);
|
|
715
714
|
this.removeDocumentListener();
|
|
715
|
+
this.removePositioningListeners();
|
|
716
716
|
this.markAsTouched();
|
|
717
717
|
}
|
|
718
|
+
updatePosition() {
|
|
719
|
+
const scrollY = window.scrollY;
|
|
720
|
+
const maxScrollY = Math.max(0, document.documentElement.scrollHeight - window.innerHeight);
|
|
721
|
+
const canScrollDown = scrollY < maxScrollY - 1;
|
|
722
|
+
this.openUpward.set(!canScrollDown);
|
|
723
|
+
}
|
|
724
|
+
addPositioningListeners() {
|
|
725
|
+
this.removePositioningListeners();
|
|
726
|
+
this.ngZone.runOutsideAngular(() => {
|
|
727
|
+
this.resizeListener = () => {
|
|
728
|
+
if (this.isOpen()) {
|
|
729
|
+
this.ngZone.run(() => this.updatePosition());
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
window.addEventListener('resize', this.resizeListener);
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
removePositioningListeners() {
|
|
736
|
+
if (this.resizeListener) {
|
|
737
|
+
window.removeEventListener('resize', this.resizeListener);
|
|
738
|
+
this.resizeListener = undefined;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
718
741
|
selectDay(day) {
|
|
719
742
|
if (!day || this.isBlocked())
|
|
720
743
|
return;
|
|
@@ -868,17 +891,19 @@ class DateTimePicker {
|
|
|
868
891
|
this.markAsTouched();
|
|
869
892
|
this.dateChange.emit(newDate);
|
|
870
893
|
}
|
|
871
|
-
// Manejo de input de texto (DD/MM/YYYY)
|
|
894
|
+
// Manejo de input de texto (DD/MM/YYYY o DD/MM/YYYY HH:MM)
|
|
872
895
|
onInputChange(event) {
|
|
873
896
|
if (this.isBlocked())
|
|
874
897
|
return;
|
|
875
898
|
const input = event.target;
|
|
876
|
-
|
|
899
|
+
const value = input.value;
|
|
900
|
+
const isDateTime = this.mode() === 'datetime';
|
|
877
901
|
// Eliminar todo lo que no sea número
|
|
878
902
|
const numbersOnly = value.replace(/\D/g, '');
|
|
879
|
-
// Limitar a 8 dígitos
|
|
880
|
-
const
|
|
881
|
-
|
|
903
|
+
// Limitar a 8 dígitos para fecha o 12 para datetime
|
|
904
|
+
const maxDigits = isDateTime ? 12 : 8;
|
|
905
|
+
const limitedNumbers = numbersOnly.slice(0, maxDigits);
|
|
906
|
+
// Formatear con separadores: DD/MM/YYYY [ HH:MM]
|
|
882
907
|
let formatted = '';
|
|
883
908
|
if (limitedNumbers.length > 0) {
|
|
884
909
|
formatted = limitedNumbers.slice(0, 2);
|
|
@@ -888,12 +913,18 @@ class DateTimePicker {
|
|
|
888
913
|
if (limitedNumbers.length > 4) {
|
|
889
914
|
formatted += '/' + limitedNumbers.slice(4, 8);
|
|
890
915
|
}
|
|
916
|
+
if (isDateTime && limitedNumbers.length > 8) {
|
|
917
|
+
formatted += ' ' + limitedNumbers.slice(8, 10);
|
|
918
|
+
}
|
|
919
|
+
if (isDateTime && limitedNumbers.length > 10) {
|
|
920
|
+
formatted += ':' + limitedNumbers.slice(10, 12);
|
|
921
|
+
}
|
|
891
922
|
}
|
|
892
923
|
this.inputTextValue.set(formatted);
|
|
893
924
|
input.value = formatted;
|
|
894
925
|
this.markAsTouched();
|
|
895
|
-
|
|
896
|
-
if (formatted.length ===
|
|
926
|
+
const completeLength = isDateTime ? 16 : 10;
|
|
927
|
+
if (formatted.length === completeLength) {
|
|
897
928
|
const parsedDate = this.parseDateInput(formatted);
|
|
898
929
|
if (parsedDate) {
|
|
899
930
|
if (this.isDateDisabled(parsedDate)) {
|
|
@@ -913,9 +944,8 @@ class DateTimePicker {
|
|
|
913
944
|
}
|
|
914
945
|
}
|
|
915
946
|
/**
|
|
916
|
-
* Selects the date segment
|
|
917
|
-
*
|
|
918
|
-
* Format: DD/MM/YYYY → segments at positions 0-1, 3-4, 6-9
|
|
947
|
+
* Selects the date/time segment under the cursor on click.
|
|
948
|
+
* Format: DD/MM/YYYY [HH:MM] → DD=0-1, MM=3-4, YYYY=6-9, HH=11-12, MM=14-15
|
|
919
949
|
*/
|
|
920
950
|
onInputClick(event) {
|
|
921
951
|
event.stopPropagation();
|
|
@@ -924,29 +954,31 @@ class DateTimePicker {
|
|
|
924
954
|
const input = event.target;
|
|
925
955
|
const pos = input.selectionStart ?? 0;
|
|
926
956
|
const value = input.value;
|
|
927
|
-
// Only do segment selection when the value looks like a date (has slashes)
|
|
928
957
|
if (!value || !value.includes('/'))
|
|
929
958
|
return;
|
|
930
|
-
|
|
931
|
-
// DD = 0..1, slash at 2, MM = 3..4, slash at 5, YYYY = 6..9
|
|
959
|
+
const hasTime = this.mode() === 'datetime' && value.includes(':');
|
|
932
960
|
let start;
|
|
933
961
|
let end;
|
|
934
962
|
if (pos <= 2) {
|
|
935
|
-
// Day segment
|
|
936
963
|
start = 0;
|
|
937
964
|
end = 2;
|
|
938
965
|
}
|
|
939
966
|
else if (pos <= 5) {
|
|
940
|
-
// Month segment
|
|
941
967
|
start = 3;
|
|
942
968
|
end = 5;
|
|
943
969
|
}
|
|
944
|
-
else {
|
|
945
|
-
// Year segment
|
|
970
|
+
else if (pos <= 10 || !hasTime) {
|
|
946
971
|
start = 6;
|
|
947
972
|
end = 10;
|
|
948
973
|
}
|
|
949
|
-
|
|
974
|
+
else if (pos <= 13) {
|
|
975
|
+
start = 11;
|
|
976
|
+
end = 13;
|
|
977
|
+
}
|
|
978
|
+
else {
|
|
979
|
+
start = 14;
|
|
980
|
+
end = 16;
|
|
981
|
+
}
|
|
950
982
|
setTimeout(() => {
|
|
951
983
|
input.setSelectionRange(start, end);
|
|
952
984
|
}, 0);
|
|
@@ -959,16 +991,27 @@ class DateTimePicker {
|
|
|
959
991
|
parseDateInput(input) {
|
|
960
992
|
if (!input || input.trim() === '')
|
|
961
993
|
return null;
|
|
962
|
-
const
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
994
|
+
const trimmed = input.trim();
|
|
995
|
+
const dateTimeMatch = trimmed.match(/^(\d{2})\/(\d{2})\/(\d{4})\s(\d{2}):(\d{2})$/);
|
|
996
|
+
const dateMatch = trimmed.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
|
|
997
|
+
const match = dateTimeMatch || dateMatch;
|
|
998
|
+
if (!match)
|
|
999
|
+
return null;
|
|
1000
|
+
const day = parseInt(match[1], 10);
|
|
1001
|
+
const month = parseInt(match[2], 10) - 1;
|
|
1002
|
+
const year = parseInt(match[3], 10);
|
|
1003
|
+
const hour = match[4] ? parseInt(match[4], 10) : 0;
|
|
1004
|
+
const minute = match[5] ? parseInt(match[5], 10) : 0;
|
|
1005
|
+
if (day >= 1 && day <= 31 &&
|
|
1006
|
+
month >= 0 && month <= 11 &&
|
|
1007
|
+
year >= 1900 && year <= 2100 &&
|
|
1008
|
+
hour >= 0 && hour <= 23 &&
|
|
1009
|
+
minute >= 0 && minute <= 59) {
|
|
1010
|
+
const date = new Date(year, month, day, hour, minute);
|
|
1011
|
+
if (date.getDate() === day &&
|
|
1012
|
+
date.getMonth() === month &&
|
|
1013
|
+
date.getFullYear() === year) {
|
|
1014
|
+
return date;
|
|
972
1015
|
}
|
|
973
1016
|
}
|
|
974
1017
|
return null;
|
|
@@ -977,7 +1020,13 @@ class DateTimePicker {
|
|
|
977
1020
|
const day = date.getDate().toString().padStart(2, '0');
|
|
978
1021
|
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
979
1022
|
const year = date.getFullYear();
|
|
980
|
-
|
|
1023
|
+
const dateStr = `${day}/${month}/${year}`;
|
|
1024
|
+
if (this.mode() === 'datetime') {
|
|
1025
|
+
const hour = date.getHours().toString().padStart(2, '0');
|
|
1026
|
+
const minute = date.getMinutes().toString().padStart(2, '0');
|
|
1027
|
+
return `${dateStr} ${hour}:${minute}`;
|
|
1028
|
+
}
|
|
1029
|
+
return dateStr;
|
|
981
1030
|
}
|
|
982
1031
|
updateInternalState(date) {
|
|
983
1032
|
this.selectedDate.set(date);
|
|
@@ -1094,37 +1143,69 @@ class DateTimeFilter {
|
|
|
1094
1143
|
isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
1095
1144
|
isTouched = signal(false, ...(ngDevMode ? [{ debugName: "isTouched" }] : []));
|
|
1096
1145
|
dropdownDirection = signal('right', ...(ngDevMode ? [{ debugName: "dropdownDirection" }] : []));
|
|
1097
|
-
// Máscara visual dinámica para la guía de fecha __/__/____
|
|
1146
|
+
// Máscara visual dinámica para la guía de fecha __/__/____ o __/__/____, __:__ __
|
|
1098
1147
|
// Devuelve un arreglo de caracteres con flag "filled" para poder dar color distinto
|
|
1099
1148
|
inputMask = computed(() => {
|
|
1100
1149
|
const raw = this.inputTextValue() || '';
|
|
1101
1150
|
const numbersOnly = raw.replace(/\D/g, '');
|
|
1151
|
+
const isDateTime = this.mode() === 'datetime';
|
|
1152
|
+
const ampmMatch = raw.toUpperCase().match(/[AP]M?/);
|
|
1153
|
+
const ampmStr = ampmMatch ? (ampmMatch[0].startsWith('P') ? 'PM' : 'AM') : 'AM';
|
|
1102
1154
|
const template = [
|
|
1103
|
-
{ char: 'd', filled: false },
|
|
1104
|
-
{ char: 'd', filled: false },
|
|
1105
|
-
{ char: '/', filled: false },
|
|
1106
|
-
{ char: 'm', filled: false },
|
|
1107
|
-
{ char: 'm', filled: false },
|
|
1108
|
-
{ char: '/', filled: false },
|
|
1109
|
-
{ char: 'y', filled: false },
|
|
1110
|
-
{ char: 'y', filled: false },
|
|
1111
|
-
{ char: 'y', filled: false },
|
|
1112
|
-
{ char: 'y', filled: false },
|
|
1155
|
+
{ char: 'd', filled: false }, // 0
|
|
1156
|
+
{ char: 'd', filled: false }, // 1
|
|
1157
|
+
{ char: '/', filled: false }, // 2
|
|
1158
|
+
{ char: 'm', filled: false }, // 3
|
|
1159
|
+
{ char: 'm', filled: false }, // 4
|
|
1160
|
+
{ char: '/', filled: false }, // 5
|
|
1161
|
+
{ char: 'y', filled: false }, // 6
|
|
1162
|
+
{ char: 'y', filled: false }, // 7
|
|
1163
|
+
{ char: 'y', filled: false }, // 8
|
|
1164
|
+
{ char: 'y', filled: false }, // 9
|
|
1113
1165
|
];
|
|
1166
|
+
if (isDateTime) {
|
|
1167
|
+
template.push({ char: ',', filled: false }, // 10
|
|
1168
|
+
{ char: ' ', filled: false }, // 11
|
|
1169
|
+
{ char: 'h', filled: false }, // 12
|
|
1170
|
+
{ char: 'h', filled: false }, // 13
|
|
1171
|
+
{ char: ':', filled: false }, // 14
|
|
1172
|
+
{ char: 'm', filled: false }, // 15
|
|
1173
|
+
{ char: 'm', filled: false }, // 16
|
|
1174
|
+
{ char: ' ', filled: false }, // 17
|
|
1175
|
+
{ char: ampmStr[0], filled: false }, // 18
|
|
1176
|
+
{ char: ampmStr[1], filled: false } // 19
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1114
1179
|
let index = 0;
|
|
1115
|
-
for (let i = 0; i < template.length
|
|
1116
|
-
if (template[i].char === '/')
|
|
1180
|
+
for (let i = 0; i < template.length; i++) {
|
|
1181
|
+
if (template[i].char === '/' || template[i].char === ',' || template[i].char === ' ' || template[i].char === ':')
|
|
1117
1182
|
continue;
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1183
|
+
if (isDateTime && (i === 18 || i === 19)) {
|
|
1184
|
+
if (numbersOnly.length >= 12) {
|
|
1185
|
+
template[i].filled = true;
|
|
1186
|
+
}
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
if (index < numbersOnly.length) {
|
|
1190
|
+
template[i] = { char: numbersOnly[index++], filled: true };
|
|
1191
|
+
}
|
|
1123
1192
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1193
|
+
// Cuando se completa el segmento, el slash/separador correspondiente pasa a "filled"
|
|
1194
|
+
if (numbersOnly.length >= 2)
|
|
1195
|
+
template[2].filled = true;
|
|
1196
|
+
if (numbersOnly.length >= 4)
|
|
1197
|
+
template[5].filled = true;
|
|
1198
|
+
if (isDateTime) {
|
|
1199
|
+
if (numbersOnly.length >= 8) {
|
|
1200
|
+
template[10].filled = true;
|
|
1201
|
+
template[11].filled = true;
|
|
1202
|
+
}
|
|
1203
|
+
if (numbersOnly.length >= 10)
|
|
1204
|
+
template[14].filled = true;
|
|
1205
|
+
if (numbersOnly.length >= 12)
|
|
1206
|
+
template[17].filled = true;
|
|
1126
1207
|
}
|
|
1127
|
-
return template;
|
|
1208
|
+
return template;
|
|
1128
1209
|
}, ...(ngDevMode ? [{ debugName: "inputMask" }] : []));
|
|
1129
1210
|
clearTrigger = input(0, ...(ngDevMode ? [{ debugName: "clearTrigger" }] : []));
|
|
1130
1211
|
// Computed Properties based on active filter
|
|
@@ -1281,11 +1362,13 @@ class DateTimeFilter {
|
|
|
1281
1362
|
return;
|
|
1282
1363
|
const input = event.target;
|
|
1283
1364
|
let value = input.value;
|
|
1284
|
-
|
|
1365
|
+
const isDateTime = this.mode() === 'datetime';
|
|
1366
|
+
// Remove all non-numeric characters for digits processing
|
|
1285
1367
|
const numbersOnly = value.replace(/\D/g, '');
|
|
1286
|
-
// Limit to 8 digits (DD/MM/YYYY)
|
|
1287
|
-
const
|
|
1288
|
-
|
|
1368
|
+
// Limit to 8 digits (DD/MM/YYYY) or 12 for datetime
|
|
1369
|
+
const maxDigits = isDateTime ? 12 : 8;
|
|
1370
|
+
const limitedNumbers = numbersOnly.slice(0, maxDigits);
|
|
1371
|
+
// Format string
|
|
1289
1372
|
let formatted = '';
|
|
1290
1373
|
if (limitedNumbers.length > 0) {
|
|
1291
1374
|
formatted = limitedNumbers.slice(0, 2);
|
|
@@ -1295,13 +1378,30 @@ class DateTimeFilter {
|
|
|
1295
1378
|
if (limitedNumbers.length > 4) {
|
|
1296
1379
|
formatted += '/' + limitedNumbers.slice(4, 8);
|
|
1297
1380
|
}
|
|
1381
|
+
if (isDateTime && limitedNumbers.length > 8) {
|
|
1382
|
+
formatted += ', ' + limitedNumbers.slice(8, 10);
|
|
1383
|
+
}
|
|
1384
|
+
if (isDateTime && limitedNumbers.length > 10) {
|
|
1385
|
+
formatted += ':' + limitedNumbers.slice(10, 12);
|
|
1386
|
+
}
|
|
1387
|
+
if (isDateTime && limitedNumbers.length === 12) {
|
|
1388
|
+
const lastChars = value.slice(-3).toUpperCase();
|
|
1389
|
+
let ampm = this.selectedAmPm();
|
|
1390
|
+
if (lastChars.includes('P'))
|
|
1391
|
+
ampm = 'PM';
|
|
1392
|
+
else if (lastChars.includes('A'))
|
|
1393
|
+
ampm = 'AM';
|
|
1394
|
+
this.selectedAmPm.set(ampm);
|
|
1395
|
+
formatted += ' ' + ampm;
|
|
1396
|
+
}
|
|
1298
1397
|
}
|
|
1299
1398
|
// Update the input value
|
|
1300
1399
|
this.inputTextValue.set(formatted);
|
|
1301
1400
|
input.value = formatted;
|
|
1302
1401
|
this.markAsTouched();
|
|
1303
|
-
|
|
1304
|
-
|
|
1402
|
+
const completeLength = isDateTime ? (formatted.length >= 20 ? 12 : -1) : 10;
|
|
1403
|
+
const isComplete = isDateTime ? limitedNumbers.length === 12 : formatted.length === 10;
|
|
1404
|
+
if (isComplete) {
|
|
1305
1405
|
const parsedDate = this.parseDateInput(formatted);
|
|
1306
1406
|
if (parsedDate) {
|
|
1307
1407
|
if (this.isDateDisabled(parsedDate)) {
|
|
@@ -1339,7 +1439,7 @@ class DateTimeFilter {
|
|
|
1339
1439
|
if (!value || !value.includes('/'))
|
|
1340
1440
|
return;
|
|
1341
1441
|
// Determine which segment the cursor is in
|
|
1342
|
-
|
|
1442
|
+
const isDateTime = this.mode() === 'datetime';
|
|
1343
1443
|
let start;
|
|
1344
1444
|
let end;
|
|
1345
1445
|
if (pos <= 2) {
|
|
@@ -1350,10 +1450,22 @@ class DateTimeFilter {
|
|
|
1350
1450
|
start = 3;
|
|
1351
1451
|
end = 5;
|
|
1352
1452
|
}
|
|
1353
|
-
else {
|
|
1453
|
+
else if (pos <= 10 || !isDateTime) {
|
|
1354
1454
|
start = 6;
|
|
1355
1455
|
end = 10;
|
|
1356
1456
|
}
|
|
1457
|
+
else if (pos <= 14) {
|
|
1458
|
+
start = 12;
|
|
1459
|
+
end = 14;
|
|
1460
|
+
}
|
|
1461
|
+
else if (pos <= 17) {
|
|
1462
|
+
start = 15;
|
|
1463
|
+
end = 17;
|
|
1464
|
+
}
|
|
1465
|
+
else {
|
|
1466
|
+
start = 18;
|
|
1467
|
+
end = 20;
|
|
1468
|
+
}
|
|
1357
1469
|
// Use setTimeout to override the browser's default selection behavior
|
|
1358
1470
|
setTimeout(() => {
|
|
1359
1471
|
input.setSelectionRange(start, end);
|
|
@@ -1384,23 +1496,37 @@ class DateTimeFilter {
|
|
|
1384
1496
|
if (!value || !value.includes('/'))
|
|
1385
1497
|
return;
|
|
1386
1498
|
const pos = input.selectionStart ?? 0;
|
|
1387
|
-
|
|
1499
|
+
const isDateTime = this.mode() === 'datetime';
|
|
1500
|
+
// Determine current segment
|
|
1388
1501
|
let currentSegment;
|
|
1389
|
-
if (pos <= 2)
|
|
1502
|
+
if (pos <= 2)
|
|
1390
1503
|
currentSegment = 0;
|
|
1391
|
-
|
|
1392
|
-
else if (pos <= 5) {
|
|
1504
|
+
else if (pos <= 5)
|
|
1393
1505
|
currentSegment = 1;
|
|
1394
|
-
|
|
1395
|
-
else {
|
|
1506
|
+
else if (pos <= 10 || !isDateTime)
|
|
1396
1507
|
currentSegment = 2;
|
|
1397
|
-
|
|
1508
|
+
else if (pos <= 14)
|
|
1509
|
+
currentSegment = 3;
|
|
1510
|
+
else if (pos <= 17)
|
|
1511
|
+
currentSegment = 4;
|
|
1512
|
+
else
|
|
1513
|
+
currentSegment = 5;
|
|
1398
1514
|
// Segment ranges
|
|
1399
|
-
const segments =
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1515
|
+
const segments = isDateTime
|
|
1516
|
+
? [
|
|
1517
|
+
{ start: 0, end: 2 }, // DD
|
|
1518
|
+
{ start: 3, end: 5 }, // MM
|
|
1519
|
+
{ start: 6, end: 10 }, // YYYY
|
|
1520
|
+
{ start: 12, end: 14 }, // HH
|
|
1521
|
+
{ start: 15, end: 17 }, // MIN
|
|
1522
|
+
{ start: 18, end: 20 }, // AMPM
|
|
1523
|
+
]
|
|
1524
|
+
: [
|
|
1525
|
+
{ start: 0, end: 2 }, // DD
|
|
1526
|
+
{ start: 3, end: 5 }, // MM
|
|
1527
|
+
{ start: 6, end: 10 }, // YYYY
|
|
1528
|
+
];
|
|
1529
|
+
const numSegments = isDateTime ? 6 : 3;
|
|
1404
1530
|
if (event.key === 'Tab') {
|
|
1405
1531
|
if (event.shiftKey) {
|
|
1406
1532
|
// Move to previous segment
|
|
@@ -1409,21 +1535,19 @@ class DateTimeFilter {
|
|
|
1409
1535
|
const prev = segments[currentSegment - 1];
|
|
1410
1536
|
setTimeout(() => input.setSelectionRange(prev.start, prev.end), 0);
|
|
1411
1537
|
}
|
|
1412
|
-
// If at first segment, let Tab work normally (move focus out)
|
|
1413
1538
|
}
|
|
1414
1539
|
else {
|
|
1415
1540
|
// Move to next segment
|
|
1416
|
-
if (currentSegment <
|
|
1541
|
+
if (currentSegment < numSegments - 1) {
|
|
1417
1542
|
event.preventDefault();
|
|
1418
1543
|
const next = segments[currentSegment + 1];
|
|
1419
1544
|
setTimeout(() => input.setSelectionRange(next.start, next.end), 0);
|
|
1420
1545
|
}
|
|
1421
|
-
// If at last segment, let Tab work normally (move focus out)
|
|
1422
1546
|
}
|
|
1423
1547
|
return;
|
|
1424
1548
|
}
|
|
1425
1549
|
if (event.key === 'ArrowRight') {
|
|
1426
|
-
if (currentSegment <
|
|
1550
|
+
if (currentSegment < numSegments - 1) {
|
|
1427
1551
|
event.preventDefault();
|
|
1428
1552
|
const next = segments[currentSegment + 1];
|
|
1429
1553
|
setTimeout(() => input.setSelectionRange(next.start, next.end), 0);
|
|
@@ -1440,16 +1564,28 @@ class DateTimeFilter {
|
|
|
1440
1564
|
}
|
|
1441
1565
|
if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
|
|
1442
1566
|
event.preventDefault();
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1567
|
+
let day = 1, month = 1, year = 2024, hour = 12, min = 0, ampm = 'AM';
|
|
1568
|
+
if (isDateTime) {
|
|
1569
|
+
const match = value.match(/^(\d{2})\/(\d{2})\/(\d{4}),\s(\d{2}):(\d{2})\s(AM|PM)$/i);
|
|
1570
|
+
if (!match)
|
|
1571
|
+
return;
|
|
1572
|
+
day = parseInt(match[1], 10);
|
|
1573
|
+
month = parseInt(match[2], 10);
|
|
1574
|
+
year = parseInt(match[3], 10);
|
|
1575
|
+
hour = parseInt(match[4], 10);
|
|
1576
|
+
min = parseInt(match[5], 10);
|
|
1577
|
+
ampm = match[6].toUpperCase();
|
|
1578
|
+
}
|
|
1579
|
+
else {
|
|
1580
|
+
const match = value.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
|
|
1581
|
+
if (!match)
|
|
1582
|
+
return;
|
|
1583
|
+
day = parseInt(match[1], 10);
|
|
1584
|
+
month = parseInt(match[2], 10);
|
|
1585
|
+
year = parseInt(match[3], 10);
|
|
1586
|
+
}
|
|
1450
1587
|
const delta = event.key === 'ArrowUp' ? 1 : -1;
|
|
1451
1588
|
if (currentSegment === 0) {
|
|
1452
|
-
// Increment/decrement day
|
|
1453
1589
|
day += delta;
|
|
1454
1590
|
const maxDay = new Date(year, month, 0).getDate();
|
|
1455
1591
|
if (day < 1)
|
|
@@ -1458,30 +1594,49 @@ class DateTimeFilter {
|
|
|
1458
1594
|
day = 1;
|
|
1459
1595
|
}
|
|
1460
1596
|
else if (currentSegment === 1) {
|
|
1461
|
-
// Increment/decrement month
|
|
1462
1597
|
month += delta;
|
|
1463
1598
|
if (month < 1)
|
|
1464
1599
|
month = 12;
|
|
1465
1600
|
if (month > 12)
|
|
1466
1601
|
month = 1;
|
|
1467
|
-
// Clamp day to valid range for new month
|
|
1468
1602
|
const maxDay = new Date(year, month, 0).getDate();
|
|
1469
1603
|
if (day > maxDay)
|
|
1470
1604
|
day = maxDay;
|
|
1471
1605
|
}
|
|
1472
|
-
else {
|
|
1473
|
-
// Increment/decrement year
|
|
1606
|
+
else if (currentSegment === 2) {
|
|
1474
1607
|
year += delta;
|
|
1475
1608
|
if (year < 1900)
|
|
1476
1609
|
year = 1900;
|
|
1477
1610
|
if (year > 2100)
|
|
1478
1611
|
year = 2100;
|
|
1479
|
-
// Clamp day (for leap year changes on Feb 29)
|
|
1480
1612
|
const maxDay = new Date(year, month, 0).getDate();
|
|
1481
1613
|
if (day > maxDay)
|
|
1482
1614
|
day = maxDay;
|
|
1483
1615
|
}
|
|
1484
|
-
|
|
1616
|
+
else if (currentSegment === 3) {
|
|
1617
|
+
hour += delta;
|
|
1618
|
+
if (hour < 1)
|
|
1619
|
+
hour = 12;
|
|
1620
|
+
if (hour > 12)
|
|
1621
|
+
hour = 1;
|
|
1622
|
+
}
|
|
1623
|
+
else if (currentSegment === 4) {
|
|
1624
|
+
min += delta;
|
|
1625
|
+
if (min < 0)
|
|
1626
|
+
min = 59;
|
|
1627
|
+
if (min > 59)
|
|
1628
|
+
min = 0;
|
|
1629
|
+
}
|
|
1630
|
+
else if (currentSegment === 5) {
|
|
1631
|
+
ampm = ampm === 'AM' ? 'PM' : 'AM';
|
|
1632
|
+
}
|
|
1633
|
+
let newFormatted = '';
|
|
1634
|
+
if (isDateTime) {
|
|
1635
|
+
newFormatted = `${day.toString().padStart(2, '0')}/${month.toString().padStart(2, '0')}/${year}, ${hour.toString().padStart(2, '0')}:${min.toString().padStart(2, '0')} ${ampm}`;
|
|
1636
|
+
}
|
|
1637
|
+
else {
|
|
1638
|
+
newFormatted = `${day.toString().padStart(2, '0')}/${month.toString().padStart(2, '0')}/${year}`;
|
|
1639
|
+
}
|
|
1485
1640
|
this.inputTextValue.set(newFormatted);
|
|
1486
1641
|
input.value = newFormatted;
|
|
1487
1642
|
// Parse and update if valid
|
|
@@ -1512,18 +1667,37 @@ class DateTimeFilter {
|
|
|
1512
1667
|
parseDateInput(input) {
|
|
1513
1668
|
if (!input || input.trim() === '')
|
|
1514
1669
|
return null;
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
const
|
|
1524
|
-
|
|
1525
|
-
if (
|
|
1526
|
-
|
|
1670
|
+
const isDateTime = this.mode() === 'datetime';
|
|
1671
|
+
if (isDateTime) {
|
|
1672
|
+
const match = input.trim().match(/^(\d{2})\/(\d{2})\/(\d{4}),\s(\d{2}):(\d{2})\s(AM|PM)$/i);
|
|
1673
|
+
if (match) {
|
|
1674
|
+
const day = parseInt(match[1], 10);
|
|
1675
|
+
const month = parseInt(match[2], 10) - 1;
|
|
1676
|
+
const year = parseInt(match[3], 10);
|
|
1677
|
+
const hour12 = parseInt(match[4], 10);
|
|
1678
|
+
const minute = parseInt(match[5], 10);
|
|
1679
|
+
const ampm = match[6].toUpperCase();
|
|
1680
|
+
if (day >= 1 && day <= 31 && month >= 0 && month <= 11 && year >= 1900 && year <= 2100 &&
|
|
1681
|
+
hour12 >= 1 && hour12 <= 12 && minute >= 0 && minute <= 59) {
|
|
1682
|
+
const hour24 = ampm === 'PM' ? (hour12 === 12 ? 12 : hour12 + 12) : (hour12 === 12 ? 0 : hour12);
|
|
1683
|
+
const date = new Date(year, month, day, hour24, minute);
|
|
1684
|
+
if (date.getDate() === day && date.getMonth() === month && date.getFullYear() === year) {
|
|
1685
|
+
return date;
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
else {
|
|
1691
|
+
const match = input.trim().match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
|
|
1692
|
+
if (match) {
|
|
1693
|
+
const day = parseInt(match[1], 10);
|
|
1694
|
+
const month = parseInt(match[2], 10) - 1;
|
|
1695
|
+
const year = parseInt(match[3], 10);
|
|
1696
|
+
if (day >= 1 && day <= 31 && month >= 0 && month <= 11 && year >= 1900 && year <= 2100) {
|
|
1697
|
+
const date = new Date(year, month, day);
|
|
1698
|
+
if (date.getDate() === day && date.getMonth() === month && date.getFullYear() === year) {
|
|
1699
|
+
return date;
|
|
1700
|
+
}
|
|
1527
1701
|
}
|
|
1528
1702
|
}
|
|
1529
1703
|
}
|
|
@@ -1591,6 +1765,15 @@ class DateTimeFilter {
|
|
|
1591
1765
|
const day = date.getDate().toString().padStart(2, '0');
|
|
1592
1766
|
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
1593
1767
|
const year = date.getFullYear();
|
|
1768
|
+
if (this.mode() === 'datetime') {
|
|
1769
|
+
let h = date.getHours();
|
|
1770
|
+
const m = date.getMinutes().toString().padStart(2, '0');
|
|
1771
|
+
const ampm = h >= 12 ? 'PM' : 'AM';
|
|
1772
|
+
h = h % 12;
|
|
1773
|
+
h = h ? h : 12;
|
|
1774
|
+
const hStr = h.toString().padStart(2, '0');
|
|
1775
|
+
return `${day}/${month}/${year}, ${hStr}:${m} ${ampm}`;
|
|
1776
|
+
}
|
|
1594
1777
|
return `${day}/${month}/${year}`;
|
|
1595
1778
|
}
|
|
1596
1779
|
markAsTouched() {
|
|
@@ -1742,7 +1925,7 @@ class DateTimeFilter {
|
|
|
1742
1925
|
useExisting: forwardRef(() => DateTimeFilter),
|
|
1743
1926
|
multi: true,
|
|
1744
1927
|
},
|
|
1745
|
-
], viewQueries: [{ propertyName: "chipRef", first: true, predicate: ["chip"], descendants: true }], ngImport: i0, template: "<div class=\"filter-chips\">\r\n @for (item of filters(); track item.value) {\r\n <div class=\"chip-input-wrapper\" #chip [class.has-value]=\"selectedDate() || inputTextValue()\"\r\n [class.active]=\"activeFilterType() === item.value\">\r\n <!-- Etiqueta flotante -->\r\n <label class=\"floating-label\">{{ item.placeholder || item.label || 'dd/mm/aaaa' }}</label>\r\n\r\n <!-- M\u00E1scara de gu\u00EDa de fecha din\u00E1mica (__/__/____) -->\r\n <div class=\"chip-input-mask\">\r\n @for (part of inputMask(); track $index) {\r\n <span class=\"mask-char\" [class.mask-char-filled]=\"part.filled\" [class.mask-char-placeholder]=\"!part.filled\">\r\n {{ part.char }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <input type=\"text\" [value]=\"inputTextValue()\" (input)=\"onInputChange($event, item.value)\"\r\n (click)=\"onInputClick($event, item.value)\"\r\n (focus)=\"onInputFocus(item.value)\" [placeholder]=\"item.placeholder || 'Seleccionar Fecha'\" class=\"chip-input\"\r\n [disabled]=\"isDisabled()\" (keydown)=\"onInputKeyDown($event, item.value)\" />\r\n\r\n <button type=\"button\" class=\"calendar-icon-button\" (click)=\"toggle(item.value)\" title=\"Abrir calendario\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n class=\"icon icon-tabler icons-tabler-outline icon-tabler-calendar-event\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\r\n <path d=\"M4 5m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z\" />\r\n <path d=\"M16 3l0 4\" />\r\n <path d=\"M8 3l0 4\" />\r\n <path d=\"M4 11l16 0\" />\r\n <path d=\"M8 15h2v2h-2z\" />\r\n </svg>\r\n </button>\r\n\r\n @if (isOpen() && activeFilterType() === item.value) {\r\n <div class=\"dropdown\" [class.open-left]=\"dropdownDirection() === 'left'\">\r\n <div class=\"datetime-content\">\r\n <!-- Secci\u00F3n del calendario -->\r\n <div class=\"calendar-section\">\r\n <!-- Navegaci\u00F3n -->\r\n <div class=\"calendar-nav\">\r\n <div class=\"nav-section\">\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"previousYear()\" title=\"A\u00F1o anterior\">\r\n \u2039\u2039\r\n </button>\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"previousMonth()\" title=\"Mes anterior\">\r\n \u2039\r\n </button>\r\n </div>\r\n\r\n <div class=\"current-date\">\r\n {{ monthName() }} {{ currentYear() }}\r\n </div>\r\n\r\n <div class=\"nav-section\">\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextMonth()\" title=\"Siguiente mes\">\r\n \u203A\r\n </button>\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextYear()\" title=\"Siguiente a\u00F1o\">\r\n \u203A\u203A\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- D\u00EDas de la semana -->\r\n <div class=\"weekdays\">\r\n <div class=\"weekday\">Dom</div>\r\n <div class=\"weekday\">Lun</div>\r\n <div class=\"weekday\">Mar</div>\r\n <div class=\"weekday\">Mi\u00E9</div>\r\n <div class=\"weekday\">Jue</div>\r\n <div class=\"weekday\">Vie</div>\r\n <div class=\"weekday\">S\u00E1b</div>\r\n </div>\r\n\r\n <!-- D\u00EDas -->\r\n <div class=\"calendar-grid\">\r\n @for (day of calendarDays(); track $index) {\r\n <div class=\"calendar-day\" [class.selected]=\"isDaySelected(day)\" [class.today]=\"isToday(day)\"\r\n [class.disabled]=\"isDayDisabled(day)\" [class.empty]=\"!day\" (click)=\"selectDay(day)\">\r\n {{ day || \"\" }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- TIME PICKER -->\r\n @if (mode() === 'datetime') {\r\n <div class=\"time-section\">\r\n <div class=\"time-header\">Horario</div>\r\n\r\n <div class=\"time-selectors\">\r\n <div class=\"time-group\">\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">Hora</div>\r\n <div class=\"time-scroll\">\r\n @for (hour of hours12(); track hour.value) {\r\n <div class=\"time-option\" [class.selected]=\"hour.value === selectedHour12()\"\r\n (click)=\"setHour12(hour.value)\">\r\n {{ hour.display }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"time-separator-vertical\">:</div>\r\n\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">Min</div>\r\n <div class=\"time-scroll\">\r\n @for (minute of minutes(); track minute) {\r\n <div class=\"time-option\" [class.selected]=\"minute === selectedMinute()\" (click)=\"setMinute(minute)\">\r\n {{ minute.toString().padStart(2, \"0\") }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">AM/PM</div>\r\n <div class=\"time-scroll ampm\">\r\n <div class=\"time-option\" [class.selected]=\"selectedAmPm() === 'AM'\" (click)=\"setAmPm('AM')\">\r\n AM\r\n </div>\r\n <div class=\"time-option\" [class.selected]=\"selectedAmPm() === 'PM'\" (click)=\"setAmPm('PM')\">\r\n PM\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- botones -->\r\n <div class=\"action-buttons\">\r\n <button type=\"button\" class=\"action-btn secondary\" (click)=\"today()\">\r\n Hoy\r\n </button>\r\n\r\n @if (mode() === 'datetime') {\r\n <button type=\"button\" class=\"action-btn primary\" (click)=\"close()\">\r\n Aceptar\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>", styles: [".datetime-container{position:relative;width:100%;overflow-x:clip}.filter-chips{display:flex;gap:10px;border-radius:12px;position:relative}.chip-input-wrapper{position:relative;display:flex;align-items:center;border-radius:8px;border-style:solid;border-color:var(--schemes-outline-variant, #c0c7cd);border-width:1px;min-width:80px;max-width:180px;height:32px;flex-shrink:0;transition:.2s ease;background-color:transparent}.chip-input-wrapper:hover{background-color:#ececcf}.chip-input-wrapper:focus-within,.chip-input-wrapper.active{color:var(--on-surface, #171c1f);border-color:#b6b69b}.floating-label{position:absolute;left:12px;top:-8px;color:var(--schemes-on-surface-variant, #454733);font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:1.1rem;line-height:12px;letter-spacing:var(--theme-label-large-letter-spacing, .1px);font-weight:var(--theme-label-large-font-weight, 500);opacity:0;pointer-events:none;transition:all .2s ease;z-index:2;background-color:#e3e3d1;padding:0 4px;border-radius:2px;text-transform:capitalize}.chip-input-wrapper:focus-within .floating-label{opacity:.6;top:-8px}.chip-input-wrapper.has-value .floating-label{opacity:.9}.chip-input{border:none;outline:none;background:transparent;padding:6px 40px 6px 8px;height:100%;width:100%;color:transparent;caret-color:var(--schemes-on-surface-variant, #454733);font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:var(--theme-label-large-font-size, 1.4rem);line-height:var(--theme-label-large-line-height, 20px);letter-spacing:var(--theme-label-large-letter-spacing, .1px);font-weight:var(--theme-label-large-font-weight, 500);border-radius:8px;position:relative;z-index:2}.chip-input::placeholder{color:var(--schemes-on-surface-variant, #454733);opacity:.6;text-transform:capitalize}.chip-input:disabled{cursor:not-allowed;opacity:.6}input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px #E3E3D1 inset;box-shadow:0 0 0 1000px #e3e3d1 inset;-webkit-text-fill-color:#454733;caret-color:#454733;transition:background-color 9999s ease-in-out 0s}input:-moz-autofill,textarea:-moz-autofill{box-shadow:0 0 0 1000px #e3e3d1 inset}input[readonly]:-webkit-autofill,input:disabled:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #E3E3D1 inset;-webkit-text-fill-color:#a9a97f}.chip-input-mask{position:absolute;left:8px;right:40px;top:50%;transform:translateY(-50%);pointer-events:none;font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:var(--theme-label-large-font-size, 14px);font-weight:var(--theme-label-large-font-weight, 500);z-index:1;display:flex;opacity:0;transition:opacity .2s ease}.chip-input-wrapper:focus-within .chip-input-mask,.chip-input-wrapper.has-value .chip-input-mask{opacity:1}.chip-input-wrapper:focus-within .chip-input::placeholder{opacity:0}.mask-char-placeholder{color:var(--schemes-on-surface-variant, #454733);opacity:.4}.mask-char-filled{color:var(--schemes-on-surface, #171c1f);opacity:1}.calendar-icon-button{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;color:var(--schemes-on-surface-variant, #454733);border-radius:4px;transition:all .2s;z-index:3}.calendar-icon-button svg{width:18px;height:18px}.icon.icon-tabler-calendar-event{width:18px;height:18px;color:var(--on-surface-variant, #40484c)}.date-picker-container{margin-top:12px;width:100%;display:flex;justify-content:flex-start}.datetime-header{width:100%;border:1px solid #787861;border-radius:5px;padding:15px;background-color:transparent;cursor:pointer;display:flex;justify-content:space-between;align-items:center;min-height:auto;transition:border-color .2s}.datetime-header:hover,.datetime-header:focus{outline:none;border-color:#a9a97f}.datetime-header.active{border-color:#a9a97f;outline:none}.datetime-header.disabled{cursor:not-allowed;opacity:.6}.selected-text{color:#454733;font-size:1.3rem;flex:1}.selected-text.placeholder{color:#787861}.header-icons{display:flex;align-items:center;gap:8px}.clear-icon{width:20px;height:20px;display:flex;align-items:center;justify-content:center;color:#787861;font-size:1.5rem;cursor:pointer;border-radius:50%;transition:all .2s}.clear-icon:hover{background-color:#7878611a;color:#454733}.arrow{width:15px;height:15px;background-image:url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\");background-repeat:no-repeat;background-size:15px;background-position:center;color:#787861;flex-shrink:0;transition:transform .2s}.arrow.open{transform:rotate(180deg)}.dropdown{position:absolute;top:100%;left:0;background:#e3e3d1;border:1px solid #787861;border-top:none;border-radius:0 0 5px 5px;z-index:1000;box-shadow:0 4px 12px #00000026;min-width:400px}.dropdown.open-left{left:auto;right:0}.datetime-content{display:flex}.calendar-section{flex:1;min-width:280px}.calendar-nav{display:flex;justify-content:space-between;align-items:center;padding:15px;border-bottom:1px solid rgba(120,120,97,.2)}.nav-section{display:flex;gap:5px}.nav-btn{background:none;border:none;color:#787861;cursor:pointer;font-size:1.2rem;padding:5px 10px;border-radius:3px;transition:all .2s}.nav-btn:hover{background-color:#a9a97f1a;color:#454733}.current-date{font-weight:500;color:#454733;font-size:1.1rem}.weekdays{display:grid;grid-template-columns:repeat(7,1fr);background:#7878611a}.weekday{padding:10px 5px;text-align:center;font-size:.9rem;font-weight:500;color:#787861}.calendar-grid{display:grid;grid-template-columns:repeat(7,1fr)}.calendar-day{padding:12px 5px;text-align:center;cursor:pointer;color:#454733;font-size:1rem;border-right:1px solid rgba(120,120,97,.1);border-bottom:1px solid rgba(120,120,97,.1);transition:all .2s}.calendar-day:hover:not(.disabled):not(.empty){background-color:#a9a97f33}.calendar-day.selected{background-color:#a9a97f;color:#e3e3d1;font-weight:500}.calendar-day.today:not(.selected){background-color:#a9a97f4d;font-weight:500}.calendar-day.disabled{color:#78786166;cursor:not-allowed}.calendar-day.empty{cursor:default}.calendar-day:nth-child(7n){border-right:none}.time-section{border-left:1px solid rgba(120,120,97,.2);min-width:140px;display:flex;flex-direction:column;background:#a9a97f0d}.time-header{padding:15px;border-bottom:1px solid rgba(120,120,97,.2);text-align:center;font-weight:500;color:#454733;background:#a9a97f1a}.time-selectors{display:flex;flex-direction:column;padding:15px;gap:20px;flex:1}.time-group{display:flex;align-items:center;gap:10px}.time-column{flex:1;display:flex;flex-direction:column;align-items:center}.time-label{font-size:.9rem;color:#787861;margin-bottom:10px;font-weight:500}.time-scroll{max-height:150px;overflow-y:auto;border:1px solid rgba(120,120,97,.2);border-radius:3px;width:50px;background:#a9a97f}.time-option{padding:8px 12px;text-align:center;cursor:pointer;color:#454733;font-size:1rem;transition:all .2s}.time-option:hover{background-color:#a9a97f1a}.time-option.selected{background-color:#a9a97f;color:#e3e3d1;font-weight:500}.time-separator-vertical{font-size:1.5rem;color:#787861;font-weight:700;align-self:flex-end;margin-bottom:10px}.time-scroll::-webkit-scrollbar{width:4px}.time-scroll::-webkit-scrollbar-track{background:#7878611a}.time-scroll::-webkit-scrollbar-thumb{background:#787861;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#a9a97f}.action-buttons{display:flex;justify-content:space-between;padding:15px;border-top:1px solid rgba(120,120,97,.2);gap:10px}.action-btn{padding:10px 20px;border:none;border-radius:3px;cursor:pointer;font-size:1rem;transition:all .2s}.action-btn.secondary{background:transparent;color:#787861;border:1px solid #787861}.action-btn.secondary:hover{background:#7878611a;color:#454733}.action-btn.primary{background:#a9a97f;color:#e3e3d1;border:1px solid #a9a97f}.action-btn.primary:hover{background:#969669;border-color:#969669}@media (max-width: 768px){.dropdown{min-width:320px}.datetime-content{flex-direction:column}.time-section{border-left:none;border-top:1px solid rgba(120,120,97,.2)}.time-selectors{flex-direction:row;justify-content:center;padding:15px}.time-group{gap:15px}.datetime-header{padding:12px 15px}.calendar-nav{padding:12px}.calendar-day{padding:10px 3px;font-size:.9rem}.action-buttons{padding:12px}}@media (max-width: 480px){.dropdown{min-width:280px}.time-section{min-width:auto}.time-scroll{width:45px}.time-selectors{padding:10px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
|
|
1928
|
+
], viewQueries: [{ propertyName: "chipRef", first: true, predicate: ["chip"], descendants: true }], ngImport: i0, template: "<div class=\"filter-chips\">\r\n @for (item of filters(); track item.value) {\r\n <div class=\"chip-input-wrapper\" #chip [class.has-value]=\"selectedDate() || inputTextValue()\"\r\n [class.active]=\"activeFilterType() === item.value\">\r\n <!-- Etiqueta flotante -->\r\n <label class=\"floating-label\">{{ item.placeholder || item.label || (item.type === 'datetime' ? 'dd/mm/aaaa, hh:mm AM/PM' : 'dd/mm/aaaa') }}</label>\r\n\r\n <!-- M\u00E1scara de gu\u00EDa de fecha din\u00E1mica (__/__/____) -->\r\n <div class=\"chip-input-mask\">\r\n @for (part of inputMask(); track $index) {\r\n <span class=\"mask-char\" [class.mask-char-filled]=\"part.filled\" [class.mask-char-placeholder]=\"!part.filled\">\r\n {{ part.char }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <input type=\"text\" [value]=\"inputTextValue()\" (input)=\"onInputChange($event, item.value)\"\r\n (click)=\"onInputClick($event, item.value)\"\r\n (focus)=\"onInputFocus(item.value)\" [placeholder]=\"item.placeholder || 'Seleccionar Fecha'\" class=\"chip-input\"\r\n [disabled]=\"isDisabled()\" (keydown)=\"onInputKeyDown($event, item.value)\" />\r\n\r\n <button type=\"button\" class=\"calendar-icon-button\" (click)=\"toggle(item.value)\" title=\"Abrir calendario\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n class=\"icon icon-tabler icons-tabler-outline icon-tabler-calendar-event\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\r\n <path d=\"M4 5m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z\" />\r\n <path d=\"M16 3l0 4\" />\r\n <path d=\"M8 3l0 4\" />\r\n <path d=\"M4 11l16 0\" />\r\n <path d=\"M8 15h2v2h-2z\" />\r\n </svg>\r\n </button>\r\n\r\n @if (isOpen() && activeFilterType() === item.value) {\r\n <div class=\"dropdown\" [class.open-left]=\"dropdownDirection() === 'left'\">\r\n <div class=\"datetime-content\">\r\n <!-- Secci\u00F3n del calendario -->\r\n <div class=\"calendar-section\">\r\n <!-- Navegaci\u00F3n -->\r\n <div class=\"calendar-nav\">\r\n <div class=\"nav-section\">\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"previousYear()\" title=\"A\u00F1o anterior\">\r\n \u2039\u2039\r\n </button>\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"previousMonth()\" title=\"Mes anterior\">\r\n \u2039\r\n </button>\r\n </div>\r\n\r\n <div class=\"current-date\">\r\n {{ monthName() }} {{ currentYear() }}\r\n </div>\r\n\r\n <div class=\"nav-section\">\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextMonth()\" title=\"Siguiente mes\">\r\n \u203A\r\n </button>\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextYear()\" title=\"Siguiente a\u00F1o\">\r\n \u203A\u203A\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- D\u00EDas de la semana -->\r\n <div class=\"weekdays\">\r\n <div class=\"weekday\">Dom</div>\r\n <div class=\"weekday\">Lun</div>\r\n <div class=\"weekday\">Mar</div>\r\n <div class=\"weekday\">Mi\u00E9</div>\r\n <div class=\"weekday\">Jue</div>\r\n <div class=\"weekday\">Vie</div>\r\n <div class=\"weekday\">S\u00E1b</div>\r\n </div>\r\n\r\n <!-- D\u00EDas -->\r\n <div class=\"calendar-grid\">\r\n @for (day of calendarDays(); track $index) {\r\n <div class=\"calendar-day\" [class.selected]=\"isDaySelected(day)\" [class.today]=\"isToday(day)\"\r\n [class.disabled]=\"isDayDisabled(day)\" [class.empty]=\"!day\" (click)=\"selectDay(day)\">\r\n {{ day || \"\" }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- TIME PICKER -->\r\n @if (mode() === 'datetime') {\r\n <div class=\"time-section\">\r\n <div class=\"time-header\">Horario</div>\r\n\r\n <div class=\"time-selectors\">\r\n <div class=\"time-group\">\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">Hora</div>\r\n <div class=\"time-scroll\">\r\n @for (hour of hours12(); track hour.value) {\r\n <div class=\"time-option\" [class.selected]=\"hour.value === selectedHour12()\"\r\n (click)=\"setHour12(hour.value)\">\r\n {{ hour.display }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"time-separator-vertical\">:</div>\r\n\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">Min</div>\r\n <div class=\"time-scroll\">\r\n @for (minute of minutes(); track minute) {\r\n <div class=\"time-option\" [class.selected]=\"minute === selectedMinute()\" (click)=\"setMinute(minute)\">\r\n {{ minute.toString().padStart(2, \"0\") }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">AM/PM</div>\r\n <div class=\"time-scroll ampm\">\r\n <div class=\"time-option\" [class.selected]=\"selectedAmPm() === 'AM'\" (click)=\"setAmPm('AM')\">\r\n AM\r\n </div>\r\n <div class=\"time-option\" [class.selected]=\"selectedAmPm() === 'PM'\" (click)=\"setAmPm('PM')\">\r\n PM\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- botones -->\r\n <div class=\"action-buttons\">\r\n <button type=\"button\" class=\"action-btn secondary\" (click)=\"today()\">\r\n Hoy\r\n </button>\r\n\r\n @if (mode() === 'datetime') {\r\n <button type=\"button\" class=\"action-btn primary\" (click)=\"close()\">\r\n Aceptar\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>", styles: [".datetime-container{position:relative;width:100%;overflow-x:clip}.filter-chips{display:flex;gap:10px;border-radius:12px;position:relative}.chip-input-wrapper{position:relative;display:flex;align-items:center;border-radius:8px;border-style:solid;border-color:var(--schemes-outline-variant, #c0c7cd);border-width:1px;min-width:80px;max-width:260px;height:32px;flex-shrink:0;transition:.2s ease;background-color:transparent}.chip-input-wrapper:hover{background-color:#ececcf}.chip-input-wrapper:focus-within,.chip-input-wrapper.active{color:var(--on-surface, #171c1f);border-color:#b6b69b}.floating-label{position:absolute;left:12px;top:-8px;color:var(--schemes-on-surface-variant, #454733);font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:1.1rem;line-height:12px;letter-spacing:var(--theme-label-large-letter-spacing, .1px);font-weight:var(--theme-label-large-font-weight, 500);opacity:0;pointer-events:none;transition:all .2s ease;z-index:2;background-color:#e3e3d1;padding:0 4px;border-radius:2px;text-transform:capitalize}.chip-input-wrapper:focus-within .floating-label{opacity:.6;top:-8px}.chip-input-wrapper.has-value .floating-label{opacity:.9}.chip-input{border:none;outline:none;background:transparent;padding:6px 40px 6px 8px;height:100%;width:100%;color:transparent;caret-color:var(--schemes-on-surface-variant, #454733);font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:var(--theme-label-large-font-size, 1.4rem);line-height:var(--theme-label-large-line-height, 20px);letter-spacing:var(--theme-label-large-letter-spacing, .1px);font-weight:var(--theme-label-large-font-weight, 500);border-radius:8px;position:relative;z-index:2}.chip-input::placeholder{color:var(--schemes-on-surface-variant, #454733);opacity:.6;text-transform:capitalize}.chip-input:disabled{cursor:not-allowed;opacity:.6}input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px #E3E3D1 inset;box-shadow:0 0 0 1000px #e3e3d1 inset;-webkit-text-fill-color:#454733;caret-color:#454733;transition:background-color 9999s ease-in-out 0s}input:-moz-autofill,textarea:-moz-autofill{box-shadow:0 0 0 1000px #e3e3d1 inset}input[readonly]:-webkit-autofill,input:disabled:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #E3E3D1 inset;-webkit-text-fill-color:#a9a97f}.chip-input-mask{position:absolute;left:8px;right:40px;top:50%;transform:translateY(-50%);pointer-events:none;font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:var(--theme-label-large-font-size, 14px);font-weight:var(--theme-label-large-font-weight, 500);z-index:1;display:flex;opacity:0;transition:opacity .2s ease}.chip-input-wrapper:focus-within .chip-input-mask,.chip-input-wrapper.has-value .chip-input-mask{opacity:1}.chip-input-wrapper:focus-within .chip-input::placeholder{opacity:0}.mask-char-placeholder{color:var(--schemes-on-surface-variant, #454733);opacity:.4}.mask-char-filled{color:var(--schemes-on-surface, #171c1f);opacity:1}.calendar-icon-button{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;color:var(--schemes-on-surface-variant, #454733);border-radius:4px;transition:all .2s;z-index:3}.calendar-icon-button svg{width:18px;height:18px}.icon.icon-tabler-calendar-event{width:18px;height:18px;color:var(--on-surface-variant, #40484c)}.date-picker-container{margin-top:12px;width:100%;display:flex;justify-content:flex-start}.datetime-header{width:100%;border:1px solid #787861;border-radius:5px;padding:15px;background-color:transparent;cursor:pointer;display:flex;justify-content:space-between;align-items:center;min-height:auto;transition:border-color .2s}.datetime-header:hover,.datetime-header:focus{outline:none;border-color:#a9a97f}.datetime-header.active{border-color:#a9a97f;outline:none}.datetime-header.disabled{cursor:not-allowed;opacity:.6}.selected-text{color:#454733;font-size:1.3rem;flex:1}.selected-text.placeholder{color:#787861}.header-icons{display:flex;align-items:center;gap:8px}.clear-icon{width:20px;height:20px;display:flex;align-items:center;justify-content:center;color:#787861;font-size:1.5rem;cursor:pointer;border-radius:50%;transition:all .2s}.clear-icon:hover{background-color:#7878611a;color:#454733}.arrow{width:15px;height:15px;background-image:url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\");background-repeat:no-repeat;background-size:15px;background-position:center;color:#787861;flex-shrink:0;transition:transform .2s}.arrow.open{transform:rotate(180deg)}.dropdown{position:absolute;top:100%;left:0;background:#e3e3d1;border:1px solid #787861;border-top:none;border-radius:0 0 5px 5px;z-index:1000;box-shadow:0 4px 12px #00000026;min-width:400px}.dropdown.open-left{left:auto;right:0}.datetime-content{display:flex}.calendar-section{flex:1;min-width:280px}.calendar-nav{display:flex;justify-content:space-between;align-items:center;padding:15px;border-bottom:1px solid rgba(120,120,97,.2)}.nav-section{display:flex;gap:5px}.nav-btn{background:none;border:none;color:#787861;cursor:pointer;font-size:1.2rem;padding:5px 10px;border-radius:3px;transition:all .2s}.nav-btn:hover{background-color:#a9a97f1a;color:#454733}.current-date{font-weight:500;color:#454733;font-size:1.1rem}.weekdays{display:grid;grid-template-columns:repeat(7,1fr);background:#7878611a}.weekday{padding:10px 5px;text-align:center;font-size:.9rem;font-weight:500;color:#787861}.calendar-grid{display:grid;grid-template-columns:repeat(7,1fr)}.calendar-day{padding:12px 5px;text-align:center;cursor:pointer;color:#454733;font-size:1rem;border-right:1px solid rgba(120,120,97,.1);border-bottom:1px solid rgba(120,120,97,.1);transition:all .2s}.calendar-day:hover:not(.disabled):not(.empty){background-color:#a9a97f33}.calendar-day.selected{background-color:#a9a97f;color:#e3e3d1;font-weight:500}.calendar-day.today:not(.selected){background-color:#a9a97f4d;font-weight:500}.calendar-day.disabled{color:#78786166;cursor:not-allowed}.calendar-day.empty{cursor:default}.calendar-day:nth-child(7n){border-right:none}.time-section{border-left:1px solid rgba(120,120,97,.2);min-width:140px;display:flex;flex-direction:column;background:#a9a97f0d}.time-header{padding:15px;border-bottom:1px solid rgba(120,120,97,.2);text-align:center;font-weight:500;color:#454733;background:#a9a97f1a}.time-selectors{display:flex;flex-direction:column;padding:15px;gap:20px;flex:1}.time-group{display:flex;align-items:center;gap:10px}.time-column{flex:1;display:flex;flex-direction:column;align-items:center}.time-label{font-size:.9rem;color:#787861;margin-bottom:10px;font-weight:500}.time-scroll{max-height:150px;overflow-y:auto;border:1px solid rgba(120,120,97,.2);border-radius:3px;width:50px;background:#a9a97f}.time-option{padding:8px 12px;text-align:center;cursor:pointer;color:#454733;font-size:1rem;transition:all .2s}.time-option:hover{background-color:#a9a97f1a}.time-option.selected{background-color:#a9a97f;color:#e3e3d1;font-weight:500}.time-separator-vertical{font-size:1.5rem;color:#787861;font-weight:700;align-self:flex-end;margin-bottom:10px}.time-scroll::-webkit-scrollbar{width:4px}.time-scroll::-webkit-scrollbar-track{background:#7878611a}.time-scroll::-webkit-scrollbar-thumb{background:#787861;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#a9a97f}.action-buttons{display:flex;justify-content:space-between;padding:15px;border-top:1px solid rgba(120,120,97,.2);gap:10px}.action-btn{padding:10px 20px;border:none;border-radius:3px;cursor:pointer;font-size:1rem;transition:all .2s}.action-btn.secondary{background:transparent;color:#787861;border:1px solid #787861}.action-btn.secondary:hover{background:#7878611a;color:#454733}.action-btn.primary{background:#a9a97f;color:#e3e3d1;border:1px solid #a9a97f}.action-btn.primary:hover{background:#969669;border-color:#969669}@media (max-width: 768px){.dropdown{min-width:320px}.datetime-content{flex-direction:column}.time-section{border-left:none;border-top:1px solid rgba(120,120,97,.2)}.time-selectors{flex-direction:row;justify-content:center;padding:15px}.time-group{gap:15px}.datetime-header{padding:12px 15px}.calendar-nav{padding:12px}.calendar-day{padding:10px 3px;font-size:.9rem}.action-buttons{padding:12px}}@media (max-width: 480px){.dropdown{min-width:280px}.time-section{min-width:auto}.time-scroll{width:45px}.time-selectors{padding:10px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
|
|
1746
1929
|
}
|
|
1747
1930
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DateTimeFilter, decorators: [{
|
|
1748
1931
|
type: Component,
|
|
@@ -1752,7 +1935,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1752
1935
|
useExisting: forwardRef(() => DateTimeFilter),
|
|
1753
1936
|
multi: true,
|
|
1754
1937
|
},
|
|
1755
|
-
], template: "<div class=\"filter-chips\">\r\n @for (item of filters(); track item.value) {\r\n <div class=\"chip-input-wrapper\" #chip [class.has-value]=\"selectedDate() || inputTextValue()\"\r\n [class.active]=\"activeFilterType() === item.value\">\r\n <!-- Etiqueta flotante -->\r\n <label class=\"floating-label\">{{ item.placeholder || item.label || 'dd/mm/aaaa' }}</label>\r\n\r\n <!-- M\u00E1scara de gu\u00EDa de fecha din\u00E1mica (__/__/____) -->\r\n <div class=\"chip-input-mask\">\r\n @for (part of inputMask(); track $index) {\r\n <span class=\"mask-char\" [class.mask-char-filled]=\"part.filled\" [class.mask-char-placeholder]=\"!part.filled\">\r\n {{ part.char }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <input type=\"text\" [value]=\"inputTextValue()\" (input)=\"onInputChange($event, item.value)\"\r\n (click)=\"onInputClick($event, item.value)\"\r\n (focus)=\"onInputFocus(item.value)\" [placeholder]=\"item.placeholder || 'Seleccionar Fecha'\" class=\"chip-input\"\r\n [disabled]=\"isDisabled()\" (keydown)=\"onInputKeyDown($event, item.value)\" />\r\n\r\n <button type=\"button\" class=\"calendar-icon-button\" (click)=\"toggle(item.value)\" title=\"Abrir calendario\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n class=\"icon icon-tabler icons-tabler-outline icon-tabler-calendar-event\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\r\n <path d=\"M4 5m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z\" />\r\n <path d=\"M16 3l0 4\" />\r\n <path d=\"M8 3l0 4\" />\r\n <path d=\"M4 11l16 0\" />\r\n <path d=\"M8 15h2v2h-2z\" />\r\n </svg>\r\n </button>\r\n\r\n @if (isOpen() && activeFilterType() === item.value) {\r\n <div class=\"dropdown\" [class.open-left]=\"dropdownDirection() === 'left'\">\r\n <div class=\"datetime-content\">\r\n <!-- Secci\u00F3n del calendario -->\r\n <div class=\"calendar-section\">\r\n <!-- Navegaci\u00F3n -->\r\n <div class=\"calendar-nav\">\r\n <div class=\"nav-section\">\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"previousYear()\" title=\"A\u00F1o anterior\">\r\n \u2039\u2039\r\n </button>\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"previousMonth()\" title=\"Mes anterior\">\r\n \u2039\r\n </button>\r\n </div>\r\n\r\n <div class=\"current-date\">\r\n {{ monthName() }} {{ currentYear() }}\r\n </div>\r\n\r\n <div class=\"nav-section\">\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextMonth()\" title=\"Siguiente mes\">\r\n \u203A\r\n </button>\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextYear()\" title=\"Siguiente a\u00F1o\">\r\n \u203A\u203A\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- D\u00EDas de la semana -->\r\n <div class=\"weekdays\">\r\n <div class=\"weekday\">Dom</div>\r\n <div class=\"weekday\">Lun</div>\r\n <div class=\"weekday\">Mar</div>\r\n <div class=\"weekday\">Mi\u00E9</div>\r\n <div class=\"weekday\">Jue</div>\r\n <div class=\"weekday\">Vie</div>\r\n <div class=\"weekday\">S\u00E1b</div>\r\n </div>\r\n\r\n <!-- D\u00EDas -->\r\n <div class=\"calendar-grid\">\r\n @for (day of calendarDays(); track $index) {\r\n <div class=\"calendar-day\" [class.selected]=\"isDaySelected(day)\" [class.today]=\"isToday(day)\"\r\n [class.disabled]=\"isDayDisabled(day)\" [class.empty]=\"!day\" (click)=\"selectDay(day)\">\r\n {{ day || \"\" }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- TIME PICKER -->\r\n @if (mode() === 'datetime') {\r\n <div class=\"time-section\">\r\n <div class=\"time-header\">Horario</div>\r\n\r\n <div class=\"time-selectors\">\r\n <div class=\"time-group\">\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">Hora</div>\r\n <div class=\"time-scroll\">\r\n @for (hour of hours12(); track hour.value) {\r\n <div class=\"time-option\" [class.selected]=\"hour.value === selectedHour12()\"\r\n (click)=\"setHour12(hour.value)\">\r\n {{ hour.display }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"time-separator-vertical\">:</div>\r\n\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">Min</div>\r\n <div class=\"time-scroll\">\r\n @for (minute of minutes(); track minute) {\r\n <div class=\"time-option\" [class.selected]=\"minute === selectedMinute()\" (click)=\"setMinute(minute)\">\r\n {{ minute.toString().padStart(2, \"0\") }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">AM/PM</div>\r\n <div class=\"time-scroll ampm\">\r\n <div class=\"time-option\" [class.selected]=\"selectedAmPm() === 'AM'\" (click)=\"setAmPm('AM')\">\r\n AM\r\n </div>\r\n <div class=\"time-option\" [class.selected]=\"selectedAmPm() === 'PM'\" (click)=\"setAmPm('PM')\">\r\n PM\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- botones -->\r\n <div class=\"action-buttons\">\r\n <button type=\"button\" class=\"action-btn secondary\" (click)=\"today()\">\r\n Hoy\r\n </button>\r\n\r\n @if (mode() === 'datetime') {\r\n <button type=\"button\" class=\"action-btn primary\" (click)=\"close()\">\r\n Aceptar\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>", styles: [".datetime-container{position:relative;width:100%;overflow-x:clip}.filter-chips{display:flex;gap:10px;border-radius:12px;position:relative}.chip-input-wrapper{position:relative;display:flex;align-items:center;border-radius:8px;border-style:solid;border-color:var(--schemes-outline-variant, #c0c7cd);border-width:1px;min-width:80px;max-width:180px;height:32px;flex-shrink:0;transition:.2s ease;background-color:transparent}.chip-input-wrapper:hover{background-color:#ececcf}.chip-input-wrapper:focus-within,.chip-input-wrapper.active{color:var(--on-surface, #171c1f);border-color:#b6b69b}.floating-label{position:absolute;left:12px;top:-8px;color:var(--schemes-on-surface-variant, #454733);font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:1.1rem;line-height:12px;letter-spacing:var(--theme-label-large-letter-spacing, .1px);font-weight:var(--theme-label-large-font-weight, 500);opacity:0;pointer-events:none;transition:all .2s ease;z-index:2;background-color:#e3e3d1;padding:0 4px;border-radius:2px;text-transform:capitalize}.chip-input-wrapper:focus-within .floating-label{opacity:.6;top:-8px}.chip-input-wrapper.has-value .floating-label{opacity:.9}.chip-input{border:none;outline:none;background:transparent;padding:6px 40px 6px 8px;height:100%;width:100%;color:transparent;caret-color:var(--schemes-on-surface-variant, #454733);font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:var(--theme-label-large-font-size, 1.4rem);line-height:var(--theme-label-large-line-height, 20px);letter-spacing:var(--theme-label-large-letter-spacing, .1px);font-weight:var(--theme-label-large-font-weight, 500);border-radius:8px;position:relative;z-index:2}.chip-input::placeholder{color:var(--schemes-on-surface-variant, #454733);opacity:.6;text-transform:capitalize}.chip-input:disabled{cursor:not-allowed;opacity:.6}input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px #E3E3D1 inset;box-shadow:0 0 0 1000px #e3e3d1 inset;-webkit-text-fill-color:#454733;caret-color:#454733;transition:background-color 9999s ease-in-out 0s}input:-moz-autofill,textarea:-moz-autofill{box-shadow:0 0 0 1000px #e3e3d1 inset}input[readonly]:-webkit-autofill,input:disabled:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #E3E3D1 inset;-webkit-text-fill-color:#a9a97f}.chip-input-mask{position:absolute;left:8px;right:40px;top:50%;transform:translateY(-50%);pointer-events:none;font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:var(--theme-label-large-font-size, 14px);font-weight:var(--theme-label-large-font-weight, 500);z-index:1;display:flex;opacity:0;transition:opacity .2s ease}.chip-input-wrapper:focus-within .chip-input-mask,.chip-input-wrapper.has-value .chip-input-mask{opacity:1}.chip-input-wrapper:focus-within .chip-input::placeholder{opacity:0}.mask-char-placeholder{color:var(--schemes-on-surface-variant, #454733);opacity:.4}.mask-char-filled{color:var(--schemes-on-surface, #171c1f);opacity:1}.calendar-icon-button{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;color:var(--schemes-on-surface-variant, #454733);border-radius:4px;transition:all .2s;z-index:3}.calendar-icon-button svg{width:18px;height:18px}.icon.icon-tabler-calendar-event{width:18px;height:18px;color:var(--on-surface-variant, #40484c)}.date-picker-container{margin-top:12px;width:100%;display:flex;justify-content:flex-start}.datetime-header{width:100%;border:1px solid #787861;border-radius:5px;padding:15px;background-color:transparent;cursor:pointer;display:flex;justify-content:space-between;align-items:center;min-height:auto;transition:border-color .2s}.datetime-header:hover,.datetime-header:focus{outline:none;border-color:#a9a97f}.datetime-header.active{border-color:#a9a97f;outline:none}.datetime-header.disabled{cursor:not-allowed;opacity:.6}.selected-text{color:#454733;font-size:1.3rem;flex:1}.selected-text.placeholder{color:#787861}.header-icons{display:flex;align-items:center;gap:8px}.clear-icon{width:20px;height:20px;display:flex;align-items:center;justify-content:center;color:#787861;font-size:1.5rem;cursor:pointer;border-radius:50%;transition:all .2s}.clear-icon:hover{background-color:#7878611a;color:#454733}.arrow{width:15px;height:15px;background-image:url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\");background-repeat:no-repeat;background-size:15px;background-position:center;color:#787861;flex-shrink:0;transition:transform .2s}.arrow.open{transform:rotate(180deg)}.dropdown{position:absolute;top:100%;left:0;background:#e3e3d1;border:1px solid #787861;border-top:none;border-radius:0 0 5px 5px;z-index:1000;box-shadow:0 4px 12px #00000026;min-width:400px}.dropdown.open-left{left:auto;right:0}.datetime-content{display:flex}.calendar-section{flex:1;min-width:280px}.calendar-nav{display:flex;justify-content:space-between;align-items:center;padding:15px;border-bottom:1px solid rgba(120,120,97,.2)}.nav-section{display:flex;gap:5px}.nav-btn{background:none;border:none;color:#787861;cursor:pointer;font-size:1.2rem;padding:5px 10px;border-radius:3px;transition:all .2s}.nav-btn:hover{background-color:#a9a97f1a;color:#454733}.current-date{font-weight:500;color:#454733;font-size:1.1rem}.weekdays{display:grid;grid-template-columns:repeat(7,1fr);background:#7878611a}.weekday{padding:10px 5px;text-align:center;font-size:.9rem;font-weight:500;color:#787861}.calendar-grid{display:grid;grid-template-columns:repeat(7,1fr)}.calendar-day{padding:12px 5px;text-align:center;cursor:pointer;color:#454733;font-size:1rem;border-right:1px solid rgba(120,120,97,.1);border-bottom:1px solid rgba(120,120,97,.1);transition:all .2s}.calendar-day:hover:not(.disabled):not(.empty){background-color:#a9a97f33}.calendar-day.selected{background-color:#a9a97f;color:#e3e3d1;font-weight:500}.calendar-day.today:not(.selected){background-color:#a9a97f4d;font-weight:500}.calendar-day.disabled{color:#78786166;cursor:not-allowed}.calendar-day.empty{cursor:default}.calendar-day:nth-child(7n){border-right:none}.time-section{border-left:1px solid rgba(120,120,97,.2);min-width:140px;display:flex;flex-direction:column;background:#a9a97f0d}.time-header{padding:15px;border-bottom:1px solid rgba(120,120,97,.2);text-align:center;font-weight:500;color:#454733;background:#a9a97f1a}.time-selectors{display:flex;flex-direction:column;padding:15px;gap:20px;flex:1}.time-group{display:flex;align-items:center;gap:10px}.time-column{flex:1;display:flex;flex-direction:column;align-items:center}.time-label{font-size:.9rem;color:#787861;margin-bottom:10px;font-weight:500}.time-scroll{max-height:150px;overflow-y:auto;border:1px solid rgba(120,120,97,.2);border-radius:3px;width:50px;background:#a9a97f}.time-option{padding:8px 12px;text-align:center;cursor:pointer;color:#454733;font-size:1rem;transition:all .2s}.time-option:hover{background-color:#a9a97f1a}.time-option.selected{background-color:#a9a97f;color:#e3e3d1;font-weight:500}.time-separator-vertical{font-size:1.5rem;color:#787861;font-weight:700;align-self:flex-end;margin-bottom:10px}.time-scroll::-webkit-scrollbar{width:4px}.time-scroll::-webkit-scrollbar-track{background:#7878611a}.time-scroll::-webkit-scrollbar-thumb{background:#787861;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#a9a97f}.action-buttons{display:flex;justify-content:space-between;padding:15px;border-top:1px solid rgba(120,120,97,.2);gap:10px}.action-btn{padding:10px 20px;border:none;border-radius:3px;cursor:pointer;font-size:1rem;transition:all .2s}.action-btn.secondary{background:transparent;color:#787861;border:1px solid #787861}.action-btn.secondary:hover{background:#7878611a;color:#454733}.action-btn.primary{background:#a9a97f;color:#e3e3d1;border:1px solid #a9a97f}.action-btn.primary:hover{background:#969669;border-color:#969669}@media (max-width: 768px){.dropdown{min-width:320px}.datetime-content{flex-direction:column}.time-section{border-left:none;border-top:1px solid rgba(120,120,97,.2)}.time-selectors{flex-direction:row;justify-content:center;padding:15px}.time-group{gap:15px}.datetime-header{padding:12px 15px}.calendar-nav{padding:12px}.calendar-day{padding:10px 3px;font-size:.9rem}.action-buttons{padding:12px}}@media (max-width: 480px){.dropdown{min-width:280px}.time-section{min-width:auto}.time-scroll{width:45px}.time-selectors{padding:10px}}\n"] }]
|
|
1938
|
+
], template: "<div class=\"filter-chips\">\r\n @for (item of filters(); track item.value) {\r\n <div class=\"chip-input-wrapper\" #chip [class.has-value]=\"selectedDate() || inputTextValue()\"\r\n [class.active]=\"activeFilterType() === item.value\">\r\n <!-- Etiqueta flotante -->\r\n <label class=\"floating-label\">{{ item.placeholder || item.label || (item.type === 'datetime' ? 'dd/mm/aaaa, hh:mm AM/PM' : 'dd/mm/aaaa') }}</label>\r\n\r\n <!-- M\u00E1scara de gu\u00EDa de fecha din\u00E1mica (__/__/____) -->\r\n <div class=\"chip-input-mask\">\r\n @for (part of inputMask(); track $index) {\r\n <span class=\"mask-char\" [class.mask-char-filled]=\"part.filled\" [class.mask-char-placeholder]=\"!part.filled\">\r\n {{ part.char }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <input type=\"text\" [value]=\"inputTextValue()\" (input)=\"onInputChange($event, item.value)\"\r\n (click)=\"onInputClick($event, item.value)\"\r\n (focus)=\"onInputFocus(item.value)\" [placeholder]=\"item.placeholder || 'Seleccionar Fecha'\" class=\"chip-input\"\r\n [disabled]=\"isDisabled()\" (keydown)=\"onInputKeyDown($event, item.value)\" />\r\n\r\n <button type=\"button\" class=\"calendar-icon-button\" (click)=\"toggle(item.value)\" title=\"Abrir calendario\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n class=\"icon icon-tabler icons-tabler-outline icon-tabler-calendar-event\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\r\n <path d=\"M4 5m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z\" />\r\n <path d=\"M16 3l0 4\" />\r\n <path d=\"M8 3l0 4\" />\r\n <path d=\"M4 11l16 0\" />\r\n <path d=\"M8 15h2v2h-2z\" />\r\n </svg>\r\n </button>\r\n\r\n @if (isOpen() && activeFilterType() === item.value) {\r\n <div class=\"dropdown\" [class.open-left]=\"dropdownDirection() === 'left'\">\r\n <div class=\"datetime-content\">\r\n <!-- Secci\u00F3n del calendario -->\r\n <div class=\"calendar-section\">\r\n <!-- Navegaci\u00F3n -->\r\n <div class=\"calendar-nav\">\r\n <div class=\"nav-section\">\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"previousYear()\" title=\"A\u00F1o anterior\">\r\n \u2039\u2039\r\n </button>\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"previousMonth()\" title=\"Mes anterior\">\r\n \u2039\r\n </button>\r\n </div>\r\n\r\n <div class=\"current-date\">\r\n {{ monthName() }} {{ currentYear() }}\r\n </div>\r\n\r\n <div class=\"nav-section\">\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextMonth()\" title=\"Siguiente mes\">\r\n \u203A\r\n </button>\r\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextYear()\" title=\"Siguiente a\u00F1o\">\r\n \u203A\u203A\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- D\u00EDas de la semana -->\r\n <div class=\"weekdays\">\r\n <div class=\"weekday\">Dom</div>\r\n <div class=\"weekday\">Lun</div>\r\n <div class=\"weekday\">Mar</div>\r\n <div class=\"weekday\">Mi\u00E9</div>\r\n <div class=\"weekday\">Jue</div>\r\n <div class=\"weekday\">Vie</div>\r\n <div class=\"weekday\">S\u00E1b</div>\r\n </div>\r\n\r\n <!-- D\u00EDas -->\r\n <div class=\"calendar-grid\">\r\n @for (day of calendarDays(); track $index) {\r\n <div class=\"calendar-day\" [class.selected]=\"isDaySelected(day)\" [class.today]=\"isToday(day)\"\r\n [class.disabled]=\"isDayDisabled(day)\" [class.empty]=\"!day\" (click)=\"selectDay(day)\">\r\n {{ day || \"\" }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- TIME PICKER -->\r\n @if (mode() === 'datetime') {\r\n <div class=\"time-section\">\r\n <div class=\"time-header\">Horario</div>\r\n\r\n <div class=\"time-selectors\">\r\n <div class=\"time-group\">\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">Hora</div>\r\n <div class=\"time-scroll\">\r\n @for (hour of hours12(); track hour.value) {\r\n <div class=\"time-option\" [class.selected]=\"hour.value === selectedHour12()\"\r\n (click)=\"setHour12(hour.value)\">\r\n {{ hour.display }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"time-separator-vertical\">:</div>\r\n\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">Min</div>\r\n <div class=\"time-scroll\">\r\n @for (minute of minutes(); track minute) {\r\n <div class=\"time-option\" [class.selected]=\"minute === selectedMinute()\" (click)=\"setMinute(minute)\">\r\n {{ minute.toString().padStart(2, \"0\") }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"time-column\">\r\n <div class=\"time-label\">AM/PM</div>\r\n <div class=\"time-scroll ampm\">\r\n <div class=\"time-option\" [class.selected]=\"selectedAmPm() === 'AM'\" (click)=\"setAmPm('AM')\">\r\n AM\r\n </div>\r\n <div class=\"time-option\" [class.selected]=\"selectedAmPm() === 'PM'\" (click)=\"setAmPm('PM')\">\r\n PM\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- botones -->\r\n <div class=\"action-buttons\">\r\n <button type=\"button\" class=\"action-btn secondary\" (click)=\"today()\">\r\n Hoy\r\n </button>\r\n\r\n @if (mode() === 'datetime') {\r\n <button type=\"button\" class=\"action-btn primary\" (click)=\"close()\">\r\n Aceptar\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>", styles: [".datetime-container{position:relative;width:100%;overflow-x:clip}.filter-chips{display:flex;gap:10px;border-radius:12px;position:relative}.chip-input-wrapper{position:relative;display:flex;align-items:center;border-radius:8px;border-style:solid;border-color:var(--schemes-outline-variant, #c0c7cd);border-width:1px;min-width:80px;max-width:260px;height:32px;flex-shrink:0;transition:.2s ease;background-color:transparent}.chip-input-wrapper:hover{background-color:#ececcf}.chip-input-wrapper:focus-within,.chip-input-wrapper.active{color:var(--on-surface, #171c1f);border-color:#b6b69b}.floating-label{position:absolute;left:12px;top:-8px;color:var(--schemes-on-surface-variant, #454733);font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:1.1rem;line-height:12px;letter-spacing:var(--theme-label-large-letter-spacing, .1px);font-weight:var(--theme-label-large-font-weight, 500);opacity:0;pointer-events:none;transition:all .2s ease;z-index:2;background-color:#e3e3d1;padding:0 4px;border-radius:2px;text-transform:capitalize}.chip-input-wrapper:focus-within .floating-label{opacity:.6;top:-8px}.chip-input-wrapper.has-value .floating-label{opacity:.9}.chip-input{border:none;outline:none;background:transparent;padding:6px 40px 6px 8px;height:100%;width:100%;color:transparent;caret-color:var(--schemes-on-surface-variant, #454733);font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:var(--theme-label-large-font-size, 1.4rem);line-height:var(--theme-label-large-line-height, 20px);letter-spacing:var(--theme-label-large-letter-spacing, .1px);font-weight:var(--theme-label-large-font-weight, 500);border-radius:8px;position:relative;z-index:2}.chip-input::placeholder{color:var(--schemes-on-surface-variant, #454733);opacity:.6;text-transform:capitalize}.chip-input:disabled{cursor:not-allowed;opacity:.6}input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px #E3E3D1 inset;box-shadow:0 0 0 1000px #e3e3d1 inset;-webkit-text-fill-color:#454733;caret-color:#454733;transition:background-color 9999s ease-in-out 0s}input:-moz-autofill,textarea:-moz-autofill{box-shadow:0 0 0 1000px #e3e3d1 inset}input[readonly]:-webkit-autofill,input:disabled:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #E3E3D1 inset;-webkit-text-fill-color:#a9a97f}.chip-input-mask{position:absolute;left:8px;right:40px;top:50%;transform:translateY(-50%);pointer-events:none;font-family:var( --theme-label-large-font-family, \"Roboto-Medium\", sans-serif );font-size:var(--theme-label-large-font-size, 14px);font-weight:var(--theme-label-large-font-weight, 500);z-index:1;display:flex;opacity:0;transition:opacity .2s ease}.chip-input-wrapper:focus-within .chip-input-mask,.chip-input-wrapper.has-value .chip-input-mask{opacity:1}.chip-input-wrapper:focus-within .chip-input::placeholder{opacity:0}.mask-char-placeholder{color:var(--schemes-on-surface-variant, #454733);opacity:.4}.mask-char-filled{color:var(--schemes-on-surface, #171c1f);opacity:1}.calendar-icon-button{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;color:var(--schemes-on-surface-variant, #454733);border-radius:4px;transition:all .2s;z-index:3}.calendar-icon-button svg{width:18px;height:18px}.icon.icon-tabler-calendar-event{width:18px;height:18px;color:var(--on-surface-variant, #40484c)}.date-picker-container{margin-top:12px;width:100%;display:flex;justify-content:flex-start}.datetime-header{width:100%;border:1px solid #787861;border-radius:5px;padding:15px;background-color:transparent;cursor:pointer;display:flex;justify-content:space-between;align-items:center;min-height:auto;transition:border-color .2s}.datetime-header:hover,.datetime-header:focus{outline:none;border-color:#a9a97f}.datetime-header.active{border-color:#a9a97f;outline:none}.datetime-header.disabled{cursor:not-allowed;opacity:.6}.selected-text{color:#454733;font-size:1.3rem;flex:1}.selected-text.placeholder{color:#787861}.header-icons{display:flex;align-items:center;gap:8px}.clear-icon{width:20px;height:20px;display:flex;align-items:center;justify-content:center;color:#787861;font-size:1.5rem;cursor:pointer;border-radius:50%;transition:all .2s}.clear-icon:hover{background-color:#7878611a;color:#454733}.arrow{width:15px;height:15px;background-image:url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\");background-repeat:no-repeat;background-size:15px;background-position:center;color:#787861;flex-shrink:0;transition:transform .2s}.arrow.open{transform:rotate(180deg)}.dropdown{position:absolute;top:100%;left:0;background:#e3e3d1;border:1px solid #787861;border-top:none;border-radius:0 0 5px 5px;z-index:1000;box-shadow:0 4px 12px #00000026;min-width:400px}.dropdown.open-left{left:auto;right:0}.datetime-content{display:flex}.calendar-section{flex:1;min-width:280px}.calendar-nav{display:flex;justify-content:space-between;align-items:center;padding:15px;border-bottom:1px solid rgba(120,120,97,.2)}.nav-section{display:flex;gap:5px}.nav-btn{background:none;border:none;color:#787861;cursor:pointer;font-size:1.2rem;padding:5px 10px;border-radius:3px;transition:all .2s}.nav-btn:hover{background-color:#a9a97f1a;color:#454733}.current-date{font-weight:500;color:#454733;font-size:1.1rem}.weekdays{display:grid;grid-template-columns:repeat(7,1fr);background:#7878611a}.weekday{padding:10px 5px;text-align:center;font-size:.9rem;font-weight:500;color:#787861}.calendar-grid{display:grid;grid-template-columns:repeat(7,1fr)}.calendar-day{padding:12px 5px;text-align:center;cursor:pointer;color:#454733;font-size:1rem;border-right:1px solid rgba(120,120,97,.1);border-bottom:1px solid rgba(120,120,97,.1);transition:all .2s}.calendar-day:hover:not(.disabled):not(.empty){background-color:#a9a97f33}.calendar-day.selected{background-color:#a9a97f;color:#e3e3d1;font-weight:500}.calendar-day.today:not(.selected){background-color:#a9a97f4d;font-weight:500}.calendar-day.disabled{color:#78786166;cursor:not-allowed}.calendar-day.empty{cursor:default}.calendar-day:nth-child(7n){border-right:none}.time-section{border-left:1px solid rgba(120,120,97,.2);min-width:140px;display:flex;flex-direction:column;background:#a9a97f0d}.time-header{padding:15px;border-bottom:1px solid rgba(120,120,97,.2);text-align:center;font-weight:500;color:#454733;background:#a9a97f1a}.time-selectors{display:flex;flex-direction:column;padding:15px;gap:20px;flex:1}.time-group{display:flex;align-items:center;gap:10px}.time-column{flex:1;display:flex;flex-direction:column;align-items:center}.time-label{font-size:.9rem;color:#787861;margin-bottom:10px;font-weight:500}.time-scroll{max-height:150px;overflow-y:auto;border:1px solid rgba(120,120,97,.2);border-radius:3px;width:50px;background:#a9a97f}.time-option{padding:8px 12px;text-align:center;cursor:pointer;color:#454733;font-size:1rem;transition:all .2s}.time-option:hover{background-color:#a9a97f1a}.time-option.selected{background-color:#a9a97f;color:#e3e3d1;font-weight:500}.time-separator-vertical{font-size:1.5rem;color:#787861;font-weight:700;align-self:flex-end;margin-bottom:10px}.time-scroll::-webkit-scrollbar{width:4px}.time-scroll::-webkit-scrollbar-track{background:#7878611a}.time-scroll::-webkit-scrollbar-thumb{background:#787861;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#a9a97f}.action-buttons{display:flex;justify-content:space-between;padding:15px;border-top:1px solid rgba(120,120,97,.2);gap:10px}.action-btn{padding:10px 20px;border:none;border-radius:3px;cursor:pointer;font-size:1rem;transition:all .2s}.action-btn.secondary{background:transparent;color:#787861;border:1px solid #787861}.action-btn.secondary:hover{background:#7878611a;color:#454733}.action-btn.primary{background:#a9a97f;color:#e3e3d1;border:1px solid #a9a97f}.action-btn.primary:hover{background:#969669;border-color:#969669}@media (max-width: 768px){.dropdown{min-width:320px}.datetime-content{flex-direction:column}.time-section{border-left:none;border-top:1px solid rgba(120,120,97,.2)}.time-selectors{flex-direction:row;justify-content:center;padding:15px}.time-group{gap:15px}.datetime-header{padding:12px 15px}.calendar-nav{padding:12px}.calendar-day{padding:10px 3px;font-size:.9rem}.action-buttons{padding:12px}}@media (max-width: 480px){.dropdown{min-width:280px}.time-section{min-width:auto}.time-scroll{width:45px}.time-selectors{padding:10px}}\n"] }]
|
|
1756
1939
|
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { chipRef: [{
|
|
1757
1940
|
type: ViewChild,
|
|
1758
1941
|
args: ['chip']
|
|
@@ -2360,9 +2543,13 @@ class SelectCustomSearch {
|
|
|
2360
2543
|
}, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : []));
|
|
2361
2544
|
onChange = (value) => { };
|
|
2362
2545
|
onTouched = () => { };
|
|
2546
|
+
resizeListener;
|
|
2363
2547
|
constructor(elementRef) {
|
|
2364
2548
|
this.elementRef = elementRef;
|
|
2365
2549
|
}
|
|
2550
|
+
ngOnDestroy() {
|
|
2551
|
+
this.removePositioningListeners();
|
|
2552
|
+
}
|
|
2366
2553
|
writeValue(value) {
|
|
2367
2554
|
this.selectedValue.set(value);
|
|
2368
2555
|
}
|
|
@@ -2388,20 +2575,41 @@ class SelectCustomSearch {
|
|
|
2388
2575
|
open() {
|
|
2389
2576
|
if (this.isBlocked())
|
|
2390
2577
|
return;
|
|
2391
|
-
|
|
2392
|
-
const spaceBelow = window.innerHeight - rect.bottom;
|
|
2393
|
-
this.openUpward.set(spaceBelow < 260);
|
|
2578
|
+
this.updatePosition();
|
|
2394
2579
|
this.isOpen.set(true);
|
|
2395
2580
|
this.searchTerm.set('');
|
|
2396
|
-
|
|
2581
|
+
requestAnimationFrame(() => {
|
|
2397
2582
|
const input = this.elementRef.nativeElement.querySelector('.search-input');
|
|
2398
2583
|
if (input)
|
|
2399
|
-
input.focus();
|
|
2584
|
+
input.focus({ preventScroll: true });
|
|
2400
2585
|
});
|
|
2586
|
+
this.addPositioningListeners();
|
|
2401
2587
|
}
|
|
2402
2588
|
close() {
|
|
2403
2589
|
this.isOpen.set(false);
|
|
2404
2590
|
this.searchTerm.set('');
|
|
2591
|
+
this.openUpward.set(false);
|
|
2592
|
+
this.removePositioningListeners();
|
|
2593
|
+
}
|
|
2594
|
+
updatePosition() {
|
|
2595
|
+
const scrollY = window.scrollY;
|
|
2596
|
+
const maxScrollY = Math.max(0, document.documentElement.scrollHeight - window.innerHeight);
|
|
2597
|
+
const canScrollDown = scrollY < maxScrollY - 1;
|
|
2598
|
+
this.openUpward.set(!canScrollDown);
|
|
2599
|
+
}
|
|
2600
|
+
addPositioningListeners() {
|
|
2601
|
+
this.removePositioningListeners();
|
|
2602
|
+
this.resizeListener = () => {
|
|
2603
|
+
if (this.isOpen())
|
|
2604
|
+
this.updatePosition();
|
|
2605
|
+
};
|
|
2606
|
+
window.addEventListener('resize', this.resizeListener);
|
|
2607
|
+
}
|
|
2608
|
+
removePositioningListeners() {
|
|
2609
|
+
if (this.resizeListener) {
|
|
2610
|
+
window.removeEventListener('resize', this.resizeListener);
|
|
2611
|
+
this.resizeListener = undefined;
|
|
2612
|
+
}
|
|
2405
2613
|
}
|
|
2406
2614
|
selectOption(option) {
|
|
2407
2615
|
if (this.isBlocked())
|
|
@@ -2717,11 +2925,11 @@ class DynamicFormFields {
|
|
|
2717
2925
|
submitBtn?.click();
|
|
2718
2926
|
}
|
|
2719
2927
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DynamicFormFields, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2720
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DynamicFormFields, isStandalone: true, selector: "lib-dynamic-form-fields", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (form()) {\n<form class=\"form\" [formGroup]=\"form()\" [class.form--compact]=\"compact()\" (keydown)=\"onEnter($event)\">\n @for (sec of sections(); track $index) {\n <section class=\"section\">\n @if (sec.title) {\n <h3 class=\"section-title\">{{ sec.title }}</h3>\n } @if (sec.description) {\n <p class=\"section-desc\">{{ sec.description }}</p>\n }\n\n <div class=\"grid\">\n @for (run of getFieldRuns(sec.fields); track $index) {\n\n @if (run.isGroup) {\n <!-- toggle: wrapper que siempre ocupa la fila completa -->\n <div class=\"col col--group-wrapper\">\n @for (f of run.fields; track f.key) {\n <div class=\"group-item\">\n <lib-toggle-custom [key]=\"f.key\" [label]=\"f.label ?? ''\" [formControlName]=\"f.key\" />\n </div>\n }\n </div>\n\n } @else {\n <!-- Campos normales (incluye checkbox y radio con su col configurable) -->\n @for (f of run.fields; track f.key) {\n <div class=\"col\" [style.--col-span]=\"f.col || 6\">\n @if (['text','number','email', 'password', 'time'].includes(f.type))\n {\n <input\n class=\"input\"\n [type]=\"f.type\"\n [placeholder]=\"f.placeholder\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n (input)=\"onUppercaseInput($event, f.type, f.key)\"\n />\n } @if (['date', 'datetime-local'].includes(f.type)) {\n <lib-date-time-picker\n [mode]=\"getDatePickerMode(f.type)\"\n [placeholder]=\"\n f.placeholder ||\n (f.type === 'date'\n ? 'Seleccionar fecha'\n : 'Seleccionar fecha y hora')\n \"\n [formControlName]=\"f.key\"\n [minDate]=\"f.minDate || null\"\n [maxDate]=\"f.maxDate || null\"\n [readonly]=\"f.readonly || false\"\n />\n } @if (f.type === 'textarea') {\n <textarea\n class=\"input textarea\"\n [placeholder]=\"f.placeholder\"\n [formControlName]=\"f.key\"\n rows=\"6\"\n [readonly]=\"f.readonly || false\"\n ></textarea>\n } @if (f.type === 'select') {\n <lib-select-custom-search\n [options]=\"f.options ?? []\"\n [placeholder]=\"f.placeholder || 'Seleccionar...'\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n />\n } @if (f.type === 'radio') {\n <div class=\"radio-group\">\n @for (o of f.options ?? []; track o.value) {\n <label class=\"radio\">\n <input\n type=\"radio\"\n [value]=\"o.value\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n />\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">{{ o.label }}</span>\n </label>\n }\n </div>\n } @if (f.type === 'checkbox') {\n <div class=\"checkbox-group\"\n [class.checkbox-group--cards]=\"f.variant === 'cards'\"\n [class.checkbox-group--lowercase]=\"f.uppercase === false\"\n [class.checkbox-group--readonly]=\"f.readonly && !f.disabled\">\n @for (o of f.options ?? []; track o.value) {\n <label class=\"checkbox\">\n <input\n type=\"checkbox\"\n [checked]=\"getCheckboxArray(f.key)?.at($index)?.value\"\n (change)=\"onCheckboxInteract($event, f, $index)\"\n [disabled]=\"f.disabled || f.readonly || false\"\n />\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-text\">\n <span class=\"checkbox-label\">{{ o.label }}</span>\n @if (o.subtitle) {\n <span class=\"checkbox-subtitle\">{{ o.subtitle }}</span>\n }\n </span>\n </label>\n }\n </div>\n } @if (f.type === 'disabled') {\n <input\n class=\"input input--disabled\"\n [placeholder]=\"f.placeholder || 'Autom\u00E1tico'\"\n disabled\n />\n } @if (ctrl(f.key)?.touched && ctrl(f.key)?.invalid) {\n <div class=\"error\">\n @if (ctrl(f.key)?.errors?.['required']) {\n <span>Campo requerido</span>\n } @if (ctrl(f.key)?.errors?.['email']) {\n <span>Correo inv\u00E1lido</span>\n } @if (ctrl(f.key)?.errors?.['pattern']) {\n <span>\n @switch (f.patternType) { @case ('numbers') { Solo se permiten\n n\u00FAmeros } @case ('phone') { Formato de tel\u00E9fono inv\u00E1lido } @case\n ('text') { Solo se permiten letras y espacios } @case ('username') {\n Solo se permiten letras, n\u00FAmeros, puntos y guiones bajos (no al\n inicio ni al final) } @case ('alphanumeric') { Solo se permiten\n letras y n\u00FAmeros } @default { Formato inv\u00E1lido } }\n </span>\n } @if (ctrl(f.key)?.errors?.['notMatching']) {\n <span>Las contrase\u00F1as no coinciden</span>\n }\n </div>\n }\n\n @if(f.label && f.type !== 'toggle') {\n <label\n [class.label-radio]=\"f.type === 'radio'\"\n [class.label-checkbox]=\"f.type === 'checkbox'\"\n [class.label-disabled]=\"f.readonly || f.disabled\"\n class=\"label\"\n >\n {{ f.label }} </label>\n }\n </div>\n }\n }\n\n }\n </div>\n </section>\n }\n</form>\n}\n", styles: [".form{width:100%}.form{display:grid}.section{padding:20px 0 0}.section-title{font-size:1.6rem;font-weight:700;margin-bottom:30px}.section-desc{margin:0 0 .75rem;color:#666}.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:16px}.form.form--compact .grid{gap:12px}.col{grid-column:span var(--col-span, 6);min-width:0;width:100%;position:relative;padding-bottom:20px}.col--group-wrapper{grid-column:span 12;display:grid;grid-template-columns:repeat(4,1fr);gap:16px;padding-bottom:0}.form.form--compact .col--group-wrapper{gap:12px}.group-item--full{grid-column:span 4}.form.form--compact .col{padding-bottom:0}.label{position:absolute;top:-8px;left:12px;font-size:1.2rem;color:#454733;background-color:var(--sl-form-surface, #E3E3D1);padding:0 4px;font-weight:500;text-transform:capitalize}.input{width:100%;border:1px solid #787861;border-radius:5px;padding:15px;background-color:transparent}input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type=date]::-webkit-calendar-picker-indicator{position:absolute;inset:0;width:auto;height:auto;color:transparent;background:transparent}.input:focus{outline:none;border-color:#a9a97f}.input--disabled{color:#888}.input:-webkit-autofill,.input:-webkit-autofill:hover,.input:-webkit-autofill:focus,.input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#454733;caret-color:#454733;transition:background-color 9999s ease-in-out 0s}.input:-moz-autofill,.textarea:-moz-autofill{box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset}.input[readonly]:-webkit-autofill,.input:disabled:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#a9a97f}.label-radio{font-size:1.4rem;position:static;padding-left:0}.radio-group,.checkbox-group{display:flex;gap:2rem;padding:.5rem 0}.form.form--compact .checkbox-group{padding:0 8px 0 0}.checkbox,.radio{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:1.4rem;color:#1c1c12;-webkit-user-select:none;user-select:none}.checkbox:has(.checkbox-subtitle){align-items:flex-start}.checkbox:has(.checkbox-subtitle) .checkbox-mark,.checkbox-group--cards .checkbox-mark{margin-top:2px}.checkbox-text{display:flex;flex-direction:column;gap:2px}.checkbox-subtitle{font-size:1.2rem;color:#787861;font-weight:400;line-height:1.3}.checkbox-label,.checkbox-subtitle{text-transform:uppercase}.checkbox-group--lowercase .checkbox-label,.checkbox-group--lowercase .checkbox-subtitle{text-transform:none}.checkbox:hover{color:#454733}.checkbox input,.radio input{position:absolute;opacity:0;pointer-events:none}.checkbox-mark{width:18px;height:18px;border:2px solid #787861;border-radius:4px;background-color:transparent;position:relative;display:inline-flex;align-items:center;justify-content:center;transition:all .2s ease}.checkbox input:checked+.checkbox-mark{background-color:#596300;border-color:#596300}.checkbox input:checked+.checkbox-mark:after{content:\"\";position:absolute;width:6px;height:10px;border:solid #fff;border-width:0 2px 2px 0;transform:translate(-50%,-60%) rotate(45deg);top:50%;left:50%}.radio-mark{width:18px;height:18px;border:2px solid #787861;border-radius:50%;background-color:transparent;position:relative;transition:all .2s ease}.radio input:checked+.radio-mark{border-color:#596300}.radio input:checked+.radio-mark:after{content:\"\";width:8px;height:8px;background-color:#454733;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.radio:hover .radio-mark{border-color:#a9a97f}.checkbox input:disabled+.checkbox-mark,.radio input:disabled+.radio-mark{border-color:#a9a97f;background-color:var(--sl-form-surface, #E3E3D1);cursor:not-allowed}.checkbox:has(input:disabled),.radio:has(input:disabled){cursor:not-allowed}.checkbox:has(input:disabled) .checkbox-text,.radio:has(input:disabled) .radio-label{color:#1c1c1266}.checkbox-group--cards .checkbox:has(input:disabled){opacity:.5;pointer-events:none}.checkbox-group--readonly .checkbox{opacity:.6;pointer-events:none;cursor:not-allowed}.checkbox-group--readonly .checkbox input:disabled+.checkbox-mark{border-color:#787861;background-color:transparent}.checkbox-group--readonly .checkbox input:disabled:checked+.checkbox-mark{background-color:#596300;border-color:#596300}.checkbox-group--cards.checkbox-group--readonly .checkbox{opacity:.8;pointer-events:none}.checkbox-group--cards .checkbox{display:flex;align-items:flex-start;width:100%;gap:12px;padding:14px 16px;background-color:#f0f0db;font-size:14px;font-weight:300;text-transform:uppercase;border-radius:10px;border:1px solid transparent;transition:all .2s ease;cursor:pointer;position:relative}.checkbox-group--cards .checkbox:hover{background-color:#dee58f}.error{position:absolute;bottom:0;left:0;font-size:1.2rem;color:#b00020;width:100%;height:15px;display:none}.col:has(.error) .error{display:block}.textarea{resize:vertical;min-height:100px;max-height:300px;line-height:1.5}.textarea:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#454733}select{appearance:none;-webkit-appearance:none;-moz-appearance:none;background-image:url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\");background-repeat:no-repeat;background-size:15px;background-position:right 15px center;cursor:pointer}select:invalid{color:#787861}select.placeholder-selected{color:#787861}select:not(.placeholder-selected){color:#000}select option{color:#454733;cursor:pointer}input[type=date]{color:#787861!important}input[type=date]:valid{color:#454733!important}.label-disabled{color:#1c1c1266}.input:disabled,.input--disabled,.input.disabled,.input[readonly]{border:1px solid #a9a97f;color:#a9a97f;cursor:not-allowed;pointer-events:none}@media (max-width: 768px){.grid{grid-template-columns:1fr}.col{grid-column:span 1!important}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: SelectCustomSearch, selector: "lib-select-custom-search", inputs: ["options", "placeholder", "readonly"], outputs: ["selectionChange"] }, { kind: "component", type: DateTimePicker, selector: "lib-date-time-picker", inputs: ["mode", "placeholder", "minDate", "maxDate", "readonly"], outputs: ["dateChange"] }, { kind: "component", type: ToggleCustom, selector: "lib-toggle-custom", inputs: ["label", "key", "disabled", "checked"], outputs: ["checkedChange", "toggleChange"] }] });
|
|
2928
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DynamicFormFields, isStandalone: true, selector: "lib-dynamic-form-fields", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (form()) {\n<form class=\"form\" [formGroup]=\"form()\" [class.form--compact]=\"compact()\" (keydown)=\"onEnter($event)\">\n @for (sec of sections(); track $index) {\n <section class=\"section\">\n @if (sec.title) {\n <h3 class=\"section-title\">{{ sec.title }}</h3>\n } @if (sec.description) {\n <p class=\"section-desc\">{{ sec.description }}</p>\n }\n\n <div class=\"grid\">\n @for (run of getFieldRuns(sec.fields); track $index) {\n\n @if (run.isGroup) {\n <!-- toggle: wrapper que siempre ocupa la fila completa -->\n <div class=\"col col--group-wrapper\">\n @for (f of run.fields; track f.key) {\n <div class=\"group-item\">\n <lib-toggle-custom [key]=\"f.key\" [label]=\"f.label ?? ''\" [formControlName]=\"f.key\" />\n </div>\n }\n </div>\n\n } @else {\n <!-- Campos normales (incluye checkbox y radio con su col configurable) -->\n @for (f of run.fields; track f.key) {\n <div class=\"col\" [style.--col-span]=\"f.col || 6\">\n @if (['text','number','email', 'password', 'time'].includes(f.type))\n {\n <input\n class=\"input\"\n [type]=\"f.type\"\n [placeholder]=\"f.placeholder\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n (input)=\"onUppercaseInput($event, f.type, f.key)\"\n />\n } @if (['date', 'datetime-local'].includes(f.type)) {\n <lib-date-time-picker\n [mode]=\"getDatePickerMode(f.type)\"\n [placeholder]=\"\n f.placeholder ||\n (f.type === 'date'\n ? 'Seleccionar fecha'\n : 'Seleccionar fecha y hora')\n \"\n [formControlName]=\"f.key\"\n [minDate]=\"f.minDate || null\"\n [maxDate]=\"f.maxDate || null\"\n [readonly]=\"f.readonly || false\"\n />\n } @if (f.type === 'textarea') {\n <textarea\n class=\"input textarea\"\n [placeholder]=\"f.placeholder\"\n [formControlName]=\"f.key\"\n rows=\"6\"\n [readonly]=\"f.readonly || false\"\n ></textarea>\n } @if (f.type === 'select') {\n <lib-select-custom-search\n [options]=\"f.options ?? []\"\n [placeholder]=\"f.placeholder || 'Seleccionar...'\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n />\n } @if (f.type === 'radio') {\n <div class=\"radio-group\">\n @for (o of f.options ?? []; track o.value) {\n <label class=\"radio\">\n <input\n type=\"radio\"\n [value]=\"o.value\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n />\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">{{ o.label }}</span>\n </label>\n }\n </div>\n } @if (f.type === 'checkbox') {\n <div class=\"checkbox-group\"\n [class.checkbox-group--cards]=\"f.variant === 'cards'\"\n [class.checkbox-group--lowercase]=\"f.uppercase === false\"\n [class.checkbox-group--readonly]=\"f.readonly && !f.disabled\">\n @for (o of f.options ?? []; track o.value) {\n <label class=\"checkbox\">\n <input\n type=\"checkbox\"\n [checked]=\"getCheckboxArray(f.key)?.at($index)?.value\"\n (change)=\"onCheckboxInteract($event, f, $index)\"\n [disabled]=\"f.disabled || f.readonly || false\"\n />\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-text\">\n <span class=\"checkbox-label\">{{ o.label }}</span>\n @if (o.subtitle) {\n <span class=\"checkbox-subtitle\">{{ o.subtitle }}</span>\n }\n </span>\n </label>\n }\n </div>\n } @if (f.type === 'disabled') {\n <input\n class=\"input input--disabled\"\n [placeholder]=\"f.placeholder || 'Autom\u00E1tico'\"\n disabled\n />\n } @if (ctrl(f.key)?.touched && ctrl(f.key)?.invalid) {\n <div class=\"error\">\n @if (ctrl(f.key)?.errors?.['required']) {\n <span>Campo requerido</span>\n } @if (ctrl(f.key)?.errors?.['email']) {\n <span>Correo inv\u00E1lido</span>\n } @if (ctrl(f.key)?.errors?.['pattern']) {\n <span>\n @switch (f.patternType) { @case ('numbers') { Solo se permiten\n n\u00FAmeros } @case ('phone') { Formato de tel\u00E9fono inv\u00E1lido } @case\n ('text') { Solo se permiten letras y espacios } @case ('username') {\n Solo se permiten letras, n\u00FAmeros, puntos y guiones bajos (no al\n inicio ni al final) } @case ('alphanumeric') { Solo se permiten\n letras y n\u00FAmeros } @default { Formato inv\u00E1lido } }\n </span>\n } @if (ctrl(f.key)?.errors?.['notMatching']) {\n <span>Las contrase\u00F1as no coinciden</span>\n }\n </div>\n }\n\n @if(f.label && f.type !== 'toggle') {\n <label\n [class.label-radio]=\"f.type === 'radio'\"\n [class.label-checkbox]=\"f.type === 'checkbox'\"\n [class.label-disabled]=\"f.readonly || f.disabled\"\n class=\"label\"\n >\n {{ f.label }} </label>\n }\n </div>\n }\n }\n\n }\n </div>\n </section>\n }\n</form>\n}\n", styles: [".form{width:100%}.form{display:grid}.section{padding:20px 0 0}.section-title{font-size:1.6rem;font-weight:700;margin-bottom:30px}.section-desc{margin:0 0 .75rem;color:#666}.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:16px}.form.form--compact .grid{gap:12px}.col{grid-column:span var(--col-span, 6);min-width:0;width:100%;position:relative;padding-bottom:20px}.col--group-wrapper{grid-column:span 12;display:grid;grid-template-columns:repeat(4,1fr);gap:16px;padding-bottom:0}.form.form--compact .col--group-wrapper{gap:12px}.group-item--full{grid-column:span 4}.form.form--compact .col{padding-bottom:0}.label{position:absolute;top:-8px;left:12px;font-size:1.2rem;color:#454733;background-color:var(--sl-form-surface, #E3E3D1);padding:0 4px;font-weight:500;text-transform:capitalize}.input{width:100%;border:1px solid #787861;border-radius:5px;padding:15px;background-color:transparent}input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type=date]::-webkit-calendar-picker-indicator{position:absolute;inset:0;width:auto;height:auto;color:transparent;background:transparent}.input:focus{outline:none;border-color:#a9a97f}.input--disabled{color:#888}.input:-webkit-autofill,.input:-webkit-autofill:hover,.input:-webkit-autofill:focus,.input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#454733;caret-color:#454733;transition:background-color 9999s ease-in-out 0s}.input:-moz-autofill,.textarea:-moz-autofill{box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset}.input[readonly]:-webkit-autofill,.input:disabled:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#a9a97f}.label-radio{font-size:1.4rem;position:static;padding-left:0}.radio-group,.checkbox-group{display:flex;gap:2rem;padding:.5rem 0}.form.form--compact .checkbox-group{padding:0 8px 0 0}.checkbox,.radio{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:1.4rem;color:#1c1c12;-webkit-user-select:none;user-select:none}.checkbox:has(.checkbox-subtitle){align-items:flex-start}.checkbox:has(.checkbox-subtitle) .checkbox-mark,.checkbox-group--cards .checkbox-mark{margin-top:2px}.checkbox-text{display:flex;flex-direction:column;gap:2px}.checkbox-subtitle{font-size:1.2rem;color:#787861;font-weight:400;line-height:1.3}.checkbox-label,.checkbox-subtitle{text-transform:uppercase}.checkbox-group--lowercase .checkbox-label,.checkbox-group--lowercase .checkbox-subtitle{text-transform:none}.checkbox:hover{color:#454733}.checkbox input,.radio input{position:absolute;opacity:0;pointer-events:none}.checkbox-mark{width:18px;height:18px;border:2px solid #787861;border-radius:4px;background-color:transparent;position:relative;display:inline-flex;align-items:center;justify-content:center;transition:all .2s ease}.checkbox input:checked+.checkbox-mark{background-color:#596300;border-color:#596300}.checkbox input:checked+.checkbox-mark:after{content:\"\";position:absolute;width:6px;height:10px;border:solid #fff;border-width:0 2px 2px 0;transform:translate(-50%,-60%) rotate(45deg);top:50%;left:50%}.radio-mark{width:18px;height:18px;border:2px solid #787861;border-radius:50%;background-color:transparent;position:relative;transition:all .2s ease}.radio input:checked+.radio-mark{border-color:#596300}.radio input:checked+.radio-mark:after{content:\"\";width:8px;height:8px;background-color:#454733;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.radio:hover .radio-mark{border-color:#a9a97f}.checkbox input:disabled+.checkbox-mark,.radio input:disabled+.radio-mark{border-color:#a9a97f;background-color:var(--sl-form-surface, #E3E3D1);cursor:not-allowed}.checkbox:has(input:disabled),.radio:has(input:disabled){cursor:not-allowed}.checkbox:has(input:disabled) .checkbox-text,.radio:has(input:disabled) .radio-label{color:#1c1c1266}.checkbox-group--cards .checkbox:has(input:disabled){opacity:.5;pointer-events:none}.checkbox-group--readonly .checkbox{opacity:.6;pointer-events:none;cursor:not-allowed}.checkbox-group--readonly .checkbox input:disabled+.checkbox-mark{border-color:#787861;background-color:transparent}.checkbox-group--readonly .checkbox input:disabled:checked+.checkbox-mark{background-color:#596300;border-color:#596300}.checkbox-group--cards.checkbox-group--readonly .checkbox{opacity:.8;pointer-events:none}.checkbox-group--cards .checkbox{display:flex;align-items:flex-start;width:100%;gap:12px;padding:14px 16px;background-color:#f0f0db;font-size:14px;font-weight:300;text-transform:uppercase;border-radius:10px;border:1px solid transparent;transition:all .2s ease;cursor:pointer;position:relative}.checkbox-group--cards .checkbox:hover{background-color:#dee58f}.error{position:absolute;bottom:0;left:0;font-size:1.2rem;color:#b00020;width:100%;height:15px;display:none}.col:has(.error) .error{display:block}.textarea{resize:vertical;min-height:100px;max-height:300px;line-height:1.5;overflow-y:auto;scrollbar-width:thin;scrollbar-color:#a9a97f transparent}.textarea::-webkit-scrollbar{width:8px}.textarea::-webkit-scrollbar-track{background:transparent;margin:4px 0}.textarea::-webkit-scrollbar-thumb{background:#a9a97f;border-radius:4px}.textarea::-webkit-scrollbar-thumb:hover{background:#787861}.textarea:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#454733}select{appearance:none;-webkit-appearance:none;-moz-appearance:none;background-image:url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\");background-repeat:no-repeat;background-size:15px;background-position:right 15px center;cursor:pointer}select:invalid{color:#787861}select.placeholder-selected{color:#787861}select:not(.placeholder-selected){color:#000}select option{color:#454733;cursor:pointer}input[type=date]{color:#787861!important}input[type=date]:valid{color:#454733!important}.label-disabled{color:#1c1c1266}.input:disabled,.input--disabled,.input.disabled,.input[readonly]{border:1px solid #a9a97f;color:#a9a97f;cursor:not-allowed;pointer-events:none}@media (max-width: 768px){.grid{grid-template-columns:1fr}.col{grid-column:span 1!important}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: SelectCustomSearch, selector: "lib-select-custom-search", inputs: ["options", "placeholder", "readonly"], outputs: ["selectionChange"] }, { kind: "component", type: DateTimePicker, selector: "lib-date-time-picker", inputs: ["mode", "placeholder", "minDate", "maxDate", "readonly"], outputs: ["dateChange"] }, { kind: "component", type: ToggleCustom, selector: "lib-toggle-custom", inputs: ["label", "key", "disabled", "checked"], outputs: ["checkedChange", "toggleChange"] }] });
|
|
2721
2929
|
}
|
|
2722
2930
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DynamicFormFields, decorators: [{
|
|
2723
2931
|
type: Component,
|
|
2724
|
-
args: [{ selector: 'lib-dynamic-form-fields', standalone: true, imports: [ReactiveFormsModule, SelectCustomSearch, DateTimePicker, ToggleCustom], template: "@if (form()) {\n<form class=\"form\" [formGroup]=\"form()\" [class.form--compact]=\"compact()\" (keydown)=\"onEnter($event)\">\n @for (sec of sections(); track $index) {\n <section class=\"section\">\n @if (sec.title) {\n <h3 class=\"section-title\">{{ sec.title }}</h3>\n } @if (sec.description) {\n <p class=\"section-desc\">{{ sec.description }}</p>\n }\n\n <div class=\"grid\">\n @for (run of getFieldRuns(sec.fields); track $index) {\n\n @if (run.isGroup) {\n <!-- toggle: wrapper que siempre ocupa la fila completa -->\n <div class=\"col col--group-wrapper\">\n @for (f of run.fields; track f.key) {\n <div class=\"group-item\">\n <lib-toggle-custom [key]=\"f.key\" [label]=\"f.label ?? ''\" [formControlName]=\"f.key\" />\n </div>\n }\n </div>\n\n } @else {\n <!-- Campos normales (incluye checkbox y radio con su col configurable) -->\n @for (f of run.fields; track f.key) {\n <div class=\"col\" [style.--col-span]=\"f.col || 6\">\n @if (['text','number','email', 'password', 'time'].includes(f.type))\n {\n <input\n class=\"input\"\n [type]=\"f.type\"\n [placeholder]=\"f.placeholder\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n (input)=\"onUppercaseInput($event, f.type, f.key)\"\n />\n } @if (['date', 'datetime-local'].includes(f.type)) {\n <lib-date-time-picker\n [mode]=\"getDatePickerMode(f.type)\"\n [placeholder]=\"\n f.placeholder ||\n (f.type === 'date'\n ? 'Seleccionar fecha'\n : 'Seleccionar fecha y hora')\n \"\n [formControlName]=\"f.key\"\n [minDate]=\"f.minDate || null\"\n [maxDate]=\"f.maxDate || null\"\n [readonly]=\"f.readonly || false\"\n />\n } @if (f.type === 'textarea') {\n <textarea\n class=\"input textarea\"\n [placeholder]=\"f.placeholder\"\n [formControlName]=\"f.key\"\n rows=\"6\"\n [readonly]=\"f.readonly || false\"\n ></textarea>\n } @if (f.type === 'select') {\n <lib-select-custom-search\n [options]=\"f.options ?? []\"\n [placeholder]=\"f.placeholder || 'Seleccionar...'\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n />\n } @if (f.type === 'radio') {\n <div class=\"radio-group\">\n @for (o of f.options ?? []; track o.value) {\n <label class=\"radio\">\n <input\n type=\"radio\"\n [value]=\"o.value\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n />\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">{{ o.label }}</span>\n </label>\n }\n </div>\n } @if (f.type === 'checkbox') {\n <div class=\"checkbox-group\"\n [class.checkbox-group--cards]=\"f.variant === 'cards'\"\n [class.checkbox-group--lowercase]=\"f.uppercase === false\"\n [class.checkbox-group--readonly]=\"f.readonly && !f.disabled\">\n @for (o of f.options ?? []; track o.value) {\n <label class=\"checkbox\">\n <input\n type=\"checkbox\"\n [checked]=\"getCheckboxArray(f.key)?.at($index)?.value\"\n (change)=\"onCheckboxInteract($event, f, $index)\"\n [disabled]=\"f.disabled || f.readonly || false\"\n />\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-text\">\n <span class=\"checkbox-label\">{{ o.label }}</span>\n @if (o.subtitle) {\n <span class=\"checkbox-subtitle\">{{ o.subtitle }}</span>\n }\n </span>\n </label>\n }\n </div>\n } @if (f.type === 'disabled') {\n <input\n class=\"input input--disabled\"\n [placeholder]=\"f.placeholder || 'Autom\u00E1tico'\"\n disabled\n />\n } @if (ctrl(f.key)?.touched && ctrl(f.key)?.invalid) {\n <div class=\"error\">\n @if (ctrl(f.key)?.errors?.['required']) {\n <span>Campo requerido</span>\n } @if (ctrl(f.key)?.errors?.['email']) {\n <span>Correo inv\u00E1lido</span>\n } @if (ctrl(f.key)?.errors?.['pattern']) {\n <span>\n @switch (f.patternType) { @case ('numbers') { Solo se permiten\n n\u00FAmeros } @case ('phone') { Formato de tel\u00E9fono inv\u00E1lido } @case\n ('text') { Solo se permiten letras y espacios } @case ('username') {\n Solo se permiten letras, n\u00FAmeros, puntos y guiones bajos (no al\n inicio ni al final) } @case ('alphanumeric') { Solo se permiten\n letras y n\u00FAmeros } @default { Formato inv\u00E1lido } }\n </span>\n } @if (ctrl(f.key)?.errors?.['notMatching']) {\n <span>Las contrase\u00F1as no coinciden</span>\n }\n </div>\n }\n\n @if(f.label && f.type !== 'toggle') {\n <label\n [class.label-radio]=\"f.type === 'radio'\"\n [class.label-checkbox]=\"f.type === 'checkbox'\"\n [class.label-disabled]=\"f.readonly || f.disabled\"\n class=\"label\"\n >\n {{ f.label }} </label>\n }\n </div>\n }\n }\n\n }\n </div>\n </section>\n }\n</form>\n}\n", styles: [".form{width:100%}.form{display:grid}.section{padding:20px 0 0}.section-title{font-size:1.6rem;font-weight:700;margin-bottom:30px}.section-desc{margin:0 0 .75rem;color:#666}.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:16px}.form.form--compact .grid{gap:12px}.col{grid-column:span var(--col-span, 6);min-width:0;width:100%;position:relative;padding-bottom:20px}.col--group-wrapper{grid-column:span 12;display:grid;grid-template-columns:repeat(4,1fr);gap:16px;padding-bottom:0}.form.form--compact .col--group-wrapper{gap:12px}.group-item--full{grid-column:span 4}.form.form--compact .col{padding-bottom:0}.label{position:absolute;top:-8px;left:12px;font-size:1.2rem;color:#454733;background-color:var(--sl-form-surface, #E3E3D1);padding:0 4px;font-weight:500;text-transform:capitalize}.input{width:100%;border:1px solid #787861;border-radius:5px;padding:15px;background-color:transparent}input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type=date]::-webkit-calendar-picker-indicator{position:absolute;inset:0;width:auto;height:auto;color:transparent;background:transparent}.input:focus{outline:none;border-color:#a9a97f}.input--disabled{color:#888}.input:-webkit-autofill,.input:-webkit-autofill:hover,.input:-webkit-autofill:focus,.input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#454733;caret-color:#454733;transition:background-color 9999s ease-in-out 0s}.input:-moz-autofill,.textarea:-moz-autofill{box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset}.input[readonly]:-webkit-autofill,.input:disabled:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#a9a97f}.label-radio{font-size:1.4rem;position:static;padding-left:0}.radio-group,.checkbox-group{display:flex;gap:2rem;padding:.5rem 0}.form.form--compact .checkbox-group{padding:0 8px 0 0}.checkbox,.radio{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:1.4rem;color:#1c1c12;-webkit-user-select:none;user-select:none}.checkbox:has(.checkbox-subtitle){align-items:flex-start}.checkbox:has(.checkbox-subtitle) .checkbox-mark,.checkbox-group--cards .checkbox-mark{margin-top:2px}.checkbox-text{display:flex;flex-direction:column;gap:2px}.checkbox-subtitle{font-size:1.2rem;color:#787861;font-weight:400;line-height:1.3}.checkbox-label,.checkbox-subtitle{text-transform:uppercase}.checkbox-group--lowercase .checkbox-label,.checkbox-group--lowercase .checkbox-subtitle{text-transform:none}.checkbox:hover{color:#454733}.checkbox input,.radio input{position:absolute;opacity:0;pointer-events:none}.checkbox-mark{width:18px;height:18px;border:2px solid #787861;border-radius:4px;background-color:transparent;position:relative;display:inline-flex;align-items:center;justify-content:center;transition:all .2s ease}.checkbox input:checked+.checkbox-mark{background-color:#596300;border-color:#596300}.checkbox input:checked+.checkbox-mark:after{content:\"\";position:absolute;width:6px;height:10px;border:solid #fff;border-width:0 2px 2px 0;transform:translate(-50%,-60%) rotate(45deg);top:50%;left:50%}.radio-mark{width:18px;height:18px;border:2px solid #787861;border-radius:50%;background-color:transparent;position:relative;transition:all .2s ease}.radio input:checked+.radio-mark{border-color:#596300}.radio input:checked+.radio-mark:after{content:\"\";width:8px;height:8px;background-color:#454733;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.radio:hover .radio-mark{border-color:#a9a97f}.checkbox input:disabled+.checkbox-mark,.radio input:disabled+.radio-mark{border-color:#a9a97f;background-color:var(--sl-form-surface, #E3E3D1);cursor:not-allowed}.checkbox:has(input:disabled),.radio:has(input:disabled){cursor:not-allowed}.checkbox:has(input:disabled) .checkbox-text,.radio:has(input:disabled) .radio-label{color:#1c1c1266}.checkbox-group--cards .checkbox:has(input:disabled){opacity:.5;pointer-events:none}.checkbox-group--readonly .checkbox{opacity:.6;pointer-events:none;cursor:not-allowed}.checkbox-group--readonly .checkbox input:disabled+.checkbox-mark{border-color:#787861;background-color:transparent}.checkbox-group--readonly .checkbox input:disabled:checked+.checkbox-mark{background-color:#596300;border-color:#596300}.checkbox-group--cards.checkbox-group--readonly .checkbox{opacity:.8;pointer-events:none}.checkbox-group--cards .checkbox{display:flex;align-items:flex-start;width:100%;gap:12px;padding:14px 16px;background-color:#f0f0db;font-size:14px;font-weight:300;text-transform:uppercase;border-radius:10px;border:1px solid transparent;transition:all .2s ease;cursor:pointer;position:relative}.checkbox-group--cards .checkbox:hover{background-color:#dee58f}.error{position:absolute;bottom:0;left:0;font-size:1.2rem;color:#b00020;width:100%;height:15px;display:none}.col:has(.error) .error{display:block}.textarea{resize:vertical;min-height:100px;max-height:300px;line-height:1.5}.textarea:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#454733}select{appearance:none;-webkit-appearance:none;-moz-appearance:none;background-image:url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\");background-repeat:no-repeat;background-size:15px;background-position:right 15px center;cursor:pointer}select:invalid{color:#787861}select.placeholder-selected{color:#787861}select:not(.placeholder-selected){color:#000}select option{color:#454733;cursor:pointer}input[type=date]{color:#787861!important}input[type=date]:valid{color:#454733!important}.label-disabled{color:#1c1c1266}.input:disabled,.input--disabled,.input.disabled,.input[readonly]{border:1px solid #a9a97f;color:#a9a97f;cursor:not-allowed;pointer-events:none}@media (max-width: 768px){.grid{grid-template-columns:1fr}.col{grid-column:span 1!important}}\n"] }]
|
|
2932
|
+
args: [{ selector: 'lib-dynamic-form-fields', standalone: true, imports: [ReactiveFormsModule, SelectCustomSearch, DateTimePicker, ToggleCustom], template: "@if (form()) {\n<form class=\"form\" [formGroup]=\"form()\" [class.form--compact]=\"compact()\" (keydown)=\"onEnter($event)\">\n @for (sec of sections(); track $index) {\n <section class=\"section\">\n @if (sec.title) {\n <h3 class=\"section-title\">{{ sec.title }}</h3>\n } @if (sec.description) {\n <p class=\"section-desc\">{{ sec.description }}</p>\n }\n\n <div class=\"grid\">\n @for (run of getFieldRuns(sec.fields); track $index) {\n\n @if (run.isGroup) {\n <!-- toggle: wrapper que siempre ocupa la fila completa -->\n <div class=\"col col--group-wrapper\">\n @for (f of run.fields; track f.key) {\n <div class=\"group-item\">\n <lib-toggle-custom [key]=\"f.key\" [label]=\"f.label ?? ''\" [formControlName]=\"f.key\" />\n </div>\n }\n </div>\n\n } @else {\n <!-- Campos normales (incluye checkbox y radio con su col configurable) -->\n @for (f of run.fields; track f.key) {\n <div class=\"col\" [style.--col-span]=\"f.col || 6\">\n @if (['text','number','email', 'password', 'time'].includes(f.type))\n {\n <input\n class=\"input\"\n [type]=\"f.type\"\n [placeholder]=\"f.placeholder\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n (input)=\"onUppercaseInput($event, f.type, f.key)\"\n />\n } @if (['date', 'datetime-local'].includes(f.type)) {\n <lib-date-time-picker\n [mode]=\"getDatePickerMode(f.type)\"\n [placeholder]=\"\n f.placeholder ||\n (f.type === 'date'\n ? 'Seleccionar fecha'\n : 'Seleccionar fecha y hora')\n \"\n [formControlName]=\"f.key\"\n [minDate]=\"f.minDate || null\"\n [maxDate]=\"f.maxDate || null\"\n [readonly]=\"f.readonly || false\"\n />\n } @if (f.type === 'textarea') {\n <textarea\n class=\"input textarea\"\n [placeholder]=\"f.placeholder\"\n [formControlName]=\"f.key\"\n rows=\"6\"\n [readonly]=\"f.readonly || false\"\n ></textarea>\n } @if (f.type === 'select') {\n <lib-select-custom-search\n [options]=\"f.options ?? []\"\n [placeholder]=\"f.placeholder || 'Seleccionar...'\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n />\n } @if (f.type === 'radio') {\n <div class=\"radio-group\">\n @for (o of f.options ?? []; track o.value) {\n <label class=\"radio\">\n <input\n type=\"radio\"\n [value]=\"o.value\"\n [formControlName]=\"f.key\"\n [readonly]=\"f.readonly || false\"\n />\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">{{ o.label }}</span>\n </label>\n }\n </div>\n } @if (f.type === 'checkbox') {\n <div class=\"checkbox-group\"\n [class.checkbox-group--cards]=\"f.variant === 'cards'\"\n [class.checkbox-group--lowercase]=\"f.uppercase === false\"\n [class.checkbox-group--readonly]=\"f.readonly && !f.disabled\">\n @for (o of f.options ?? []; track o.value) {\n <label class=\"checkbox\">\n <input\n type=\"checkbox\"\n [checked]=\"getCheckboxArray(f.key)?.at($index)?.value\"\n (change)=\"onCheckboxInteract($event, f, $index)\"\n [disabled]=\"f.disabled || f.readonly || false\"\n />\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-text\">\n <span class=\"checkbox-label\">{{ o.label }}</span>\n @if (o.subtitle) {\n <span class=\"checkbox-subtitle\">{{ o.subtitle }}</span>\n }\n </span>\n </label>\n }\n </div>\n } @if (f.type === 'disabled') {\n <input\n class=\"input input--disabled\"\n [placeholder]=\"f.placeholder || 'Autom\u00E1tico'\"\n disabled\n />\n } @if (ctrl(f.key)?.touched && ctrl(f.key)?.invalid) {\n <div class=\"error\">\n @if (ctrl(f.key)?.errors?.['required']) {\n <span>Campo requerido</span>\n } @if (ctrl(f.key)?.errors?.['email']) {\n <span>Correo inv\u00E1lido</span>\n } @if (ctrl(f.key)?.errors?.['pattern']) {\n <span>\n @switch (f.patternType) { @case ('numbers') { Solo se permiten\n n\u00FAmeros } @case ('phone') { Formato de tel\u00E9fono inv\u00E1lido } @case\n ('text') { Solo se permiten letras y espacios } @case ('username') {\n Solo se permiten letras, n\u00FAmeros, puntos y guiones bajos (no al\n inicio ni al final) } @case ('alphanumeric') { Solo se permiten\n letras y n\u00FAmeros } @default { Formato inv\u00E1lido } }\n </span>\n } @if (ctrl(f.key)?.errors?.['notMatching']) {\n <span>Las contrase\u00F1as no coinciden</span>\n }\n </div>\n }\n\n @if(f.label && f.type !== 'toggle') {\n <label\n [class.label-radio]=\"f.type === 'radio'\"\n [class.label-checkbox]=\"f.type === 'checkbox'\"\n [class.label-disabled]=\"f.readonly || f.disabled\"\n class=\"label\"\n >\n {{ f.label }} </label>\n }\n </div>\n }\n }\n\n }\n </div>\n </section>\n }\n</form>\n}\n", styles: [".form{width:100%}.form{display:grid}.section{padding:20px 0 0}.section-title{font-size:1.6rem;font-weight:700;margin-bottom:30px}.section-desc{margin:0 0 .75rem;color:#666}.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:16px}.form.form--compact .grid{gap:12px}.col{grid-column:span var(--col-span, 6);min-width:0;width:100%;position:relative;padding-bottom:20px}.col--group-wrapper{grid-column:span 12;display:grid;grid-template-columns:repeat(4,1fr);gap:16px;padding-bottom:0}.form.form--compact .col--group-wrapper{gap:12px}.group-item--full{grid-column:span 4}.form.form--compact .col{padding-bottom:0}.label{position:absolute;top:-8px;left:12px;font-size:1.2rem;color:#454733;background-color:var(--sl-form-surface, #E3E3D1);padding:0 4px;font-weight:500;text-transform:capitalize}.input{width:100%;border:1px solid #787861;border-radius:5px;padding:15px;background-color:transparent}input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type=date]::-webkit-calendar-picker-indicator{position:absolute;inset:0;width:auto;height:auto;color:transparent;background:transparent}.input:focus{outline:none;border-color:#a9a97f}.input--disabled{color:#888}.input:-webkit-autofill,.input:-webkit-autofill:hover,.input:-webkit-autofill:focus,.input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#454733;caret-color:#454733;transition:background-color 9999s ease-in-out 0s}.input:-moz-autofill,.textarea:-moz-autofill{box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset}.input[readonly]:-webkit-autofill,.input:disabled:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#a9a97f}.label-radio{font-size:1.4rem;position:static;padding-left:0}.radio-group,.checkbox-group{display:flex;gap:2rem;padding:.5rem 0}.form.form--compact .checkbox-group{padding:0 8px 0 0}.checkbox,.radio{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:1.4rem;color:#1c1c12;-webkit-user-select:none;user-select:none}.checkbox:has(.checkbox-subtitle){align-items:flex-start}.checkbox:has(.checkbox-subtitle) .checkbox-mark,.checkbox-group--cards .checkbox-mark{margin-top:2px}.checkbox-text{display:flex;flex-direction:column;gap:2px}.checkbox-subtitle{font-size:1.2rem;color:#787861;font-weight:400;line-height:1.3}.checkbox-label,.checkbox-subtitle{text-transform:uppercase}.checkbox-group--lowercase .checkbox-label,.checkbox-group--lowercase .checkbox-subtitle{text-transform:none}.checkbox:hover{color:#454733}.checkbox input,.radio input{position:absolute;opacity:0;pointer-events:none}.checkbox-mark{width:18px;height:18px;border:2px solid #787861;border-radius:4px;background-color:transparent;position:relative;display:inline-flex;align-items:center;justify-content:center;transition:all .2s ease}.checkbox input:checked+.checkbox-mark{background-color:#596300;border-color:#596300}.checkbox input:checked+.checkbox-mark:after{content:\"\";position:absolute;width:6px;height:10px;border:solid #fff;border-width:0 2px 2px 0;transform:translate(-50%,-60%) rotate(45deg);top:50%;left:50%}.radio-mark{width:18px;height:18px;border:2px solid #787861;border-radius:50%;background-color:transparent;position:relative;transition:all .2s ease}.radio input:checked+.radio-mark{border-color:#596300}.radio input:checked+.radio-mark:after{content:\"\";width:8px;height:8px;background-color:#454733;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.radio:hover .radio-mark{border-color:#a9a97f}.checkbox input:disabled+.checkbox-mark,.radio input:disabled+.radio-mark{border-color:#a9a97f;background-color:var(--sl-form-surface, #E3E3D1);cursor:not-allowed}.checkbox:has(input:disabled),.radio:has(input:disabled){cursor:not-allowed}.checkbox:has(input:disabled) .checkbox-text,.radio:has(input:disabled) .radio-label{color:#1c1c1266}.checkbox-group--cards .checkbox:has(input:disabled){opacity:.5;pointer-events:none}.checkbox-group--readonly .checkbox{opacity:.6;pointer-events:none;cursor:not-allowed}.checkbox-group--readonly .checkbox input:disabled+.checkbox-mark{border-color:#787861;background-color:transparent}.checkbox-group--readonly .checkbox input:disabled:checked+.checkbox-mark{background-color:#596300;border-color:#596300}.checkbox-group--cards.checkbox-group--readonly .checkbox{opacity:.8;pointer-events:none}.checkbox-group--cards .checkbox{display:flex;align-items:flex-start;width:100%;gap:12px;padding:14px 16px;background-color:#f0f0db;font-size:14px;font-weight:300;text-transform:uppercase;border-radius:10px;border:1px solid transparent;transition:all .2s ease;cursor:pointer;position:relative}.checkbox-group--cards .checkbox:hover{background-color:#dee58f}.error{position:absolute;bottom:0;left:0;font-size:1.2rem;color:#b00020;width:100%;height:15px;display:none}.col:has(.error) .error{display:block}.textarea{resize:vertical;min-height:100px;max-height:300px;line-height:1.5;overflow-y:auto;scrollbar-width:thin;scrollbar-color:#a9a97f transparent}.textarea::-webkit-scrollbar{width:8px}.textarea::-webkit-scrollbar-track{background:transparent;margin:4px 0}.textarea::-webkit-scrollbar-thumb{background:#a9a97f;border-radius:4px}.textarea::-webkit-scrollbar-thumb:hover{background:#787861}.textarea:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--sl-form-surface, #E3E3D1) inset;-webkit-text-fill-color:#454733}select{appearance:none;-webkit-appearance:none;-moz-appearance:none;background-image:url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\");background-repeat:no-repeat;background-size:15px;background-position:right 15px center;cursor:pointer}select:invalid{color:#787861}select.placeholder-selected{color:#787861}select:not(.placeholder-selected){color:#000}select option{color:#454733;cursor:pointer}input[type=date]{color:#787861!important}input[type=date]:valid{color:#454733!important}.label-disabled{color:#1c1c1266}.input:disabled,.input--disabled,.input.disabled,.input[readonly]{border:1px solid #a9a97f;color:#a9a97f;cursor:not-allowed;pointer-events:none}@media (max-width: 768px){.grid{grid-template-columns:1fr}.col{grid-column:span 1!important}}\n"] }]
|
|
2725
2933
|
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }] } });
|
|
2726
2934
|
|
|
2727
2935
|
class WizardForm {
|
|
@@ -2973,6 +3181,7 @@ class DialogAlertComponent {
|
|
|
2973
3181
|
key: "observations",
|
|
2974
3182
|
label: "Observaciones",
|
|
2975
3183
|
type: "textarea",
|
|
3184
|
+
readonly: true,
|
|
2976
3185
|
placeholder: "Escriba las observaciones...",
|
|
2977
3186
|
col: 12,
|
|
2978
3187
|
}
|
|
@@ -4638,7 +4847,8 @@ echarts.use([
|
|
|
4638
4847
|
GraphicComponent,
|
|
4639
4848
|
DataZoomComponent,
|
|
4640
4849
|
VisualMapComponent,
|
|
4641
|
-
LegendComponent
|
|
4850
|
+
LegendComponent,
|
|
4851
|
+
TitleComponent
|
|
4642
4852
|
]);
|
|
4643
4853
|
const UI_CHART_TOKENS = {
|
|
4644
4854
|
fontFamily: 'Inter, sans-serif',
|
|
@@ -4682,20 +4892,25 @@ const UI_CHART_TOKENS = {
|
|
|
4682
4892
|
class BaseChart {
|
|
4683
4893
|
options = input.required(...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
4684
4894
|
chartClick = output();
|
|
4895
|
+
chartInit = output();
|
|
4685
4896
|
onChartClick(event) {
|
|
4686
4897
|
this.chartClick.emit(event);
|
|
4687
4898
|
}
|
|
4899
|
+
onChartInit(chart) {
|
|
4900
|
+
this.chartInit.emit(chart);
|
|
4901
|
+
}
|
|
4688
4902
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4689
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: BaseChart, isStandalone: true, selector: "lib-base-chart", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { chartClick: "chartClick" }, providers: [provideEchartsCore({ echarts })], ngImport: i0, template: "<div echarts class=\"ui-base-chart\" [options]=\"options()\" [autoResize]=\"true\" (chartClick)=\"onChartClick($event)\">\r\n</div>", styles: [".ui-base-chart{display:block;width:100%;height:100%;min-height:320px}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4903
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: BaseChart, isStandalone: true, selector: "lib-base-chart", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { chartClick: "chartClick", chartInit: "chartInit" }, providers: [provideEchartsCore({ echarts })], ngImport: i0, template: "<div echarts class=\"ui-base-chart\" [options]=\"options()\" [autoResize]=\"true\" (chartClick)=\"onChartClick($event)\" (chartInit)=\"onChartInit($event)\">\r\n</div>", styles: [".ui-base-chart{display:block;width:100%;height:100%;min-height:320px}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4690
4904
|
}
|
|
4691
4905
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseChart, decorators: [{
|
|
4692
4906
|
type: Component,
|
|
4693
|
-
args: [{ selector: 'lib-base-chart', imports: [NgxEchartsDirective], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div echarts class=\"ui-base-chart\" [options]=\"options()\" [autoResize]=\"true\" (chartClick)=\"onChartClick($event)\">\r\n</div>", styles: [".ui-base-chart{display:block;width:100%;height:100%;min-height:320px}\n"] }]
|
|
4694
|
-
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], chartClick: [{ type: i0.Output, args: ["chartClick"] }] } });
|
|
4907
|
+
args: [{ selector: 'lib-base-chart', imports: [NgxEchartsDirective], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div echarts class=\"ui-base-chart\" [options]=\"options()\" [autoResize]=\"true\" (chartClick)=\"onChartClick($event)\" (chartInit)=\"onChartInit($event)\">\r\n</div>", styles: [".ui-base-chart{display:block;width:100%;height:100%;min-height:320px}\n"] }]
|
|
4908
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], chartClick: [{ type: i0.Output, args: ["chartClick"] }], chartInit: [{ type: i0.Output, args: ["chartInit"] }] } });
|
|
4695
4909
|
|
|
4696
4910
|
function buildBarChartOptions(data, multiSeries, horizontal = false) {
|
|
4697
|
-
const
|
|
4698
|
-
const
|
|
4911
|
+
const threshold = horizontal ? 6 : 12;
|
|
4912
|
+
const showScroll = data.length > threshold;
|
|
4913
|
+
const zoomEnd = showScroll ? Math.floor((threshold / data.length) * 100) : 100;
|
|
4699
4914
|
const isMulti = !!multiSeries && multiSeries.length > 0;
|
|
4700
4915
|
const xAxisData = data.map(item => item.label);
|
|
4701
4916
|
const series = isMulti
|
|
@@ -4900,7 +5115,7 @@ class BarChart {
|
|
|
4900
5115
|
toggleExpand = () => this.isExpanded.update(v => !v);
|
|
4901
5116
|
options = computed(() => buildBarChartOptions(this.data(), this.multiSeries(), this.horizontal()), ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
4902
5117
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BarChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4903
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BarChart, isStandalone: true, selector: "lib-bar-chart", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, multiSeries: { classPropertyName: "multiSeries", publicName: "multiSeries", isSignal: true, isRequired: false, transformFunction: null }, horizontal: { classPropertyName: "horizontal", publicName: "horizontal", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"bar-chart-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"bar-chart-header\">\r\n <h3 class=\"bar-chart-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" class=\"chart-wrapper\" />\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}\r\n", styles: [":host{display:block;width:100%;min-width:0}.bar-chart-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.bar-chart-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.bar-chart-container.expanded .chart-wrapper{min-height:unset;height:100%}.bar-chart-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.bar-chart-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}\n"], dependencies: [{ kind: "component", type: BaseChart, selector: "lib-base-chart", inputs: ["options"], outputs: ["chartClick"] }] });
|
|
5118
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BarChart, isStandalone: true, selector: "lib-bar-chart", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, multiSeries: { classPropertyName: "multiSeries", publicName: "multiSeries", isSignal: true, isRequired: false, transformFunction: null }, horizontal: { classPropertyName: "horizontal", publicName: "horizontal", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"bar-chart-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"bar-chart-header\">\r\n <h3 class=\"bar-chart-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" class=\"chart-wrapper\" />\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}\r\n", styles: [":host{display:block;width:100%;min-width:0}.bar-chart-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.bar-chart-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.bar-chart-container.expanded .chart-wrapper{min-height:unset;height:100%}.bar-chart-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.bar-chart-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}\n"], dependencies: [{ kind: "component", type: BaseChart, selector: "lib-base-chart", inputs: ["options"], outputs: ["chartClick", "chartInit"] }] });
|
|
4904
5119
|
}
|
|
4905
5120
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BarChart, decorators: [{
|
|
4906
5121
|
type: Component,
|
|
@@ -5122,7 +5337,7 @@ class LineChart {
|
|
|
5122
5337
|
toggleExpand = () => this.isExpanded.update(v => !v);
|
|
5123
5338
|
options = computed(() => buildLineChartOptions(this.data(), this.multiSeries()), ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
5124
5339
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LineChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5125
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: LineChart, isStandalone: true, selector: "lib-line-chart", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, multiSeries: { classPropertyName: "multiSeries", publicName: "multiSeries", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"line-chart-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"line-chart-header\">\r\n <h3 class=\"line-chart-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" class=\"chart-wrapper\" />\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}\r\n", styles: [":host{display:block;width:100%;min-width:0}.line-chart-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.line-chart-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.line-chart-container.expanded .chart-wrapper{min-height:unset;height:100%}.line-chart-header{display:flex;justify-content:space-between;align-items:center}.line-chart-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}\n"], dependencies: [{ kind: "component", type: BaseChart, selector: "lib-base-chart", inputs: ["options"], outputs: ["chartClick"] }] });
|
|
5340
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: LineChart, isStandalone: true, selector: "lib-line-chart", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, multiSeries: { classPropertyName: "multiSeries", publicName: "multiSeries", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"line-chart-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"line-chart-header\">\r\n <h3 class=\"line-chart-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" class=\"chart-wrapper\" />\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}\r\n", styles: [":host{display:block;width:100%;min-width:0}.line-chart-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.line-chart-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.line-chart-container.expanded .chart-wrapper{min-height:unset;height:100%}.line-chart-header{display:flex;justify-content:space-between;align-items:center}.line-chart-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}\n"], dependencies: [{ kind: "component", type: BaseChart, selector: "lib-base-chart", inputs: ["options"], outputs: ["chartClick", "chartInit"] }] });
|
|
5126
5341
|
}
|
|
5127
5342
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LineChart, decorators: [{
|
|
5128
5343
|
type: Component,
|
|
@@ -5136,6 +5351,25 @@ function buildDonutChartOptions(data) {
|
|
|
5136
5351
|
const total = getTotal(data);
|
|
5137
5352
|
const showLegend = data.length > 10;
|
|
5138
5353
|
const splitLegend = data.length > 14;
|
|
5354
|
+
// Legend tooltip: shows name + value on hover
|
|
5355
|
+
const dataMap = new Map(data.map(d => [d.label, d.value]));
|
|
5356
|
+
const legendTooltip = {
|
|
5357
|
+
show: true,
|
|
5358
|
+
backgroundColor: '#ffffff',
|
|
5359
|
+
borderColor: '#d9dcc7',
|
|
5360
|
+
borderWidth: 1,
|
|
5361
|
+
textStyle: {
|
|
5362
|
+
color: UI_CHART_TOKENS.text,
|
|
5363
|
+
fontSize: 12,
|
|
5364
|
+
fontFamily: UI_CHART_TOKENS.fontFamily,
|
|
5365
|
+
},
|
|
5366
|
+
extraCssText: 'border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,0.10);padding:8px 10px;',
|
|
5367
|
+
formatter: (params) => {
|
|
5368
|
+
const name = typeof params === 'string' ? params : params?.name;
|
|
5369
|
+
const val = dataMap.get(name);
|
|
5370
|
+
return val !== undefined ? `${name}: <b>${val}</b>` : name;
|
|
5371
|
+
},
|
|
5372
|
+
};
|
|
5139
5373
|
let legendConfig = {};
|
|
5140
5374
|
if (showLegend) {
|
|
5141
5375
|
if (splitLegend) {
|
|
@@ -5153,6 +5387,7 @@ function buildDonutChartOptions(data) {
|
|
|
5153
5387
|
itemWidth: 12,
|
|
5154
5388
|
itemHeight: 12,
|
|
5155
5389
|
itemGap: 10,
|
|
5390
|
+
tooltip: legendTooltip,
|
|
5156
5391
|
textStyle: {
|
|
5157
5392
|
fontSize: 11,
|
|
5158
5393
|
fontFamily: UI_CHART_TOKENS.fontFamily,
|
|
@@ -5171,6 +5406,7 @@ function buildDonutChartOptions(data) {
|
|
|
5171
5406
|
itemWidth: 12,
|
|
5172
5407
|
itemHeight: 12,
|
|
5173
5408
|
itemGap: 10,
|
|
5409
|
+
tooltip: legendTooltip,
|
|
5174
5410
|
textStyle: {
|
|
5175
5411
|
fontSize: 11,
|
|
5176
5412
|
fontFamily: UI_CHART_TOKENS.fontFamily,
|
|
@@ -5193,6 +5429,7 @@ function buildDonutChartOptions(data) {
|
|
|
5193
5429
|
itemWidth: 12,
|
|
5194
5430
|
itemHeight: 12,
|
|
5195
5431
|
itemGap: 10,
|
|
5432
|
+
tooltip: legendTooltip,
|
|
5196
5433
|
textStyle: {
|
|
5197
5434
|
fontSize: 11,
|
|
5198
5435
|
fontFamily: UI_CHART_TOKENS.fontFamily,
|
|
@@ -5357,15 +5594,29 @@ class DonutChart {
|
|
|
5357
5594
|
this.drilledGroup.set(clickedItem.label);
|
|
5358
5595
|
}
|
|
5359
5596
|
}
|
|
5597
|
+
chartInstance = null;
|
|
5598
|
+
onChartInit(chart) {
|
|
5599
|
+
this.chartInstance = chart;
|
|
5600
|
+
chart.on('legendselectchanged', (event) => {
|
|
5601
|
+
const selected = event.selected;
|
|
5602
|
+
const currentData = this.displayData();
|
|
5603
|
+
const visibleTotal = currentData
|
|
5604
|
+
.filter(item => selected[item.label] !== false)
|
|
5605
|
+
.reduce((sum, item) => sum + item.value, 0);
|
|
5606
|
+
chart.setOption({
|
|
5607
|
+
title: { text: `${visibleTotal}` }
|
|
5608
|
+
});
|
|
5609
|
+
});
|
|
5610
|
+
}
|
|
5360
5611
|
resetDrillDown() {
|
|
5361
5612
|
this.drilledGroup.set(null);
|
|
5362
5613
|
}
|
|
5363
5614
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DonutChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5364
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DonutChart, isStandalone: true, selector: "lib-donut-chart", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, drillDown: { classPropertyName: "drillDown", publicName: "drillDown", isSignal: true, isRequired: false, transformFunction: null }, groupByPrefix: { classPropertyName: "groupByPrefix", publicName: "groupByPrefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sectionClick: "sectionClick" }, ngImport: i0, template: "<div class=\"donut-chart-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"donut-chart-header\">\r\n <h3 class=\"donut-chart-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" (chartClick)=\"onChartClick($event)\" class=\"chart-wrapper\" />\r\n \r\n @if (drilledGroup()) {\r\n <button class=\"back-btn\" (click)=\"resetDrillDown()\" type=\"button\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m15 18-6-6 6-6\"/></svg>\r\n <span>Volver</span>\r\n </button>\r\n }\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.donut-chart-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.donut-chart-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.donut-chart-container.expanded .chart-wrapper{min-height:unset;height:100%}.donut-chart-header{display:flex;justify-content:space-between;align-items:center}.donut-chart-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}.back-btn{position:absolute;top:24px;right:60px;display:flex;align-items:center;gap:6px;background-color:#d9df88;border:1px solid rgba(97,102,31,.2);padding:6px 12px;border-radius:12px;cursor:pointer;color:#61661f;font-family:Inter,sans-serif;font-size:13px;font-weight:500;box-shadow:0 4px 12px #0000000d;transition:all .2s ease;z-index:100}.back-btn:hover{background-color:#61661f;color:#fff;box-shadow:0 6px 14px #61661f33;transform:translateY(-1px)}.back-btn:active{transform:translateY(0)}\n"], dependencies: [{ kind: "component", type: BaseChart, selector: "lib-base-chart", inputs: ["options"], outputs: ["chartClick"] }, { kind: "ngmodule", type: CommonModule }] });
|
|
5615
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DonutChart, isStandalone: true, selector: "lib-donut-chart", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, drillDown: { classPropertyName: "drillDown", publicName: "drillDown", isSignal: true, isRequired: false, transformFunction: null }, groupByPrefix: { classPropertyName: "groupByPrefix", publicName: "groupByPrefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sectionClick: "sectionClick" }, host: { properties: { "attr.title": "null" } }, ngImport: i0, template: "<div class=\"donut-chart-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"donut-chart-header\">\r\n <h3 class=\"donut-chart-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" (chartClick)=\"onChartClick($event)\" (chartInit)=\"onChartInit($event)\" class=\"chart-wrapper\" />\r\n \r\n @if (drilledGroup()) {\r\n <button class=\"back-btn\" (click)=\"resetDrillDown()\" type=\"button\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m15 18-6-6 6-6\"/></svg>\r\n <span>Volver</span>\r\n </button>\r\n }\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.donut-chart-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.donut-chart-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.donut-chart-container.expanded .chart-wrapper{min-height:unset;height:100%}.donut-chart-header{display:flex;justify-content:space-between;align-items:center}.donut-chart-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}.back-btn{position:absolute;top:24px;right:60px;display:flex;align-items:center;gap:6px;background-color:#d9df88;border:1px solid rgba(97,102,31,.2);padding:6px 12px;border-radius:12px;cursor:pointer;color:#61661f;font-family:Inter,sans-serif;font-size:13px;font-weight:500;box-shadow:0 4px 12px #0000000d;transition:all .2s ease;z-index:100}.back-btn:hover{background-color:#61661f;color:#fff;box-shadow:0 6px 14px #61661f33;transform:translateY(-1px)}.back-btn:active{transform:translateY(0)}\n"], dependencies: [{ kind: "component", type: BaseChart, selector: "lib-base-chart", inputs: ["options"], outputs: ["chartClick", "chartInit"] }, { kind: "ngmodule", type: CommonModule }] });
|
|
5365
5616
|
}
|
|
5366
5617
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DonutChart, decorators: [{
|
|
5367
5618
|
type: Component,
|
|
5368
|
-
args: [{ selector: 'lib-donut-chart', standalone: true, imports: [BaseChart, CommonModule], template: "<div class=\"donut-chart-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"donut-chart-header\">\r\n <h3 class=\"donut-chart-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" (chartClick)=\"onChartClick($event)\" class=\"chart-wrapper\" />\r\n \r\n @if (drilledGroup()) {\r\n <button class=\"back-btn\" (click)=\"resetDrillDown()\" type=\"button\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m15 18-6-6 6-6\"/></svg>\r\n <span>Volver</span>\r\n </button>\r\n }\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.donut-chart-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.donut-chart-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.donut-chart-container.expanded .chart-wrapper{min-height:unset;height:100%}.donut-chart-header{display:flex;justify-content:space-between;align-items:center}.donut-chart-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}.back-btn{position:absolute;top:24px;right:60px;display:flex;align-items:center;gap:6px;background-color:#d9df88;border:1px solid rgba(97,102,31,.2);padding:6px 12px;border-radius:12px;cursor:pointer;color:#61661f;font-family:Inter,sans-serif;font-size:13px;font-weight:500;box-shadow:0 4px 12px #0000000d;transition:all .2s ease;z-index:100}.back-btn:hover{background-color:#61661f;color:#fff;box-shadow:0 6px 14px #61661f33;transform:translateY(-1px)}.back-btn:active{transform:translateY(0)}\n"] }]
|
|
5619
|
+
args: [{ selector: 'lib-donut-chart', standalone: true, imports: [BaseChart, CommonModule], host: { '[attr.title]': 'null' }, template: "<div class=\"donut-chart-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"donut-chart-header\">\r\n <h3 class=\"donut-chart-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" (chartClick)=\"onChartClick($event)\" (chartInit)=\"onChartInit($event)\" class=\"chart-wrapper\" />\r\n \r\n @if (drilledGroup()) {\r\n <button class=\"back-btn\" (click)=\"resetDrillDown()\" type=\"button\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m15 18-6-6 6-6\"/></svg>\r\n <span>Volver</span>\r\n </button>\r\n }\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.donut-chart-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.donut-chart-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.donut-chart-container.expanded .chart-wrapper{min-height:unset;height:100%}.donut-chart-header{display:flex;justify-content:space-between;align-items:center}.donut-chart-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}.back-btn{position:absolute;top:24px;right:60px;display:flex;align-items:center;gap:6px;background-color:#d9df88;border:1px solid rgba(97,102,31,.2);padding:6px 12px;border-radius:12px;cursor:pointer;color:#61661f;font-family:Inter,sans-serif;font-size:13px;font-weight:500;box-shadow:0 4px 12px #0000000d;transition:all .2s ease;z-index:100}.back-btn:hover{background-color:#61661f;color:#fff;box-shadow:0 6px 14px #61661f33;transform:translateY(-1px)}.back-btn:active{transform:translateY(0)}\n"] }]
|
|
5369
5620
|
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], drillDown: [{ type: i0.Input, args: [{ isSignal: true, alias: "drillDown", required: false }] }], groupByPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupByPrefix", required: false }] }], sectionClick: [{ type: i0.Output, args: ["sectionClick"] }] } });
|
|
5370
5621
|
|
|
5371
5622
|
function buildHeatmapOptions(config) {
|
|
@@ -5446,18 +5697,24 @@ function buildHeatmapOptions(config) {
|
|
|
5446
5697
|
},
|
|
5447
5698
|
},
|
|
5448
5699
|
visualMap: {
|
|
5700
|
+
type: 'piecewise',
|
|
5449
5701
|
min: minVal,
|
|
5450
5702
|
max: maxVal,
|
|
5451
|
-
|
|
5703
|
+
splitNumber: 5,
|
|
5452
5704
|
orient: 'horizontal',
|
|
5453
5705
|
left: 'center',
|
|
5454
5706
|
bottom: '0',
|
|
5455
|
-
itemWidth:
|
|
5456
|
-
itemHeight:
|
|
5707
|
+
itemWidth: 14,
|
|
5708
|
+
itemHeight: 14,
|
|
5709
|
+
itemGap: 8,
|
|
5710
|
+
itemSymbol: 'rect',
|
|
5711
|
+
showLabel: false, // Hide the "10-20" piece labels
|
|
5712
|
+
text: ['Más', 'Menos'], // Labels at the max and min ends
|
|
5457
5713
|
textStyle: {
|
|
5458
5714
|
color: UI_CHART_TOKENS.muted,
|
|
5459
|
-
fontSize:
|
|
5715
|
+
fontSize: 12,
|
|
5460
5716
|
fontFamily: UI_CHART_TOKENS.fontFamily,
|
|
5717
|
+
fontWeight: 500
|
|
5461
5718
|
},
|
|
5462
5719
|
inRange: {
|
|
5463
5720
|
color: [
|
|
@@ -5504,7 +5761,7 @@ class Heatmap {
|
|
|
5504
5761
|
}
|
|
5505
5762
|
options = computed(() => buildHeatmapOptions(this.config()), ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
5506
5763
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: Heatmap, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5507
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: Heatmap, isStandalone: true, selector: "lib-heatmap", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"heatmap-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"heatmap-header\">\r\n <h3 class=\"heatmap-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" class=\"chart-wrapper\" />\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.heatmap-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.heatmap-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.heatmap-container.expanded .chart-wrapper{min-height:unset;height:100%}.heatmap-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.heatmap-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}\n"], dependencies: [{ kind: "component", type: BaseChart, selector: "lib-base-chart", inputs: ["options"], outputs: ["chartClick"] }] });
|
|
5764
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: Heatmap, isStandalone: true, selector: "lib-heatmap", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"heatmap-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"heatmap-header\">\r\n <h3 class=\"heatmap-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <lib-base-chart [options]=\"options()\" class=\"chart-wrapper\" />\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.heatmap-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.heatmap-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{flex:1;min-height:300px;display:block;width:100%;min-width:0}.heatmap-container.expanded .chart-wrapper{min-height:unset;height:100%}.heatmap-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.heatmap-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}\n"], dependencies: [{ kind: "component", type: BaseChart, selector: "lib-base-chart", inputs: ["options"], outputs: ["chartClick", "chartInit"] }] });
|
|
5508
5765
|
}
|
|
5509
5766
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: Heatmap, decorators: [{
|
|
5510
5767
|
type: Component,
|
|
@@ -5513,21 +5770,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5513
5770
|
|
|
5514
5771
|
class GeoAPIMaps {
|
|
5515
5772
|
points = input([], ...(ngDevMode ? [{ debugName: "points" }] : []));
|
|
5773
|
+
cameras = input([], ...(ngDevMode ? [{ debugName: "cameras" }] : []));
|
|
5774
|
+
mapContainer;
|
|
5516
5775
|
map;
|
|
5517
5776
|
markers = [];
|
|
5777
|
+
cameraMarkers = [];
|
|
5518
5778
|
constructor() {
|
|
5779
|
+
// Reactivo a cambios de puntos
|
|
5519
5780
|
effect(() => {
|
|
5520
5781
|
const pts = this.points();
|
|
5521
5782
|
if (this.map && pts.length > 0) {
|
|
5522
5783
|
this.renderPoints(pts);
|
|
5523
5784
|
}
|
|
5524
5785
|
});
|
|
5786
|
+
// Reactivo a cambios de cámaras
|
|
5787
|
+
effect(() => {
|
|
5788
|
+
const cams = this.cameras();
|
|
5789
|
+
if (this.map && cams.length > 0) {
|
|
5790
|
+
this.renderCameras(cams);
|
|
5791
|
+
}
|
|
5792
|
+
});
|
|
5525
5793
|
}
|
|
5526
5794
|
ngAfterViewInit() {
|
|
5527
5795
|
this.initMap();
|
|
5528
5796
|
}
|
|
5529
5797
|
initMap() {
|
|
5530
|
-
const mapElement =
|
|
5798
|
+
const mapElement = this.mapContainer?.nativeElement;
|
|
5531
5799
|
if (!mapElement)
|
|
5532
5800
|
return;
|
|
5533
5801
|
this.map = new google.maps.Map(mapElement, {
|
|
@@ -5549,6 +5817,10 @@ class GeoAPIMaps {
|
|
|
5549
5817
|
if (this.points().length > 0) {
|
|
5550
5818
|
this.renderPoints(this.points());
|
|
5551
5819
|
}
|
|
5820
|
+
// Render cameras if they already exist when map is ready
|
|
5821
|
+
if (this.cameras().length > 0) {
|
|
5822
|
+
this.renderCameras(this.cameras());
|
|
5823
|
+
}
|
|
5552
5824
|
}
|
|
5553
5825
|
goToLocation(lat, lng) {
|
|
5554
5826
|
if (!this.map)
|
|
@@ -5583,33 +5855,42 @@ class GeoAPIMaps {
|
|
|
5583
5855
|
map: this.map,
|
|
5584
5856
|
content: dot,
|
|
5585
5857
|
});
|
|
5858
|
+
const statusColor = point.immobilized ? '#ef4444' : '#3b82f6';
|
|
5586
5859
|
const content = `
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5860
|
+
<div style="padding:0 12px 12px 12px;font-family:'Inter',-apple-system,sans-serif;
|
|
5861
|
+
min-width:200px;color:#374151;">
|
|
5862
|
+
<div style="font-weight:700;font-size:15px;color:#111827;">
|
|
5863
|
+
${point.subpoenaNumber}
|
|
5864
|
+
${point.immobilized ? '<span style="font-size:11px;background:#ef4444;color:white;border-radius:4px;padding:1px 6px;margin-bottom:8px;vertical-align:middle;">Inmovilizado</span>' : ''}
|
|
5865
|
+
</div>
|
|
5866
|
+
|
|
5867
|
+
<div style="font-size:12px;color:#9ca3af;margin-bottom:10px;display:flex;gap:8px;">
|
|
5868
|
+
<span>📍 ${point.locationLabel}</span>
|
|
5869
|
+
</div>
|
|
5870
|
+
|
|
5871
|
+
<div style="display:flex;flex-direction:column;gap:4px;">
|
|
5872
|
+
<div style="display:flex;justify-content:space-between;gap:16px;font-size:13px;">
|
|
5873
|
+
<span style="color:#9ca3af;">Fecha</span>
|
|
5874
|
+
<span style="font-weight:600;color:#374151;">${new Date(point.dateTime).toLocaleString('es-CO', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false })}</span>
|
|
5590
5875
|
</div>
|
|
5591
|
-
<div style="
|
|
5592
|
-
|
|
5876
|
+
<div style="display:flex;justify-content:space-between;gap:16px;font-size:13px;">
|
|
5877
|
+
<span style="color:#9ca3af;">Infracción</span>
|
|
5878
|
+
<span style="font-weight:600;color:#374151;">${point.infractionCode}</span>
|
|
5593
5879
|
</div>
|
|
5594
|
-
<div style="
|
|
5595
|
-
|
|
5880
|
+
<div style="display:flex;justify-content:space-between;gap:16px;font-size:13px;">
|
|
5881
|
+
<span style="color:#9ca3af;">Placa</span>
|
|
5882
|
+
<span style="font-weight:600;color:#374151;">${point.plate}</span>
|
|
5596
5883
|
</div>
|
|
5597
|
-
<div style="
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
<div style="font-size: 13px;">
|
|
5603
|
-
<span style="color: #9ca3af;">Placa:</span>
|
|
5604
|
-
<span style="font-weight: 500; color: #374151;">${point.plate}</span>
|
|
5605
|
-
</div>
|
|
5606
|
-
<div style="display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; margin-top: 4px; color: ${point.immobilized ? '#ef4444' : '#3b82f6'};">
|
|
5607
|
-
<span style="width: 8px; height: 8px; border-radius: 50%; background-color: ${point.immobilized ? '#ef4444' : '#3b82f6'};"></span>
|
|
5884
|
+
<div style="border-top:1px solid #e5e7eb;margin-top:6px;padding-top:6px;
|
|
5885
|
+
display:flex;justify-content:space-between;font-size:13px;font-weight:700;">
|
|
5886
|
+
<span style="color:${statusColor};">Estado</span>
|
|
5887
|
+
<span style="display:flex;align-items:center;gap:6px;color:${statusColor};">
|
|
5888
|
+
<span style="width:8px;height:8px;border-radius:50%;background-color:${statusColor};"></span>
|
|
5608
5889
|
${point.immobilized ? 'Inmovilizado' : 'Normal'}
|
|
5609
|
-
</
|
|
5890
|
+
</span>
|
|
5610
5891
|
</div>
|
|
5611
5892
|
</div>
|
|
5612
|
-
|
|
5893
|
+
</div>`;
|
|
5613
5894
|
marker.addListener('mouseover', () => {
|
|
5614
5895
|
if (!lockedMarker) {
|
|
5615
5896
|
infoWindow.setContent(content);
|
|
@@ -5638,28 +5919,124 @@ class GeoAPIMaps {
|
|
|
5638
5919
|
this.map.fitBounds(bounds);
|
|
5639
5920
|
}
|
|
5640
5921
|
}
|
|
5922
|
+
// ─── GeoPointCameras markers ─────────────────────────────────────────────────
|
|
5923
|
+
clearCameraMarkers() {
|
|
5924
|
+
this.cameraMarkers.forEach(m => (m.map = null));
|
|
5925
|
+
this.cameraMarkers = [];
|
|
5926
|
+
}
|
|
5927
|
+
renderCameras(cameras) {
|
|
5928
|
+
this.clearCameraMarkers();
|
|
5929
|
+
const infoWindow = new google.maps.InfoWindow();
|
|
5930
|
+
let lockedMarker = null;
|
|
5931
|
+
// 1. Encontrar el total mayor para destacarlo
|
|
5932
|
+
const maxTotal = Math.max(...cameras.map(c => c.total));
|
|
5933
|
+
// 2. Centrar el mapa para que se vean todas las cámaras al inicio
|
|
5934
|
+
if (cameras.length > 0) {
|
|
5935
|
+
const bounds = new google.maps.LatLngBounds();
|
|
5936
|
+
cameras.forEach(c => bounds.extend({ lat: c.latitude, lng: c.longitude }));
|
|
5937
|
+
this.map.fitBounds(bounds);
|
|
5938
|
+
}
|
|
5939
|
+
cameras.forEach(cam => {
|
|
5940
|
+
// 3. Color diferente si es el de mayor total
|
|
5941
|
+
const isTop = cam.total === maxTotal;
|
|
5942
|
+
const bgColor = isTop ? '#dc2626' : '#7c3aed'; // rojo para el top, morado para el resto
|
|
5943
|
+
const pin = document.createElement('div');
|
|
5944
|
+
pin.innerHTML = `
|
|
5945
|
+
<div style="
|
|
5946
|
+
background:${bgColor}; color:white; border-radius:8px;
|
|
5947
|
+
padding:4px 8px; font-size:12px; font-weight:700;
|
|
5948
|
+
border:2px solid white; box-shadow:0 2px 6px rgba(0,0,0,.3);
|
|
5949
|
+
display:flex; align-items:center; gap:4px; cursor:pointer; white-space:nowrap;">
|
|
5950
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24"
|
|
5951
|
+
fill="white">
|
|
5952
|
+
<path d="M15 8v8H5V8h10m1-2H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h12a1 1 0 0 0
|
|
5953
|
+
1-1v-3.5l4 4v-11l-4 4V7a1 1 0 0 0-1-1z"/>
|
|
5954
|
+
</svg>
|
|
5955
|
+
${cam.total}
|
|
5956
|
+
</div>`;
|
|
5957
|
+
const marker = new google.maps.marker.AdvancedMarkerElement({
|
|
5958
|
+
position: { lat: cam.latitude, lng: cam.longitude },
|
|
5959
|
+
map: this.map,
|
|
5960
|
+
content: pin,
|
|
5961
|
+
title: cam.name,
|
|
5962
|
+
});
|
|
5963
|
+
const codesHtml = Object.entries(cam.by_code)
|
|
5964
|
+
.map(([code, count]) => `
|
|
5965
|
+
<div style="display:flex;justify-content:space-between;gap:16px;font-size:13px;">
|
|
5966
|
+
<span style="color:#9ca3af;">${code}</span>
|
|
5967
|
+
<span style="font-weight:600;color:#374151;">${count}</span>
|
|
5968
|
+
</div>`)
|
|
5969
|
+
.join('');
|
|
5970
|
+
const content = `
|
|
5971
|
+
<div style="padding:0 12px 12px 12px;font-family:'Inter',-apple-system,sans-serif;
|
|
5972
|
+
min-width:200px;color:#374151;">
|
|
5973
|
+
<div style="font-weight:700;font-size:15px;color:#111827;">
|
|
5974
|
+
${cam.name}
|
|
5975
|
+
${isTop ? '<span style="font-size:11px;background:#dc2626;color:white;border-radius:4px;padding:1px 6px;margin-bottom:8px;vertical-align:middle;">Más Infracciones</span>' : ''}
|
|
5976
|
+
</div>
|
|
5977
|
+
<!-- <div style="font-size:12px;color:#9ca3af;margin-bottom:4px;">ID: ${cam.id}</div> -->
|
|
5978
|
+
|
|
5979
|
+
<!-- 4. Coordenadas en el tooltip -->
|
|
5980
|
+
<div style="font-size:12px;color:#9ca3af;margin-bottom:10px;display:flex;gap:8px;">
|
|
5981
|
+
<span>📍 ${cam.locationLabel}</span>
|
|
5982
|
+
</div>
|
|
5983
|
+
|
|
5984
|
+
<div style="display:flex;flex-direction:column;gap:4px;">
|
|
5985
|
+
<div style="margin-top:8px;font-size:14px;color:#6b7280;">Código(s) de Infracciones</div>
|
|
5986
|
+
${codesHtml}
|
|
5987
|
+
<div style="border-top:1px solid #e5e7eb;margin-top:6px;padding-top:6px;
|
|
5988
|
+
display:flex;justify-content:space-between;font-size:13px;font-weight:700;">
|
|
5989
|
+
<span style="color:${bgColor};">Total</span>
|
|
5990
|
+
<span style="color:${bgColor};">${cam.total}</span>
|
|
5991
|
+
</div>
|
|
5992
|
+
</div>
|
|
5993
|
+
</div>`;
|
|
5994
|
+
marker.addListener('mouseover', () => {
|
|
5995
|
+
if (!lockedMarker) {
|
|
5996
|
+
infoWindow.setContent(content);
|
|
5997
|
+
infoWindow.open(this.map, marker);
|
|
5998
|
+
}
|
|
5999
|
+
});
|
|
6000
|
+
marker.addListener('mouseout', () => { if (!lockedMarker)
|
|
6001
|
+
infoWindow.close(); });
|
|
6002
|
+
marker.addListener('click', () => {
|
|
6003
|
+
lockedMarker = marker;
|
|
6004
|
+
infoWindow.setContent(content);
|
|
6005
|
+
infoWindow.open(this.map, marker);
|
|
6006
|
+
});
|
|
6007
|
+
infoWindow.addListener('closeclick', () => { lockedMarker = null; });
|
|
6008
|
+
this.cameraMarkers.push(marker);
|
|
6009
|
+
});
|
|
6010
|
+
}
|
|
5641
6011
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: GeoAPIMaps, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5642
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: GeoAPIMaps, isStandalone: true, selector: "lib-geo-api-maps", inputs: { points: { classPropertyName: "points", publicName: "points", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div
|
|
6012
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: GeoAPIMaps, isStandalone: true, selector: "lib-geo-api-maps", inputs: { points: { classPropertyName: "points", publicName: "points", isSignal: true, isRequired: false, transformFunction: null }, cameras: { classPropertyName: "cameras", publicName: "cameras", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "mapContainer", first: true, predicate: ["mapContainer"], descendants: true, static: true }], ngImport: i0, template: "<div #mapContainer class=\"map\"></div>\r\n", styles: [":host{display:block;width:100%;height:100%;position:relative}.map{position:absolute;inset:0;z-index:1;border-radius:12px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
5643
6013
|
}
|
|
5644
6014
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: GeoAPIMaps, decorators: [{
|
|
5645
6015
|
type: Component,
|
|
5646
|
-
args: [{ selector: 'lib-geo-api-maps', standalone: true, imports: [CommonModule], template: "<div
|
|
5647
|
-
}], ctorParameters: () => [], propDecorators: { points: [{ type: i0.Input, args: [{ isSignal: true, alias: "points", required: false }] }] } }
|
|
6016
|
+
args: [{ selector: 'lib-geo-api-maps', standalone: true, imports: [CommonModule], template: "<div #mapContainer class=\"map\"></div>\r\n", styles: [":host{display:block;width:100%;height:100%;position:relative}.map{position:absolute;inset:0;z-index:1;border-radius:12px}\n"] }]
|
|
6017
|
+
}], ctorParameters: () => [], propDecorators: { points: [{ type: i0.Input, args: [{ isSignal: true, alias: "points", required: false }] }], cameras: [{ type: i0.Input, args: [{ isSignal: true, alias: "cameras", required: false }] }], mapContainer: [{
|
|
6018
|
+
type: ViewChild,
|
|
6019
|
+
args: ['mapContainer', { static: true }]
|
|
6020
|
+
}] } });
|
|
5648
6021
|
|
|
5649
6022
|
class MapGeo {
|
|
5650
6023
|
title = input('Mapa Geográfico', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
5651
6024
|
isExpanded = signal(false, ...(ngDevMode ? [{ debugName: "isExpanded" }] : []));
|
|
5652
6025
|
points = input([], ...(ngDevMode ? [{ debugName: "points" }] : []));
|
|
6026
|
+
cameras = input([], ...(ngDevMode ? [{ debugName: "cameras" }] : []));
|
|
6027
|
+
immobilizedCount = computed(() => this.points().filter(p => p.immobilized).length, ...(ngDevMode ? [{ debugName: "immobilizedCount" }] : []));
|
|
6028
|
+
normalCount = computed(() => this.points().filter(p => !p.immobilized).length, ...(ngDevMode ? [{ debugName: "normalCount" }] : []));
|
|
6029
|
+
totalCameras = computed(() => this.cameras().length, ...(ngDevMode ? [{ debugName: "totalCameras" }] : []));
|
|
5653
6030
|
toggleExpand() {
|
|
5654
6031
|
this.isExpanded.update((value) => !value);
|
|
5655
6032
|
}
|
|
5656
6033
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MapGeo, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5657
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MapGeo, isStandalone: true, selector: "lib-map-geo", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, points: { classPropertyName: "points", publicName: "points", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"map-geo-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"map-geo-header\">\r\n <h3 class=\"map-geo-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <div class=\"chart-wrapper\">\r\n <lib-geo-api-maps [points]=\"points()\" />\r\n </div>\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.map-geo-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.map-geo-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{position:relative;width:100%;height:450px;min-height:450px;display:block;min-width:0}.map-geo-container.expanded .chart-wrapper{flex:1;height:auto;min-height:0}.map-geo-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.map-geo-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}\n"], dependencies: [{ kind: "component", type: GeoAPIMaps, selector: "lib-geo-api-maps", inputs: ["points"] }] });
|
|
6034
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MapGeo, isStandalone: true, selector: "lib-map-geo", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, points: { classPropertyName: "points", publicName: "points", isSignal: true, isRequired: false, transformFunction: null }, cameras: { classPropertyName: "cameras", publicName: "cameras", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"map-geo-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"map-geo-header\">\r\n <h3 class=\"map-geo-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <div class=\"chart-wrapper\">\r\n <lib-geo-api-maps [points]=\"points()\" [cameras]=\"cameras()\" />\r\n </div>\r\n @if (points().length > 0) {\r\n <div class=\"map-summary\">\r\n <span class=\"map-badge blue\">\r\n <span class=\"map-dot blue\"></span>\r\n Normal: {{ normalCount() }}\r\n </span>\r\n <span class=\"map-badge red\">\r\n <span class=\"map-dot red\"></span>\r\n Inmovilizado: {{ immobilizedCount() }}\r\n </span>\r\n <span class=\"map-badge total\">Total: {{ points().length }}</span>\r\n </div>\r\n }\r\n @if (cameras().length > 0) {\r\n <div class=\"map-summary\">\r\n <span class=\"map-badge purple\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M15 8v8H5V8h10m1-2H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-3.5l4 4v-11l-4 4V7a1 1 0 0 0-1-1z\"/>\r\n </svg>\r\n C\u00E1maras: {{ totalCameras() }}\r\n </span>\r\n </div>\r\n }\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.map-geo-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.map-geo-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{position:relative;width:100%;height:450px;min-height:450px;display:block;min-width:0}.map-geo-container.expanded .chart-wrapper{flex:1;height:auto;min-height:0}.map-geo-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.map-geo-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}.map-summary{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.map-badge{display:inline-flex;align-items:center;gap:5px;font-family:Inter,sans-serif;font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;white-space:nowrap}.map-badge.blue{background-color:#3b82f61f;color:#2563eb}.map-badge.red{background-color:#ef44441f;color:#dc2626}.map-badge.purple{background-color:#7c3aed1f;color:#7c3aed}.map-badge.total{background-color:#3741511a;color:#374151}.map-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.map-dot.blue{background-color:#3b82f6}.map-dot.red{background-color:#ef4444}\n"], dependencies: [{ kind: "component", type: GeoAPIMaps, selector: "lib-geo-api-maps", inputs: ["points", "cameras"] }] });
|
|
5658
6035
|
}
|
|
5659
6036
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MapGeo, decorators: [{
|
|
5660
6037
|
type: Component,
|
|
5661
|
-
args: [{ selector: 'lib-map-geo', imports: [GeoAPIMaps], template: "<div class=\"map-geo-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"map-geo-header\">\r\n <h3 class=\"map-geo-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <div class=\"chart-wrapper\">\r\n <lib-geo-api-maps [points]=\"points()\" />\r\n </div>\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.map-geo-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.map-geo-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{position:relative;width:100%;height:450px;min-height:450px;display:block;min-width:0}.map-geo-container.expanded .chart-wrapper{flex:1;height:auto;min-height:0}.map-geo-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.map-geo-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}\n"] }]
|
|
5662
|
-
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], points: [{ type: i0.Input, args: [{ isSignal: true, alias: "points", required: false }] }] } });
|
|
6038
|
+
args: [{ selector: 'lib-map-geo', imports: [GeoAPIMaps], template: "<div class=\"map-geo-container\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"map-geo-header\">\r\n <h3 class=\"map-geo-title\">{{ title() }}</h3>\r\n <button class=\"expand-btn\" (click)=\"toggleExpand()\" type=\"button\" [attr.aria-label]=\"isExpanded() ? 'Minimize chart' : 'Maximize chart'\">\r\n @if (isExpanded()) {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-minimize-2\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-maximize-2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>\r\n }\r\n </button>\r\n </div>\r\n <div class=\"chart-wrapper\">\r\n <lib-geo-api-maps [points]=\"points()\" [cameras]=\"cameras()\" />\r\n </div>\r\n @if (points().length > 0) {\r\n <div class=\"map-summary\">\r\n <span class=\"map-badge blue\">\r\n <span class=\"map-dot blue\"></span>\r\n Normal: {{ normalCount() }}\r\n </span>\r\n <span class=\"map-badge red\">\r\n <span class=\"map-dot red\"></span>\r\n Inmovilizado: {{ immobilizedCount() }}\r\n </span>\r\n <span class=\"map-badge total\">Total: {{ points().length }}</span>\r\n </div>\r\n }\r\n @if (cameras().length > 0) {\r\n <div class=\"map-summary\">\r\n <span class=\"map-badge purple\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M15 8v8H5V8h10m1-2H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-3.5l4 4v-11l-4 4V7a1 1 0 0 0-1-1z\"/>\r\n </svg>\r\n C\u00E1maras: {{ totalCameras() }}\r\n </span>\r\n </div>\r\n }\r\n</div>\r\n@if (isExpanded()) {\r\n <div class=\"overlay\" (click)=\"toggleExpand()\"></div>\r\n}", styles: [":host{display:block;width:100%;min-width:0}.map-geo-container{width:100%;min-width:0;display:flex;flex-direction:column;gap:16px;background-color:#f0f0db;padding:24px 16px 16px;border-radius:20px;position:relative;transition:all .3s ease}.map-geo-container.expanded{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;box-shadow:0 25px 50px -12px #00000040;margin:0}.chart-wrapper{position:relative;width:100%;height:450px;min-height:450px;display:block;min-width:0}.map-geo-container.expanded .chart-wrapper{flex:1;height:auto;min-height:0}.map-geo-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.map-geo-title{font-size:20px;font-weight:600;color:#333;font-family:Inter,sans-serif}.expand-btn{background:transparent;border:none;cursor:pointer;color:#61661f;padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s}.expand-btn:hover{background-color:#61661f1a}.overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9998}.map-summary{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.map-badge{display:inline-flex;align-items:center;gap:5px;font-family:Inter,sans-serif;font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;white-space:nowrap}.map-badge.blue{background-color:#3b82f61f;color:#2563eb}.map-badge.red{background-color:#ef44441f;color:#dc2626}.map-badge.purple{background-color:#7c3aed1f;color:#7c3aed}.map-badge.total{background-color:#3741511a;color:#374151}.map-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.map-dot.blue{background-color:#3b82f6}.map-dot.red{background-color:#ef4444}\n"] }]
|
|
6039
|
+
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], points: [{ type: i0.Input, args: [{ isSignal: true, alias: "points", required: false }] }], cameras: [{ type: i0.Input, args: [{ isSignal: true, alias: "cameras", required: false }] }] } });
|
|
5663
6040
|
|
|
5664
6041
|
class TableChart {
|
|
5665
6042
|
title = input('Table Chart', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
@@ -5962,6 +6339,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5962
6339
|
args: [{ selector: 'lib-document-upload', standalone: true, imports: [], template: "<div class=\"upload-container\" (dragover)=\"onDragOver($event)\" (dragleave)=\"onDragLeave()\" (drop)=\"onDrop($event)\"\r\n [class.dragging]=\"isDragging()\">\r\n\r\n <input type=\"file\" #fileInput [accept]=\"accept()\" [multiple]=\"multiple()\" (change)=\"onFileSelect($event)\" hidden />\r\n\r\n <div class=\"upload-zone\" (click)=\"fileInput.click()\">\r\n <svg class=\"upload-icon\" viewBox=\"0 0 486.3 486.3\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <g>\r\n <path d=\"M395.5,135.8c-5.2-30.9-20.5-59.1-43.9-80.5c-26-23.8-59.8-36.9-95-36.9c-27.2,0-53.7,7.8-76.4,22.5 c-18.9,12.2-34.6,28.7-45.7,48.1c-4.8-0.9-9.8-1.4-14.8-1.4c-42.5,0-77.1,34.6-77.1,77.1c0,5.5,0.6,10.8,1.6,16 C16.7,200.7,0,232.9,0,267.2c0,27.7,10.3,54.6,29.1,75.9c19.3,21.8,44.8,34.7,72,36.2c0.3,0,0.5,0,0.8,0h86 c7.5,0,13.5-6,13.5-13.5s-6-13.5-13.5-13.5h-85.6C61.4,349.8,27,310.9,27,267.1c0-28.3,15.2-54.7,39.7-69 c5.7-3.3,8.1-10.2,5.9-16.4c-2-5.4-3-11.1-3-17.2c0-27.6,22.5-50.1,50.1-50.1c5.9,0,11.7,1,17.1,3c6.6,2.4,13.9-0.6,16.9-6.9 c18.7-39.7,59.1-65.3,103-65.3c59,0,107.7,44.2,113.3,102.8c0.6,6.1,5.2,11,11.2,12c44.5,7.6,78.1,48.7,78.1,95.6 c0,49.7-39.1,92.9-87.3,96.6h-73.7c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5h74.2c0.3,0,0.6,0,1,0c30.5-2.2,59-16.2,80.2-39.6 c21.1-23.2,32.6-53,32.6-84C486.2,199.5,447.9,149.6,395.5,135.8z\"/>\r\n <path d=\"M324.2,280c5.3-5.3,5.3-13.8,0-19.1l-71.5-71.5c-2.5-2.5-6-4-9.5-4s-7,1.4-9.5,4l-71.5,71.5c-5.3,5.3-5.3,13.8,0,19.1 c2.6,2.6,6.1,4,9.5,4s6.9-1.3,9.5-4l48.5-48.5v222.9c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5V231.5l48.5,48.5 C310.4,285.3,318.9,285.3,324.2,280z\"/>\r\n </g>\r\n </svg>\r\n <p class=\"upload-label\"><strong>{{ label() }}</strong></p>\r\n <small class=\"upload-helper\">{{ helperText() }}</small>\r\n </div>\r\n\r\n @if (files().length > 0) {\r\n <div class=\"files-row\">\r\n @for (file of files(); track file.name) {\r\n <div class=\"file-card\">\r\n <button type=\"button\" class=\"file-card-remove\" (click)=\"removeFile(file)\" title=\"Eliminar archivo\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n <svg class=\"file-card-icon\" viewBox=\"0 0 64 64\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M12 4 L12 60 L52 60 L52 20 L36 4 Z\" fill=\"#e3e3d1\" stroke=\"#8a9a2f\" stroke-width=\"2.5\" stroke-linejoin=\"round\"/>\r\n <path d=\"M36 4 L36 20 L52 20\" fill=\"none\" stroke=\"#8a9a2f\" stroke-width=\"2.5\" stroke-linejoin=\"round\"/>\r\n <rect x=\"20\" y=\"30\" width=\"24\" height=\"2.5\" rx=\"1.25\" fill=\"#8a9a2f\"/>\r\n <rect x=\"20\" y=\"37\" width=\"24\" height=\"2.5\" rx=\"1.25\" fill=\"#8a9a2f\"/>\r\n <rect x=\"20\" y=\"44\" width=\"16\" height=\"2.5\" rx=\"1.25\" fill=\"#8a9a2f\"/>\r\n </svg>\r\n <span class=\"file-card-ext\">{{ getFileExtension(file) }}</span>\r\n <span class=\"file-card-name\" [title]=\"file.name\">{{ file.name }}</span>\r\n <span class=\"file-card-size\">{{ formatSize(file.size) }}</span>\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>", styles: [".upload-container{display:flex;flex-direction:column;gap:16px}.upload-zone{border:2px dashed #8a9a2f;border-radius:8px;padding:48px;text-align:center;cursor:pointer;background-color:#f5f7e8;transition:background .2s}.upload-zone:hover,.dragging .upload-zone{background-color:#eaeecc}.upload-icon{width:56px;height:56px;fill:#8a9a2f;display:block;margin:0 auto 12px}.upload-label{font-size:1.4rem;color:#454733;margin:0 0 6px}.upload-helper{font-size:1.2rem;color:#8a9a2f}.files-row{display:flex;flex-direction:row;gap:12px;overflow-x:auto;padding:4px 2px 8px;scrollbar-width:thin;scrollbar-color:#8a9a2f #f0f0e0}.files-row::-webkit-scrollbar{height:6px}.files-row::-webkit-scrollbar-track{background:#f0f0e0;border-radius:3px}.files-row::-webkit-scrollbar-thumb{background:#8a9a2f;border-radius:3px}.file-card{position:relative;flex-shrink:0;width:132px;height:140px;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:4px;padding:10px 10px 12px;border:1px solid #c5c9a0;border-radius:10px;background-color:#f5f7e8;transition:border-color .2s,background .2s;overflow:hidden}.file-card:hover{border-color:#8a9a2f;background-color:#eaeecc}.file-card-icon{width:52px;height:52px;flex-shrink:0;margin-bottom:2px}.file-card-ext{font-size:1rem;font-weight:700;color:#8a9a2f;letter-spacing:.04em;line-height:1}.file-card-name{width:100%;font-size:1.1rem;color:#454733;text-align:center;overflow:hidden;display:-webkit-box;line-clamp:2;-webkit-box-orient:vertical;line-height:1.3;word-break:break-all}.file-card-size{font-size:1rem;color:#8a9a6e;line-height:1}.file-card-remove{position:absolute;top:6px;right:6px;width:22px;height:22px;display:flex;align-items:center;justify-content:center;background:#ffffffd9;border:1px solid #c5c9a0;border-radius:50%;cursor:pointer;color:#787861;padding:0;transition:background .15s,color .15s,border-color .15s;line-height:1}.file-card-remove:hover{background:#c33;border-color:#c33;color:#fff}.file-card-remove svg{width:12px;height:12px}\n"] }]
|
|
5963
6340
|
}], propDecorators: { filesChanged: [{ type: i0.Output, args: ["filesChanged"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], helperText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helperText", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxSizeMB: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSizeMB", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }] } });
|
|
5964
6341
|
|
|
6342
|
+
class CardHistory {
|
|
6343
|
+
DataCard = input(...(ngDevMode ? [undefined, { debugName: "DataCard" }] : []));
|
|
6344
|
+
isExpanded = signal(false, ...(ngDevMode ? [{ debugName: "isExpanded" }] : []));
|
|
6345
|
+
months = [
|
|
6346
|
+
'enero',
|
|
6347
|
+
'febrero',
|
|
6348
|
+
'marzo',
|
|
6349
|
+
'abril',
|
|
6350
|
+
'mayo',
|
|
6351
|
+
'junio',
|
|
6352
|
+
'julio',
|
|
6353
|
+
'agosto',
|
|
6354
|
+
'septiembre',
|
|
6355
|
+
'octubre',
|
|
6356
|
+
'noviembre',
|
|
6357
|
+
'diciembre',
|
|
6358
|
+
];
|
|
6359
|
+
toggleExpanded() {
|
|
6360
|
+
this.isExpanded.set(!this.isExpanded());
|
|
6361
|
+
}
|
|
6362
|
+
formatDate(isoDate) {
|
|
6363
|
+
const date = new Date(isoDate);
|
|
6364
|
+
const day = date.getDate();
|
|
6365
|
+
const month = this.months[date.getMonth()];
|
|
6366
|
+
const year = date.getFullYear();
|
|
6367
|
+
return `${day} ${month} ${year}`;
|
|
6368
|
+
}
|
|
6369
|
+
// getBadgeClass(status: string): string {
|
|
6370
|
+
// const statusLower = status.toLowerCase();
|
|
6371
|
+
// if (statusLower.includes('operativo') || statusLower.includes('operacional')) {
|
|
6372
|
+
// return 'badge-operational';
|
|
6373
|
+
// } else if (statusLower.includes('mantenimiento')) {
|
|
6374
|
+
// return 'badge-maintenance';
|
|
6375
|
+
// } else if (statusLower.includes('sin ficha') || statusLower.includes('sin fecha')) {
|
|
6376
|
+
// return 'badge-no-date';
|
|
6377
|
+
// }
|
|
6378
|
+
// return 'badge-operational';
|
|
6379
|
+
// }
|
|
6380
|
+
statusData = {
|
|
6381
|
+
activo: { label: 'Activo', class: 'badge-active' },
|
|
6382
|
+
inactivo: { label: 'Inactivo', class: 'badge-inactive' },
|
|
6383
|
+
eliminado: { label: 'Eliminado', class: 'badge-retired' },
|
|
6384
|
+
obsoleto: { label: 'Obsoleto', class: 'badge-obsolete' },
|
|
6385
|
+
operativo: { label: 'Operativo', class: 'badge-operativo' },
|
|
6386
|
+
mantenimiento: { label: 'En mantenimiento', class: 'badge-maintenance' },
|
|
6387
|
+
fallas: { label: 'Con fallas', class: 'badge-failures' },
|
|
6388
|
+
baja: { label: 'Dado de baja', class: 'badge-deactivated' },
|
|
6389
|
+
default: { label: 'Desconocido', class: 'badge-default' },
|
|
6390
|
+
};
|
|
6391
|
+
getBadgeClass(status) {
|
|
6392
|
+
const normalizedStatus = status?.toLowerCase().trim();
|
|
6393
|
+
return this.statusData[normalizedStatus]?.class ?? this.statusData['default'].class;
|
|
6394
|
+
}
|
|
6395
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CardHistory, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6396
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: CardHistory, isStandalone: true, selector: "lib-card-history", inputs: { DataCard: { classPropertyName: "DataCard", publicName: "DataCard", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"card-history\">\r\n <span class=\"card-date\">{{ formatDate(DataCard()?.date || \"\") }}</span>\r\n <div class=\"event-card\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"event-header\" (click)=\"toggleExpanded()\">\r\n <div class=\"event-info\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"expand-icon icon icon-tabler icons-tabler-outline icon-tabler-chevron-up\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\r\n <path d=\"M6 15l6 -6l6 6\" />\r\n </svg>\r\n <span class=\"event-type\">{{ DataCard()?.title }}</span>\r\n <span class=\"event-time\">{{ DataCard()?.time }}</span>\r\n </div>\r\n <div class=\"status-badges\">\r\n <span\r\n class=\"badge\"\r\n [ngClass]=\"getBadgeClass(DataCard()?.previousStatus || '')\"\r\n >\r\n {{ DataCard()?.previousStatus }}\r\n </span>\r\n\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"icon icon-tabler icons-tabler-outline icon-tabler-chevrons-right\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\r\n <path d=\"M7 7l5 5l-5 5\" />\r\n <path d=\"M13 7l5 5l-5 5\" />\r\n </svg>\r\n\r\n <span\r\n class=\"badge\"\r\n [ngClass]=\"getBadgeClass(DataCard()?.currentStatus || '')\"\r\n >\r\n {{ DataCard()?.currentStatus }}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"event-details\">\r\n <div class=\"responsible-info\">\r\n <div class=\"avatar\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"icon icon-tabler icons-tabler-outline icon-tabler-user\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\r\n <path d=\"M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0\" />\r\n <path d=\"M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2\" />\r\n </svg>\r\n </div>\r\n <div class=\"responsible-details\">\r\n <h4>Responsable</h4>\r\n <div class=\"responsible-name\">{{ DataCard()?.responsible }}</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"technical-description\">\r\n <div class=\"tech-label\">Descripci\u00F3n t\u00E9cnica</div>\r\n <div class=\"tech-content\">\r\n {{ DataCard()?.description }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".card-history{display:flex;flex-direction:column;gap:15px}.card-date{color:#1c1c12;font-size:1.4rem;font-weight:600}.event-card{background-color:#f0f0db;border-radius:8px;margin-bottom:15px;overflow:hidden;border:1px solid #c7c7ad}.event-header{padding:12px 16px;display:flex;align-items:center;justify-content:space-between;cursor:pointer}.event-header:hover{background-color:#e0e0c8}.event-info{display:flex;align-items:center;gap:8px}.expand-icon{font-size:12px;transform:rotate(180deg);transition:transform .2s}.event-card.expanded .expand-icon{transform:rotate(90deg)}.event-type{font-weight:600;font-size:1.4rem;color:#1c1c12}.event-time{color:#454733;font-size:1.1rem}.status-badges{display:flex;align-items:center;gap:8px}.badge{padding:6px 10px;border-radius:6px;font-size:1.2rem;font-weight:600;border:none}.badge-maintenance{background:#bfd100;color:#4f5700}.badge-operational{background-color:#78db5c;color:#0f5e00}.badge-no-date{background-color:#bfe9ff;color:#004d65}.event-details{max-height:0;overflow:hidden;padding:0 10px;background-color:#f0f0e0;transition:max-height .3s ease-in-out,padding .3s ease-in-out}.event-card.expanded .event-details{max-height:300px;padding:20px 10px}.responsible-info{display:flex;align-items:center;gap:12px;margin-bottom:15px;padding:20px 10px;background-color:#ebe8d6;border-radius:8px}.avatar{width:36px;height:36px;border-radius:50%;background-color:#bfd100;display:flex;align-items:center;justify-content:center;font-weight:700}.avatar img{width:24px;height:24px}.responsible-details h4{font-size:1.2rem;color:#454733;margin-bottom:2px;font-weight:400}.responsible-name{font-size:1.4rem;font-weight:600;color:#1c1c12}.technical-description{padding:20px 10px;background-color:#ebe8d6;border-radius:8px;height:120px}.tech-label{font-size:1.2rem;color:#454733;margin-bottom:5px}.tech-content{font-size:1.4rem;color:#1c1c12;font-weight:600}.badge-active{color:#006d2f;font-weight:600;background-color:#c6f6c1;border-radius:8px;padding:6px 10px}.badge-inactive{color:#454733e7;font-weight:600;background-color:#e0e0e0;border-radius:8px;padding:6px 10px}.badge-retired{color:#ba1a1a;font-weight:600;background-color:#ffe5e5;border-radius:8px;padding:6px 10px}.badge-obsolete{color:#454733;font-weight:600;border:1px solid #c7c7ad;border-radius:8px;padding:6px 10px}.badge-operativo{color:#0f5e00;font-weight:600;background-color:#80ff66;border-radius:8px;padding:6px 10px}.badge-maintenance{color:#4f5700;font-weight:600;background-color:#bfd100;border-radius:8px;padding:6px 10px}.badge-failures{color:#94000a;font-weight:600;background-color:#fcd;border-radius:8px;padding:6px 10px}.badge-deactivated{color:#ba1a1a;font-weight:600;border:1px solid #ba1a1a;border-radius:8px;padding:6px 10px}.badge-default{color:#6b6b47;font-weight:600;border:1px dashed #c7c7ad;border-radius:8px;padding:6px 10px;font-style:italic}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
6397
|
+
}
|
|
6398
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CardHistory, decorators: [{
|
|
6399
|
+
type: Component,
|
|
6400
|
+
args: [{ selector: 'lib-card-history', imports: [NgClass], template: "<div class=\"card-history\">\r\n <span class=\"card-date\">{{ formatDate(DataCard()?.date || \"\") }}</span>\r\n <div class=\"event-card\" [class.expanded]=\"isExpanded()\">\r\n <div class=\"event-header\" (click)=\"toggleExpanded()\">\r\n <div class=\"event-info\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"expand-icon icon icon-tabler icons-tabler-outline icon-tabler-chevron-up\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\r\n <path d=\"M6 15l6 -6l6 6\" />\r\n </svg>\r\n <span class=\"event-type\">{{ DataCard()?.title }}</span>\r\n <span class=\"event-time\">{{ DataCard()?.time }}</span>\r\n </div>\r\n <div class=\"status-badges\">\r\n <span\r\n class=\"badge\"\r\n [ngClass]=\"getBadgeClass(DataCard()?.previousStatus || '')\"\r\n >\r\n {{ DataCard()?.previousStatus }}\r\n </span>\r\n\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"icon icon-tabler icons-tabler-outline icon-tabler-chevrons-right\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\r\n <path d=\"M7 7l5 5l-5 5\" />\r\n <path d=\"M13 7l5 5l-5 5\" />\r\n </svg>\r\n\r\n <span\r\n class=\"badge\"\r\n [ngClass]=\"getBadgeClass(DataCard()?.currentStatus || '')\"\r\n >\r\n {{ DataCard()?.currentStatus }}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"event-details\">\r\n <div class=\"responsible-info\">\r\n <div class=\"avatar\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"icon icon-tabler icons-tabler-outline icon-tabler-user\">\r\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\r\n <path d=\"M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0\" />\r\n <path d=\"M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2\" />\r\n </svg>\r\n </div>\r\n <div class=\"responsible-details\">\r\n <h4>Responsable</h4>\r\n <div class=\"responsible-name\">{{ DataCard()?.responsible }}</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"technical-description\">\r\n <div class=\"tech-label\">Descripci\u00F3n t\u00E9cnica</div>\r\n <div class=\"tech-content\">\r\n {{ DataCard()?.description }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".card-history{display:flex;flex-direction:column;gap:15px}.card-date{color:#1c1c12;font-size:1.4rem;font-weight:600}.event-card{background-color:#f0f0db;border-radius:8px;margin-bottom:15px;overflow:hidden;border:1px solid #c7c7ad}.event-header{padding:12px 16px;display:flex;align-items:center;justify-content:space-between;cursor:pointer}.event-header:hover{background-color:#e0e0c8}.event-info{display:flex;align-items:center;gap:8px}.expand-icon{font-size:12px;transform:rotate(180deg);transition:transform .2s}.event-card.expanded .expand-icon{transform:rotate(90deg)}.event-type{font-weight:600;font-size:1.4rem;color:#1c1c12}.event-time{color:#454733;font-size:1.1rem}.status-badges{display:flex;align-items:center;gap:8px}.badge{padding:6px 10px;border-radius:6px;font-size:1.2rem;font-weight:600;border:none}.badge-maintenance{background:#bfd100;color:#4f5700}.badge-operational{background-color:#78db5c;color:#0f5e00}.badge-no-date{background-color:#bfe9ff;color:#004d65}.event-details{max-height:0;overflow:hidden;padding:0 10px;background-color:#f0f0e0;transition:max-height .3s ease-in-out,padding .3s ease-in-out}.event-card.expanded .event-details{max-height:300px;padding:20px 10px}.responsible-info{display:flex;align-items:center;gap:12px;margin-bottom:15px;padding:20px 10px;background-color:#ebe8d6;border-radius:8px}.avatar{width:36px;height:36px;border-radius:50%;background-color:#bfd100;display:flex;align-items:center;justify-content:center;font-weight:700}.avatar img{width:24px;height:24px}.responsible-details h4{font-size:1.2rem;color:#454733;margin-bottom:2px;font-weight:400}.responsible-name{font-size:1.4rem;font-weight:600;color:#1c1c12}.technical-description{padding:20px 10px;background-color:#ebe8d6;border-radius:8px;height:120px}.tech-label{font-size:1.2rem;color:#454733;margin-bottom:5px}.tech-content{font-size:1.4rem;color:#1c1c12;font-weight:600}.badge-active{color:#006d2f;font-weight:600;background-color:#c6f6c1;border-radius:8px;padding:6px 10px}.badge-inactive{color:#454733e7;font-weight:600;background-color:#e0e0e0;border-radius:8px;padding:6px 10px}.badge-retired{color:#ba1a1a;font-weight:600;background-color:#ffe5e5;border-radius:8px;padding:6px 10px}.badge-obsolete{color:#454733;font-weight:600;border:1px solid #c7c7ad;border-radius:8px;padding:6px 10px}.badge-operativo{color:#0f5e00;font-weight:600;background-color:#80ff66;border-radius:8px;padding:6px 10px}.badge-maintenance{color:#4f5700;font-weight:600;background-color:#bfd100;border-radius:8px;padding:6px 10px}.badge-failures{color:#94000a;font-weight:600;background-color:#fcd;border-radius:8px;padding:6px 10px}.badge-deactivated{color:#ba1a1a;font-weight:600;border:1px solid #ba1a1a;border-radius:8px;padding:6px 10px}.badge-default{color:#6b6b47;font-weight:600;border:1px dashed #c7c7ad;border-radius:8px;padding:6px 10px;font-style:italic}\n"] }]
|
|
6401
|
+
}], propDecorators: { DataCard: [{ type: i0.Input, args: [{ isSignal: true, alias: "DataCard", required: false }] }] } });
|
|
6402
|
+
|
|
5965
6403
|
// src/app/components/public-api.ts
|
|
5966
6404
|
// Exportar los componentes
|
|
5967
6405
|
|
|
@@ -5969,5 +6407,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5969
6407
|
* Generated bundle index. Do not edit.
|
|
5970
6408
|
*/
|
|
5971
6409
|
|
|
5972
|
-
export { BarChart, BaseChart, Button, ButtonCards, CARD_BG, CardContent, Colors, DateTimeFilter, DateTimePicker, DevicesCarousel, DialogAlertComponent, DialogConfirmation, DocumentUpload, DonutChart, DynamicFormFields, FeatureCard, Footer, GeoAPIMaps, Heatmap, InfoGroup, Input, InputNumberFilter, InputSelectFilter, InputTextFilter, InputTimeFilter, KpiCard, LineChart, LoadImage, Loader, MapGeo, ModalForm, NotFoundModal, NotFoundSection, NotificationModal, OptionCard, PaginationComponent, PdfViewer, PdfViewerService, ProcessingOverlay, ProgressBar, ProgressFormService, QuickAccessCards, SelectCustomSearch, SideCard, SideCardDetail, TOAST_EVENTS, Table, TableChart, Tabs, TitleFilters, Toast, ToastHelper, ToastService, ToggleCustom, UI_CHART_TOKENS, WizardForm };
|
|
6410
|
+
export { BarChart, BaseChart, Button, ButtonCards, CARD_BG, CardContent, CardHistory, Colors, DateTimeFilter, DateTimePicker, DevicesCarousel, DialogAlertComponent, DialogConfirmation, DocumentUpload, DonutChart, DynamicFormFields, FeatureCard, Footer, GeoAPIMaps, Heatmap, InfoGroup, Input, InputNumberFilter, InputSelectFilter, InputTextFilter, InputTimeFilter, KpiCard, LineChart, LoadImage, Loader, MapGeo, ModalForm, NotFoundModal, NotFoundSection, NotificationModal, OptionCard, PaginationComponent, PdfViewer, PdfViewerService, ProcessingOverlay, ProgressBar, ProgressFormService, QuickAccessCards, SelectCustomSearch, SideCard, SideCardDetail, TOAST_EVENTS, Table, TableChart, Tabs, TitleFilters, Toast, ToastHelper, ToastService, ToggleCustom, UI_CHART_TOKENS, WizardForm };
|
|
5973
6411
|
//# sourceMappingURL=sapenlinea-components.mjs.map
|