valtech-components 4.0.970 → 4.0.972
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/organisms/page-block/page-block.component.mjs +254 -0
- package/esm2022/lib/components/organisms/page-block/types.mjs +20 -0
- package/esm2022/lib/components/organisms/rich-editor/article-to-tiptap.mjs +110 -0
- package/esm2022/lib/components/organisms/rich-editor/rich-editor.component.mjs +287 -0
- package/esm2022/lib/components/organisms/rich-editor/rich-editor.i18n.mjs +27 -0
- package/esm2022/lib/components/organisms/rich-editor/tiptap-to-article.mjs +136 -0
- package/esm2022/lib/components/organisms/rich-editor/types.mjs +2 -0
- package/esm2022/lib/components/organisms/video-player/types.mjs +12 -0
- package/esm2022/lib/components/organisms/video-player/video-player.component.mjs +235 -0
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +13 -1
- package/fesm2022/valtech-components.mjs +1060 -3
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/page-block/page-block.component.d.ts +65 -0
- package/lib/components/organisms/page-block/types.d.ts +102 -0
- package/lib/components/organisms/rich-editor/article-to-tiptap.d.ts +3 -0
- package/lib/components/organisms/rich-editor/rich-editor.component.d.ts +46 -0
- package/lib/components/organisms/rich-editor/rich-editor.i18n.d.ts +26 -0
- package/lib/components/organisms/rich-editor/tiptap-to-article.d.ts +38 -0
- package/lib/components/organisms/rich-editor/types.d.ts +21 -0
- package/lib/components/organisms/video-player/types.d.ts +45 -0
- package/lib/components/organisms/video-player/video-player.component.d.ts +42 -0
- package/lib/version.d.ts +1 -1
- package/package.json +5 -1
- package/public-api.d.ts +8 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import { FaqCategory } from '../faq/types';
|
|
3
|
+
import { PageBlock, PageCTABlockProps, PageCTAIntent, PageFAQBlockProps, PageGalleryBlockProps, PageHeroBlockProps, PageTextBlockProps } from './types';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* `val-page-block`
|
|
7
|
+
*
|
|
8
|
+
* Organism que renderiza UN bloque del constructor de páginas de plataforma
|
|
9
|
+
* (ADR-077, `services/page` en el backend). Es el punto de la lib donde el
|
|
10
|
+
* catálogo de bloques (`hero`, `text`, `gallery`, `cta`, `faq`) mapea 1:1 a
|
|
11
|
+
* componentes reales — la razón de ser del ADR: "un rediseño de la lib
|
|
12
|
+
* mejora todas las páginas publicadas sin tocar sus datos".
|
|
13
|
+
*
|
|
14
|
+
* Presentacional puro: recibe `props` ya tipados (espejo exacto del `Block`
|
|
15
|
+
* del backend), sin llamadas HTTP propias ni conocimiento de a qué app
|
|
16
|
+
* pertenece la página. El bloque `cta` NO navega — emite `(ctaAction)` con
|
|
17
|
+
* la intención cruda (`{ action }`) para que el consumidor (la app) la
|
|
18
|
+
* resuelva contra su propio routing (ADR-077: "el CTA guarda una intención,
|
|
19
|
+
* nunca una URL").
|
|
20
|
+
*
|
|
21
|
+
* El caller típico itera `Page.Blocks` y renderiza uno de estos por bloque:
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```html
|
|
25
|
+
* @for (block of page().blocks; track $index) {
|
|
26
|
+
* <val-page-block [props]="block" (ctaAction)="onCtaAction($event)" />
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare class PageBlockComponent {
|
|
31
|
+
/** El bloque a renderizar — espejo de `page.Block` (backend). */
|
|
32
|
+
props: PageBlock;
|
|
33
|
+
/**
|
|
34
|
+
* Emite la intención cruda del CTA al hacer click (`{ action }`, nunca una
|
|
35
|
+
* URL — ver comentario de clase). El consumidor decide qué hacer con
|
|
36
|
+
* `action`; este componente no la interpreta.
|
|
37
|
+
*/
|
|
38
|
+
ctaAction: EventEmitter<PageCTAIntent>;
|
|
39
|
+
/** Fallback de imagen rota (convención de la lib) — un slot, una signal. */
|
|
40
|
+
readonly heroImageFailed: import("@angular/core").WritableSignal<boolean>;
|
|
41
|
+
/** Índices de `gallery.images` cuya carga falló (`error` del `<img>`). */
|
|
42
|
+
readonly failedGalleryImages: import("@angular/core").WritableSignal<Set<number>>;
|
|
43
|
+
get hero(): PageHeroBlockProps;
|
|
44
|
+
get text(): PageTextBlockProps;
|
|
45
|
+
get gallery(): PageGalleryBlockProps;
|
|
46
|
+
get cta(): PageCTABlockProps;
|
|
47
|
+
get faq(): PageFAQBlockProps;
|
|
48
|
+
/**
|
|
49
|
+
* `text.body` es texto plano (no markdown — a diferencia de
|
|
50
|
+
* `val-article`/`val-faq`, `blocks_validate.go` solo exige un string no
|
|
51
|
+
* vacío). Partido por línea para que `val-text` (un `<p>` por línea)
|
|
52
|
+
* respete los saltos que el autor escribió, sin interpretar sintaxis.
|
|
53
|
+
*/
|
|
54
|
+
textParagraphs(): string[];
|
|
55
|
+
/**
|
|
56
|
+
* `val-faq` agrupa por categoría; el bloque `faq` de `services/page` no
|
|
57
|
+
* tiene categorías (solo `items` planos) — se envuelve en una única
|
|
58
|
+
* categoría sin label (`hideSingleCategoryLabel` default `true` la oculta).
|
|
59
|
+
*/
|
|
60
|
+
faqCategories(): FaqCategory[];
|
|
61
|
+
onCtaClick(): void;
|
|
62
|
+
onGalleryImageError(index: number): void;
|
|
63
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<PageBlockComponent, never>;
|
|
64
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<PageBlockComponent, "val-page-block", never, { "props": { "alias": "props"; "required": false; }; }, { "ctaAction": "ctaAction"; }, never, never, true, never>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tipos del organism `val-page-block` — constructor de páginas de plataforma
|
|
3
|
+
* (ADR-077: `docs/adr/077-constructor-de-paginas-de-plataforma.md`, primera
|
|
4
|
+
* aplicación real en Eklesee, Bloque 4:
|
|
5
|
+
* `docs/eklesee/03-roadmap-y-abiertos.md`).
|
|
6
|
+
*
|
|
7
|
+
* Espejo 1:1 de `Block`/`Props` en `backend/go/services/page/types.go` +
|
|
8
|
+
* `backend/go/services/page/blocks_validate.go` — la forma de cada `props`
|
|
9
|
+
* sale de ahí, no se inventa acá. El catálogo de esta primera pasada son 5
|
|
10
|
+
* tipos (`hero`, `text`, `gallery`, `cta`, `faq`); `countdown`/`sponsors`/
|
|
11
|
+
* `progress` (catálogo completo del ADR) quedan fuera hasta que Bingo migre.
|
|
12
|
+
*
|
|
13
|
+
* El componente es i18n-agnóstico y agnóstico al dominio a propósito (mismo
|
|
14
|
+
* criterio que `val-faq`/`val-article`): recibe `props` ya resueltos, sin
|
|
15
|
+
* llamadas HTTP propias ni conocimiento de rutas de ninguna app. La app que
|
|
16
|
+
* lo consume (Eklesee) resuelve `PageCTAIntent.action` a una ruta real —
|
|
17
|
+
* este organism solo la emite via `(ctaAction)`.
|
|
18
|
+
*/
|
|
19
|
+
/** hero — props: `title` (requerido), `subtitle`/`image`/`align` (opcionales). */
|
|
20
|
+
export interface PageHeroBlockProps {
|
|
21
|
+
title: string;
|
|
22
|
+
subtitle?: string;
|
|
23
|
+
/** URL de la imagen de fondo/acompañante. */
|
|
24
|
+
image?: string;
|
|
25
|
+
align?: 'left' | 'center' | 'right';
|
|
26
|
+
}
|
|
27
|
+
/** text — props: `body` (requerido), `heading` (opcional). */
|
|
28
|
+
export interface PageTextBlockProps {
|
|
29
|
+
body: string;
|
|
30
|
+
heading?: string;
|
|
31
|
+
}
|
|
32
|
+
/** gallery — props: `images` (requerido, 1..20 URLs, validado en backend). */
|
|
33
|
+
export interface PageGalleryBlockProps {
|
|
34
|
+
images: string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Intención del CTA, NUNCA una URL (ADR-077: "el link del vendedor puede
|
|
38
|
+
* regenerarse... sin dejar páginas publicadas apuntando a un token muerto").
|
|
39
|
+
* El catálogo de `action` es del backend (`page.CTAAction`, hoy solo
|
|
40
|
+
* `apply_membership` — ver `services/page/types.go`). Este componente NO
|
|
41
|
+
* resuelve la intención a una ruta: solo la recibe y la reemite tal cual via
|
|
42
|
+
* `(ctaAction)` para que la app la resuelva contra su propio routing.
|
|
43
|
+
*/
|
|
44
|
+
export interface PageCTAIntent {
|
|
45
|
+
action: string;
|
|
46
|
+
}
|
|
47
|
+
/** cta — props: `label` (requerido), `intent.action` (requerido). */
|
|
48
|
+
export interface PageCTABlockProps {
|
|
49
|
+
label: string;
|
|
50
|
+
intent: PageCTAIntent;
|
|
51
|
+
}
|
|
52
|
+
/** Un ítem de FAQ (pregunta + respuesta en texto plano). */
|
|
53
|
+
export interface PageFAQItemProps {
|
|
54
|
+
question: string;
|
|
55
|
+
answer: string;
|
|
56
|
+
}
|
|
57
|
+
/** faq — props: `items` (requerido, 1..50, validado en backend). */
|
|
58
|
+
export interface PageFAQBlockProps {
|
|
59
|
+
items: PageFAQItemProps[];
|
|
60
|
+
}
|
|
61
|
+
/** Discriminador de bloque — espejo de `page.BlockType` (backend). */
|
|
62
|
+
export type PageBlockType = 'hero' | 'text' | 'gallery' | 'cta' | 'faq';
|
|
63
|
+
interface PageBlockBase {
|
|
64
|
+
/**
|
|
65
|
+
* Orden de renderizado dentro de `Page.Blocks`. El backend lo re-estampa
|
|
66
|
+
* SIEMPRE a partir de la posición del array al guardar (`SetBlocks` —
|
|
67
|
+
* regla #7 backend/go/CLAUDE.md: nunca confiar en un `order` que venga del
|
|
68
|
+
* cliente). Opcional acá: el consumidor típico ya itera el array en el
|
|
69
|
+
* orden real, este campo es informativo.
|
|
70
|
+
*/
|
|
71
|
+
order?: number;
|
|
72
|
+
}
|
|
73
|
+
export interface PageHeroBlock extends PageBlockBase {
|
|
74
|
+
type: 'hero';
|
|
75
|
+
props: PageHeroBlockProps;
|
|
76
|
+
}
|
|
77
|
+
export interface PageTextBlock extends PageBlockBase {
|
|
78
|
+
type: 'text';
|
|
79
|
+
props: PageTextBlockProps;
|
|
80
|
+
}
|
|
81
|
+
export interface PageGalleryBlock extends PageBlockBase {
|
|
82
|
+
type: 'gallery';
|
|
83
|
+
props: PageGalleryBlockProps;
|
|
84
|
+
}
|
|
85
|
+
export interface PageCTABlock extends PageBlockBase {
|
|
86
|
+
type: 'cta';
|
|
87
|
+
props: PageCTABlockProps;
|
|
88
|
+
}
|
|
89
|
+
export interface PageFAQBlock extends PageBlockBase {
|
|
90
|
+
type: 'faq';
|
|
91
|
+
props: PageFAQBlockProps;
|
|
92
|
+
}
|
|
93
|
+
/** Unión discriminada — espejo de `page.Block` (backend, `Props map[string]any` tipado por `Type`). */
|
|
94
|
+
export type PageBlock = PageHeroBlock | PageTextBlock | PageGalleryBlock | PageCTABlock | PageFAQBlock;
|
|
95
|
+
/**
|
|
96
|
+
* Props de `<val-page-block>`. Alias de `PageBlock` con el nombre
|
|
97
|
+
* `*Metadata` que sigue el resto de la lib (`convención: Props interface
|
|
98
|
+
* → *Metadata`) — mismo tipo, dos nombres para dos contextos de uso (el
|
|
99
|
+
* array de la página vs. el `@Input` de un componente puntual).
|
|
100
|
+
*/
|
|
101
|
+
export type PageBlockMetadata = PageBlock;
|
|
102
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { AfterViewInit, ElementRef, EventEmitter, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { ArticleMetadata } from '../article/types';
|
|
3
|
+
import { RichEditorMetadata, RichEditorToolbarButton } from './types';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* val-rich-editor
|
|
7
|
+
*
|
|
8
|
+
* Organism: editor WYSIWYG reusable para toda la plataforma, sobre TipTap.
|
|
9
|
+
* Emite `ArticleMetadata` — el mismo contrato que `val-article` renderiza,
|
|
10
|
+
* que también producen Markdown (`parseMarkdownArticle`) y (a futuro) el
|
|
11
|
+
* page builder. El consumer nunca toca TipTap directamente.
|
|
12
|
+
*
|
|
13
|
+
* Cobertura de la toolbar v1: negrita, cursiva, título (H2), subtítulo (H3),
|
|
14
|
+
* lista con/sin viñetas, cita, separador, imagen. Ver `tiptap-to-article.ts`
|
|
15
|
+
* para qué tipos de `ArticleElement` puede producir el editor hoy.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```html
|
|
19
|
+
* <val-rich-editor
|
|
20
|
+
* [props]="{ initialValue: recipe.descriptionArticle, placeholder: 'Escribe la preparación...' }"
|
|
21
|
+
* (articleChange)="onArticleChange($event)"
|
|
22
|
+
* />
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class RichEditorComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|
26
|
+
props: RichEditorMetadata;
|
|
27
|
+
articleChange: EventEmitter<ArticleMetadata>;
|
|
28
|
+
editorHost: ElementRef<HTMLElement>;
|
|
29
|
+
private i18n;
|
|
30
|
+
private editor?;
|
|
31
|
+
/** Se recalcula en cada `onUpdate`/`onSelectionUpdate` para reflejar el
|
|
32
|
+
* mark/nodo activo bajo el cursor (ej. el botón "B" resaltado si el
|
|
33
|
+
* cursor está dentro de texto en negrita). */
|
|
34
|
+
private readonly _toolbarTick;
|
|
35
|
+
readonly toolbarButtons: import("@angular/core").WritableSignal<RichEditorToolbarButton[]>;
|
|
36
|
+
constructor();
|
|
37
|
+
private t;
|
|
38
|
+
ngAfterViewInit(): void;
|
|
39
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
40
|
+
private emitArticle;
|
|
41
|
+
private refreshToolbar;
|
|
42
|
+
runCommand(token: string): void;
|
|
43
|
+
ngOnDestroy(): void;
|
|
44
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RichEditorComponent, never>;
|
|
45
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RichEditorComponent, "val-rich-editor", never, { "props": { "alias": "props"; "required": false; }; }, { "articleChange": "articleChange"; }, never, never, true, never>;
|
|
46
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defaults i18n (es/en) del `val-rich-editor`. Auto-registrados en el
|
|
3
|
+
* constructor (namespace `RichEditor`) — el consumer nunca los registra.
|
|
4
|
+
*/
|
|
5
|
+
export declare const RICH_EDITOR_I18N: {
|
|
6
|
+
readonly es: {
|
|
7
|
+
readonly bold: "Negrita";
|
|
8
|
+
readonly italic: "Cursiva";
|
|
9
|
+
readonly heading2: "Título";
|
|
10
|
+
readonly heading3: "Subtítulo";
|
|
11
|
+
readonly bulletList: "Lista con viñetas";
|
|
12
|
+
readonly orderedList: "Lista numerada";
|
|
13
|
+
readonly quote: "Cita";
|
|
14
|
+
readonly separator: "Separador";
|
|
15
|
+
};
|
|
16
|
+
readonly en: {
|
|
17
|
+
readonly bold: "Bold";
|
|
18
|
+
readonly italic: "Italic";
|
|
19
|
+
readonly heading2: "Heading";
|
|
20
|
+
readonly heading3: "Subheading";
|
|
21
|
+
readonly bulletList: "Bullet list";
|
|
22
|
+
readonly orderedList: "Numbered list";
|
|
23
|
+
readonly quote: "Quote";
|
|
24
|
+
readonly separator: "Separator";
|
|
25
|
+
};
|
|
26
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ArticleElement, ArticleMetadata } from '../article/types';
|
|
2
|
+
/**
|
|
3
|
+
* Convierte el documento JSON de TipTap (ProseMirror) a `ArticleElement[]`
|
|
4
|
+
* sin pasar por HTML intermedio — es la mitad "guardar" de `val-rich-editor`,
|
|
5
|
+
* que alimenta el mismo `val-article` que ya usan Markdown
|
|
6
|
+
* (`parseMarkdownArticle`) y las instrucciones de receta de Okhelia. Ver
|
|
7
|
+
* `article-to-tiptap.ts` para la conversión inversa (hidratar el editor con
|
|
8
|
+
* contenido existente).
|
|
9
|
+
*
|
|
10
|
+
* Cobertura: los nodos que trae `@tiptap/starter-kit` por default (doc,
|
|
11
|
+
* paragraph, heading, bulletList/orderedList/listItem, blockquote, codeBlock,
|
|
12
|
+
* horizontalRule) + marks inline (bold, italic vía <strong>/<em>, igual
|
|
13
|
+
* criterio que `allowPartialBold` de ArticleTextElement/ArticleNoteElement).
|
|
14
|
+
* NO cubre todavía: tablas, ni extensiones custom para `note`/`diagram`/
|
|
15
|
+
* `command` (esos requerirían nodos TipTap propios — factible, pendiente de
|
|
16
|
+
* decidir si vale la pena). `image` sí está cubierto (ver case 'image').
|
|
17
|
+
*/
|
|
18
|
+
export interface TiptapNode {
|
|
19
|
+
type: string;
|
|
20
|
+
attrs?: Record<string, unknown>;
|
|
21
|
+
content?: TiptapNode[];
|
|
22
|
+
text?: string;
|
|
23
|
+
marks?: Array<{
|
|
24
|
+
type: string;
|
|
25
|
+
attrs?: Record<string, unknown>;
|
|
26
|
+
}>;
|
|
27
|
+
}
|
|
28
|
+
export interface TiptapDoc {
|
|
29
|
+
type: 'doc';
|
|
30
|
+
content: TiptapNode[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Convierte un doc de TipTap a `ArticleElement[]`. Función pura — sin
|
|
34
|
+
* Angular DI, usable también desde Node (mismo criterio que
|
|
35
|
+
* `parseMarkdownArticle`).
|
|
36
|
+
*/
|
|
37
|
+
export declare function tiptapDocToArticleElements(doc: TiptapDoc): ArticleElement[];
|
|
38
|
+
export declare function tiptapDocToArticle(doc: TiptapDoc, config?: Partial<ArticleMetadata>): ArticleMetadata;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ArticleMetadata } from '../article/types';
|
|
2
|
+
/**
|
|
3
|
+
* Props de `val-rich-editor` (object-first, como el resto de la lib).
|
|
4
|
+
*/
|
|
5
|
+
export interface RichEditorMetadata {
|
|
6
|
+
/** Contenido inicial — pasar el `ArticleMetadata` ya guardado para editar
|
|
7
|
+
* algo existente. Vacío/undefined = editor en blanco. */
|
|
8
|
+
initialValue?: ArticleMetadata;
|
|
9
|
+
/** Texto de placeholder cuando el editor está vacío. */
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
/** Deshabilita la edición (solo lectura, sin toolbar interactiva). */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Un botón de la toolbar — identifica el comando TipTap y su estado activo. */
|
|
15
|
+
export interface RichEditorToolbarButton {
|
|
16
|
+
token: string;
|
|
17
|
+
icon: string;
|
|
18
|
+
label: string;
|
|
19
|
+
isActive: boolean;
|
|
20
|
+
disabled: boolean;
|
|
21
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tipos de `val-video-player` (ADR-087 — video como servicio de plataforma).
|
|
3
|
+
*
|
|
4
|
+
* Espejo agnóstico al dominio de `content.VideoAsset` (backend Go,
|
|
5
|
+
* `backend/go/services/content/video.go`) — mismos nombres de campo en
|
|
6
|
+
* camelCase. Cualquier app pasa acá el `VideoAsset` que le devuelve SU propio
|
|
7
|
+
* backend (sermón en Eklesee, receta en Okhelia, animal en Chesed, artículo de
|
|
8
|
+
* ayuda) con un mapeo trivial; el componente no conoce ni le importa de qué
|
|
9
|
+
* dominio viene.
|
|
10
|
+
*/
|
|
11
|
+
export type VideoPlayerSource = 'upload' | 'link';
|
|
12
|
+
/** Solo aplica a `source: 'upload'`. Un link normalizado con éxito nace en 'ready'. */
|
|
13
|
+
export type VideoPlayerStatus = 'uploading' | 'processing' | 'ready' | 'failed' | 'rejected';
|
|
14
|
+
export interface VideoPlayerCaption {
|
|
15
|
+
locale: string;
|
|
16
|
+
url: string;
|
|
17
|
+
}
|
|
18
|
+
export interface VideoPlayerAsset {
|
|
19
|
+
source: VideoPlayerSource;
|
|
20
|
+
/**
|
|
21
|
+
* `source:'upload'` → URL de reproducción ya presignada por el backend
|
|
22
|
+
* (TTL corto, ~15 min — ADR-087 §6). Úsala directo, no la cachees ni la
|
|
23
|
+
* persistas: se recalcula en cada lectura del documento.
|
|
24
|
+
* `source:'link'` → URL normalizada del proveedor (no se usa para el
|
|
25
|
+
* embed, ver `externalId`).
|
|
26
|
+
*/
|
|
27
|
+
url?: string;
|
|
28
|
+
/** `'youtube' | 'vimeo'` — solo si `source: 'link'`. */
|
|
29
|
+
provider?: string;
|
|
30
|
+
/**
|
|
31
|
+
* ID ya normalizado por el backend — el ÚNICO dato que arma el iframe de
|
|
32
|
+
* embed. El componente NUNCA arma un `src` con datos crudos del usuario.
|
|
33
|
+
*/
|
|
34
|
+
externalId?: string;
|
|
35
|
+
durationSec?: number;
|
|
36
|
+
/** Portada — se muestra mientras el video no está `ready` (mejor percepción de carga). */
|
|
37
|
+
thumbnail?: string;
|
|
38
|
+
captions?: VideoPlayerCaption[];
|
|
39
|
+
status?: VideoPlayerStatus;
|
|
40
|
+
/**
|
|
41
|
+
* Motivo legible de `failed`/`rejected`, ya en el idioma que decidió el
|
|
42
|
+
* backend (es-CL) — se muestra tal cual, no es un código a traducir.
|
|
43
|
+
*/
|
|
44
|
+
failReason?: string;
|
|
45
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SafeResourceUrl } from '@angular/platform-browser';
|
|
2
|
+
import { VideoPlayerAsset } from './types';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* `val-video-player` — reproductor de video de plataforma (ADR-087, "Fase 1 —
|
|
6
|
+
* Reproducción"). Presentacional/dumb: recibe un `VideoPlayerAsset` YA
|
|
7
|
+
* RESUELTO por el backend de turno y decide el render, sin fetch propio.
|
|
8
|
+
*
|
|
9
|
+
* - `source:'upload'` + `status:'ready'` → `<video>` nativo (`preload="none"`
|
|
10
|
+
* + portada — ADR-087 §8, cero bytes de video hasta que alguien le da play).
|
|
11
|
+
* - `source:'upload'` + `uploading|processing` → portada (si hay) + mensaje.
|
|
12
|
+
* - `source:'upload'` + `failed|rejected` → mensaje legible con `failReason`
|
|
13
|
+
* (texto ya resuelto por el backend, se muestra tal cual).
|
|
14
|
+
* - `source:'link'` → iframe **siempre** contra un patrón fijo por proveedor
|
|
15
|
+
* conocido (`youtube-nocookie.com/embed/{id}` · `player.vimeo.com/video/{id}`),
|
|
16
|
+
* nunca un `src` armado con datos crudos del usuario. Proveedor no
|
|
17
|
+
* reconocido → mensaje, nunca un iframe "por si acaso".
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <val-video-player [video]="doc.video" />
|
|
21
|
+
*/
|
|
22
|
+
export declare class VideoPlayerComponent {
|
|
23
|
+
private readonly i18n;
|
|
24
|
+
private readonly sanitizer;
|
|
25
|
+
/** El `VideoAsset` ya resuelto por el backend. `null`/`undefined` → no renderiza nada. */
|
|
26
|
+
readonly video: import("@angular/core").InputSignal<VideoPlayerAsset>;
|
|
27
|
+
readonly asset: import("@angular/core").Signal<VideoPlayerAsset>;
|
|
28
|
+
readonly thumbFailed: import("@angular/core").WritableSignal<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Arma el embed SIEMPRE contra un patrón fijo por proveedor conocido — el
|
|
31
|
+
* `externalId` es el único dato del backend que entra en el `src`. Un
|
|
32
|
+
* proveedor no reconocido devuelve `null` (el template cae al mensaje, no a
|
|
33
|
+
* un iframe "por si acaso"). `bypassSecurityTrustResourceUrl` es seguro acá
|
|
34
|
+
* porque el string completo lo arma este componente, nunca el usuario.
|
|
35
|
+
*/
|
|
36
|
+
readonly embedUrl: import("@angular/core").Signal<SafeResourceUrl>;
|
|
37
|
+
constructor();
|
|
38
|
+
private buildEmbedUrl;
|
|
39
|
+
t(key: string): string;
|
|
40
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<VideoPlayerComponent, never>;
|
|
41
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<VideoPlayerComponent, "val-video-player", never, { "video": { "alias": "video"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
42
|
+
}
|
package/lib/version.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "valtech-components",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.972",
|
|
4
4
|
"private": false,
|
|
5
5
|
"bin": {
|
|
6
6
|
"valtech-firebase-config": "./src/lib/services/firebase/scripts/generate-sw-config.js"
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
"@dicebear/initials": "^9.4.2",
|
|
49
49
|
"@dicebear/pixel-art": "^9.4.2",
|
|
50
50
|
"@dicebear/shapes": "^9.4.2",
|
|
51
|
+
"@tiptap/core": "^2.27.2",
|
|
52
|
+
"@tiptap/extension-image": "^2.27.2",
|
|
53
|
+
"@tiptap/pm": "^2.27.2",
|
|
54
|
+
"@tiptap/starter-kit": "^2.27.2",
|
|
51
55
|
"@zxing/browser": "^0.2.0",
|
|
52
56
|
"@zxing/library": "^0.22.0",
|
|
53
57
|
"compressorjs": "^1.3.0",
|
package/public-api.d.ts
CHANGED
|
@@ -247,6 +247,10 @@ export * from './lib/components/organisms/attachment-uploader/attachment-uploade
|
|
|
247
247
|
export * from './lib/components/organisms/attachment-uploader/types';
|
|
248
248
|
export * from './lib/components/organisms/article/article.component';
|
|
249
249
|
export * from './lib/components/organisms/article/types';
|
|
250
|
+
export * from './lib/components/organisms/rich-editor/rich-editor.component';
|
|
251
|
+
export * from './lib/components/organisms/rich-editor/types';
|
|
252
|
+
export * from './lib/components/organisms/rich-editor/tiptap-to-article';
|
|
253
|
+
export * from './lib/components/organisms/rich-editor/article-to-tiptap';
|
|
250
254
|
export * from './lib/components/organisms/banner/banner.component';
|
|
251
255
|
export * from './lib/components/organisms/banner/types';
|
|
252
256
|
export * from './lib/components/organisms/change-password-modal/change-password-modal.component';
|
|
@@ -580,3 +584,7 @@ export { ThreadPanelComponent } from './lib/components/organisms/thread-panel/th
|
|
|
580
584
|
export * from './lib/services/forms';
|
|
581
585
|
export * from './lib/services/metering.service';
|
|
582
586
|
export { ValQuotaWarningComponent } from './lib/components/val-quota-warning/val-quota-warning.component';
|
|
587
|
+
export * from './lib/components/organisms/page-block/page-block.component';
|
|
588
|
+
export * from './lib/components/organisms/page-block/types';
|
|
589
|
+
export * from './lib/components/organisms/video-player/video-player.component';
|
|
590
|
+
export * from './lib/components/organisms/video-player/types';
|