@solcre-org/core-ui 2.12.13 → 2.12.15

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.
@@ -0,0 +1,105 @@
1
+ /* ******************************************** */
2
+ /** COMPONENT: SKELETON
3
+ /* ******************************************** */
4
+
5
+ /* ******************************************** */
6
+ /** COMPONENTS : SKELETON
7
+ /* ******************************************** */
8
+
9
+
10
+ /* SKELETON */
11
+
12
+ .c-skeleton,
13
+ .c-skeleton-image{
14
+ --_sk-input-h: 4.6rem;
15
+ --_sk-input-bg: var(--color-neutral-300);
16
+ --_sk-text-h: .4rem;
17
+
18
+ --_sk-btn-h: 3.6rem;
19
+ --_sk-btn-w: 15rem;
20
+ }
21
+
22
+ .c-skeleton > *,
23
+ .c-skeleton-image{
24
+ position: relative;
25
+ overflow: hidden;
26
+ background-color: var(--sk-input-bg,var(--_sk-input-bg));
27
+ }
28
+
29
+ .c-skeleton > *:not(:first-child) {
30
+ margin-top: 2.5rem;
31
+ }
32
+
33
+ .c-skeleton > *:not(.c-skeleton__check):before,
34
+ .c-skeleton-check__text::before,
35
+ .c-skeleton-image::before{
36
+ content: "";
37
+ position: absolute;
38
+ top: 0;
39
+ bottom: 0;
40
+ left: 0;
41
+ width: 100%;
42
+ transform: translate3d(-100%,0,0);
43
+ background: linear-gradient(70deg, transparent 30%, hsl(var(--color-neutral-100-hsl)/80%), transparent 70%);
44
+ animation: skeletonAnimation 3s infinite;
45
+ z-index: 1;
46
+ }
47
+
48
+ .c-skeleton__input{
49
+ width: 100%;
50
+ height: var(--_sk-input-h);
51
+ min-width: 25rem;
52
+ border-radius: var(--_entry-input-br);
53
+ }
54
+
55
+ .c-skeleton__textarea{
56
+ height: calc(var(--_sk-input-h)*3);
57
+ border-radius: var(--_entry-textarea-br, var(--_entry-input-br));
58
+ }
59
+
60
+
61
+ .c-skeleton__btn{
62
+ width: var(--_sk-btn-w);
63
+ height: var(--_sk-btn-h);
64
+ border-radius: var(--app-main-br, 8px);
65
+ }
66
+
67
+ .c-skeleton__check{
68
+ display: grid;
69
+ grid-template-columns: auto 1fr;
70
+ background-color: transparent;
71
+ align-items: center;
72
+ gap: 2rem;
73
+ }
74
+
75
+ .c-skeleton-check__check{
76
+ width: calc(var(--_sk-input-h)*.5);
77
+ aspect-ratio: 1;
78
+ background-color: var(--_sk-input-bg);
79
+ border-radius: 0.4em;
80
+ }
81
+
82
+ .c-skeleton__text,
83
+ .c-skeleton-check__text{
84
+ width: 100%;
85
+ height: var(--_sk-text-h);
86
+ background-color: var(--_sk-input-bg);
87
+ }
88
+
89
+ .c-skeleton-image{
90
+ position: absolute;
91
+ left: 0;
92
+ top: 0;
93
+ width: 100%;
94
+ height: 100%;
95
+ object-fit: cover;
96
+ }
97
+
98
+
99
+
100
+ @keyframes skeletonAnimation {
101
+ 100% {
102
+ transform: translate3d(100%,0,0);
103
+ }
104
+ }
105
+
@@ -68,6 +68,7 @@
68
68
  /* ⭐️ */ @import url(inc/components/calendar.css);
69
69
  /* ⭐️ */ @import url(inc/components/progressbar.css);
70
70
  /* ✅ */ @import url(inc/components/image-carousel.css); /* !(new) */
71
+ /* ✅ */ @import url(inc/components/skeleton.css); /* !(new) */
71
72
 
72
73
 
73
74
  /* Utilities */
@@ -955,6 +955,352 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
955
955
  }]
956
956
  }] });
957
957
 
958
+ var SkeletonType;
959
+ (function (SkeletonType) {
960
+ SkeletonType["INPUT"] = "input";
961
+ SkeletonType["TEXTAREA"] = "textarea";
962
+ SkeletonType["BUTTON"] = "button";
963
+ SkeletonType["CHECKBOX"] = "checkbox";
964
+ SkeletonType["IMAGE"] = "image";
965
+ SkeletonType["TEXT"] = "text";
966
+ SkeletonType["CARD"] = "card";
967
+ SkeletonType["LIST"] = "list";
968
+ SkeletonType["AVATAR"] = "avatar";
969
+ })(SkeletonType || (SkeletonType = {}));
970
+
971
+ var SkeletonSize;
972
+ (function (SkeletonSize) {
973
+ SkeletonSize["SMALL"] = "small";
974
+ SkeletonSize["MEDIUM"] = "medium";
975
+ SkeletonSize["LARGE"] = "large";
976
+ SkeletonSize["EXTRA_LARGE"] = "extra-large";
977
+ })(SkeletonSize || (SkeletonSize = {}));
978
+
979
+ var SkeletonAnimation;
980
+ (function (SkeletonAnimation) {
981
+ SkeletonAnimation["PULSE"] = "pulse";
982
+ SkeletonAnimation["WAVE"] = "wave";
983
+ SkeletonAnimation["SHIMMER"] = "shimmer";
984
+ SkeletonAnimation["NONE"] = "none";
985
+ })(SkeletonAnimation || (SkeletonAnimation = {}));
986
+
987
+ class GenericSkeletonComponent {
988
+ config = input();
989
+ items = input();
990
+ type = input();
991
+ size = input();
992
+ width = input();
993
+ height = input();
994
+ animated = input(true);
995
+ animation = input(SkeletonAnimation.PULSE);
996
+ lines = input(1);
997
+ customClass = input('');
998
+ ariaLabel = input('Loading content');
999
+ SkeletonType = SkeletonType;
1000
+ SkeletonSize = SkeletonSize;
1001
+ SkeletonAnimation = SkeletonAnimation;
1002
+ skeletonItems = computed(() => {
1003
+ const config = this.config();
1004
+ const items = this.items();
1005
+ const type = this.type();
1006
+ if (config?.items) {
1007
+ return config.items;
1008
+ }
1009
+ if (items) {
1010
+ return items;
1011
+ }
1012
+ if (type) {
1013
+ return [{
1014
+ type,
1015
+ size: this.size(),
1016
+ width: this.width(),
1017
+ height: this.height(),
1018
+ animated: this.animated(),
1019
+ animation: this.animation(),
1020
+ lines: this.lines(),
1021
+ customClass: this.customClass(),
1022
+ ariaLabel: this.ariaLabel()
1023
+ }];
1024
+ }
1025
+ return [{
1026
+ type: SkeletonType.TEXT,
1027
+ size: this.size() || SkeletonSize.MEDIUM,
1028
+ animated: this.animated(),
1029
+ animation: this.animation(),
1030
+ lines: this.lines(),
1031
+ customClass: this.customClass(),
1032
+ ariaLabel: this.ariaLabel()
1033
+ }];
1034
+ });
1035
+ containerClasses = computed(() => {
1036
+ const config = this.config();
1037
+ const baseClasses = ['c-skeleton'];
1038
+ if (config?.containerClass) {
1039
+ baseClasses.push(config.containerClass);
1040
+ }
1041
+ if (config?.animated !== false && this.animated()) {
1042
+ const animation = config?.animation || this.animation();
1043
+ baseClasses.push(`c-skeleton--${animation}`);
1044
+ }
1045
+ return baseClasses.join(' ');
1046
+ });
1047
+ getItemClasses(item) {
1048
+ const classes = [];
1049
+ switch (item.type) {
1050
+ case SkeletonType.INPUT:
1051
+ classes.push('c-skeleton__input');
1052
+ break;
1053
+ case SkeletonType.TEXTAREA:
1054
+ classes.push('c-skeleton__textarea');
1055
+ break;
1056
+ case SkeletonType.BUTTON:
1057
+ classes.push('c-skeleton__btn');
1058
+ break;
1059
+ case SkeletonType.CHECKBOX:
1060
+ classes.push('c-skeleton__check', 'c-skeleton-check');
1061
+ break;
1062
+ case SkeletonType.IMAGE:
1063
+ classes.push('c-skeleton-image');
1064
+ break;
1065
+ case SkeletonType.TEXT:
1066
+ classes.push('c-skeleton__text');
1067
+ break;
1068
+ case SkeletonType.CARD:
1069
+ classes.push('c-skeleton__card');
1070
+ break;
1071
+ case SkeletonType.LIST:
1072
+ classes.push('c-skeleton__list');
1073
+ break;
1074
+ case SkeletonType.AVATAR:
1075
+ classes.push('c-skeleton__avatar');
1076
+ break;
1077
+ }
1078
+ if (item.size) {
1079
+ classes.push(`c-skeleton--${item.size}`);
1080
+ }
1081
+ if (item.animated !== false) {
1082
+ const animation = item.animation || this.animation();
1083
+ classes.push(`c-skeleton--${animation}`);
1084
+ }
1085
+ if (item.customClass) {
1086
+ classes.push(item.customClass);
1087
+ }
1088
+ return classes.join(' ');
1089
+ }
1090
+ getItemStyles(item) {
1091
+ const styles = {};
1092
+ if (item.width) {
1093
+ styles['width'] = item.width;
1094
+ }
1095
+ if (item.height) {
1096
+ styles['height'] = item.height;
1097
+ }
1098
+ const config = this.config();
1099
+ if (config?.spacing) {
1100
+ styles['margin-bottom'] = config.spacing;
1101
+ }
1102
+ return styles;
1103
+ }
1104
+ getTextLines(item) {
1105
+ const lines = item.lines || this.lines() || 1;
1106
+ return Array.from({ length: lines }, (_, i) => i);
1107
+ }
1108
+ getListItems(item) {
1109
+ const items = item.listConfig?.items || 3;
1110
+ return Array.from({ length: items }, (_, i) => i);
1111
+ }
1112
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericSkeletonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1113
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: GenericSkeletonComponent, isStandalone: true, selector: "core-generic-skeleton", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, animated: { classPropertyName: "animated", publicName: "animated", isSignal: true, isRequired: false, transformFunction: null }, animation: { classPropertyName: "animation", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, customClass: { classPropertyName: "customClass", publicName: "customClass", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div [class]=\"containerClasses()\" [attr.aria-label]=\"ariaLabel()\">\n <ng-container *ngFor=\"let item of skeletonItems()\">\n \n <!-- Skeleton Input -->\n <div *ngIf=\"item.type === SkeletonType.INPUT\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading input field'\">\n </div>\n \n <!-- Skeleton Textarea -->\n <div *ngIf=\"item.type === SkeletonType.TEXTAREA\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading textarea field'\">\n </div>\n \n <!-- Skeleton Button -->\n <div *ngIf=\"item.type === SkeletonType.BUTTON\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading button'\">\n </div>\n \n <!-- Skeleton Checkbox -->\n <div *ngIf=\"item.type === SkeletonType.CHECKBOX\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading checkbox'\">\n <div class=\"c-skeleton-check__check\"></div>\n <div *ngIf=\"item.checkboxConfig?.showText !== false\" \n class=\"c-skeleton-check__text\"\n [style.width]=\"item.checkboxConfig?.textWidth || 'auto'\">\n </div>\n </div>\n \n <!-- Skeleton Image -->\n <div *ngIf=\"item.type === SkeletonType.IMAGE\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading image'\">\n </div>\n \n <!-- Skeleton Text -->\n <div *ngIf=\"item.type === SkeletonType.TEXT\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading text'\">\n <div *ngFor=\"let line of getTextLines(item)\"\n [class]=\"getItemClasses(item)\"\n [style.width]=\"line === getTextLines(item).length - 1 ? '75%' : '100%'\">\n </div>\n </div>\n \n <!-- Skeleton Avatar -->\n <div *ngIf=\"item.type === SkeletonType.AVATAR\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading avatar'\">\n </div>\n \n <!-- Skeleton Card -->\n <div *ngIf=\"item.type === SkeletonType.CARD\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading card'\">\n <div class=\"c-skeleton__card-header\"></div>\n <div class=\"c-skeleton__card-body\">\n <div class=\"c-skeleton__text\"></div>\n <div class=\"c-skeleton__text\" style=\"width: 80%;\"></div>\n <div class=\"c-skeleton__text\" style=\"width: 60%;\"></div>\n </div>\n </div>\n \n <!-- Skeleton List -->\n <div *ngIf=\"item.type === SkeletonType.LIST\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading list'\">\n <div *ngFor=\"let listItem of getListItems(item)\" class=\"c-skeleton__list-item\">\n <div *ngIf=\"item.listConfig?.showAvatar\" class=\"c-skeleton__avatar c-skeleton__avatar--small\"></div>\n <div class=\"c-skeleton__list-content\">\n <div class=\"c-skeleton__text\"></div>\n <div *ngIf=\"item.listConfig?.showSecondaryText\" \n class=\"c-skeleton__text c-skeleton__text--secondary\" \n style=\"width: 70%;\"></div>\n </div>\n </div>\n </div>\n \n </ng-container>\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1114
+ }
1115
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericSkeletonComponent, decorators: [{
1116
+ type: Component,
1117
+ args: [{ selector: 'core-generic-skeleton', standalone: true, imports: [CommonModule], template: "<div [class]=\"containerClasses()\" [attr.aria-label]=\"ariaLabel()\">\n <ng-container *ngFor=\"let item of skeletonItems()\">\n \n <!-- Skeleton Input -->\n <div *ngIf=\"item.type === SkeletonType.INPUT\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading input field'\">\n </div>\n \n <!-- Skeleton Textarea -->\n <div *ngIf=\"item.type === SkeletonType.TEXTAREA\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading textarea field'\">\n </div>\n \n <!-- Skeleton Button -->\n <div *ngIf=\"item.type === SkeletonType.BUTTON\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading button'\">\n </div>\n \n <!-- Skeleton Checkbox -->\n <div *ngIf=\"item.type === SkeletonType.CHECKBOX\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading checkbox'\">\n <div class=\"c-skeleton-check__check\"></div>\n <div *ngIf=\"item.checkboxConfig?.showText !== false\" \n class=\"c-skeleton-check__text\"\n [style.width]=\"item.checkboxConfig?.textWidth || 'auto'\">\n </div>\n </div>\n \n <!-- Skeleton Image -->\n <div *ngIf=\"item.type === SkeletonType.IMAGE\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading image'\">\n </div>\n \n <!-- Skeleton Text -->\n <div *ngIf=\"item.type === SkeletonType.TEXT\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading text'\">\n <div *ngFor=\"let line of getTextLines(item)\"\n [class]=\"getItemClasses(item)\"\n [style.width]=\"line === getTextLines(item).length - 1 ? '75%' : '100%'\">\n </div>\n </div>\n \n <!-- Skeleton Avatar -->\n <div *ngIf=\"item.type === SkeletonType.AVATAR\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading avatar'\">\n </div>\n \n <!-- Skeleton Card -->\n <div *ngIf=\"item.type === SkeletonType.CARD\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading card'\">\n <div class=\"c-skeleton__card-header\"></div>\n <div class=\"c-skeleton__card-body\">\n <div class=\"c-skeleton__text\"></div>\n <div class=\"c-skeleton__text\" style=\"width: 80%;\"></div>\n <div class=\"c-skeleton__text\" style=\"width: 60%;\"></div>\n </div>\n </div>\n \n <!-- Skeleton List -->\n <div *ngIf=\"item.type === SkeletonType.LIST\"\n [class]=\"getItemClasses(item)\"\n [ngStyle]=\"getItemStyles(item)\"\n [attr.aria-label]=\"item.ariaLabel || 'Loading list'\">\n <div *ngFor=\"let listItem of getListItems(item)\" class=\"c-skeleton__list-item\">\n <div *ngIf=\"item.listConfig?.showAvatar\" class=\"c-skeleton__avatar c-skeleton__avatar--small\"></div>\n <div class=\"c-skeleton__list-content\">\n <div class=\"c-skeleton__text\"></div>\n <div *ngIf=\"item.listConfig?.showSecondaryText\" \n class=\"c-skeleton__text c-skeleton__text--secondary\" \n style=\"width: 70%;\"></div>\n </div>\n </div>\n </div>\n \n </ng-container>\n</div>" }]
1118
+ }] });
1119
+
1120
+ class SkeletonService {
1121
+ presetConfigs = {
1122
+ form: {
1123
+ items: [
1124
+ { type: SkeletonType.INPUT },
1125
+ { type: SkeletonType.INPUT },
1126
+ { type: SkeletonType.TEXTAREA },
1127
+ { type: SkeletonType.CHECKBOX, checkboxConfig: { showText: true } },
1128
+ { type: SkeletonType.BUTTON, width: '120px' }
1129
+ ],
1130
+ animated: true,
1131
+ animation: SkeletonAnimation.PULSE
1132
+ },
1133
+ userCard: {
1134
+ items: [
1135
+ { type: SkeletonType.AVATAR, size: SkeletonSize.LARGE },
1136
+ { type: SkeletonType.TEXT, lines: 2 },
1137
+ { type: SkeletonType.TEXT, width: '60%' }
1138
+ ],
1139
+ animated: true,
1140
+ animation: SkeletonAnimation.SHIMMER
1141
+ },
1142
+ articleList: {
1143
+ items: [
1144
+ {
1145
+ type: SkeletonType.LIST,
1146
+ listConfig: {
1147
+ items: 5,
1148
+ showAvatar: true,
1149
+ showSecondaryText: true
1150
+ }
1151
+ }
1152
+ ],
1153
+ animated: true,
1154
+ animation: SkeletonAnimation.WAVE
1155
+ },
1156
+ imageGallery: {
1157
+ items: [
1158
+ { type: SkeletonType.IMAGE, height: '200px' },
1159
+ { type: SkeletonType.IMAGE, height: '200px' },
1160
+ { type: SkeletonType.IMAGE, height: '200px' }
1161
+ ],
1162
+ containerClass: 'skeleton-gallery',
1163
+ animated: true,
1164
+ animation: SkeletonAnimation.PULSE
1165
+ },
1166
+ dataTable: {
1167
+ items: [
1168
+ { type: SkeletonType.TEXT, height: '40px', width: '100%' },
1169
+ { type: SkeletonType.TEXT, height: '35px', width: '100%' },
1170
+ { type: SkeletonType.TEXT, height: '35px', width: '100%' },
1171
+ { type: SkeletonType.TEXT, height: '35px', width: '100%' },
1172
+ { type: SkeletonType.TEXT, height: '35px', width: '100%' }
1173
+ ],
1174
+ animated: true,
1175
+ animation: SkeletonAnimation.SHIMMER
1176
+ },
1177
+ dashboard: {
1178
+ items: [
1179
+ { type: SkeletonType.CARD, height: '150px' },
1180
+ { type: SkeletonType.CARD, height: '150px' },
1181
+ { type: SkeletonType.CARD, height: '300px' }
1182
+ ],
1183
+ animated: true,
1184
+ animation: SkeletonAnimation.PULSE
1185
+ }
1186
+ };
1187
+ getPresetConfig(preset) {
1188
+ return { ...this.presetConfigs[preset] };
1189
+ }
1190
+ createFormSkeleton(fields = 3, includeButton = true) {
1191
+ const items = [];
1192
+ for (let i = 0; i < fields; i++) {
1193
+ items.push({ type: SkeletonType.INPUT });
1194
+ }
1195
+ if (includeButton) {
1196
+ items.push({ type: SkeletonType.BUTTON, width: '120px' });
1197
+ }
1198
+ return {
1199
+ items,
1200
+ animated: true,
1201
+ animation: SkeletonAnimation.PULSE
1202
+ };
1203
+ }
1204
+ createListSkeleton(itemCount = 5, showAvatar = false, showSecondaryText = false) {
1205
+ return {
1206
+ items: [{
1207
+ type: SkeletonType.LIST,
1208
+ listConfig: {
1209
+ items: itemCount,
1210
+ showAvatar,
1211
+ showSecondaryText
1212
+ }
1213
+ }],
1214
+ animated: true,
1215
+ animation: SkeletonAnimation.WAVE
1216
+ };
1217
+ }
1218
+ createTextSkeleton(lines = 3, width) {
1219
+ return {
1220
+ items: [{
1221
+ type: SkeletonType.TEXT,
1222
+ lines,
1223
+ width
1224
+ }],
1225
+ animated: true,
1226
+ animation: SkeletonAnimation.PULSE
1227
+ };
1228
+ }
1229
+ createImageSkeleton(width, height) {
1230
+ return {
1231
+ items: [{
1232
+ type: SkeletonType.IMAGE,
1233
+ width: width || '100%',
1234
+ height: height || '200px'
1235
+ }],
1236
+ animated: true,
1237
+ animation: SkeletonAnimation.SHIMMER
1238
+ };
1239
+ }
1240
+ createCardSkeleton(includeAvatar = false, textLines = 3) {
1241
+ const items = [];
1242
+ if (includeAvatar) {
1243
+ items.push({ type: SkeletonType.AVATAR });
1244
+ }
1245
+ items.push({
1246
+ type: SkeletonType.TEXT,
1247
+ lines: textLines
1248
+ });
1249
+ return {
1250
+ items,
1251
+ animated: true,
1252
+ animation: SkeletonAnimation.PULSE
1253
+ };
1254
+ }
1255
+ combineConfigs(...configs) {
1256
+ const combinedItems = [];
1257
+ let finalAnimation = SkeletonAnimation.PULSE;
1258
+ let finalAnimated = true;
1259
+ let finalContainerClass = '';
1260
+ configs.forEach(config => {
1261
+ combinedItems.push(...config.items);
1262
+ if (config.animation) {
1263
+ finalAnimation = config.animation;
1264
+ }
1265
+ if (config.animated !== undefined) {
1266
+ finalAnimated = config.animated;
1267
+ }
1268
+ if (config.containerClass) {
1269
+ finalContainerClass += ` ${config.containerClass}`;
1270
+ }
1271
+ });
1272
+ return {
1273
+ items: combinedItems,
1274
+ animated: finalAnimated,
1275
+ animation: finalAnimation,
1276
+ containerClass: finalContainerClass.trim() || undefined
1277
+ };
1278
+ }
1279
+ createCustomSkeleton(type, options = {}) {
1280
+ return {
1281
+ items: [{
1282
+ type,
1283
+ animated: true,
1284
+ animation: SkeletonAnimation.PULSE,
1285
+ ...options
1286
+ }],
1287
+ animated: true,
1288
+ animation: options.animation || SkeletonAnimation.PULSE
1289
+ };
1290
+ }
1291
+ getAvailablePresets() {
1292
+ return Object.keys(this.presetConfigs);
1293
+ }
1294
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SkeletonService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1295
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SkeletonService, providedIn: 'root' });
1296
+ }
1297
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SkeletonService, decorators: [{
1298
+ type: Injectable,
1299
+ args: [{
1300
+ providedIn: 'root'
1301
+ }]
1302
+ }] });
1303
+
958
1304
  class ImagePreviewComponent {
959
1305
  imageModalService = inject(ImageModalService);
960
1306
  src = input.required();
@@ -967,19 +1313,39 @@ class ImagePreviewComponent {
967
1313
  cursor = input('pointer');
968
1314
  loading = input('lazy');
969
1315
  isRelative = input(false);
1316
+ showSkeleton = input(true);
1317
+ skeletonAnimation = input(SkeletonAnimation.SHIMMER);
1318
+ isImageLoading = signal(true);
1319
+ hasImageError = signal(false);
1320
+ SkeletonType = SkeletonType;
1321
+ onImageLoad() {
1322
+ this.isImageLoading.set(false);
1323
+ this.hasImageError.set(false);
1324
+ }
1325
+ onImageError() {
1326
+ this.isImageLoading.set(false);
1327
+ this.hasImageError.set(true);
1328
+ }
970
1329
  onImageClick() {
971
- this.imageModalService.openImageModal({
972
- src: this.src(),
973
- alt: this.alt(),
974
- title: this.title()
975
- });
1330
+ if (!this.isImageLoading() && !this.hasImageError()) {
1331
+ this.imageModalService.openImageModal({
1332
+ src: this.src(),
1333
+ alt: this.alt(),
1334
+ title: this.title()
1335
+ });
1336
+ }
1337
+ }
1338
+ onSkeletonClick() {
1339
+ if (!this.isImageLoading()) {
1340
+ this.onImageClick();
1341
+ }
976
1342
  }
977
1343
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ImagePreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
978
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: ImagePreviewComponent, isStandalone: true, selector: "core-image-preview", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: true, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, objectFit: { classPropertyName: "objectFit", publicName: "objectFit", isSignal: true, isRequired: false, transformFunction: null }, borderRadius: { classPropertyName: "borderRadius", publicName: "borderRadius", isSignal: true, isRequired: false, transformFunction: null }, cursor: { classPropertyName: "cursor", publicName: "cursor", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, isRelative: { classPropertyName: "isRelative", publicName: "isRelative", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"c-img-preview\" \n (click)=\"onImageClick()\">\n <img \n [src]=\"src()\" \n [alt]=\"alt()\"\n [title]=\"title()\"\n [loading]=\"loading()\"\n [style.object-fit]=\"objectFit()\"\n [style.border-radius]=\"borderRadius()\"\n [style.cursor]=\"cursor()\">\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
1344
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: ImagePreviewComponent, isStandalone: true, selector: "core-image-preview", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: true, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, objectFit: { classPropertyName: "objectFit", publicName: "objectFit", isSignal: true, isRequired: false, transformFunction: null }, borderRadius: { classPropertyName: "borderRadius", publicName: "borderRadius", isSignal: true, isRequired: false, transformFunction: null }, cursor: { classPropertyName: "cursor", publicName: "cursor", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, isRelative: { classPropertyName: "isRelative", publicName: "isRelative", isSignal: true, isRequired: false, transformFunction: null }, showSkeleton: { classPropertyName: "showSkeleton", publicName: "showSkeleton", isSignal: true, isRequired: false, transformFunction: null }, skeletonAnimation: { classPropertyName: "skeletonAnimation", publicName: "skeletonAnimation", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"c-img-preview\" \n [class.c-img-preview--loading]=\"isImageLoading() && showSkeleton()\"\n [class.c-img-preview--error]=\"hasImageError()\"\n [style.width]=\"width()\"\n [style.height]=\"height()\"\n [style.border-radius]=\"borderRadius()\"\n [style.position]=\"isRelative() ? 'relative' : 'static'\">\n \n @if (isImageLoading() && showSkeleton()) {\n <div class=\"c-img-preview__skeleton\"\n (click)=\"onSkeletonClick()\">\n <core-generic-skeleton \n [type]=\"SkeletonType.IMAGE\"\n [width]=\"width() || '100%'\"\n [height]=\"height() || '200px'\"\n [animation]=\"skeletonAnimation()\"\n [ariaLabel]=\"'Loading image: ' + (alt() || 'Image')\">\n </core-generic-skeleton>\n </div>\n }\n \n @if (!isImageLoading() && !hasImageError()) {\n <img \n [src]=\"src()\" \n [alt]=\"alt()\"\n [title]=\"title()\"\n [loading]=\"loading()\"\n [style.object-fit]=\"objectFit()\"\n [style.border-radius]=\"borderRadius()\"\n [style.cursor]=\"cursor()\"\n (click)=\"onImageClick()\">\n }\n \n @if (isImageLoading()) {\n <img \n [src]=\"src()\"\n [alt]=\"alt()\"\n style=\"display: none;\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError()\">\n }\n \n @if (hasImageError()) {\n <div class=\"c-img-preview__error\"\n [style.width]=\"width() || '100%'\"\n [style.height]=\"height() || '200px'\"\n [style.border-radius]=\"borderRadius()\">\n <div class=\"c-img-preview__error-content\">\n <span class=\"c-img-preview__error-icon\">\uD83D\uDCF7</span>\n <span class=\"c-img-preview__error-text\">Error al cargar imagen</span>\n </div>\n </div>\n }\n \n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: GenericSkeletonComponent, selector: "core-generic-skeleton", inputs: ["config", "items", "type", "size", "width", "height", "animated", "animation", "lines", "customClass", "ariaLabel"] }] });
979
1345
  }
980
1346
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ImagePreviewComponent, decorators: [{
981
1347
  type: Component,
982
- args: [{ selector: 'core-image-preview', standalone: true, imports: [CommonModule], template: "<div class=\"c-img-preview\" \n (click)=\"onImageClick()\">\n <img \n [src]=\"src()\" \n [alt]=\"alt()\"\n [title]=\"title()\"\n [loading]=\"loading()\"\n [style.object-fit]=\"objectFit()\"\n [style.border-radius]=\"borderRadius()\"\n [style.cursor]=\"cursor()\">\n</div>" }]
1348
+ args: [{ selector: 'core-image-preview', standalone: true, imports: [CommonModule, GenericSkeletonComponent], template: "<div class=\"c-img-preview\" \n [class.c-img-preview--loading]=\"isImageLoading() && showSkeleton()\"\n [class.c-img-preview--error]=\"hasImageError()\"\n [style.width]=\"width()\"\n [style.height]=\"height()\"\n [style.border-radius]=\"borderRadius()\"\n [style.position]=\"isRelative() ? 'relative' : 'static'\">\n \n @if (isImageLoading() && showSkeleton()) {\n <div class=\"c-img-preview__skeleton\"\n (click)=\"onSkeletonClick()\">\n <core-generic-skeleton \n [type]=\"SkeletonType.IMAGE\"\n [width]=\"width() || '100%'\"\n [height]=\"height() || '200px'\"\n [animation]=\"skeletonAnimation()\"\n [ariaLabel]=\"'Loading image: ' + (alt() || 'Image')\">\n </core-generic-skeleton>\n </div>\n }\n \n @if (!isImageLoading() && !hasImageError()) {\n <img \n [src]=\"src()\" \n [alt]=\"alt()\"\n [title]=\"title()\"\n [loading]=\"loading()\"\n [style.object-fit]=\"objectFit()\"\n [style.border-radius]=\"borderRadius()\"\n [style.cursor]=\"cursor()\"\n (click)=\"onImageClick()\">\n }\n \n @if (isImageLoading()) {\n <img \n [src]=\"src()\"\n [alt]=\"alt()\"\n style=\"display: none;\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError()\">\n }\n \n @if (hasImageError()) {\n <div class=\"c-img-preview__error\"\n [style.width]=\"width() || '100%'\"\n [style.height]=\"height() || '200px'\"\n [style.border-radius]=\"borderRadius()\">\n <div class=\"c-img-preview__error-content\">\n <span class=\"c-img-preview__error-icon\">\uD83D\uDCF7</span>\n <span class=\"c-img-preview__error-text\">Error al cargar imagen</span>\n </div>\n </div>\n }\n \n</div>" }]
983
1349
  }] });
984
1350
 
985
1351
  class FileFieldComponent extends BaseFieldComponent {
@@ -1467,7 +1833,7 @@ class FileFieldComponent extends BaseFieldComponent {
1467
1833
  this.onBlur();
1468
1834
  }
1469
1835
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: FileFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1470
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: FileFieldComponent, isStandalone: true, selector: "core-file-field", usesInheritance: true, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n <div class=\"c-attachments__pic\">\n @if(isPreviewFile(file) && getOriginalUrl(file)) {\n <core-image-preview\n [src]=\"getOriginalUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n } @else if(getPreviewUrl(file)) {\n <core-image-preview\n [src]=\"getPreviewUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n }\n </div>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }, { kind: "pipe", type: IconCompatPipe, name: "coreIconCompat" }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading", "isRelative"] }] });
1836
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: FileFieldComponent, isStandalone: true, selector: "core-file-field", usesInheritance: true, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n <div class=\"c-attachments__pic\">\n @if(isPreviewFile(file) && getOriginalUrl(file)) {\n <core-image-preview\n [src]=\"getOriginalUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n } @else if(getPreviewUrl(file)) {\n <core-image-preview\n [src]=\"getPreviewUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n }\n </div>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }, { kind: "pipe", type: IconCompatPipe, name: "coreIconCompat" }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading", "isRelative", "showSkeleton", "skeletonAnimation"] }] });
1471
1837
  }
1472
1838
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: FileFieldComponent, decorators: [{
1473
1839
  type: Component,
@@ -11619,11 +11985,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
11619
11985
  // Este archivo es generado automáticamente por scripts/update-version.js
11620
11986
  // No edites manualmente este archivo
11621
11987
  const VERSION = {
11622
- full: '2.12.13',
11988
+ full: '2.12.15',
11623
11989
  major: 2,
11624
11990
  minor: 12,
11625
- patch: 13,
11626
- timestamp: '2025-09-08T15:36:53.831Z',
11991
+ patch: 15,
11992
+ timestamp: '2025-09-08T19:48:26.568Z',
11627
11993
  buildDate: '8/9/2025'
11628
11994
  };
11629
11995
 
@@ -13201,7 +13567,7 @@ class CarouselComponent {
13201
13567
  };
13202
13568
  }
13203
13569
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13204
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: CarouselComponent, isStandalone: true, selector: "core-carousel", inputs: { images: { classPropertyName: "images", publicName: "images", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:resize": "onResize()", "keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "carouselHolder", first: true, predicate: ["carouselHolder"], descendants: true, isSignal: true }, { propertyName: "carouselViewport", first: true, predicate: ["carouselViewport"], descendants: true, isSignal: true }], ngImport: i0, template: "<div \n [ngClass]=\"carouselClasses()\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n #carouselViewport\n [class.is-multiple]=\"perView() > 1\">\n \n <div class=\"c-img-carousel__viewport\">\n <div class=\"c-img-carousel__holder js-img-carousel-holder\" #carouselHolder>\n <div \n *ngFor=\"let image of images(); let i = index\"\n class=\"c-img-carousel__slide js-img-carousel-slide\">\n <div class=\"c-img-carousel__slide-inner\">\n <core-image-preview\n [src]=\"image.url\"\n [alt]=\"image.alt || 'Image ' + (i + 1)\"\n [title]=\"image.title || image.alt || 'Image ' + (i + 1)\">\n </core-image-preview>\n </div>\n </div>\n </div>\n \n @if (!config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n \n <div \n *ngIf=\"showDots()\"\n class=\"c-img-carousel__dots js-img-carousel-nav\"\n aria-label=\"Navegaci\u00F3n\">\n <button\n *ngFor=\"let page of dots(); let i = index\"\n class=\"c-img-carousel__dot js-img-carousel-dot\"\n type=\"button\"\n (click)=\"goToPage(i)\"\n [class.c-img-carousel__dot--active]=\"currentPage() === i\"\n [attr.aria-label]=\"'Ir a p\u00E1gina ' + (i + 1)\"\n [attr.aria-current]=\"currentPage() === i ? 'true' : 'false'\">\n </button>\n </div>\n </div>\n @if(config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading", "isRelative"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
13570
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: CarouselComponent, isStandalone: true, selector: "core-carousel", inputs: { images: { classPropertyName: "images", publicName: "images", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:resize": "onResize()", "keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "carouselHolder", first: true, predicate: ["carouselHolder"], descendants: true, isSignal: true }, { propertyName: "carouselViewport", first: true, predicate: ["carouselViewport"], descendants: true, isSignal: true }], ngImport: i0, template: "<div \n [ngClass]=\"carouselClasses()\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n #carouselViewport\n [class.is-multiple]=\"perView() > 1\">\n \n <div class=\"c-img-carousel__viewport\">\n <div class=\"c-img-carousel__holder js-img-carousel-holder\" #carouselHolder>\n <div \n *ngFor=\"let image of images(); let i = index\"\n class=\"c-img-carousel__slide js-img-carousel-slide\">\n <div class=\"c-img-carousel__slide-inner\">\n <core-image-preview\n [src]=\"image.url\"\n [alt]=\"image.alt || 'Image ' + (i + 1)\"\n [title]=\"image.title || image.alt || 'Image ' + (i + 1)\">\n </core-image-preview>\n </div>\n </div>\n </div>\n \n @if (!config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n \n <div \n *ngIf=\"showDots()\"\n class=\"c-img-carousel__dots js-img-carousel-nav\"\n aria-label=\"Navegaci\u00F3n\">\n <button\n *ngFor=\"let page of dots(); let i = index\"\n class=\"c-img-carousel__dot js-img-carousel-dot\"\n type=\"button\"\n (click)=\"goToPage(i)\"\n [class.c-img-carousel__dot--active]=\"currentPage() === i\"\n [attr.aria-label]=\"'Ir a p\u00E1gina ' + (i + 1)\"\n [attr.aria-current]=\"currentPage() === i ? 'true' : 'false'\">\n </button>\n </div>\n </div>\n @if(config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading", "isRelative", "showSkeleton", "skeletonAnimation"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
13205
13571
  }
13206
13572
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CarouselComponent, decorators: [{
13207
13573
  type: Component,
@@ -13541,5 +13907,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
13541
13907
  * Generated bundle index. Do not edit.
13542
13908
  */
13543
13909
 
13544
- export { ActiveFiltersComponent, AlertComponent, AlertContainerComponent, AlertService, AlertType, ApiConfigurationProvider, BaseFieldComponent, ButtonContext, ButtonSize, ButtonType, CacheBustingInterceptor, CardComponent, CarouselComponent, CheckboxFieldComponent, ConfigurationModel, ConfirmationDialogComponent, ConfirmationDialogService, CoreHostDirective, CoreUiHttpLoaderFactory, CoreUiTranslateLoader, CoreUiTranslateService, DataListComponent, DataListItemComponent, DateFieldComponent, DateUtility, DatetimeFieldComponent, DialogActions, DocumentAction, DocumentDisplayMode, DropdownComponent, DropdownDirection, DropdownService, DynamicFieldDirective, DynamicFieldsHelper, FieldErrorsComponent, FieldType, FileFieldComponent, FileModel, FileTemplateModel, FileTemplateType, FileType, FileTypeModel, FileUploadService, FilterModalComponent, FilterService, FilterType, GenericButtonComponent, GenericDocumentationComponent, GenericModalComponent, GenericPaginationComponent, GenericRatingComponent, GenericSidebarComponent, GenericStepsComponent, GenericTableComponent, GenericTabsComponent, GenericTimelineComponent, GlobalApiConfigService, HeaderComponent, HeaderConfigurationService, HeaderElementType, HeaderService, HttpLoaderFactory, ImageModalComponent, ImageModalService, ImagePreviewComponent, LayoutAuth, LayoutBreakpoint, LayoutComponent, LayoutService, LayoutStateService, LayoutType, LoaderComponent, LoaderService, MainNavComponent, MainNavService, ModalMode, ModelApiService, MultiEntryFieldComponent, MultiEntryOutputFormat, NumberFieldComponent, NumberFieldConfigType, NumberFieldType, NumberRange, PERMISSION_ACTIONS_PROVIDER, PERMISSION_PROVIDER, PERMISSION_RESOURCES_PROVIDER, PaginationService, PasswordFieldComponent, PermissionEnumsService, PermissionModel, PermissionService, PermissionWrapperService, PermissionsActions, PermissionsInterceptor, PermissionsResources, ProgressBarComponent, ProgressBarSize, RatingService, RatingSize, RatingType, ResetPasswordModel, RoleModel, SelectFieldComponent, ServerSelectFieldComponent, ServerSelectService, SidebarCustomModalComponent, SidebarCustomModalService, SidebarHeight, SidebarMobileModalService, SidebarMobileType, SidebarPosition, SidebarService, SidebarState, SidebarTemplateRegistryService, SidebarVisibility, SidebarWidth, SmartFieldComponent, SortDirection, SortMode, StepSize, StepStatus, StepType, StepsService, SwitchFieldComponent, TableAction, TableActionService, TableDataService, TableSortService, TextAreaFieldComponent, TextFieldComponent, TimeFieldComponent, TimeInterval, TimelineService, TimelineStatus, TimelineType, TranslationMergeService, UsersModel, VERSION, equalToValidator, isSameDate, provideCoreUiTranslateLoader, providePermissionActions, providePermissionEnums, providePermissionResources, providePermissionService, providePermissionServiceFactory, provideTranslateLoader };
13910
+ export { ActiveFiltersComponent, AlertComponent, AlertContainerComponent, AlertService, AlertType, ApiConfigurationProvider, BaseFieldComponent, ButtonContext, ButtonSize, ButtonType, CacheBustingInterceptor, CardComponent, CarouselComponent, CheckboxFieldComponent, ConfigurationModel, ConfirmationDialogComponent, ConfirmationDialogService, CoreHostDirective, CoreUiHttpLoaderFactory, CoreUiTranslateLoader, CoreUiTranslateService, DataListComponent, DataListItemComponent, DateFieldComponent, DateUtility, DatetimeFieldComponent, DialogActions, DocumentAction, DocumentDisplayMode, DropdownComponent, DropdownDirection, DropdownService, DynamicFieldDirective, DynamicFieldsHelper, FieldErrorsComponent, FieldType, FileFieldComponent, FileModel, FileTemplateModel, FileTemplateType, FileType, FileTypeModel, FileUploadService, FilterModalComponent, FilterService, FilterType, GenericButtonComponent, GenericDocumentationComponent, GenericModalComponent, GenericPaginationComponent, GenericRatingComponent, GenericSidebarComponent, GenericSkeletonComponent, GenericStepsComponent, GenericTableComponent, GenericTabsComponent, GenericTimelineComponent, GlobalApiConfigService, HeaderComponent, HeaderConfigurationService, HeaderElementType, HeaderService, HttpLoaderFactory, ImageModalComponent, ImageModalService, ImagePreviewComponent, LayoutAuth, LayoutBreakpoint, LayoutComponent, LayoutService, LayoutStateService, LayoutType, LoaderComponent, LoaderService, MainNavComponent, MainNavService, ModalMode, ModelApiService, MultiEntryFieldComponent, MultiEntryOutputFormat, NumberFieldComponent, NumberFieldConfigType, NumberFieldType, NumberRange, PERMISSION_ACTIONS_PROVIDER, PERMISSION_PROVIDER, PERMISSION_RESOURCES_PROVIDER, PaginationService, PasswordFieldComponent, PermissionEnumsService, PermissionModel, PermissionService, PermissionWrapperService, PermissionsActions, PermissionsInterceptor, PermissionsResources, ProgressBarComponent, ProgressBarSize, RatingService, RatingSize, RatingType, ResetPasswordModel, RoleModel, SelectFieldComponent, ServerSelectFieldComponent, ServerSelectService, SidebarCustomModalComponent, SidebarCustomModalService, SidebarHeight, SidebarMobileModalService, SidebarMobileType, SidebarPosition, SidebarService, SidebarState, SidebarTemplateRegistryService, SidebarVisibility, SidebarWidth, SkeletonAnimation, SkeletonService, SkeletonSize, SkeletonType, SmartFieldComponent, SortDirection, SortMode, StepSize, StepStatus, StepType, StepsService, SwitchFieldComponent, TableAction, TableActionService, TableDataService, TableSortService, TextAreaFieldComponent, TextFieldComponent, TimeFieldComponent, TimeInterval, TimelineService, TimelineStatus, TimelineType, TranslationMergeService, UsersModel, VERSION, equalToValidator, isSameDate, provideCoreUiTranslateLoader, providePermissionActions, providePermissionEnums, providePermissionResources, providePermissionService, providePermissionServiceFactory, provideTranslateLoader };
13545
13911
  //# sourceMappingURL=solcre-org-core-ui.mjs.map