valtech-components 2.0.729 → 2.0.730

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 (25) hide show
  1. package/esm2022/lib/services/markdown-article/legal-content.service.mjs +65 -14
  2. package/esm2022/lib/services/markdown-article/markdown-article-parser.mjs +266 -0
  3. package/esm2022/lib/services/markdown-article/markdown-article-parser.service.mjs +6 -275
  4. package/esm2022/lib/services/preferences/index.mjs +3 -0
  5. package/esm2022/lib/services/preferences/preferences.service.mjs +164 -0
  6. package/esm2022/lib/services/preferences/preferences.types.mjs +7 -0
  7. package/esm2022/lib/version.mjs +2 -2
  8. package/esm2022/public-api.mjs +7 -1
  9. package/fesm2022/valtech-components.mjs +452 -244
  10. package/fesm2022/valtech-components.mjs.map +1 -1
  11. package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +1 -1
  12. package/lib/components/atoms/text/text.component.d.ts +1 -1
  13. package/lib/components/molecules/features-list/features-list.component.d.ts +1 -1
  14. package/lib/components/organisms/article/article.component.d.ts +3 -3
  15. package/lib/components/organisms/bottom-nav/bottom-nav.component.d.ts +1 -1
  16. package/lib/components/organisms/toolbar/toolbar.component.d.ts +1 -1
  17. package/lib/services/markdown-article/legal-content.service.d.ts +49 -7
  18. package/lib/services/markdown-article/markdown-article-parser.d.ts +16 -0
  19. package/lib/services/markdown-article/markdown-article-parser.service.d.ts +3 -22
  20. package/lib/services/preferences/index.d.ts +2 -0
  21. package/lib/services/preferences/preferences.service.d.ts +51 -0
  22. package/lib/services/preferences/preferences.types.d.ts +35 -0
  23. package/lib/version.d.ts +1 -1
  24. package/package.json +1 -1
  25. package/public-api.d.ts +2 -0
@@ -43,7 +43,7 @@ export declare class RightsFooterComponent {
43
43
  /**
44
44
  * Computed helper for color prop in template.
45
45
  */
46
- propsColor: import("@angular/core").Signal<"primary" | "secondary" | "tertiary" | "success" | "warning" | "danger" | "light" | "medium" | "dark">;
46
+ propsColor: import("@angular/core").Signal<"medium" | "primary" | "secondary" | "tertiary" | "success" | "warning" | "danger" | "light" | "dark">;
47
47
  /**
48
48
  * Computed helper for withMargin prop in template.
49
49
  */
@@ -11,7 +11,7 @@ export declare class TextComponent {
11
11
  */
12
12
  displayContent: import("@angular/core").Signal<string>;
13
13
  propsColor: import("@angular/core").Signal<import("@ionic/core").Color>;
14
- propsSize: import("@angular/core").Signal<"medium" | "small" | "large" | "xlarge">;
14
+ propsSize: import("@angular/core").Signal<"small" | "medium" | "large" | "xlarge">;
15
15
  propsBold: import("@angular/core").Signal<boolean>;
16
16
  propsProcessLinks: import("@angular/core").Signal<boolean>;
17
17
  propsAllowPartialBold: import("@angular/core").Signal<boolean>;
@@ -48,7 +48,7 @@ export declare class FeaturesListComponent {
48
48
  iconColor: string;
49
49
  iconSize: number;
50
50
  mode: "horizontal" | "vertical";
51
- gap: "medium" | "small" | "large";
51
+ gap: "small" | "medium" | "large";
52
52
  alignment: "start" | "center";
53
53
  }>;
54
54
  /** Resolved icon color (handles Ionic colors and CSS colors) */
@@ -45,7 +45,7 @@ export declare class ArticleComponent implements OnInit {
45
45
  getVideoElement(element: ArticleElement): ArticleVideoElement;
46
46
  getCustomElement(element: ArticleElement): ArticleCustomElement;
47
47
  getQuoteTextProps(element: ArticleElement): {
48
- size: "medium" | "small" | "large" | "xlarge";
48
+ size: "small" | "medium" | "large" | "xlarge";
49
49
  color: import("@ionic/core").Color;
50
50
  content?: string;
51
51
  bold: boolean;
@@ -61,7 +61,7 @@ export declare class ArticleComponent implements OnInit {
61
61
  showQuoteMark?: boolean;
62
62
  };
63
63
  getHighlightTextProps(element: ArticleElement): {
64
- size: "medium" | "small" | "large" | "xlarge";
64
+ size: "small" | "medium" | "large" | "xlarge";
65
65
  color: import("@ionic/core").Color;
66
66
  content?: string;
67
67
  bold: boolean;
@@ -90,7 +90,7 @@ export declare class ArticleComponent implements OnInit {
90
90
  contentInterpolation?: Record<string, string | number>;
91
91
  icon?: import("valtech-components").IconMetada;
92
92
  shape?: "round";
93
- size?: "small" | "default" | "large";
93
+ size?: "small" | "large" | "default";
94
94
  fill?: "default" | "clear" | "outline" | "solid";
95
95
  type: "button" | "submit" | "reset";
96
96
  token?: string;
@@ -63,7 +63,7 @@ export declare class BottomNavComponent implements OnInit, OnDestroy {
63
63
  i18nNamespace?: string;
64
64
  hideLabels: boolean;
65
65
  safeArea: boolean;
66
- animation: "fade" | "scale" | "slide" | "none";
66
+ animation: "none" | "slide" | "fade" | "scale";
67
67
  maxWidth: string;
68
68
  }>;
69
69
  /** Computed tabs with FAB inserted if present */
@@ -72,7 +72,7 @@ export declare class ToolbarComponent implements OnInit {
72
72
  };
73
73
  showFlags?: boolean;
74
74
  color: import("@ionic/core").Color;
75
- size?: "small" | "default" | "large";
75
+ size?: "small" | "large" | "default";
76
76
  fill?: "default" | "clear" | "outline" | "solid";
77
77
  shape?: "round";
78
78
  expand?: "full" | "block";
@@ -1,31 +1,73 @@
1
+ import { InjectionToken, Provider } from '@angular/core';
1
2
  import { Observable } from 'rxjs';
2
3
  import { ArticleMetadata } from '../../components/organisms/article/types';
3
4
  import * as i0 from "@angular/core";
4
5
  export type LegalSlug = 'terms' | 'privacy' | 'cookies' | 'data-usage' | 'legal-notice' | string;
6
+ /**
7
+ * Factory that returns a Record<slug, ArticleMetadata> for a given locale.
8
+ * Use a dynamic `import()` so each locale module is code-split by the bundler.
9
+ */
10
+ export type LegalContentFactory = () => Promise<Record<string, ArticleMetadata>>;
11
+ export interface LegalContentConfig {
12
+ /** Pre-generated content factories keyed by locale (e.g. `{ es: () => import('./generated/legal-content.es') ... }`). */
13
+ factories?: Record<string, LegalContentFactory>;
14
+ /** Override default `/assets/legal` base path used when no factory matches. */
15
+ basePath?: string;
16
+ /** Fallback locale (default `es`). Set null to disable. */
17
+ fallbackLocale?: string | null;
18
+ }
19
+ export declare const LEGAL_CONTENT_CONFIG: InjectionToken<LegalContentConfig>;
5
20
  export interface LegalLoadOptions {
6
- /** Two-letter locale code (es, en, pt). Falls back to `es` on 404. */
21
+ /** Two-letter locale code (es, en, pt). */
7
22
  locale?: string;
8
- /** Override base path (default `/assets/legal`). */
23
+ /** Override base path for runtime mode (default `/assets/legal`). */
9
24
  basePath?: string;
10
25
  /** Fallback locale tried when the requested one is missing. Set null to disable. */
11
26
  fallbackLocale?: string | null;
12
27
  }
13
28
  /**
14
- * Loads Markdown legal documents from `/assets/legal/{locale}/{slug}.md` and parses them
15
- * into ArticleMetadata ready for `<val-article>`. Caches parsed results by `locale:slug`
16
- * so multiple views consuming the same doc share one HTTP request.
29
+ * Loads legal articles via one of two modes:
30
+ *
31
+ * 1. **Build-time** (preferred): when the app provides `LEGAL_CONTENT_CONFIG.factories`
32
+ * via `provideLegalContent()`, the service dynamically imports the matching
33
+ * locale module and returns the pre-parsed `ArticleMetadata` synchronously
34
+ * (wrapped in an Observable). Each locale is code-split.
35
+ *
36
+ * 2. **Runtime**: when no factory matches, falls back to fetching
37
+ * `/assets/legal/{locale}/{slug}.md` and parsing on the fly.
38
+ *
39
+ * Both modes cache by `locale:slug` so concurrent loads share one promise/HTTP request.
17
40
  */
18
41
  export declare class LegalContentService {
19
42
  private readonly http;
20
43
  private readonly parser;
44
+ private readonly config;
21
45
  private readonly DEFAULT_BASE;
22
46
  private readonly cache;
47
+ private readonly factoryCache;
23
48
  load(slug: LegalSlug, options?: LegalLoadOptions): Observable<ArticleMetadata>;
24
- /** Returns the raw Markdown string without parsing. Useful for debugging. */
49
+ /** Raw Markdown only available in runtime mode (HTTP). */
25
50
  raw(slug: LegalSlug, options?: LegalLoadOptions): Observable<string>;
26
- /** Clears the in-memory cache. Call when the user changes locale at runtime. */
51
+ /** Clears in-memory caches. Call on runtime locale change. */
27
52
  invalidate(): void;
53
+ private loadOne;
54
+ private runFactory;
28
55
  private fetchAndParse;
29
56
  static ɵfac: i0.ɵɵFactoryDeclaration<LegalContentService, never>;
30
57
  static ɵprov: i0.ɵɵInjectableDeclaration<LegalContentService>;
31
58
  }
59
+ /**
60
+ * Wires pre-generated legal content into `LegalContentService`. Call from `main.ts`
61
+ * (or any `providers: []` array). The factories use dynamic `import()` so each
62
+ * locale is code-split — only the active locale's bundle is loaded.
63
+ *
64
+ * @example
65
+ * provideLegalContent({
66
+ * factories: {
67
+ * es: () => import('./app/generated/legal-content.es').then((m) => m.LEGAL_CONTENT_ES),
68
+ * en: () => import('./app/generated/legal-content.en').then((m) => m.LEGAL_CONTENT_EN),
69
+ * pt: () => import('./app/generated/legal-content.pt').then((m) => m.LEGAL_CONTENT_PT),
70
+ * },
71
+ * })
72
+ */
73
+ export declare function provideLegalContent(config: LegalContentConfig): Provider;
@@ -0,0 +1,16 @@
1
+ import { ArticleMetadata } from '../../components/organisms/article/types';
2
+ /**
3
+ * Pure Markdown → ArticleMetadata parser. No Angular deps — usable from Node scripts
4
+ * (build-time generation) and from the Angular `MarkdownArticleParserService` wrapper.
5
+ *
6
+ * Supported syntax:
7
+ * - Headings (#, ##, ### …) → title / subtitle
8
+ * - Paragraphs → paragraph (with `processLinks` + `allowPartialBold`)
9
+ * - Lists (-, *, 1.) → unordered / ordered list (- [ ] / - [x] for checklist)
10
+ * - Blockquotes (>) → quote, with GitHub callouts `> [!NOTE|TIP|INFO|WARNING|CAUTION|IMPORTANT]` mapped to notes
11
+ * - Code fences (```lang) → code
12
+ * - Box-drawing ASCII art (┌┐└┘│─) auto-wrapped as code
13
+ * - Tables → flattened into paragraphs with bold keys
14
+ * - Horizontal rules (---, ***, ___) → separator
15
+ */
16
+ export declare function parseMarkdownArticle(markdown: string, config?: Partial<ArticleMetadata>): ArticleMetadata;
@@ -1,31 +1,12 @@
1
1
  import { ArticleMetadata } from '../../components/organisms/article/types';
2
2
  import * as i0 from "@angular/core";
3
3
  /**
4
- * Converts Markdown documents into ArticleMetadata for the val-article organism.
5
- *
6
- * Supported syntax:
7
- * - Headings (#, ##, ### …) → title / subtitle
8
- * - Paragraphs → paragraph (with `processLinks` + `allowPartialBold`)
9
- * - Lists (-, *, 1.) → unordered / ordered list (- [ ] / - [x] for checklist)
10
- * - Blockquotes (>) → quote, with GitHub callouts `> [!NOTE|TIP|INFO|WARNING|CAUTION|IMPORTANT]` mapped to notes
11
- * - Code fences (```lang) → code
12
- * - Box-drawing ASCII art (┌┐└┘│─) auto-wrapped as code
13
- * - Tables → flattened into paragraphs with bold keys
14
- * - Horizontal rules (---, ***, ___) → separator
4
+ * Angular service wrapper for the pure {@link parseMarkdownArticle} function.
5
+ * Provided in root so it can be injected anywhere. The actual parsing logic lives in
6
+ * `markdown-article-parser.ts` and is also usable from Node scripts (build-time generation).
15
7
  */
16
8
  export declare class MarkdownArticleParserService {
17
9
  parse(markdown: string, config?: Partial<ArticleMetadata>): ArticleMetadata;
18
- private normalize;
19
- private startsNewBlock;
20
- private makeHeading;
21
- private makeQuoteOrCallout;
22
- private makeNote;
23
- /**
24
- * Tables are flattened into a header subtitle (if present) followed by one paragraph per
25
- * data row using `**col[0]:** col[1] · **col[2]:** col[3] …` format. val-article has no
26
- * native table element so this preserves the information without breaking the layout.
27
- */
28
- private makeTable;
29
10
  static ɵfac: i0.ɵɵFactoryDeclaration<MarkdownArticleParserService, never>;
30
11
  static ɵprov: i0.ɵɵInjectableDeclaration<MarkdownArticleParserService>;
31
12
  }
@@ -0,0 +1,2 @@
1
+ export * from './preferences.service';
2
+ export * from './preferences.types';
@@ -0,0 +1,51 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import { AuthService } from '../auth/auth.service';
3
+ import { ValtechAuthConfig } from '../auth/types';
4
+ import { FirestoreService } from '../firebase/firestore.service';
5
+ import { I18nService } from '../i18n/i18n.service';
6
+ import { ThemeService } from '../theme.service';
7
+ import { PreferencesLanguage, PreferencesTheme, PreferencesUpdate, PreferencesUpdateResponse } from './preferences.types';
8
+ import * as i0 from "@angular/core";
9
+ /**
10
+ * PreferencesService — preferencias del user en el doc canónico Firestore
11
+ * `/apps/{appId}/users/{uid}/preferences/main`.
12
+ *
13
+ * Read reactivo (signals) via listener Firestore.
14
+ * Write via `PUT /v2/auth/preferences` (cliente NUNCA escribe Firestore directo —
15
+ * ver memoria `feedback_no_direct_firestore_writes`).
16
+ *
17
+ * Side-effects automáticos:
18
+ * - Cuando `theme()` cambia → `ThemeService.Theme = ...`
19
+ * - Cuando `language()` cambia → `I18nService.setLanguage(...)`
20
+ *
21
+ * Auto-bind al user actual via `AuthService.user()`. Sin user (logout) → unbind.
22
+ */
23
+ export declare class PreferencesService {
24
+ private config;
25
+ private firestore;
26
+ private auth;
27
+ private http;
28
+ private themeService;
29
+ private i18n;
30
+ private readonly _theme;
31
+ private readonly _language;
32
+ private readonly _notificationsMaster;
33
+ /** `true` después del primer snapshot Firestore. Antes, defaults sin side-effects. */
34
+ private readonly _synced;
35
+ readonly theme: import("@angular/core").Signal<PreferencesTheme>;
36
+ readonly language: import("@angular/core").Signal<PreferencesLanguage>;
37
+ readonly notificationsMaster: import("@angular/core").Signal<boolean>;
38
+ readonly synced: import("@angular/core").Signal<boolean>;
39
+ private subscription?;
40
+ private currentUserId?;
41
+ constructor(config: ValtechAuthConfig, firestore: FirestoreService, auth: AuthService, http: HttpClient, themeService: ThemeService | null, i18n: I18nService | null);
42
+ /** Actualiza preferencias via backend. Optimistic UI: aplica local, revierte si falla. */
43
+ update(partial: PreferencesUpdate): Promise<PreferencesUpdateResponse>;
44
+ setTheme(theme: PreferencesTheme): Promise<PreferencesUpdateResponse>;
45
+ setLanguage(language: PreferencesLanguage): Promise<PreferencesUpdateResponse>;
46
+ setNotificationsMaster(enabled: boolean): Promise<PreferencesUpdateResponse>;
47
+ private bindToUser;
48
+ private unbind;
49
+ static ɵfac: i0.ɵɵFactoryDeclaration<PreferencesService, [null, null, null, null, { optional: true; }, { optional: true; }]>;
50
+ static ɵprov: i0.ɵɵInjectableDeclaration<PreferencesService>;
51
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Preferences types — Fase 1 schema simple (theme + language + notifications.master).
3
+ * Doc canónico: /apps/{appId}/users/{uid}/preferences/main
4
+ * Cliente NUNCA escribe directo — todas las mutaciones via PUT /v2/auth/preferences.
5
+ */
6
+ export type PreferencesTheme = 'light' | 'dark' | 'auto';
7
+ export type PreferencesLanguage = 'es' | 'en' | 'pt';
8
+ /** Forma del doc tal como lo escribe el backend (Admin SDK). */
9
+ export interface PreferencesDocument {
10
+ theme?: PreferencesTheme;
11
+ language?: PreferencesLanguage;
12
+ notifications?: {
13
+ master?: boolean;
14
+ };
15
+ /** serverTimestamp escrito por el backend en cada sync. */
16
+ syncedAt?: unknown;
17
+ }
18
+ /** Payload aceptado por `PUT /v2/auth/preferences` — partial update. */
19
+ export interface PreferencesUpdate {
20
+ theme?: PreferencesTheme;
21
+ language?: PreferencesLanguage;
22
+ notifications?: {
23
+ master?: boolean;
24
+ };
25
+ }
26
+ /** Response del backend tras el PUT. */
27
+ export interface PreferencesUpdateResponse {
28
+ operationId: string;
29
+ theme: PreferencesTheme | '';
30
+ language: PreferencesLanguage | '';
31
+ notifications: {
32
+ master?: boolean;
33
+ };
34
+ updated: boolean;
35
+ }
package/lib/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Current version of valtech-components.
3
3
  * This is automatically updated during the publish process.
4
4
  */
5
- export declare const VERSION = "2.0.729";
5
+ export declare const VERSION = "2.0.730";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valtech-components",
3
- "version": "2.0.729",
3
+ "version": "2.0.730",
4
4
  "private": false,
5
5
  "bin": {
6
6
  "valtech-firebase-config": "./src/lib/services/firebase/scripts/generate-sw-config.js"
package/public-api.d.ts CHANGED
@@ -239,11 +239,13 @@ export * from './lib/services/qr-generator/types';
239
239
  export * from './lib/services/modal/modal.service';
240
240
  export * from './lib/services/modal/types';
241
241
  export * from './lib/services/meta';
242
+ export * from './lib/services/markdown-article/markdown-article-parser';
242
243
  export * from './lib/services/markdown-article/markdown-article-parser.service';
243
244
  export * from './lib/services/markdown-article/legal-content.service';
244
245
  export * from './lib/services/firebase';
245
246
  export * from './lib/services/auth';
246
247
  export * from './lib/services/i18n';
248
+ export * from './lib/services/preferences';
247
249
  export * from './lib/services/app-config';
248
250
  export * from './lib/services/presets';
249
251
  export * from './lib/services/skeleton';