valtech-components 2.0.325 → 2.0.328

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/esm2022/lib/components/atoms/button/button.component.mjs +18 -18
  2. package/esm2022/lib/components/atoms/display/display.component.mjs +13 -16
  3. package/esm2022/lib/components/atoms/text/text.component.mjs +19 -19
  4. package/esm2022/lib/components/atoms/title/title.component.mjs +7 -7
  5. package/esm2022/lib/components/atoms/title/types.mjs +6 -2
  6. package/esm2022/lib/components/molecules/alert-box/alert-box.component.mjs +6 -6
  7. package/esm2022/lib/components/molecules/language-selector/language-selector.component.mjs +6 -17
  8. package/esm2022/lib/components/organisms/form/form.component.mjs +1 -1
  9. package/esm2022/lib/services/lang-provider/lang-provider.service.mjs +198 -2
  10. package/esm2022/lib/shared/utils/simple-content.mjs +119 -0
  11. package/esm2022/public-api.mjs +3 -4
  12. package/fesm2022/valtech-components.mjs +520 -837
  13. package/fesm2022/valtech-components.mjs.map +1 -1
  14. package/lib/components/atoms/button/button.component.d.ts +3 -3
  15. package/lib/components/atoms/display/display.component.d.ts +2 -3
  16. package/lib/components/atoms/text/text.component.d.ts +3 -3
  17. package/lib/components/atoms/title/title.component.d.ts +1 -2
  18. package/lib/components/atoms/title/types.d.ts +10 -4
  19. package/lib/components/molecules/alert-box/alert-box.component.d.ts +3 -3
  20. package/lib/components/molecules/language-selector/language-selector.component.d.ts +1 -3
  21. package/lib/services/lang-provider/lang-provider.service.d.ts +108 -1
  22. package/lib/shared/utils/simple-content.d.ts +120 -0
  23. package/package.json +1 -1
  24. package/public-api.d.ts +1 -3
  25. package/esm2022/lib/services/content-loader.service.mjs +0 -185
  26. package/esm2022/lib/services/content.service.mjs +0 -327
  27. package/esm2022/lib/shared/utils/reactive-content.mjs +0 -117
  28. package/lib/services/content-loader.service.d.ts +0 -98
  29. package/lib/services/content.service.d.ts +0 -296
  30. package/lib/shared/utils/reactive-content.d.ts +0 -109
@@ -5,7 +5,7 @@ import * as i1 from '@angular/common';
5
5
  import { CommonModule, NgStyle, AsyncPipe, NgFor, NgClass } from '@angular/common';
6
6
  import { addIcons } from 'ionicons';
7
7
  import { addOutline, addCircleOutline, alertOutline, alertCircleOutline, arrowBackOutline, arrowForwardOutline, arrowDownOutline, checkmarkCircleOutline, ellipsisHorizontalOutline, notificationsOutline, openOutline, closeOutline, chatbubblesOutline, shareOutline, heart, heartOutline, homeOutline, eyeOffOutline, eyeOutline, scanOutline, chevronDownOutline, chevronForwardOutline, checkmarkOutline, clipboardOutline, copyOutline, filterOutline, locationOutline, calendarOutline, businessOutline, logoTwitter, logoInstagram, logoLinkedin, logoYoutube, logoTiktok, logoFacebook, createOutline, trashOutline, playOutline, refreshOutline, documentTextOutline, lockClosedOutline, informationCircleOutline, logoNpm, chevronDown, language, globe, chevronBackOutline } from 'ionicons/icons';
8
- import { map, BehaviorSubject, distinctUntilChanged, shareReplay, Subscription, of, combineLatest } from 'rxjs';
8
+ import { BehaviorSubject, distinctUntilChanged, shareReplay, map, Subscription, of, combineLatest } from 'rxjs';
9
9
  import { Router, RouterLink } from '@angular/router';
10
10
  import { Browser } from '@capacitor/browser';
11
11
  import * as i1$1 from '@angular/platform-browser';
@@ -219,6 +219,125 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
219
219
  type: Output
220
220
  }] } });
221
221
 
222
+ /**
223
+ * Simplified content utilities for the new LangService-only system.
224
+ * This replaces the old reactive-content.ts with a much simpler approach.
225
+ */
226
+ /**
227
+ * Helper function to determine if component should use reactive content.
228
+ * @param metadata Component metadata
229
+ * @returns True if component should use reactive content
230
+ */
231
+ function shouldUseReactiveContent(metadata) {
232
+ return !metadata.content && !!(metadata.contentKey && metadata.contentClass);
233
+ }
234
+ /**
235
+ * Extract content configuration from metadata.
236
+ * @param metadata Component metadata
237
+ * @returns Content configuration for LangService
238
+ */
239
+ function extractContentConfig(metadata) {
240
+ return {
241
+ className: metadata.contentClass || '',
242
+ key: metadata.contentKey || '',
243
+ fallback: metadata.contentFallback,
244
+ };
245
+ }
246
+ /**
247
+ * Create reactive content metadata with defaults.
248
+ * @param config Partial content configuration
249
+ * @returns Complete reactive content metadata
250
+ */
251
+ function createReactiveContentMetadata(config) {
252
+ return {
253
+ content: config.content,
254
+ contentKey: config.contentKey,
255
+ contentClass: config.contentClass,
256
+ contentFallback: config.contentFallback,
257
+ };
258
+ }
259
+ /**
260
+ * Interpolate content string with values.
261
+ * Replaces placeholders like {{key}} or {key} with actual values.
262
+ *
263
+ * @param content - Content string with placeholders
264
+ * @param values - Values to interpolate
265
+ * @returns Interpolated string
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * interpolateContent('Hello {{name}}!', { name: 'World' })
270
+ * // Returns: 'Hello World!'
271
+ * ```
272
+ */
273
+ function interpolateContent$1(content, values) {
274
+ if (!values || !content) {
275
+ return content;
276
+ }
277
+ return content.replace(/\{\{?(\w+)\}?\}/g, (match, key) => {
278
+ const value = values[key];
279
+ return value !== undefined ? String(value) : match;
280
+ });
281
+ }
282
+ /**
283
+ * Check if component should use reactive content with interpolation.
284
+ * @param metadata Component metadata with interpolation
285
+ * @returns True if component should use reactive content with interpolation
286
+ */
287
+ function shouldUseReactiveContentWithInterpolation(metadata) {
288
+ return shouldUseReactiveContent(metadata) && !!metadata.contentInterpolation;
289
+ }
290
+ /**
291
+ * Extract content configuration with interpolation from metadata.
292
+ * @param metadata Component metadata with interpolation
293
+ * @returns Content configuration for LangService with interpolation data
294
+ */
295
+ function extractContentConfigWithInterpolation(metadata) {
296
+ return {
297
+ className: metadata.contentClass || '',
298
+ key: metadata.contentKey || '',
299
+ fallback: metadata.contentFallback,
300
+ interpolation: metadata.contentInterpolation,
301
+ };
302
+ }
303
+ /**
304
+ * Helper function to get reactive content with interpolation using LangService.
305
+ * This provides a unified way to get reactive, interpolated content.
306
+ *
307
+ * @param langService - The LangService instance
308
+ * @param metadata - Component metadata with interpolation
309
+ * @returns Observable that emits interpolated content
310
+ *
311
+ * @example
312
+ * ```typescript
313
+ * const content$ = fromContentWithInterpolation(this.langService, {
314
+ * contentClass: 'MyComponent',
315
+ * contentKey: 'greeting',
316
+ * contentInterpolation: { name: 'World' }
317
+ * });
318
+ * ```
319
+ */
320
+ function fromContentWithInterpolation$1(langService, // LangService type would cause circular dependency
321
+ metadata) {
322
+ // Observable<string> but avoiding import
323
+ const config = extractContentConfigWithInterpolation(metadata);
324
+ if (!config.className || !config.key) {
325
+ throw new Error('fromContentWithInterpolation requires both contentClass and contentKey');
326
+ }
327
+ return langService.getContentWithInterpolation(config.className, config.key, config.interpolation, config.fallback);
328
+ }
329
+ /**
330
+ * Helper function to get static content with interpolation.
331
+ * This provides interpolation for static content strings.
332
+ *
333
+ * @param content - Static content string
334
+ * @param interpolationData - Values to interpolate
335
+ * @returns Interpolated string
336
+ */
337
+ function interpolateStaticContent(content, interpolationData) {
338
+ return interpolateContent$1(content, interpolationData);
339
+ }
340
+
222
341
  const ENABLED = 'ENABLED';
223
342
  const DISABLED = 'DISABLED';
224
343
  const WORKING = 'WORKING';
@@ -434,191 +553,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
434
553
  }]
435
554
  }], ctorParameters: () => [] });
436
555
 
437
- /**
438
- * Create a reactive content observable from a content key.
439
- * This is the primary utility for the `fromContent` pattern with unified support
440
- * for both simple content and content with interpolation.
441
- *
442
- * @param langService - The language service instance
443
- * @param config - Content configuration with optional interpolation
444
- * @returns Observable that emits the content string and updates on language change
445
- *
446
- * @example Simple content:
447
- * ```typescript
448
- * // Component-specific content
449
- * this.title$ = fromContent(this.langService, {
450
- * className: 'HeaderComponent',
451
- * key: 'title',
452
- * fallback: 'Default Title'
453
- * });
454
- *
455
- * // Global content (no className needed)
456
- * this.saveButton$ = fromContent(this.langService, {
457
- * key: 'save'
458
- * });
459
- * ```
460
- *
461
- * @example Content with interpolation:
462
- * ```typescript
463
- * // Content: "Hello {name}, you have {count} messages"
464
- * this.greeting$ = fromContent(this.langService, {
465
- * className: 'WelcomeComponent',
466
- * key: 'greeting',
467
- * interpolation: { name: 'John', count: 5 }
468
- * });
469
- * // Results in: "Hello John, you have 5 messages"
470
- * ```
471
- */
472
- function fromContent(langService, config) {
473
- // Use _global as default className if not provided
474
- const finalClassName = config.className || '_global';
475
- const contentObservable = langService.getContent(finalClassName, config.key, config.fallback);
476
- // If interpolation is provided, apply it
477
- if (config.interpolation) {
478
- return contentObservable.pipe(map(content => interpolateContent(content, config.interpolation)));
479
- }
480
- return contentObservable;
481
- }
482
- /**
483
- * Create a reactive content observable with interpolation support.
484
- *
485
- * @deprecated Use fromContent() with interpolation property instead.
486
- * This method is kept for backward compatibility.
487
- *
488
- * @param langService - The language service instance
489
- * @param config - Interpolated content configuration
490
- * @returns Observable that emits the interpolated content string
491
- *
492
- * @example Migration:
493
- * ```typescript
494
- * // OLD (deprecated):
495
- * this.greeting$ = fromContentWithInterpolation(this.langService, {
496
- * className: 'WelcomeComponent',
497
- * key: 'greeting',
498
- * interpolation: { name: 'John', count: 5 }
499
- * });
500
- *
501
- * // NEW (recommended):
502
- * this.greeting$ = fromContent(this.langService, {
503
- * className: 'WelcomeComponent',
504
- * key: 'greeting',
505
- * interpolation: { name: 'John', count: 5 }
506
- * });
507
- * ```
508
- */
509
- function fromContentWithInterpolation(langService, config) {
510
- // Delegate to the unified fromContent method
511
- return fromContent(langService, config);
512
- }
513
- /**
514
- * Create multiple reactive content observables at once.
515
- * Useful when a component needs several content strings.
516
- *
517
- * @param langService - The language service instance
518
- * @param className - The component class name
519
- * @param keys - Array of content keys to retrieve
520
- * @returns Observable that emits an object with all requested content
521
- *
522
- * @example
523
- * ```typescript
524
- * this.content$ = fromMultipleContent(this.langService, 'FormComponent', [
525
- * 'title', 'submitButton', 'cancelButton'
526
- * ]);
527
- *
528
- * // In template
529
- * <ng-container *ngIf="content$ | async as content">
530
- * <h2>{{ content.title }}</h2>
531
- * <button>{{ content.submitButton }}</button>
532
- * <button>{{ content.cancelButton }}</button>
533
- * </ng-container>
534
- * ```
535
- */
536
- function fromMultipleContent(langService, className, keys) {
537
- return langService.getMultipleContent(className, keys);
538
- }
539
- /**
540
- * Helper function to interpolate values into a content string.
541
- * Replaces placeholders in the format {key} with corresponding values.
542
- *
543
- * @param content - The content string with placeholders
544
- * @param values - Object with values to interpolate
545
- * @returns The interpolated string
546
- *
547
- * @example
548
- * ```typescript
549
- * const result = interpolateContent("Hello {name}!", { name: "World" });
550
- * // Returns: "Hello World!"
551
- * ```
552
- */
553
- function interpolateContent(content, values) {
554
- if (!values)
555
- return content;
556
- return Object.entries(values).reduce((result, [key, value]) => {
557
- return result.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
558
- }, content);
559
- }
560
- /**
561
- * Factory function to create a content helper bound to a specific component class.
562
- * This creates a more convenient API for components that need multiple content strings.
563
- *
564
- * @param langService - The language service instance
565
- * @param className - The component class name
566
- * @returns Object with convenient methods for content retrieval
567
- *
568
- * @example
569
- * ```typescript
570
- * export class MyComponent {
571
- * private content = createContentHelper(this.langService, 'MyComponent');
572
- *
573
- * constructor(private langService: LangService) {}
574
- *
575
- * ngOnInit() {
576
- * this.title$ = this.content.get('title');
577
- * this.allContent$ = this.content.getMultiple(['title', 'description']);
578
- * }
579
- * }
580
- * ```
581
- */
582
- function createContentHelper(langService, className) {
583
- return {
584
- /**
585
- * Get a single content string reactively.
586
- */
587
- get(key, fallback) {
588
- return fromContent(langService, { className, key, fallback });
589
- },
590
- /**
591
- * Get multiple content strings reactively.
592
- */
593
- getMultiple(keys) {
594
- return fromMultipleContent(langService, className, keys);
595
- },
596
- /**
597
- * Get content with interpolation.
598
- */
599
- getWithInterpolation(key, interpolation, fallback) {
600
- return fromContentWithInterpolation(langService, {
601
- className,
602
- key,
603
- interpolation,
604
- fallback,
605
- });
606
- },
607
- /**
608
- * Get a single content string synchronously (current language only).
609
- */
610
- getText(key, fallback) {
611
- return langService.getText(className, key, fallback);
612
- },
613
- /**
614
- * Check if a content key exists.
615
- */
616
- hasContent(key) {
617
- return langService.hasContent(className, key);
618
- },
619
- };
620
- }
621
-
622
556
  const LANG = 'LANG';
623
557
  const THEME = 'THEME';
624
558
 
@@ -991,348 +925,221 @@ class LangService {
991
925
  const targetContent = classContent.Content[lang] || {};
992
926
  return Object.keys(referenceContent).filter(key => !targetContent[key] || typeof targetContent[key] !== 'string');
993
927
  }
994
- // Legacy getters/setters for backward compatibility
995
- get Lang() {
996
- return this.currentLang;
997
- }
998
- set Lang(lang) {
999
- this.setLang(lang);
1000
- }
1001
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, deps: [{ token: ValtechConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1002
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, providedIn: 'root' }); }
1003
- }
1004
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, decorators: [{
1005
- type: Injectable,
1006
- args: [{
1007
- providedIn: 'root',
1008
- }]
1009
- }], ctorParameters: () => [{ type: undefined, decorators: [{
1010
- type: Inject,
1011
- args: [ValtechConfigService]
1012
- }] }] });
1013
-
1014
- /**
1015
- * ContentService - High-level reactive content management service.
1016
- *
1017
- * This service provides a clean, convenient API for reactive content management
1018
- * without requiring direct interaction with LangService. It acts as a facade
1019
- * that simplifies the most common content operations.
1020
- *
1021
- * @example Basic usage:
1022
- * ```typescript
1023
- * @Component({})
1024
- * export class MyComponent {
1025
- * content = inject(ContentService);
1026
- *
1027
- * title$ = this.content.fromContent({
1028
- * className: 'MyComponent',
1029
- * key: 'title'
1030
- * });
1031
- *
1032
- * constructor() {}
1033
- * }
1034
- * ```
1035
- */
1036
- class ContentService {
1037
- constructor(langService) {
1038
- this.langService = langService;
1039
- }
1040
- /**
1041
- * Get current language as an observable stream.
1042
- * Emits whenever the language changes.
1043
- */
1044
- get currentLang$() {
1045
- return this.langService.currentLang$;
1046
- }
1047
- /**
1048
- * Get current language synchronously.
1049
- */
1050
- get currentLang() {
1051
- return this.langService.currentLang;
1052
- }
1053
928
  /**
1054
- * Set the current language.
1055
- * This will trigger updates in all reactive content.
929
+ * Register or update content for a component dynamically.
930
+ * This allows registering content at runtime without APP_INITIALIZER.
1056
931
  *
1057
- * @param lang - The language to set
1058
- */
1059
- setLang(lang) {
1060
- this.langService.setLang(lang);
1061
- }
1062
- /**
1063
- * Create a reactive content observable from a content key.
1064
- * This is the primary method for reactive content with unified support
1065
- * for both simple content and content with interpolation.
1066
- *
1067
- * @param config - Content configuration with optional interpolation. If className is omitted, searches in global content.
1068
- * @returns Observable that emits the content string and updates on language change
1069
- *
1070
- * @example Simple global content:
1071
- * ```typescript
1072
- * // Searches in global content (no className needed)
1073
- * okButton$ = this.content.fromContent({
1074
- * key: 'ok',
1075
- * fallback: 'OK'
1076
- * });
1077
- * ```
1078
- *
1079
- * @example Component-specific content:
1080
- * ```typescript
1081
- * title$ = this.content.fromContent({
1082
- * className: 'HeaderComponent',
1083
- * key: 'title',
1084
- * fallback: 'Default Title'
1085
- * });
1086
- * ```
932
+ * @param className - The component class name
933
+ * @param content - The multilingual content object
934
+ * @param merge - Whether to merge with existing content (default: true)
1087
935
  *
1088
- * @example Content with interpolation:
936
+ * @example
1089
937
  * ```typescript
1090
- * // Global content with interpolation
1091
- * confirmation$ = this.content.fromContent({
1092
- * key: 'deleteConfirmation',
1093
- * interpolation: { itemName: 'archivo' }
1094
- * });
1095
- *
1096
- * // Component content with interpolation
1097
- * greeting$ = this.content.fromContent({
1098
- * className: 'WelcomeComponent',
1099
- * key: 'greeting',
1100
- * interpolation: { name: 'John', count: 5 }
938
+ * this.langService.registerContent('MyComponent', {
939
+ * [LANGUAGES.ES]: { title: 'Título', description: 'Descripción' },
940
+ * [LANGUAGES.EN]: { title: 'Title', description: 'Description' }
1101
941
  * });
1102
942
  * ```
1103
943
  */
1104
- fromContent(config) {
1105
- return fromContent(this.langService, config);
944
+ registerContent(className, content, merge = true) {
945
+ if (!className) {
946
+ console.error('LangService: className is required for registerContent');
947
+ return;
948
+ }
949
+ if (!content || typeof content !== 'object') {
950
+ console.error('LangService: Invalid content provided for registerContent');
951
+ return;
952
+ }
953
+ console.log(`LangService: Registering content for "${className}"`, {
954
+ merge,
955
+ languages: Object.keys(content),
956
+ });
957
+ // Initialize component content if it doesn't exist
958
+ if (!this.content[className]) {
959
+ this.content[className] = new TextContent({});
960
+ }
961
+ // Merge or replace content for each language
962
+ Object.entries(content).forEach(([lang, langContent]) => {
963
+ if (!langContent || typeof langContent !== 'object') {
964
+ console.warn(`LangService: Invalid content for language "${lang}" in "${className}"`);
965
+ return;
966
+ }
967
+ if (!this.content[className].Content[lang]) {
968
+ this.content[className].Content[lang] = {};
969
+ }
970
+ if (merge) {
971
+ this.content[className].Content[lang] = {
972
+ ...this.content[className].Content[lang],
973
+ ...langContent,
974
+ };
975
+ }
976
+ else {
977
+ this.content[className].Content[lang] = { ...langContent };
978
+ }
979
+ });
980
+ // Update available languages
981
+ this.detectAvailableLanguages();
982
+ console.log(`LangService: Content registered successfully for "${className}"`);
1106
983
  }
1107
984
  /**
1108
- * Create a reactive content observable with interpolation support.
985
+ * Update multiple content registrations at once.
1109
986
  *
1110
- * @deprecated Use fromContent() with interpolation property instead.
1111
- * This method is kept for backward compatibility.
987
+ * @param contentMap - Map of className to content
988
+ * @param merge - Whether to merge with existing content (default: true)
1112
989
  *
1113
- * @param config - Interpolated content configuration. If className is omitted, searches in global content.
1114
- * @returns Observable that emits the interpolated content string
1115
- *
1116
- * @example Migration:
990
+ * @example
1117
991
  * ```typescript
1118
- * // OLD (deprecated):
1119
- * greeting$ = this.content.fromContentWithInterpolation({
1120
- * className: 'WelcomeComponent',
1121
- * key: 'greeting',
1122
- * interpolation: { name: 'John', count: 5 }
1123
- * });
1124
- *
1125
- * // NEW (recommended):
1126
- * greeting$ = this.content.fromContent({
1127
- * className: 'WelcomeComponent',
1128
- * key: 'greeting',
1129
- * interpolation: { name: 'John', count: 5 }
992
+ * this.langService.registerMultipleContent({
993
+ * 'Component1': { [LANGUAGES.ES]: { key1: 'valor1' } },
994
+ * 'Component2': { [LANGUAGES.EN]: { key2: 'value2' } }
1130
995
  * });
1131
996
  * ```
1132
997
  */
1133
- fromContentWithInterpolation(config) {
1134
- // Delegate to the unified fromContent method
1135
- return this.fromContent(config);
998
+ registerMultipleContent(contentMap, merge = true) {
999
+ if (!contentMap || typeof contentMap !== 'object') {
1000
+ console.error('LangService: Invalid contentMap provided for registerMultipleContent');
1001
+ return;
1002
+ }
1003
+ console.log('LangService: Registering multiple content entries', {
1004
+ classes: Object.keys(contentMap),
1005
+ merge,
1006
+ });
1007
+ Object.entries(contentMap).forEach(([className, content]) => {
1008
+ this.registerContent(className, content, merge);
1009
+ });
1010
+ console.log('LangService: Multiple content registration completed');
1136
1011
  }
1137
1012
  /**
1138
- * Create multiple reactive content observables at once.
1139
- * Useful when a component needs several content strings.
1140
- *
1141
- * @param className - The component class name
1142
- * @param keys - Array of content keys to retrieve
1143
- * @returns Observable that emits an object with all requested content
1144
- *
1145
- * @example
1146
- * ```typescript
1147
- * content$ = this.content.fromMultipleContent('FormComponent', [
1148
- * 'title', 'submitButton', 'cancelButton'
1149
- * ]);
1013
+ * Remove content for a specific component.
1150
1014
  *
1151
- * // In template
1152
- * <ng-container *ngIf="content$ | async as content">
1153
- * <h2>{{ content['title'] }}</h2>
1154
- * <button>{{ content['submitButton'] }}</button>
1155
- * <button>{{ content['cancelButton'] }}</button>
1156
- * </ng-container>
1157
- * ```
1015
+ * @param className - The component class name to remove
1158
1016
  */
1159
- fromMultipleContent(className, keys) {
1160
- return fromMultipleContent(this.langService, className, keys);
1161
- }
1162
- getText(classNameOrKey, keyOrFallback, fallback) {
1163
- // Handle overloaded signatures
1164
- if (keyOrFallback === undefined ||
1165
- (typeof keyOrFallback === 'string' && fallback === undefined)) {
1166
- // Single parameter or two parameters (key, fallback) - treat as global content
1167
- return this.langService.getText('_global', classNameOrKey, keyOrFallback);
1017
+ removeContent(className) {
1018
+ if (!className) {
1019
+ console.error('LangService: className is required for removeContent');
1020
+ return;
1021
+ }
1022
+ if (this.content[className]) {
1023
+ delete this.content[className];
1024
+ this.detectAvailableLanguages();
1025
+ console.log(`LangService: Content removed for "${className}"`);
1168
1026
  }
1169
1027
  else {
1170
- // Three parameters (className, key, fallback) - treat as component content
1171
- return this.langService.getText(classNameOrKey, keyOrFallback, fallback);
1028
+ console.warn(`LangService: No content found for "${className}" to remove`);
1172
1029
  }
1173
1030
  }
1174
1031
  /**
1175
- * Get a single global content string synchronously.
1176
- * This is a convenience method that's equivalent to getText(key, fallback).
1032
+ * Get a list of all registered component classes.
1177
1033
  *
1178
- * @param key - The text key
1179
- * @param fallback - Optional fallback text if key is not found
1180
- * @returns The text string or fallback
1034
+ * @returns Array of registered class names
1035
+ */
1036
+ getRegisteredClasses() {
1037
+ return Object.keys(this.content);
1038
+ }
1039
+ /**
1040
+ * Get the complete content configuration (for debugging purposes).
1041
+ * Returns a deep copy to prevent accidental mutations.
1181
1042
  *
1182
- * @example
1183
- * ```typescript
1184
- * const okText = this.content.getGlobalText('ok');
1185
- * const cancelText = this.content.getGlobalText('cancel', 'Cancel');
1186
- * ```
1043
+ * @returns Complete content configuration
1187
1044
  */
1188
- getGlobalText(key, fallback) {
1189
- return this.langService.getText('_global', key, fallback);
1045
+ getContentConfiguration() {
1046
+ return JSON.parse(JSON.stringify(this.content));
1190
1047
  }
1191
1048
  /**
1192
- * Check if a content key exists for a component.
1049
+ * Clear all content and reset to initial state.
1050
+ * Useful for testing or complete reinitialization.
1051
+ */
1052
+ clearAllContent() {
1053
+ console.log('LangService: Clearing all content');
1054
+ this.content = {};
1055
+ this.availableLanguages = [LANGUAGES.ES]; // Reset to default
1056
+ this.warnedMissingLanguages.clear();
1057
+ console.log('LangService: All content cleared');
1058
+ }
1059
+ /**
1060
+ * Get content with interpolation support.
1061
+ * Retrieves content and replaces placeholders with provided values.
1193
1062
  *
1194
1063
  * @param className - The component class name
1195
1064
  * @param key - The text key
1196
- * @returns True if the key exists in any language
1197
- *
1198
- * @example
1199
- * ```typescript
1200
- * if (this.content.hasContent('MyComponent', 'optionalText')) {
1201
- * // Show optional content
1202
- * }
1203
- * ```
1065
+ * @param interpolationData - Object with values to interpolate
1066
+ * @param fallback - Optional fallback text if key is not found
1067
+ * @returns Text with interpolated values
1204
1068
  */
1205
- hasContent(className, key) {
1206
- return this.langService.hasContent(className, key);
1069
+ getTextWithInterpolation(className, key, interpolationData, fallback) {
1070
+ const content = this.getText(className, key, fallback);
1071
+ return this.interpolateString(content, interpolationData);
1207
1072
  }
1208
1073
  /**
1209
- * Helper function to interpolate values into a content string.
1210
- * Useful for processing content strings manually.
1211
- *
1212
- * @param content - The content string with placeholders
1213
- * @param values - Object with values to interpolate
1214
- * @returns The interpolated string
1074
+ * Get reactive content with interpolation support.
1075
+ * Returns an Observable that emits interpolated content when language changes.
1215
1076
  *
1216
- * @example
1217
- * ```typescript
1218
- * const result = this.content.interpolate("Hello {name}!", { name: "World" });
1219
- * // Returns: "Hello World!"
1220
- * ```
1077
+ * @param className - The component class name
1078
+ * @param key - The text key
1079
+ * @param interpolationData - Object with values to interpolate
1080
+ * @param fallback - Optional fallback text if key is not found
1081
+ * @returns Observable that emits interpolated text
1221
1082
  */
1222
- interpolate(content, values) {
1223
- return interpolateContent(content, values);
1083
+ getContentWithInterpolation(className, key, interpolationData, fallback) {
1084
+ return this.getContent(className, key, fallback).pipe(map(content => this.interpolateString(content, interpolationData)));
1224
1085
  }
1225
1086
  /**
1226
- * Create a content helper bound to a specific component class.
1227
- * This provides a scoped API for components that need multiple content strings.
1087
+ * Interpolate a string with provided values.
1088
+ * Replaces placeholders like {{key}} or {key} with actual values.
1228
1089
  *
1229
- * @param className - The component class name
1230
- * @returns Content helper with methods scoped to the class
1090
+ * @param content - Content string with placeholders
1091
+ * @param values - Values to interpolate
1092
+ * @returns Interpolated string
1231
1093
  *
1232
1094
  * @example
1233
1095
  * ```typescript
1234
- * export class MyComponent {
1235
- * private contentHelper = this.content.createHelper('MyComponent');
1236
- *
1237
- * ngOnInit() {
1238
- * this.title$ = this.contentHelper.get('title');
1239
- * this.allContent$ = this.contentHelper.getMultiple(['title', 'description']);
1240
- * }
1241
- *
1242
- * constructor(private content: ContentService) {}
1243
- * }
1096
+ * interpolateString('Hello {{name}}!', { name: 'World' })
1097
+ * // Returns: 'Hello World!'
1244
1098
  * ```
1245
1099
  */
1246
- createHelper(className) {
1247
- return createContentHelper(this.langService, className);
1100
+ interpolateString(content, values) {
1101
+ if (!values || !content) {
1102
+ return content;
1103
+ }
1104
+ return content.replace(/\{\{?(\w+)\}?\}/g, (match, key) => {
1105
+ const value = values[key];
1106
+ return value !== undefined ? String(value) : match;
1107
+ });
1248
1108
  }
1249
1109
  /**
1250
- * Create a scoped content service for a specific component class.
1251
- * This provides an even more convenient API for components with many content needs.
1110
+ * Legacy function equivalent to the old fromContentWithInterpolation.
1111
+ * Provides reactive content with interpolation support for backward compatibility.
1252
1112
  *
1253
1113
  * @param className - The component class name
1254
- * @returns Scoped content service
1255
- *
1256
- * @example
1257
- * ```typescript
1258
- * export class MyComponent {
1259
- * private content = inject(ContentService).forComponent('MyComponent');
1260
- *
1261
- * // Simple content
1262
- * title$ = this.content.get('title');
1263
- *
1264
- * // Content with interpolation
1265
- * greeting$ = this.content.get('greeting', {
1266
- * interpolation: { name: 'John' }
1267
- * });
1268
- *
1269
- * // Content with fallback
1270
- * subtitle$ = this.content.get('subtitle', {
1271
- * fallback: 'Default Subtitle'
1272
- * });
1273
- *
1274
- * // Multiple texts
1275
- * allTexts$ = this.content.getMultiple(['title', 'subtitle', 'description']);
1114
+ * @param key - The text key
1115
+ * @param interpolationData - Object with values to interpolate
1116
+ * @param fallback - Optional fallback text if key is not found
1117
+ * @returns Observable that emits interpolated text
1276
1118
  *
1277
- * constructor() {}
1278
- * }
1279
- * ```
1119
+ * @deprecated Use getContentWithInterpolation instead
1280
1120
  */
1281
- forComponent(className) {
1282
- return {
1283
- /**
1284
- * Get a single content string reactively for this component.
1285
- * Supports optional interpolation.
1286
- */
1287
- get: (key, options) => {
1288
- return this.fromContent({
1289
- className,
1290
- key,
1291
- fallback: options?.fallback,
1292
- interpolation: options?.interpolation,
1293
- });
1294
- },
1295
- /**
1296
- * Get content with interpolation for this component.
1297
- * @deprecated Use get() with interpolation option instead.
1298
- */
1299
- getWithInterpolation: (key, interpolation, fallback) => {
1300
- return this.fromContent({
1301
- className,
1302
- key,
1303
- interpolation,
1304
- fallback,
1305
- });
1306
- },
1307
- /**
1308
- * Get multiple content strings for this component.
1309
- */
1310
- getMultiple: (keys) => {
1311
- return this.fromMultipleContent(className, keys);
1312
- },
1313
- /**
1314
- * Get a single content string synchronously for this component.
1315
- */
1316
- getText: (key, fallback) => {
1317
- return this.getText(className, key, fallback);
1318
- },
1319
- /**
1320
- * Check if a content key exists for this component.
1321
- */
1322
- hasContent: (key) => {
1323
- return this.hasContent(className, key);
1324
- },
1325
- };
1121
+ fromContentWithInterpolation(className, key, interpolationData, fallback) {
1122
+ return this.getContentWithInterpolation(className, key, interpolationData, fallback);
1123
+ }
1124
+ // Legacy getters/setters for backward compatibility
1125
+ get Lang() {
1126
+ return this.currentLang;
1326
1127
  }
1327
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentService, deps: [{ token: LangService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1328
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentService, providedIn: 'root' }); }
1128
+ set Lang(lang) {
1129
+ this.setLang(lang);
1130
+ }
1131
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, deps: [{ token: ValtechConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1132
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, providedIn: 'root' }); }
1329
1133
  }
1330
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentService, decorators: [{
1134
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, decorators: [{
1331
1135
  type: Injectable,
1332
1136
  args: [{
1333
1137
  providedIn: 'root',
1334
1138
  }]
1335
- }], ctorParameters: () => [{ type: LangService }] });
1139
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
1140
+ type: Inject,
1141
+ args: [ValtechConfigService]
1142
+ }] }] });
1336
1143
 
1337
1144
  /**
1338
1145
  * val-button
@@ -1376,10 +1183,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1376
1183
  * @output onClick - Emits when the button is clicked
1377
1184
  */
1378
1185
  class ButtonComponent {
1379
- constructor(download, icon, navigation, contentService) {
1186
+ constructor(download, icon, navigation, langService) {
1380
1187
  this.download = download;
1381
1188
  this.navigation = navigation;
1382
- this.contentService = contentService;
1189
+ this.langService = langService;
1383
1190
  this.states = ComponentStates;
1384
1191
  this.subscriptions = new Subscription();
1385
1192
  /**
@@ -1401,26 +1208,25 @@ class ButtonComponent {
1401
1208
  setupDisplayText() {
1402
1209
  if (this.props.text) {
1403
1210
  // Static text takes precedence
1404
- this.displayText$ = of(this.props.text);
1211
+ if (this.props.contentInterpolation) {
1212
+ // Static text with interpolation
1213
+ const interpolatedText = interpolateStaticContent(this.props.text, this.props.contentInterpolation);
1214
+ this.displayText$ = of(interpolatedText);
1215
+ }
1216
+ else {
1217
+ // Simple static text
1218
+ this.displayText$ = of(this.props.text);
1219
+ }
1405
1220
  }
1406
1221
  else if (this.props.contentKey && this.props.contentClass) {
1407
1222
  // Reactive content from language service
1408
1223
  if (this.props.contentInterpolation) {
1409
1224
  // With interpolation
1410
- this.displayText$ = this.contentService.fromContentWithInterpolation({
1411
- className: this.props.contentClass,
1412
- key: this.props.contentKey,
1413
- fallback: this.props.contentFallback,
1414
- interpolation: this.props.contentInterpolation,
1415
- });
1225
+ this.displayText$ = this.langService.getContentWithInterpolation(this.props.contentClass, this.props.contentKey, this.props.contentInterpolation, this.props.contentFallback);
1416
1226
  }
1417
1227
  else {
1418
1228
  // Simple reactive content
1419
- this.displayText$ = this.contentService.fromContent({
1420
- className: this.props.contentClass,
1421
- key: this.props.contentKey,
1422
- fallback: this.props.contentFallback,
1423
- });
1229
+ this.displayText$ = this.langService.getContent(this.props.contentClass, this.props.contentKey, this.props.contentFallback);
1424
1230
  }
1425
1231
  }
1426
1232
  else {
@@ -1444,7 +1250,7 @@ class ButtonComponent {
1444
1250
  }
1445
1251
  this.onClick.emit(this.props.token);
1446
1252
  }
1447
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ButtonComponent, deps: [{ token: DownloadService }, { token: IconService }, { token: NavigationService }, { token: ContentService }], target: i0.ɵɵFactoryTarget.Component }); }
1253
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ButtonComponent, deps: [{ token: DownloadService }, { token: IconService }, { token: NavigationService }, { token: LangService }], target: i0.ɵɵFactoryTarget.Component }); }
1448
1254
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ButtonComponent, isStandalone: true, selector: "val-button", inputs: { props: "props" }, outputs: { onClick: "onClick" }, ngImport: i0, template: `
1449
1255
  <ion-button
1450
1256
  [type]="props.type"
@@ -1486,7 +1292,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1486
1292
  <ion-text *ngIf="props.state !== states.WORKING">{{ displayText$ | async }}</ion-text>
1487
1293
  </ion-button>
1488
1294
  `, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-button{font-family:var(--ion-default-font),Arial,sans-serif;min-width:6.25rem;margin:0}ion-button.small{--padding-bottom: 12px;--padding-end: 14px;--padding-start: 14px;--padding-top: 12px}ion-button.button-clear{padding:0;margin:0}\n"] }]
1489
- }], ctorParameters: () => [{ type: DownloadService }, { type: IconService }, { type: NavigationService }, { type: ContentService }], propDecorators: { props: [{
1295
+ }], ctorParameters: () => [{ type: DownloadService }, { type: IconService }, { type: NavigationService }, { type: LangService }], propDecorators: { props: [{
1490
1296
  type: Input
1491
1297
  }], onClick: [{
1492
1298
  type: Output
@@ -1763,9 +1569,9 @@ const SecondarySolidBlockIconHrefButton = (text, icon, href, target) => {
1763
1569
  * @input props: DisplayMetadata - Configuration for the display (content/contentConfig, color, size)
1764
1570
  */
1765
1571
  class DisplayComponent {
1766
- constructor(contentService) {
1767
- this.contentService = contentService;
1572
+ constructor() {
1768
1573
  this.subscriptions = new Subscription();
1574
+ this.langService = inject(LangService);
1769
1575
  }
1770
1576
  ngOnInit() {
1771
1577
  this.initializeDisplayContent();
@@ -1781,18 +1587,15 @@ class DisplayComponent {
1781
1587
  }
1782
1588
  // Use reactive content if configured
1783
1589
  if (this.props.contentConfig) {
1784
- this.displayContent$ = this.contentService.fromContent({
1785
- className: this.props.contentConfig.className || '_global',
1786
- key: this.props.contentConfig.key,
1787
- fallback: this.props.contentConfig.fallback || this.props.contentConfig.key,
1788
- interpolation: this.props.contentConfig.interpolation,
1789
- });
1590
+ this.displayContent$ = this.langService.getContent(this.props.contentConfig.className || '_global', this.props.contentConfig.key, this.props.contentConfig.fallback || this.props.contentConfig.key
1591
+ // interpolation: this.props.contentConfig.interpolation,
1592
+ );
1790
1593
  return;
1791
1594
  }
1792
1595
  // No content configured - use empty string
1793
1596
  this.displayContent$ = of('');
1794
1597
  }
1795
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DisplayComponent, deps: [{ token: ContentService }], target: i0.ɵɵFactoryTarget.Component }); }
1598
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DisplayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1796
1599
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: DisplayComponent, isStandalone: true, selector: "val-display", inputs: { props: "props" }, ngImport: i0, template: `
1797
1600
  <ion-text [color]="props.color">
1798
1601
  <p [class]="props.size">
@@ -1810,7 +1613,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1810
1613
  </p>
1811
1614
  </ion-text>
1812
1615
  `, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.small{font-size:1.5rem;line-height:2rem;font-weight:800}@media (min-width: 768px){.small{font-size:2rem;line-height:2.5rem}}.medium{font-size:2rem;line-height:2.5rem;font-weight:800}@media (min-width: 768px){.medium{font-size:2.5rem;line-height:3rem}}.large{font-size:2.5rem;line-height:3rem;font-weight:800}@media (min-width: 768px){.large{font-size:3rem;line-height:3.5rem}}.xlarge{font-size:3rem;line-height:2.5rem;font-weight:800}@media (min-width: 768px){.xlarge{font-size:4.375rem;line-height:4.125rem}}\n"] }]
1813
- }], ctorParameters: () => [{ type: ContentService }], propDecorators: { props: [{
1616
+ }], ctorParameters: () => [], propDecorators: { props: [{
1814
1617
  type: Input
1815
1618
  }] } });
1816
1619
  /**
@@ -2592,8 +2395,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2592
2395
  * @input props: TextMetadata - Configuration for the text (content, styling, and reactive content options)
2593
2396
  */
2594
2397
  class TextComponent {
2595
- constructor(contentService, linkProcessor) {
2596
- this.contentService = contentService;
2398
+ constructor(langService, linkProcessor) {
2399
+ this.langService = langService;
2597
2400
  this.linkProcessor = linkProcessor;
2598
2401
  this.subscription = new Subscription();
2599
2402
  }
@@ -2610,26 +2413,25 @@ class TextComponent {
2610
2413
  setupDisplayContent() {
2611
2414
  if (this.props.content) {
2612
2415
  // Static content takes precedence
2613
- this.displayContent$ = of(this.props.content);
2416
+ if (this.props.contentInterpolation) {
2417
+ // Static content with interpolation
2418
+ const interpolatedContent = interpolateStaticContent(this.props.content, this.props.contentInterpolation);
2419
+ this.displayContent$ = of(interpolatedContent);
2420
+ }
2421
+ else {
2422
+ // Simple static content
2423
+ this.displayContent$ = of(this.props.content);
2424
+ }
2614
2425
  }
2615
- else if (this.props.contentKey && this.props.contentClass) {
2426
+ else if (shouldUseReactiveContent(this.props)) {
2616
2427
  // Reactive content from language service
2617
2428
  if (this.props.contentInterpolation) {
2618
2429
  // With interpolation
2619
- this.displayContent$ = this.contentService.fromContentWithInterpolation({
2620
- className: this.props.contentClass,
2621
- key: this.props.contentKey,
2622
- fallback: this.props.contentFallback,
2623
- interpolation: this.props.contentInterpolation,
2624
- });
2430
+ this.displayContent$ = this.langService.getContentWithInterpolation(this.props.contentClass, this.props.contentKey, this.props.contentInterpolation, this.props.contentFallback);
2625
2431
  }
2626
2432
  else {
2627
2433
  // Simple reactive content
2628
- this.displayContent$ = this.contentService.fromContent({
2629
- className: this.props.contentClass,
2630
- key: this.props.contentKey,
2631
- fallback: this.props.contentFallback,
2632
- });
2434
+ this.displayContent$ = this.langService.getContent(this.props.contentClass, this.props.contentKey, this.props.contentFallback);
2633
2435
  }
2634
2436
  }
2635
2437
  else {
@@ -2654,7 +2456,7 @@ class TextComponent {
2654
2456
  processedContent = processedContent.replace(/<strong>(.*?)<\/strong>/gi, '<span class="partial-bold">$1</span>');
2655
2457
  return processedContent;
2656
2458
  }
2657
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TextComponent, deps: [{ token: ContentService }, { token: LinkProcessorService }], target: i0.ɵɵFactoryTarget.Component }); }
2459
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TextComponent, deps: [{ token: LangService }, { token: LinkProcessorService }], target: i0.ɵɵFactoryTarget.Component }); }
2658
2460
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: TextComponent, isStandalone: true, selector: "val-text", inputs: { props: "props" }, ngImport: i0, template: `
2659
2461
  <ion-text [color]="props.color">
2660
2462
  @if (props.processLinks) {
@@ -2694,7 +2496,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2694
2496
  }
2695
2497
  </ion-text>
2696
2498
  `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.small{font-size:.75rem;line-height:1.25rem;font-weight:400}.small.bold{font-size:.75rem;line-height:1.25rem;font-weight:700}.medium{font-size:.875rem;line-height:1.5rem;font-weight:400}@media (min-width: 768px){.medium{font-size:1rem;line-height:1.5rem}}.medium.bold{font-size:.875rem;line-height:1.5rem;font-weight:700}@media (min-width: 768px){.medium.bold{font-size:1rem;line-height:1.5rem}}.large{font-size:1rem;line-height:1.5rem;font-weight:400}@media (min-width: 768px){.large{font-size:1.125rem;line-height:1.5rem}}.large.bold{font-size:1rem;line-height:1.5rem;font-weight:700}@media (min-width: 768px){.large.bold{font-size:1.125rem;line-height:1.5rem}}.xlarge{font-size:1.125rem;line-height:1.5rem;font-weight:400}@media (min-width: 768px){.xlarge{font-size:1.5rem;line-height:2rem}}.xlarge.bold{font-size:1.125rem;line-height:1.5rem;font-weight:700}@media (min-width: 768px){.xlarge.bold{font-size:1.5rem;line-height:2rem}}:host ::ng-deep .partial-bold{font-weight:700}\n"] }]
2697
- }], ctorParameters: () => [{ type: ContentService }, { type: LinkProcessorService }], propDecorators: { props: [{
2499
+ }], ctorParameters: () => [{ type: LangService }, { type: LinkProcessorService }], propDecorators: { props: [{
2698
2500
  type: Input
2699
2501
  }] } });
2700
2502
  /**
@@ -2750,123 +2552,6 @@ function createTextProps(contentConfig, styleConfig = {}) {
2750
2552
  };
2751
2553
  }
2752
2554
 
2753
- /**
2754
- * Enhanced content utilities for multi-language component support.
2755
- * Extends the base content utilities to provide specialized helpers for different component patterns.
2756
- */
2757
- /**
2758
- * Helper class for managing reactive content in components.
2759
- */
2760
- class ComponentContentHelper {
2761
- constructor(contentService, defaultClassName) {
2762
- this.contentService = contentService;
2763
- this.defaultClassName = defaultClassName;
2764
- }
2765
- /**
2766
- * Resolves content based on hybrid configuration (static vs reactive).
2767
- */
2768
- resolveContent(config) {
2769
- // Static content takes precedence
2770
- if (config.content !== undefined) {
2771
- return config.content;
2772
- }
2773
- // Use reactive content if configured
2774
- if (config.contentConfig) {
2775
- return this.contentService.fromContent({
2776
- className: config.contentConfig.className || this.defaultClassName || '_global',
2777
- key: config.contentConfig.key,
2778
- fallback: config.contentConfig.fallback,
2779
- interpolation: config.contentConfig.interpolation,
2780
- });
2781
- }
2782
- // No content configured
2783
- return '';
2784
- }
2785
- /**
2786
- * Resolves multiple text properties for components with multiple text fields.
2787
- */
2788
- resolveMultipleTexts(config) {
2789
- const result = {};
2790
- Object.entries(config.textConfigs).forEach(([property, contentConfig]) => {
2791
- result[property] = this.contentService.fromContent({
2792
- className: contentConfig.className || this.defaultClassName || '_global',
2793
- key: contentConfig.key,
2794
- fallback: contentConfig.fallback,
2795
- interpolation: contentConfig.interpolation,
2796
- });
2797
- });
2798
- return result;
2799
- }
2800
- /**
2801
- * Creates a reactive content configuration for array items.
2802
- * Useful for list components where items might have translatable text.
2803
- */
2804
- createArrayItemConfig(baseKey, index, fallback) {
2805
- return {
2806
- className: this.defaultClassName || '_global',
2807
- key: `${baseKey}.${index}`,
2808
- fallback: fallback,
2809
- };
2810
- }
2811
- /**
2812
- * Helper for button/action text that commonly needs translation.
2813
- */
2814
- createActionConfig(actionKey, fallback) {
2815
- return {
2816
- className: '_global',
2817
- key: actionKey,
2818
- fallback: fallback,
2819
- };
2820
- }
2821
- }
2822
- /**
2823
- * Factory function to create content helpers for components.
2824
- */
2825
- function createComponentContentHelper(contentService, componentClassName) {
2826
- return new ComponentContentHelper(contentService, componentClassName);
2827
- }
2828
- /**
2829
- * Utility function to determine if content should be reactive.
2830
- */
2831
- function shouldUseReactiveContent(config) {
2832
- return config.content === undefined && config.contentConfig !== undefined;
2833
- }
2834
- /**
2835
- * Enhanced props factory for components that support reactive content.
2836
- */
2837
- function createReactiveProps(contentHelper, staticProps, contentConfig) {
2838
- return {
2839
- ...staticProps,
2840
- ...contentConfig,
2841
- };
2842
- }
2843
- /**
2844
- * Helper for list components that need to mix static and reactive content.
2845
- */
2846
- class ListContentHelper {
2847
- constructor(contentHelper) {
2848
- this.contentHelper = contentHelper;
2849
- }
2850
- /**
2851
- * Resolves a list configuration into final items.
2852
- */
2853
- resolveListItems(config) {
2854
- const items = [];
2855
- // Add static items first
2856
- if (config.staticItems) {
2857
- items.push(...config.staticItems);
2858
- }
2859
- // Add reactive items
2860
- if (config.reactiveItems) {
2861
- for (let i = 0; i < config.reactiveItems.count; i++) {
2862
- const item = config.reactiveItems.itemTemplate(this.contentHelper, i);
2863
- items.push(item);
2864
- }
2865
- }
2866
- return items;
2867
- }
2868
- }
2869
-
2870
2555
  /**
2871
2556
  * val-title
2872
2557
  *
@@ -2906,14 +2591,14 @@ class ListContentHelper {
2906
2591
  */
2907
2592
  class TitleComponent {
2908
2593
  constructor() {
2909
- this.contentService = inject(ContentService);
2594
+ this.langService = inject(LangService);
2910
2595
  }
2911
2596
  ngOnInit() {
2912
- this.contentHelper = createComponentContentHelper(this.contentService);
2913
2597
  // Always convert to Observable for consistent template handling
2914
2598
  if (shouldUseReactiveContent(this.props)) {
2915
- // Use reactive content
2916
- this.displayContent$ = this.contentHelper.resolveContent(this.props);
2599
+ // Use reactive content with LangService
2600
+ const config = extractContentConfig(this.props);
2601
+ this.displayContent$ = this.langService.getContent(config.className, config.key, config.fallback);
2917
2602
  }
2918
2603
  else {
2919
2604
  // Convert static content to Observable
@@ -2978,7 +2663,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2978
2663
  * ```typescript
2979
2664
  * const props = createTitleProps(
2980
2665
  * { size: 'large', color: 'primary', bold: true },
2981
- * { contentConfig: { key: 'pageTitle', fallback: 'Default Title' } }
2666
+ * {
2667
+ * contentKey: 'pageTitle',
2668
+ * contentClass: 'MyComponent',
2669
+ * contentFallback: 'Default Title'
2670
+ * }
2982
2671
  * );
2983
2672
  * ```
2984
2673
  */
@@ -3013,8 +2702,8 @@ class AlertBoxComponent {
3013
2702
  getLegacyTextProps() {
3014
2703
  return this.props.text;
3015
2704
  }
3016
- constructor(contentService) {
3017
- this.contentService = contentService;
2705
+ constructor(langService) {
2706
+ this.langService = langService;
3018
2707
  this.subscriptions = new Subscription();
3019
2708
  }
3020
2709
  ngOnInit() {
@@ -3043,7 +2732,7 @@ class AlertBoxComponent {
3043
2732
  this.computedTextProps.contentConfig = reactiveProps.textConfig;
3044
2733
  }
3045
2734
  }
3046
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AlertBoxComponent, deps: [{ token: ContentService }], target: i0.ɵɵFactoryTarget.Component }); }
2735
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AlertBoxComponent, deps: [{ token: LangService }], target: i0.ɵɵFactoryTarget.Component }); }
3047
2736
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: AlertBoxComponent, isStandalone: true, selector: "val-alert-box", inputs: { props: "props" }, ngImport: i0, template: `
3048
2737
  <val-box [props]="props.box">
3049
2738
  <div class="content-container" body>
@@ -3073,7 +2762,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3073
2762
  </div>
3074
2763
  </val-box>
3075
2764
  `, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.text{margin-left:.25rem}.content-container{display:flex;align-items:flex-start}\n"] }]
3076
- }], ctorParameters: () => [{ type: ContentService }], propDecorators: { props: [{
2765
+ }], ctorParameters: () => [{ type: LangService }], propDecorators: { props: [{
3077
2766
  type: Input
3078
2767
  }] } });
3079
2768
 
@@ -4271,9 +3960,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
4271
3960
  * @output languageChange: EventEmitter<string> - Emitted when language changes
4272
3961
  */
4273
3962
  class LanguageSelectorComponent {
4274
- constructor(langService, contentService) {
3963
+ constructor(langService) {
4275
3964
  this.langService = langService;
4276
- this.contentService = contentService;
4277
3965
  /**
4278
3966
  * Language selector configuration object.
4279
3967
  * @type {LanguageSelectorMetadata}
@@ -4337,20 +4025,11 @@ class LanguageSelectorComponent {
4337
4025
  }
4338
4026
  else if (this.props.labelConfig) {
4339
4027
  // Reactive label
4340
- this.label$ = this.contentService.fromContent({
4341
- className: this.props.labelConfig.className || '_global',
4342
- key: this.props.labelConfig.key,
4343
- fallback: this.props.labelConfig.fallback || 'Language',
4344
- interpolation: this.props.labelConfig.interpolation,
4345
- });
4028
+ this.label$ = this.langService.getContent(this.props.labelConfig.className || '_global', this.props.labelConfig.key, this.props.labelConfig.fallback || 'Language');
4346
4029
  }
4347
4030
  else {
4348
4031
  // Default label from global content
4349
- this.label$ = this.contentService.fromContent({
4350
- className: '_global',
4351
- key: 'language',
4352
- fallback: 'Idioma',
4353
- });
4032
+ this.label$ = this.langService.getContent('_global', 'language', 'Idioma');
4354
4033
  }
4355
4034
  }
4356
4035
  initializePopoverProps() {
@@ -4431,7 +4110,7 @@ class LanguageSelectorComponent {
4431
4110
  this.languageChange.emit(selectedLanguage);
4432
4111
  }
4433
4112
  }
4434
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LanguageSelectorComponent, deps: [{ token: LangService }, { token: ContentService }], target: i0.ɵɵFactoryTarget.Component }); }
4113
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LanguageSelectorComponent, deps: [{ token: LangService }], target: i0.ɵɵFactoryTarget.Component }); }
4435
4114
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LanguageSelectorComponent, isStandalone: true, selector: "val-language-selector", inputs: { props: "props" }, outputs: { languageChange: "languageChange" }, ngImport: i0, template: `
4436
4115
  <val-popover-selector [props]="popoverProps" (selectionChange)="onLanguageChange($event)"> </val-popover-selector>
4437
4116
  `, isInline: true, styles: [":host{display:inline-block;width:auto}val-popover-selector .popover-selector-container{display:inline-block;width:auto}val-popover-selector .selector-trigger .trigger-text{display:inline-flex;align-items:center;gap:8px;font-weight:700}val-popover-selector .selector-trigger .trigger-text .flag-emoji{font-size:1.2em;line-height:1;filter:drop-shadow(0 1px 2px rgba(0,0,0,.1));transition:transform .2s ease}val-popover-selector .selector-trigger.has-flag .trigger-text{letter-spacing:.025em}val-popover-selector .selector-trigger:hover:not([disabled]) .trigger-text .flag-emoji{transform:scale(1.1)}val-popover-selector .option-content{gap:10px;padding:8px 0}val-popover-selector .option-content .flag-emoji{font-size:1.1em;filter:drop-shadow(0 1px 2px rgba(0,0,0,.08))}val-popover-selector .option-content span{font-weight:600;letter-spacing:.01em}.language-flag{font-size:1.2em;margin-right:6px;vertical-align:middle;line-height:1;filter:drop-shadow(0 1px 3px rgba(0,0,0,.1));transition:all .2s ease}@media (max-width: 768px){val-popover-selector .selector-trigger .trigger-text{font-size:13px;gap:6px}val-popover-selector .selector-trigger .trigger-text .flag-emoji{font-size:1.1em}}val-popover-selector .selector-trigger:hover:not([disabled]) .trigger-text .flag-emoji{transform:scale(1.1) rotate(3deg);transition:transform .25s cubic-bezier(.4,0,.2,1)}val-popover-selector .selector-trigger:active .trigger-text .flag-emoji{transform:scale(1.05)}val-popover-selector .language-changing .flag-emoji{animation:languageSwitch .4s ease-in-out}@keyframes languageSwitch{0%{transform:scale(1)}50%{transform:scale(1.15) rotate(8deg)}to{transform:scale(1)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PopoverSelectorComponent, selector: "val-popover-selector", inputs: ["props"], outputs: ["selectionChange"] }] }); }
@@ -4441,7 +4120,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
4441
4120
  args: [{ selector: 'val-language-selector', standalone: true, imports: [CommonModule, PopoverSelectorComponent], template: `
4442
4121
  <val-popover-selector [props]="popoverProps" (selectionChange)="onLanguageChange($event)"> </val-popover-selector>
4443
4122
  `, styles: [":host{display:inline-block;width:auto}val-popover-selector .popover-selector-container{display:inline-block;width:auto}val-popover-selector .selector-trigger .trigger-text{display:inline-flex;align-items:center;gap:8px;font-weight:700}val-popover-selector .selector-trigger .trigger-text .flag-emoji{font-size:1.2em;line-height:1;filter:drop-shadow(0 1px 2px rgba(0,0,0,.1));transition:transform .2s ease}val-popover-selector .selector-trigger.has-flag .trigger-text{letter-spacing:.025em}val-popover-selector .selector-trigger:hover:not([disabled]) .trigger-text .flag-emoji{transform:scale(1.1)}val-popover-selector .option-content{gap:10px;padding:8px 0}val-popover-selector .option-content .flag-emoji{font-size:1.1em;filter:drop-shadow(0 1px 2px rgba(0,0,0,.08))}val-popover-selector .option-content span{font-weight:600;letter-spacing:.01em}.language-flag{font-size:1.2em;margin-right:6px;vertical-align:middle;line-height:1;filter:drop-shadow(0 1px 3px rgba(0,0,0,.1));transition:all .2s ease}@media (max-width: 768px){val-popover-selector .selector-trigger .trigger-text{font-size:13px;gap:6px}val-popover-selector .selector-trigger .trigger-text .flag-emoji{font-size:1.1em}}val-popover-selector .selector-trigger:hover:not([disabled]) .trigger-text .flag-emoji{transform:scale(1.1) rotate(3deg);transition:transform .25s cubic-bezier(.4,0,.2,1)}val-popover-selector .selector-trigger:active .trigger-text .flag-emoji{transform:scale(1.05)}val-popover-selector .language-changing .flag-emoji{animation:languageSwitch .4s ease-in-out}@keyframes languageSwitch{0%{transform:scale(1)}50%{transform:scale(1.15) rotate(8deg)}to{transform:scale(1)}}\n"] }]
4444
- }], ctorParameters: () => [{ type: LangService }, { type: ContentService }], propDecorators: { props: [{
4123
+ }], ctorParameters: () => [{ type: LangService }], propDecorators: { props: [{
4445
4124
  type: Input
4446
4125
  }], languageChange: [{
4447
4126
  type: Output
@@ -8109,187 +7788,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
8109
7788
  type: Output
8110
7789
  }] } });
8111
7790
 
8112
- /**
8113
- * ContentLoader Service - Dynamic content loading system.
8114
- *
8115
- * REFACTORED: Now uses ValtechConfigService properly instead of hacking LangService.
8116
- * This provides a clean, maintainable way to register content dynamically.
8117
- *
8118
- * @example Basic usage:
8119
- * ```typescript
8120
- * // user-page.content.ts
8121
- * export const UserPageContent = {
8122
- * es: { title: 'Mi Página de Usuario', welcome: 'Bienvenido {{name}}' },
8123
- * en: { title: 'My User Page', welcome: 'Welcome {{name}}' }
8124
- * };
8125
- *
8126
- * // In component
8127
- * import { UserPageContent } from './user-page.content';
8128
- * registerContent('UserPage', UserPageContent);
8129
- * ```
8130
- */
8131
- class ContentLoaderService {
8132
- constructor() {
8133
- this.valtechConfig = inject(ValtechConfigService);
8134
- this.registeredContent = new Map();
8135
- }
8136
- /**
8137
- * Register content for a specific component/page class.
8138
- * ✅ CLEAN: Uses proper ValtechConfigService API instead of hacking LangService
8139
- */
8140
- registerContent(className, content) {
8141
- // Store locally for tracking
8142
- this.registeredContent.set(className, content);
8143
- // Update the configuration properly
8144
- this.addContentToProvider(className, content);
8145
- console.log(`✅ ContentLoader: Registered content for "${className}"`);
8146
- }
8147
- /**
8148
- * Register multiple content modules at once.
8149
- */
8150
- loadContent(contentModules) {
8151
- console.log(`🔄 ContentLoader: Loading ${contentModules.length} content modules...`);
8152
- contentModules.forEach(module => {
8153
- this.registerContent(module.className, module.content);
8154
- });
8155
- console.log('✅ ContentLoader: All content modules loaded successfully');
8156
- }
8157
- /**
8158
- * Check if content is registered for a class.
8159
- */
8160
- hasContentFor(className) {
8161
- return this.registeredContent.has(className);
8162
- }
8163
- /**
8164
- * Get all registered class names.
8165
- */
8166
- getRegisteredClasses() {
8167
- return Array.from(this.registeredContent.keys());
8168
- }
8169
- /**
8170
- * Get registered content for a specific class.
8171
- */
8172
- getContentFor(className) {
8173
- return this.registeredContent.get(className);
8174
- }
8175
- /**
8176
- * Remove content registration for a class.
8177
- */
8178
- unregisterContent(className) {
8179
- const existed = this.registeredContent.has(className);
8180
- this.registeredContent.delete(className);
8181
- // Also remove from the provider
8182
- if (existed && this.valtechConfig.content) {
8183
- const updatedContent = { ...this.valtechConfig.content };
8184
- delete updatedContent[className];
8185
- this.valtechConfig.content = updatedContent;
8186
- console.log(`🗑️ ContentLoader: Unregistered content for "${className}"`);
8187
- }
8188
- return existed;
8189
- }
8190
- /**
8191
- * Clear all registered content.
8192
- */
8193
- clearAllContent() {
8194
- this.registeredContent.clear();
8195
- console.log('🧹 ContentLoader: Cleared all registered content');
8196
- }
8197
- /**
8198
- * Get current content provider state.
8199
- * Useful for debugging.
8200
- */
8201
- getContentProvider() {
8202
- return this.valtechConfig.content;
8203
- }
8204
- /**
8205
- * ✅ CLEAN: Add content to provider using proper API
8206
- * @private
8207
- */
8208
- addContentToProvider(className, content) {
8209
- try {
8210
- // Get current content provider
8211
- const currentContent = this.valtechConfig.content || {};
8212
- // Create TextContent instance
8213
- const textContent = new TextContent(content);
8214
- // Update the content provider properly
8215
- const updatedContent = {
8216
- ...currentContent,
8217
- [className]: textContent,
8218
- };
8219
- // Set the updated content - this is the clean way
8220
- this.valtechConfig.content = updatedContent;
8221
- console.log(`📝 ContentLoader: Added "${className}" to content provider`);
8222
- }
8223
- catch (error) {
8224
- console.error(`❌ ContentLoader: Error adding content for "${className}":`, error);
8225
- }
8226
- }
8227
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
8228
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentLoaderService, providedIn: 'root' }); }
8229
- }
8230
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentLoaderService, decorators: [{
8231
- type: Injectable,
8232
- args: [{
8233
- providedIn: 'root',
8234
- }]
8235
- }] });
8236
- /**
8237
- * Helper function to create a content module.
8238
- */
8239
- function createContentModule(className, content) {
8240
- return { className, content };
8241
- }
8242
- /**
8243
- * ✅ CLEAN: Global registry using proper array instead of globalThis hack
8244
- */
8245
- const globalContentRegistry = [];
8246
- /**
8247
- * Simple function to register content directly.
8248
- * ✅ IMPROVED: Cleaner global registry management
8249
- */
8250
- function registerContent(className, content) {
8251
- // Add to global registry
8252
- globalContentRegistry.push({ className, content });
8253
- console.log(`📝 registerContent: Queued "${className}" for registration`);
8254
- }
8255
- /**
8256
- * Load all content from the global registry.
8257
- * ✅ IMPROVED: Better error handling and logging
8258
- */
8259
- function loadRegisteredContent(contentLoader) {
8260
- if (globalContentRegistry.length === 0) {
8261
- console.log('ℹ️ ContentLoader: No content registered to load');
8262
- return;
8263
- }
8264
- console.log(`🚀 ContentLoader: Loading ${globalContentRegistry.length} registered content modules...`);
8265
- try {
8266
- // Load all content
8267
- contentLoader.loadContent([...globalContentRegistry]);
8268
- // Clear the registry after loading
8269
- globalContentRegistry.length = 0;
8270
- console.log('🎉 ContentLoader: All registered content loaded and registry cleared');
8271
- }
8272
- catch (error) {
8273
- console.error('❌ ContentLoader: Error loading registered content:', error);
8274
- }
8275
- }
8276
- /**
8277
- * ✅ NEW: Debugging helper
8278
- * Get current global registry state
8279
- */
8280
- function getRegisteredContentQueue() {
8281
- return [...globalContentRegistry];
8282
- }
8283
- /**
8284
- * ✅ NEW: Debugging helper
8285
- * Clear the global registry without loading
8286
- */
8287
- function clearRegisteredContentQueue() {
8288
- const count = globalContentRegistry.length;
8289
- globalContentRegistry.length = 0;
8290
- console.log(`🧹 ContentLoader: Cleared ${count} items from registration queue`);
8291
- }
8292
-
8293
7791
  const text = {
8294
7792
  es: {
8295
7793
  spanish: 'Español',
@@ -8456,6 +7954,191 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
8456
7954
  }]
8457
7955
  }], ctorParameters: () => [{ type: i2.ToastController }] });
8458
7956
 
7957
+ /**
7958
+ * Create a reactive content observable from a content key.
7959
+ * This is the primary utility for the `fromContent` pattern with unified support
7960
+ * for both simple content and content with interpolation.
7961
+ *
7962
+ * @param langService - The language service instance
7963
+ * @param config - Content configuration with optional interpolation
7964
+ * @returns Observable that emits the content string and updates on language change
7965
+ *
7966
+ * @example Simple content:
7967
+ * ```typescript
7968
+ * // Component-specific content
7969
+ * this.title$ = fromContent(this.langService, {
7970
+ * className: 'HeaderComponent',
7971
+ * key: 'title',
7972
+ * fallback: 'Default Title'
7973
+ * });
7974
+ *
7975
+ * // Global content (no className needed)
7976
+ * this.saveButton$ = fromContent(this.langService, {
7977
+ * key: 'save'
7978
+ * });
7979
+ * ```
7980
+ *
7981
+ * @example Content with interpolation:
7982
+ * ```typescript
7983
+ * // Content: "Hello {name}, you have {count} messages"
7984
+ * this.greeting$ = fromContent(this.langService, {
7985
+ * className: 'WelcomeComponent',
7986
+ * key: 'greeting',
7987
+ * interpolation: { name: 'John', count: 5 }
7988
+ * });
7989
+ * // Results in: "Hello John, you have 5 messages"
7990
+ * ```
7991
+ */
7992
+ function fromContent(langService, config) {
7993
+ // Use _global as default className if not provided
7994
+ const finalClassName = config.className || '_global';
7995
+ const contentObservable = langService.getContent(finalClassName, config.key, config.fallback);
7996
+ // If interpolation is provided, apply it
7997
+ if (config.interpolation) {
7998
+ return contentObservable.pipe(map(content => interpolateContent(content, config.interpolation)));
7999
+ }
8000
+ return contentObservable;
8001
+ }
8002
+ /**
8003
+ * Create a reactive content observable with interpolation support.
8004
+ *
8005
+ * @deprecated Use fromContent() with interpolation property instead.
8006
+ * This method is kept for backward compatibility.
8007
+ *
8008
+ * @param langService - The language service instance
8009
+ * @param config - Interpolated content configuration
8010
+ * @returns Observable that emits the interpolated content string
8011
+ *
8012
+ * @example Migration:
8013
+ * ```typescript
8014
+ * // OLD (deprecated):
8015
+ * this.greeting$ = fromContentWithInterpolation(this.langService, {
8016
+ * className: 'WelcomeComponent',
8017
+ * key: 'greeting',
8018
+ * interpolation: { name: 'John', count: 5 }
8019
+ * });
8020
+ *
8021
+ * // NEW (recommended):
8022
+ * this.greeting$ = fromContent(this.langService, {
8023
+ * className: 'WelcomeComponent',
8024
+ * key: 'greeting',
8025
+ * interpolation: { name: 'John', count: 5 }
8026
+ * });
8027
+ * ```
8028
+ */
8029
+ function fromContentWithInterpolation(langService, config) {
8030
+ // Delegate to the unified fromContent method
8031
+ return fromContent(langService, config);
8032
+ }
8033
+ /**
8034
+ * Create multiple reactive content observables at once.
8035
+ * Useful when a component needs several content strings.
8036
+ *
8037
+ * @param langService - The language service instance
8038
+ * @param className - The component class name
8039
+ * @param keys - Array of content keys to retrieve
8040
+ * @returns Observable that emits an object with all requested content
8041
+ *
8042
+ * @example
8043
+ * ```typescript
8044
+ * this.content$ = fromMultipleContent(this.langService, 'FormComponent', [
8045
+ * 'title', 'submitButton', 'cancelButton'
8046
+ * ]);
8047
+ *
8048
+ * // In template
8049
+ * <ng-container *ngIf="content$ | async as content">
8050
+ * <h2>{{ content.title }}</h2>
8051
+ * <button>{{ content.submitButton }}</button>
8052
+ * <button>{{ content.cancelButton }}</button>
8053
+ * </ng-container>
8054
+ * ```
8055
+ */
8056
+ function fromMultipleContent(langService, className, keys) {
8057
+ return langService.getMultipleContent(className, keys);
8058
+ }
8059
+ /**
8060
+ * Helper function to interpolate values into a content string.
8061
+ * Replaces placeholders in the format {key} with corresponding values.
8062
+ *
8063
+ * @param content - The content string with placeholders
8064
+ * @param values - Object with values to interpolate
8065
+ * @returns The interpolated string
8066
+ *
8067
+ * @example
8068
+ * ```typescript
8069
+ * const result = interpolateContent("Hello {name}!", { name: "World" });
8070
+ * // Returns: "Hello World!"
8071
+ * ```
8072
+ */
8073
+ function interpolateContent(content, values) {
8074
+ if (!values)
8075
+ return content;
8076
+ return Object.entries(values).reduce((result, [key, value]) => {
8077
+ return result.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
8078
+ }, content);
8079
+ }
8080
+ /**
8081
+ * Factory function to create a content helper bound to a specific component class.
8082
+ * This creates a more convenient API for components that need multiple content strings.
8083
+ *
8084
+ * @param langService - The language service instance
8085
+ * @param className - The component class name
8086
+ * @returns Object with convenient methods for content retrieval
8087
+ *
8088
+ * @example
8089
+ * ```typescript
8090
+ * export class MyComponent {
8091
+ * private content = createContentHelper(this.langService, 'MyComponent');
8092
+ *
8093
+ * constructor(private langService: LangService) {}
8094
+ *
8095
+ * ngOnInit() {
8096
+ * this.title$ = this.content.get('title');
8097
+ * this.allContent$ = this.content.getMultiple(['title', 'description']);
8098
+ * }
8099
+ * }
8100
+ * ```
8101
+ */
8102
+ function createContentHelper(langService, className) {
8103
+ return {
8104
+ /**
8105
+ * Get a single content string reactively.
8106
+ */
8107
+ get(key, fallback) {
8108
+ return fromContent(langService, { className, key, fallback });
8109
+ },
8110
+ /**
8111
+ * Get multiple content strings reactively.
8112
+ */
8113
+ getMultiple(keys) {
8114
+ return fromMultipleContent(langService, className, keys);
8115
+ },
8116
+ /**
8117
+ * Get content with interpolation.
8118
+ */
8119
+ getWithInterpolation(key, interpolation, fallback) {
8120
+ return fromContentWithInterpolation(langService, {
8121
+ className,
8122
+ key,
8123
+ interpolation,
8124
+ fallback,
8125
+ });
8126
+ },
8127
+ /**
8128
+ * Get a single content string synchronously (current language only).
8129
+ */
8130
+ getText(key, fallback) {
8131
+ return langService.getText(className, key, fallback);
8132
+ },
8133
+ /**
8134
+ * Check if a content key exists.
8135
+ */
8136
+ hasContent(key) {
8137
+ return langService.hasContent(className, key);
8138
+ },
8139
+ };
8140
+ }
8141
+
8459
8142
  /*
8460
8143
  * Public API Surface of valtech-components
8461
8144
  */
@@ -8464,5 +8147,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
8464
8147
  * Generated bundle index. Do not edit.
8465
8148
  */
8466
8149
 
8467
- export { ARTICLE_SPACING, ActionType, AlertBoxComponent, ArticleBuilder, ArticleComponent, AvatarComponent, BannerComponent, BaseDefault, BoxComponent, ButtonComponent, ButtonGroupComponent, CardComponent, CardSection, CardType, CheckInputComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CommentInputComponent, ComponentContentHelper, ComponentStates, ContentLoaderComponent, ContentLoaderService, ContentService, DateInputComponent, DisplayComponent, DividerComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FileInputComponent, FooterComponent, FormComponent, FormFooterComponent, GlobalContent, HeaderComponent, HintComponent, HourInputComponent, HrefComponent, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InputType, ItemListComponent, LANGUAGES, LangService, LanguageSelectorComponent, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessorService, LinksCakeComponent, ListContentHelper, LocalStorageService, MOTION, NavigationService, NoContentComponent, NotesBoxComponent, NumberInputComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PasswordInputComponent, PinInputComponent, PopoverSelectorComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProgressBarComponent, ProgressStatusComponent, PrompterComponent, RadioInputComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SelectSearchComponent, SimpleComponent, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, TextComponent, TextContent, TextInputComponent, ThemeOption, ThemeService, TitleBlockComponent, TitleComponent, ToastService, ToolbarActionType, ToolbarComponent, ValtechConfigService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, clearRegisteredContentQueue, content, createButtonProps, createComponentContentHelper, createContentHelper, createContentModule, createDisplayProps, createReactiveProps, createTextProps, createTitleProps, fromContent, fromContentWithInterpolation, fromMultipleContent, getRegisteredContentQueue, globalContentData, goToTop, interpolateContent, isAtEnd, loadRegisteredContent, maxLength, registerContent, replaceSpecialChars, resolveColor, resolveInputDefaultValue, shouldUseReactiveContent };
8150
+ export { ARTICLE_SPACING, ActionType, AlertBoxComponent, ArticleBuilder, ArticleComponent, AvatarComponent, BannerComponent, BaseDefault, BoxComponent, ButtonComponent, ButtonGroupComponent, CardComponent, CardSection, CardType, CheckInputComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CommentInputComponent, ComponentStates, ContentLoaderComponent, DateInputComponent, DisplayComponent, DividerComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FileInputComponent, FooterComponent, FormComponent, FormFooterComponent, GlobalContent, HeaderComponent, HintComponent, HourInputComponent, HrefComponent, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InputType, ItemListComponent, LANGUAGES, LangService, LanguageSelectorComponent, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessorService, LinksCakeComponent, LocalStorageService, MOTION, NavigationService, NoContentComponent, NotesBoxComponent, NumberInputComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PasswordInputComponent, PinInputComponent, PopoverSelectorComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProgressBarComponent, ProgressStatusComponent, PrompterComponent, RadioInputComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SelectSearchComponent, SimpleComponent, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, TextComponent, TextContent, TextInputComponent, ThemeOption, ThemeService, TitleBlockComponent, TitleComponent, ToastService, ToolbarActionType, ToolbarComponent, ValtechConfigService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, content, createButtonProps, createContentHelper, createDisplayProps, createReactiveContentMetadata, createTextProps, createTitleProps, extractContentConfig, extractContentConfigWithInterpolation, fromContent, fromContentWithInterpolation, fromMultipleContent, globalContentData, goToTop, interpolateContent, interpolateStaticContent, isAtEnd, maxLength, replaceSpecialChars, resolveColor, resolveInputDefaultValue, shouldUseReactiveContent, shouldUseReactiveContentWithInterpolation };
8468
8151
  //# sourceMappingURL=valtech-components.mjs.map