@aster-editor/angular 0.4.2 → 0.5.0

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/README.md CHANGED
@@ -92,22 +92,26 @@ export class ArticleFormComponent {
92
92
 
93
93
  ## 🎛️ Inputs et outputs
94
94
 
95
- | Input | Type | Défaut effectif | À chaud |
96
- | ----------------------- | -------------------------- | --------------- | ----------------------------------------------------------- |
97
- | `toolbar` | `ToolbarConfig` | `'standard'` | Remonte l'éditeur : contenu conservé, historique perdu |
98
- | `theme` | `AsterTheme` | `'light'` | Oui |
99
- | `locale` | `AsterLocale` | `'fr'` | Oui, toolbar comprise |
100
- | `placeholder` | `string \| undefined` | chaîne i18n | Oui |
101
- | `readonly` | `boolean` | `false` | Oui, cumulé avec le `disabled` du formulaire |
102
- | `config` | `Partial<AsterUiOptions>` | `{}` | Seules les clés ci-dessus sont relues ; le reste au montage |
103
- | `wordPaste` | `boolean` | `true` | Oui |
104
- | `ariaLabel` | `string \| undefined` | aucun | Oui : `aria-label` sur le contenteditable |
105
- | `ariaLabelledBy` | `string \| undefined` | aucun | Oui : `aria-labelledby` sur le contenteditable |
106
- | `variables` | `readonly AsterVariable[]` | aucune | Oui : `editor.variables.define(...)`, fusion par nom |
107
- | `variableValues` | `VariableValues` | aucune | Oui : `editor.variables.setValues(...)`, fusion par nom |
108
- | `variableResolver` | `VariableResolver` | aucun | Non, lu au montage |
109
- | `allowUnknownVariables` | `boolean` | `true` | Non, lu au montage |
110
- | `variableSuggestion` | `boolean` | `true` | Non, lu au montage |
95
+ | Input | Type | Défaut effectif | À chaud |
96
+ | ----------------------- | ----------------------------- | --------------- | ----------------------------------------------------------- |
97
+ | `toolbar` | `ToolbarConfig` | `'standard'` | Remonte l'éditeur : contenu conservé, historique perdu |
98
+ | `theme` | `AsterTheme` | `'light'` | Oui |
99
+ | `locale` | `AsterLocale` | `'fr'` | Oui, toolbar comprise |
100
+ | `placeholder` | `string \| undefined` | chaîne i18n | Oui |
101
+ | `readonly` | `boolean` | `false` | Oui, cumulé avec le `disabled` du formulaire |
102
+ | `config` | `Partial<AsterUiOptions>` | `{}` | Seules les clés ci-dessus sont relues ; le reste au montage |
103
+ | `wordPaste` | `boolean` | `true` | Oui |
104
+ | `ariaLabel` | `string \| undefined` | aucun | Oui : `aria-label` sur le contenteditable |
105
+ | `ariaLabelledBy` | `string \| undefined` | aucun | Oui : `aria-labelledby` sur le contenteditable |
106
+ | `variables` | `readonly AsterVariable[]` | aucune | Oui : `editor.variables.define(...)`, fusion par nom |
107
+ | `variableValues` | `VariableValues` | aucune | Oui : `editor.variables.setValues(...)`, fusion par nom |
108
+ | `variableResolver` | `VariableResolver` | aucun | Non, lu au montage |
109
+ | `allowUnknownVariables` | `boolean` | `true` | Non, lu au montage |
110
+ | `variableSuggestion` | `boolean` | `true` | Non, lu au montage |
111
+ | `importFidelity` | `'styled' \| 'semantic'` | `'styled'` | Lu à chaque `importDocx` |
112
+ | `exportInTemplate` | `boolean` | `true` | Lu à chaque `exportDocx` |
113
+ | `pageView` | `boolean \| PageViewOptions` | `false` | Oui : la vue page est remontée |
114
+ | `layout` | `DocumentLayout \| undefined` | aucune | Oui : vue page et export, voir « Fidélité Word » |
111
115
 
112
116
  Un contenteditable ne s'associe pas à un `<label for>` : nomme la zone de saisie avec
113
117
  `ariaLabel`, ou `ariaLabelledBy` pointant sur l'`id` de ton libellé visible. Les deux sont
@@ -127,6 +131,7 @@ dans l'éditeur.
127
131
  | `focused` | `void` | Focus du contenu |
128
132
  | `blurred` | `void` | Focus perdu vers l'extérieur de l'éditeur (pas vers la toolbar) ; marque le contrôle `touched` |
129
133
  | `variablesChanged` | `VariableValues` | Valeurs ou déclarations de variables changées (`setValues`, `define`, `resolve`, import) |
134
+ | `layoutChanged` | `DocumentLayout` | Mise en page effective changée : import, input `layout`, dialogue « Mise en page » |
130
135
 
131
136
  API publique du composant :
132
137
 
@@ -134,10 +139,17 @@ API publique du composant :
134
139
  `commands.run(...)`, `tiptap`…), `null` avant le montage et après la destruction.
135
140
  - `variableNames` : `Signal<readonly string[]>`, noms des variables présentes dans le document,
136
141
  relus sur `change` et `variablesChange`.
142
+ - `importedTemplate` : `Signal<ArrayBuffer | null>`, le `.docx` du dernier import, intact.
143
+ - `layout` : `Signal<DocumentLayout | null>`, mise en page effective (input `layout`, sinon
144
+ import ou dialogue « Mise en page »).
145
+ - `lostObjects` : `Signal<readonly DocxLostObject[]>`, objets Word non représentables du dernier
146
+ import.
137
147
  - `getHTML(options?)` : HTML du document, `{ variables: 'resolve' }` substitue les valeurs.
138
148
  - `resolveVariables()` : appelle le résolveur pour les variables sans valeur, rend les valeurs.
139
149
  - `importDocx(file: File): Promise<DocxImportResult>` : voir plus bas.
140
- - `exportDocx(options?: DocxExportOptions): Promise<Blob>` : voir « Variables et modèles ».
150
+ - `exportDocx(options?: DocxExportOptions): Promise<Blob>` : voir « Variables et modèles » et
151
+ « Fidélité Word ».
152
+ - `compareWithTemplate(): Promise<FidelityReport | null>` : voir « Fidélité Word ».
141
153
 
142
154
  La vue source, le plein écran et le menu contextuel de table de `@aster-editor/ui` sont montés
143
155
  par `createAster` et donc disponibles dans le composant : via les widgets `source` /
@@ -151,7 +163,10 @@ Types réexportés pour ne pas dépendre de `core`, `ui` ou `word` : `AsterEdito
151
163
  `PasteTransformer`, `ToolbarConfig`, `ToolbarPreset`, `UploadHandler`, `AsterVariable`,
152
164
  `VariableValues`, `VariableResolver`, `VariableSource`, `VariableRenderMode`, `GetHtmlOptions`,
153
165
  `AsterUiOptions`, `DocxImportResult`, `DocxImportWarning`, `DocxExportOptions`,
154
- `DocxExportVariableOptions`, `DocxExportWarning`, `DocxVariableMode`.
166
+ `DocxExportVariableOptions`, `DocxExportWarning`, `DocxVariableMode`, et pour la fidélité Word :
167
+ `DocumentLayout`, `PageSetup`, `PageMargins`, `HeaderFooterSet`, `HeaderFooterContent`,
168
+ `PageViewOptions`, `PageViewInput`, `DocxImportFidelity`, `DocxLostObject`, `FidelityReport`,
169
+ `FidelityProperty`, `FidelityPropertyGroup`, `FidelityExample`.
155
170
 
156
171
  Un input dédié laissé à `undefined` n'écrase pas la valeur venue de `config` ou de
157
172
  `provideAster`. Passe des objets **stables** dans `config` (champ de classe, pas un littéral dans
@@ -234,10 +249,16 @@ export class ImportComponent {
234
249
  }
235
250
  ```
236
251
 
237
- `importDocx` charge `@aster-editor/word` par `import()` : mammoth reste dans un chunk séparé et
238
- n'est téléchargé qu'au premier import. Le contenu est remplacé avec émission de `change`, un
252
+ `importDocx` charge `@aster-editor/word` par `import()` : le lecteur reste dans un chunk séparé
253
+ et n'est téléchargé qu'au premier import. Le contenu est remplacé avec émission de `change`, un
239
254
  formulaire lié voit donc la nouvelle valeur. Le handler d'upload de l'éditeur est réutilisé pour
240
- les images embarquées. Appelé avant le montage, il rejette avec une erreur explicite.
255
+ les images embarquées. Appelé avant le montage, il rejette avec une erreur explicite. Par défaut
256
+ l'import est **stylé** (`importFidelity: 'styled'`) : polices, tailles, couleurs, interlignes,
257
+ bordures, tableaux et listes sont conservés, et le composant garde le gabarit et la mise en page
258
+ du document, voir « Fidélité Word ». `importFidelity: 'semantic'` retrouve le HTML propre de
259
+ mammoth (comportement 0.4.x), sans mise en page. Attention à la différence avec la lib : le
260
+ composant choisit `styled` pour toi, alors que `importDocx` de `@aster-editor/word` appelé
261
+ directement reste en `semantic` en 0.5.0 (bascule prévue en 0.6).
241
262
 
242
263
  > ⚠️ **Vite à froid** : sur `ng serve`, le tout premier `importDocx` d'une session déclenche
243
264
  > l'optimisation de `mammoth` par Vite et **recharge la page** en plein import, sans erreur.
@@ -367,6 +388,101 @@ Pour un aperçu résolu sans export, `editor().getHTML({ variables: 'resolve' })
367
388
  avec les valeurs substituées en texte brut ; `resolveVariables()` appelle d'abord le résolveur
368
389
  pour les variables manquantes.
369
390
 
391
+ ## 📐 Fidélité Word
392
+
393
+ Objectif : un `.docx` importé **ressort comme l'original** partout où l'utilisateur n'a rien
394
+ touché. Le composant enchaîne les quatre briques de `@aster-editor/word` sans que l'application
395
+ ait à les connaître.
396
+
397
+ ### Import stylé et mise en page
398
+
399
+ `importDocx` (mode `styled` par défaut) conserve trois choses dans des signals :
400
+
401
+ - `importedTemplate()` : le `.docx` d'origine, intact (`ArrayBuffer`) ;
402
+ - `layout()` : la mise en page lue dans la dernière section (`DocumentLayout` : format,
403
+ orientation, marges, colonnes, police par défaut, langue, en-têtes et pieds en HTML stylé) ;
404
+ - `lostObjects()` : les objets Word que l'éditeur ne sait pas représenter (zones de texte, formes,
405
+ équations, commentaires, révisions…), avec leur position (`body`, `header`…).
406
+
407
+ ### Vue page
408
+
409
+ ```html
410
+ <aster-editor [pageView]="true" (layoutChanged)="layout = $event" />
411
+ ```
412
+
413
+ `pageView` (`true`, ou `{ layout, pagination, showHeadersFooters }`) rend une feuille aux
414
+ dimensions et marges de `layout()`, avec les en-têtes et pieds `default` en lecture seule
415
+ au-dessus et au-dessous du corps et une pagination **approximative** (coupures « Page n sur N »
416
+ posées en décorations, jamais dans le HTML) ; importe `@aster-editor/ui/themes/page.css` (inclus
417
+ dans `aster.css`). Après un import, la mise en page lue est appliquée à la vue page active. Le
418
+ bouton « Mise en page » de la toolbar (widget `pageLayout`, preset `full` ; `standard` n'a que
419
+ l'interligne et les retraits) peut l'activer, la modifier ou la retirer : le composant relit alors
420
+ la mise en page, `layout()` suit et `layoutChanged` est émis. La vue page survit à un remontage
421
+ (`toolbar`). `config.pageView` est honoré, l'input dédié prime.
422
+
423
+ L'input `layout` impose une mise en page : il prime sur celle de l'import et sur celle du
424
+ dialogue, se répercute sur la vue page active et sur `exportDocx`. Comme il masque ce que le
425
+ dialogue pose ensuite, tiens-le à jour depuis `layoutChanged` (`[layout]="layout()"` +
426
+ `(layoutChanged)="layout.set($event)"`) : c'est ce que fait la page « Modèle » de la démo pour
427
+ ses éditeurs d'en-tête et de pied.
428
+
429
+ ### Export dans le gabarit
430
+
431
+ ```ts
432
+ const blob = await this.editor().exportDocx({ variables: { mode: 'fields' } });
433
+ ```
434
+
435
+ Sans `options.template`, `exportDocx` réutilise `importedTemplate()` dès qu'il existe
436
+ (`exportInTemplate`, vrai par défaut) : styles, numérotation, thème, polices, en-têtes, pieds,
437
+ sections et propriétés du document ressortent **identiques à l'octet**, seul le corps est
438
+ régénéré depuis l'éditeur. La mise en page effective (`layout()`) est transmise elle aussi : avec
439
+ un gabarit, elle ne sert qu'à régénérer un en-tête ou un pied dont le HTML a changé (le reste
440
+ vient du gabarit) ; sans gabarit, elle pilote l'export neuf (format, marges, en-têtes, pieds,
441
+ police par défaut). `exportInTemplate: false` force l'export neuf, un `options.template`
442
+ explicite reste honoré.
443
+
444
+ ### Rapport de fidélité
445
+
446
+ ```ts
447
+ const report = await this.editor().compareWithTemplate();
448
+ if (report) console.log(report.score, report.properties, report.changedParts);
449
+ ```
450
+
451
+ `compareWithTemplate()` exporte le document courant dans son gabarit (valeurs du magasin de
452
+ variables, mise en page effective, comme `exportDocx({ template })`) puis le compare à
453
+ l'original propriété par propriété (`compareDocx` de `word`, chargé à la demande) : score
454
+ pondéré entre 0 et 1, propriétés conservées / perdues par groupe (`text`, `paragraph-style`,
455
+ `paragraph-format`, `run-format`, `list`, `table`, `image`, `note`, `header-footer`, `section`,
456
+ `package-part`) avec jusqu'à cinq exemples, parties du paquet identiques ou non, objets perdus,
457
+ notes. `null` sans gabarit importé. Un aller-retour sans modification vise un score ≥ 0,98 ;
458
+ c'est le critère d'acceptation, pas une impression visuelle. Scores mesurés sur les fixtures et
459
+ le document client dans [`fixtures/docx/README.md`](../../fixtures/docx/README.md) (1 pour les
460
+ fixtures 11, 13 et 15 ; 0,889 pour le document client, dont les trois sections ressortent en
461
+ une seule).
462
+
463
+ ### Limites
464
+
465
+ - **Pas de pagination exacte** : la vue page donne le format, les marges, les en-têtes et pieds,
466
+ les sauts de page explicites, et une pagination **approximative** (coupures visuelles, numéros
467
+ de page, tableaux et listes jamais coupés) qui ne garantit pas le même nombre de pages que Word.
468
+ - **Objets non représentables** : conservés tels quels dans le gabarit quand ils sont hors du
469
+ corps (en-têtes, pieds), remplacés par leur texte et listés dans `lostObjects()` quand ils sont
470
+ dans le corps édité.
471
+ - **Sections multiples** : seule la dernière section du document est lue (`layout()`) et
472
+ survit à l'export dans le gabarit ; un document à plusieurs formats de page ressort avec un
473
+ seul.
474
+ - Avec un gabarit, les options `page`, `pageSize`, `header`, `footer`, `defaultFont`, `lang`,
475
+ `headingStyles` de l'export sont ignorées, ainsi que `layout.page`, `layout.columns`,
476
+ `layout.titlePage`, `layout.defaultFont` et `layout.lang` : le gabarit les porte (JSDoc de
477
+ `template` dans `packages/word/src/export/types.ts`). `variables`, `toc`, `numberedHeadings`,
478
+ `title`, `creator`, `layout.headers` et `layout.footers` s'appliquent.
479
+ - Seuls les en-têtes et pieds `default` sont affichés par la vue page ; `first` et `even` sont
480
+ conservés dans le gabarit et dans `layout()`. Un en-tête ou pied édité via `[layout]` est
481
+ régénéré par l'export neuf et perd ce que celui-ci ne sait pas écrire (tableaux complexes,
482
+ images ancrées, champs autres que `PAGE` / `NUMPAGES` / fusion).
483
+ - Le chemin `semantic` ne renseigne ni `layout()` (objet vide) ni `lostObjects()` ; le gabarit
484
+ (`importedTemplate()`) est conservé sur les deux chemins.
485
+
370
486
  ## 📋 Collage depuis Word
371
487
 
372
488
  Avec `wordPaste` (vrai par défaut), le composant charge `@aster-editor/word` au montage (jamais
@@ -380,15 +496,18 @@ et le collage reste brut. Passer `wordPaste` à `false` laisse le module chargé
380
496
  `apps/demo` (`npm run demo`, http://localhost:4200) montre cinq pages chargées à la demande,
381
497
  chacune avec son titre de document : `/` playground (preset, thème, langue, lecture seule,
382
498
  compteurs, sortie HTML / JSON), `/form` reactive form avec validateur « requis » sur le contenu
383
- riche, `/import` dépôt de `.docx` avec avertissements, `/readonly` rendu figé en thème `night`,
384
- `/template` modèle à variables (exemple `08-variables-braces.docx` servi depuis
385
- `public/samples/`, formulaire généré, aperçu puces / résolu, export dans les trois modes).
499
+ riche, `/import` dépôt de `.docx` avec sélecteur `styled` / `semantic`, mise en page lue et
500
+ avertissements (exemple `13-styles-nommes.docx`), `/readonly` rendu figé en thème `night`,
501
+ `/template` modèle à variables (exemples `08-variables-braces.docx` et `16-sections.docx` servis
502
+ depuis `public/samples/`, formulaire généré, aperçu puces / résolu, vue page, en-tête et pied
503
+ éditables, export dans les trois modes ou dans le gabarit, rapport de fidélité, objets non
504
+ représentables).
386
505
 
387
506
  ## 🧪 Tests
388
507
 
389
508
  ```bash
390
- npx ng test aster-angular --watch=false # 39 tests du composant et de provideAster
391
- npx ng test demo --watch=false # 23 tests des pages de la démo
509
+ npx ng test aster-angular --watch=false # 49 tests du composant et de provideAster (importFidelity, exportInTemplate, pageView, layout, compareWithTemplate compris)
510
+ npx ng test demo --watch=false # 30 tests des pages de la démo (Import : sélecteur styled / semantic ; Modèle : vue page, en-tête et pied, rapport de fidélité, objets perdus)
392
511
  npm run e2e -- --project=demo # tests Playwright sur la démo, page Modèle comprise (ng serve lancé par Playwright)
393
512
  ```
394
513
 
@@ -1,7 +1,68 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import { ChangeDetectionStrategy, Component, DestroyRef, InjectionToken, afterNextRender, computed, effect, forwardRef, inject, input, makeEnvironmentProviders, output, signal, untracked, viewChild } from "@angular/core";
3
3
  import { NG_VALUE_ACCESSOR } from "@angular/forms";
4
- import { createAster } from "@aster-editor/ui";
4
+ import { PAGE_VIEW_CHANGE_EVENT, getActivePageView } from "@aster-editor/core";
5
+ import { createAster, pageViewApiOf } from "@aster-editor/ui";
6
+ function setOrRemoveAttribute(element, name, value) {
7
+ if (value === void 0 || value === "") element.removeAttribute(name);
8
+ else element.setAttribute(name, value);
9
+ }
10
+ function applyAriaAttributes(editor, label, labelledBy) {
11
+ setOrRemoveAttribute(editor.contentElement, "aria-label", label);
12
+ setOrRemoveAttribute(editor.contentElement, "aria-labelledby", labelledBy);
13
+ }
14
+ function applyPlaceholder(editor, placeholder) {
15
+ const tiptap = editor.tiptap;
16
+ const extension = tiptap.extensionManager.extensions.find((candidate) => candidate.name === "placeholder");
17
+ if (extension?.type !== "extension") return;
18
+ const factory = extension.config.addProseMirrorPlugins;
19
+ if (!factory) return;
20
+ const options = {
21
+ ...extension.options,
22
+ placeholder: () => placeholder ?? editor.i18n.t("editor.placeholder")
23
+ };
24
+ const plugins = factory.call({
25
+ name: extension.name,
26
+ options,
27
+ storage: extension.storage,
28
+ editor: tiptap,
29
+ type: null,
30
+ parent: void 0
31
+ });
32
+ for (const plugin of plugins) {
33
+ tiptap.unregisterPlugin(plugin.spec.key ?? extension.name);
34
+ tiptap.registerPlugin(plugin);
35
+ }
36
+ }
37
+ function resolvePageViewOptions(pageView, layout) {
38
+ if (pageView === void 0 || pageView === false) return pageView;
39
+ const base = pageView === true ? {} : pageView;
40
+ return layout ? {
41
+ ...base,
42
+ layout
43
+ } : base;
44
+ }
45
+ function setPageView(editor, options) {
46
+ const api = pageViewApiOf(editor);
47
+ if (!api) return;
48
+ if (options === void 0 || options === false) api.setPageView(false);
49
+ else api.setPageView(options === true ? {} : options);
50
+ }
51
+ function readPageViewLayout(editor) {
52
+ const active = getActivePageView(editor.contentElement);
53
+ if (!active) return null;
54
+ return active.layout ?? pageViewApiOf(editor)?.getLayout() ?? null;
55
+ }
56
+ function applyLayoutToPageView(editor, layout) {
57
+ const api = pageViewApiOf(editor);
58
+ const active = getActivePageView(editor.contentElement);
59
+ if (!api || !active || api.getLayout() === layout) return false;
60
+ api.setPageView({
61
+ ...active,
62
+ layout
63
+ });
64
+ return true;
65
+ }
5
66
  const ASTER_CONFIG = new InjectionToken("ASTER_CONFIG");
6
67
  function provideAster(config) {
7
68
  return makeEnvironmentProviders([{
@@ -10,9 +71,50 @@ function provideAster(config) {
10
71
  }]);
11
72
  }
12
73
  const ASTER_UPLOAD_HANDLER = new InjectionToken("ASTER_UPLOAD_HANDLER");
13
- function setOrRemoveAttribute(element, name, value) {
14
- if (value === void 0 || value === "") element.removeAttribute(name);
15
- else element.setAttribute(name, value);
74
+ async function importWord(file, defaults) {
75
+ const { importDocx } = await import("@aster-editor/word");
76
+ return importDocx(file, {
77
+ ...defaults.upload ? { upload: defaults.upload } : {},
78
+ fidelity: defaults.fidelity
79
+ });
80
+ }
81
+ function resolveExportOptions(editor, options, defaults) {
82
+ const variables = {
83
+ ...options.variables,
84
+ values: options.variables?.values ?? editor.variables.getValues()
85
+ };
86
+ const template = options.template ?? (defaults.inTemplate && defaults.template ? defaults.template : void 0);
87
+ const layout = options.layout ?? defaults.layout ?? void 0;
88
+ return {
89
+ ...options,
90
+ variables,
91
+ ...template !== void 0 ? { template } : {},
92
+ ...layout !== void 0 ? { layout } : {}
93
+ };
94
+ }
95
+ async function exportWord(editor, options) {
96
+ const { exportDocx } = await import("@aster-editor/word");
97
+ return exportDocx(editor.getHTML(), options);
98
+ }
99
+ async function compareWithTemplate(template, exported) {
100
+ const { compareDocx } = await import("@aster-editor/word");
101
+ return compareDocx(template, await exported.arrayBuffer());
102
+ }
103
+ async function loadWordPasteTransformer() {
104
+ const { wordPasteTransformer } = await import("@aster-editor/word");
105
+ return wordPasteTransformer();
106
+ }
107
+ function declareImportedVariables(editor, found, known) {
108
+ if (found.length === 0) return;
109
+ editor.variables.define(found);
110
+ const values = untracked(known);
111
+ if (!values) return;
112
+ const overrides = {};
113
+ for (const variable of found) {
114
+ const value = values[variable.name];
115
+ if (variable.value !== void 0 && value !== void 0 && value !== variable.value) overrides[variable.name] = value;
116
+ }
117
+ if (Object.keys(overrides).length > 0) editor.variables.setValues(overrides);
16
118
  }
17
119
  function sameNames(a, b) {
18
120
  return a.length === b.length && a.every((name, index) => name === b[index]);
@@ -32,13 +134,27 @@ var AsterEditorComponent = class AsterEditorComponent {
32
134
  variableResolver = input(void 0, ...ngDevMode ? [{ debugName: "variableResolver" }] : /* istanbul ignore next */ []);
33
135
  allowUnknownVariables = input(void 0, ...ngDevMode ? [{ debugName: "allowUnknownVariables" }] : /* istanbul ignore next */ []);
34
136
  variableSuggestion = input(void 0, ...ngDevMode ? [{ debugName: "variableSuggestion" }] : /* istanbul ignore next */ []);
137
+ importFidelity = input(void 0, ...ngDevMode ? [{ debugName: "importFidelity" }] : /* istanbul ignore next */ []);
138
+ exportInTemplate = input(true, ...ngDevMode ? [{ debugName: "exportInTemplate" }] : /* istanbul ignore next */ []);
139
+ pageView = input(void 0, ...ngDevMode ? [{ debugName: "pageView" }] : /* istanbul ignore next */ []);
140
+ layoutOverride = input(void 0, {
141
+ ...ngDevMode ? { debugName: "layoutOverride" } : /* istanbul ignore next */ {},
142
+ alias: "layout"
143
+ });
35
144
  ready = output();
36
145
  changed = output();
37
146
  focused = output();
38
147
  blurred = output();
39
148
  variablesChanged = output();
149
+ layoutChanged = output();
40
150
  editorState = signal(null, ...ngDevMode ? [{ debugName: "editorState" }] : /* istanbul ignore next */ []);
41
151
  editor = this.editorState.asReadonly();
152
+ importedTemplateState = signal(null, ...ngDevMode ? [{ debugName: "importedTemplateState" }] : /* istanbul ignore next */ []);
153
+ importedTemplate = this.importedTemplateState.asReadonly();
154
+ lostObjectsState = signal([], ...ngDevMode ? [{ debugName: "lostObjectsState" }] : /* istanbul ignore next */ []);
155
+ lostObjects = this.lostObjectsState.asReadonly();
156
+ layoutState = signal(null, ...ngDevMode ? [{ debugName: "layoutState" }] : /* istanbul ignore next */ []);
157
+ layout = computed(() => this.layoutOverride() ?? this.layoutState(), ...ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []);
42
158
  variableNamesState = signal([], {
43
159
  ...ngDevMode ? { debugName: "variableNamesState" } : /* istanbul ignore next */ {},
44
160
  equal: sameNames
@@ -68,8 +184,11 @@ var AsterEditorComponent = class AsterEditorComponent {
68
184
  return Object.keys(source).length > 0 ? source : void 0;
69
185
  }, ...ngDevMode ? [{ debugName: "resolvedVariableSource" }] : /* istanbul ignore next */ []);
70
186
  resolvedVariableSuggestion = computed(() => this.variableSuggestion() ?? this.mergedConfig().variableSuggestion, ...ngDevMode ? [{ debugName: "resolvedVariableSuggestion" }] : /* istanbul ignore next */ []);
187
+ resolvedPageView = computed(() => this.pageView() ?? this.mergedConfig().pageView, ...ngDevMode ? [{ debugName: "resolvedPageView" }] : /* istanbul ignore next */ []);
71
188
  instance = null;
72
189
  mountedToolbar = null;
190
+ mountedPageView = void 0;
191
+ emittedLayout = null;
73
192
  subscriptions = [];
74
193
  pendingValue = null;
75
194
  wordTransformer = null;
@@ -98,14 +217,14 @@ var AsterEditorComponent = class AsterEditorComponent {
98
217
  effect(() => {
99
218
  const placeholder = this.resolvedPlaceholder();
100
219
  untracked(() => {
101
- if (this.instance) this.applyPlaceholder(this.instance.editor, placeholder);
220
+ if (this.instance) applyPlaceholder(this.instance.editor, placeholder);
102
221
  });
103
222
  });
104
223
  effect(() => {
105
224
  const label = this.ariaLabel();
106
225
  const labelledBy = this.ariaLabelledBy();
107
226
  untracked(() => {
108
- if (this.instance) this.applyAriaAttributes(this.instance.editor, label, labelledBy);
227
+ if (this.instance) applyAriaAttributes(this.instance.editor, label, labelledBy);
109
228
  });
110
229
  });
111
230
  effect(() => {
@@ -131,30 +250,51 @@ var AsterEditorComponent = class AsterEditorComponent {
131
250
  if (values && this.instance) this.instance.editor.variables.setValues(values);
132
251
  });
133
252
  });
253
+ effect(() => {
254
+ const pageView = this.resolvedPageView();
255
+ untracked(() => {
256
+ if (this.instance && this.mountedPageView !== pageView) {
257
+ this.mountedPageView = pageView;
258
+ setPageView(this.instance.editor, resolvePageViewOptions(pageView, this.layout()));
259
+ }
260
+ });
261
+ });
262
+ effect(() => {
263
+ const layout = this.layout();
264
+ untracked(() => {
265
+ if (layout && this.instance) applyLayoutToPageView(this.instance.editor, layout);
266
+ this.notifyLayout(layout);
267
+ });
268
+ });
134
269
  }
135
270
  async importDocx(file) {
136
271
  this.requireEditor("importDocx");
137
- const upload = untracked(() => this.resolvedOptions().upload);
138
- const { importDocx } = await import("@aster-editor/word");
139
- const result = await importDocx(file, upload ? { upload } : {});
272
+ const result = await importWord(file, untracked(() => ({
273
+ upload: this.resolvedOptions().upload,
274
+ fidelity: this.importFidelity() ?? "styled"
275
+ })));
140
276
  const editor = this.instance?.editor;
141
277
  if (editor && !editor.isDestroyed()) {
142
278
  editor.setHTML(result.html, true);
143
- this.declareImportedVariables(editor, result.variables);
279
+ declareImportedVariables(editor, result.variables, () => this.variableValues());
280
+ this.importedTemplateState.set(result.template);
281
+ this.lostObjectsState.set(result.lost);
282
+ this.layoutState.set(result.layout);
144
283
  }
145
284
  return result;
146
285
  }
147
286
  async exportDocx(options = {}) {
148
287
  const editor = this.requireEditor("exportDocx");
149
- const { exportDocx } = await import("@aster-editor/word");
150
- const variables = {
151
- ...options.variables,
152
- values: options.variables?.values ?? editor.variables.getValues()
153
- };
154
- return exportDocx(editor.getHTML(), {
155
- ...options,
156
- variables
157
- });
288
+ return exportWord(editor, untracked(() => resolveExportOptions(editor, options, {
289
+ template: this.importedTemplate(),
290
+ layout: this.layout(),
291
+ inTemplate: this.exportInTemplate()
292
+ })));
293
+ }
294
+ async compareWithTemplate() {
295
+ const template = this.importedTemplate();
296
+ if (!template) return null;
297
+ return compareWithTemplate(template, await this.exportDocx({ template }));
158
298
  }
159
299
  getHTML(options) {
160
300
  return this.instance?.editor.getHTML(options) ?? this.pendingValue ?? "";
@@ -189,28 +329,27 @@ var AsterEditorComponent = class AsterEditorComponent {
189
329
  const editor = instance.editor;
190
330
  this.instance = instance;
191
331
  this.mountedToolbar = options.toolbar ?? "standard";
332
+ this.mountedPageView = untracked(() => this.resolvedPageView());
192
333
  this.pendingValue = null;
193
- this.subscriptions = [
194
- editor.on("ready", ({ editor: ready }) => this.ready.emit(ready)),
195
- editor.on("change", ({ editor: changed }) => {
196
- const html = changed.getHTML();
197
- this.onChange?.(html);
198
- this.changed.emit(html);
199
- this.refreshVariableNames(changed);
200
- }),
201
- editor.on("variablesChange", ({ editor: source, values }) => {
202
- this.refreshVariableNames(source);
203
- this.variablesChanged.emit(values);
204
- }),
205
- editor.on("focus", () => this.focused.emit()),
206
- editor.on("blur", ({ event }) => {
207
- const related = event.relatedTarget;
208
- if (related instanceof Node && instance.element.contains(related)) return;
209
- this.onTouched?.();
210
- this.blurred.emit();
211
- })
212
- ];
213
- untracked(() => this.applyAriaAttributes(editor, this.ariaLabel(), this.ariaLabelledBy()));
334
+ const onPageViewChange = () => this.readLayoutFromPageView(editor);
335
+ editor.contentElement.addEventListener(PAGE_VIEW_CHANGE_EVENT, onPageViewChange);
336
+ this.subscriptions = [() => editor.contentElement.removeEventListener(PAGE_VIEW_CHANGE_EVENT, onPageViewChange)];
337
+ this.subscriptions.push(editor.on("ready", ({ editor: ready }) => this.ready.emit(ready)), editor.on("change", ({ editor: changed }) => {
338
+ const html = changed.getHTML();
339
+ this.onChange?.(html);
340
+ this.changed.emit(html);
341
+ this.refreshVariableNames(changed);
342
+ }), editor.on("variablesChange", ({ editor: source, values }) => {
343
+ this.refreshVariableNames(source);
344
+ this.variablesChanged.emit(values);
345
+ }), editor.on("focus", () => this.focused.emit()), editor.on("blur", ({ event }) => {
346
+ const related = event.relatedTarget;
347
+ if (related instanceof Node && instance.element.contains(related)) return;
348
+ this.onTouched?.();
349
+ this.blurred.emit();
350
+ }));
351
+ untracked(() => applyAriaAttributes(editor, this.ariaLabel(), this.ariaLabelledBy()));
352
+ this.readLayoutFromPageView(editor);
214
353
  if (untracked(() => this.wordPaste())) this.loadWordPaste();
215
354
  this.refreshVariableNames(editor);
216
355
  this.editorState.set(editor);
@@ -221,6 +360,7 @@ var AsterEditorComponent = class AsterEditorComponent {
221
360
  this.instance?.destroy();
222
361
  this.instance = null;
223
362
  this.mountedToolbar = null;
363
+ this.mountedPageView = void 0;
224
364
  this.editorState.set(null);
225
365
  this.variableNamesState.set([]);
226
366
  }
@@ -261,9 +401,22 @@ var AsterEditorComponent = class AsterEditorComponent {
261
401
  pasteTransformers: [this.lazyWordTransformer, ...merged.pasteTransformers ?? []],
262
402
  upload: merged.upload ?? this.uploadHandler ?? void 0,
263
403
  variables: variableSource,
264
- variableSuggestion: this.resolvedVariableSuggestion()
404
+ variableSuggestion: this.resolvedVariableSuggestion(),
405
+ pageView: resolvePageViewOptions(this.resolvedPageView(), this.layout())
265
406
  };
266
407
  }
408
+ readLayoutFromPageView(editor) {
409
+ const current = readPageViewLayout(editor);
410
+ if (!current || current === untracked(() => this.layoutState()) || current === untracked(() => this.layoutOverride())) return;
411
+ this.layoutState.set(current);
412
+ if (untracked(() => this.layout()) !== current) this.notifyLayout(current);
413
+ }
414
+ notifyLayout(layout) {
415
+ if (layout && layout !== this.emittedLayout) {
416
+ this.emittedLayout = layout;
417
+ this.layoutChanged.emit(layout);
418
+ }
419
+ }
267
420
  requireEditor(method) {
268
421
  const editor = this.instance?.editor;
269
422
  if (!editor) throw new Error(`[aster-editor/angular] ${method}: editor is not mounted yet`);
@@ -272,54 +425,15 @@ var AsterEditorComponent = class AsterEditorComponent {
272
425
  refreshVariableNames(editor) {
273
426
  this.variableNamesState.set(editor.variables.getNames());
274
427
  }
275
- declareImportedVariables(editor, found) {
276
- if (found.length === 0) return;
277
- editor.variables.define(found);
278
- const known = untracked(() => this.variableValues());
279
- if (!known) return;
280
- const overrides = {};
281
- for (const variable of found) {
282
- const value = known[variable.name];
283
- if (variable.value !== void 0 && value !== void 0 && value !== variable.value) overrides[variable.name] = value;
284
- }
285
- if (Object.keys(overrides).length > 0) editor.variables.setValues(overrides);
286
- }
287
428
  loadWordPaste() {
288
429
  if (this.wordTransformer || this.wordLoading) return;
289
- this.wordLoading = import("@aster-editor/word").then((word) => {
290
- this.wordTransformer = word.wordPasteTransformer();
430
+ this.wordLoading = loadWordPasteTransformer().then((transformer) => {
431
+ this.wordTransformer = transformer;
291
432
  }).catch((error) => {
292
433
  this.wordLoading = null;
293
434
  console.warn("[aster-editor/angular] @aster-editor/word unavailable, paste kept raw", error);
294
435
  });
295
436
  }
296
- applyAriaAttributes(editor, label, labelledBy) {
297
- setOrRemoveAttribute(editor.contentElement, "aria-label", label);
298
- setOrRemoveAttribute(editor.contentElement, "aria-labelledby", labelledBy);
299
- }
300
- applyPlaceholder(editor, placeholder) {
301
- const tiptap = editor.tiptap;
302
- const extension = tiptap.extensionManager.extensions.find((candidate) => candidate.name === "placeholder");
303
- if (extension?.type !== "extension") return;
304
- const factory = extension.config.addProseMirrorPlugins;
305
- if (!factory) return;
306
- const options = {
307
- ...extension.options,
308
- placeholder: () => placeholder ?? editor.i18n.t("editor.placeholder")
309
- };
310
- const plugins = factory.call({
311
- name: extension.name,
312
- options,
313
- storage: extension.storage,
314
- editor: tiptap,
315
- type: null,
316
- parent: void 0
317
- });
318
- for (const plugin of plugins) {
319
- tiptap.unregisterPlugin(plugin.spec.key ?? extension.name);
320
- tiptap.registerPlugin(plugin);
321
- }
322
- }
323
437
  static ɵfac = i0.ɵɵngDeclareFactory({
324
438
  minVersion: "12.0.0",
325
439
  version: "22.2.2",
@@ -432,6 +546,34 @@ var AsterEditorComponent = class AsterEditorComponent {
432
546
  isSignal: true,
433
547
  isRequired: false,
434
548
  transformFunction: null
549
+ },
550
+ importFidelity: {
551
+ classPropertyName: "importFidelity",
552
+ publicName: "importFidelity",
553
+ isSignal: true,
554
+ isRequired: false,
555
+ transformFunction: null
556
+ },
557
+ exportInTemplate: {
558
+ classPropertyName: "exportInTemplate",
559
+ publicName: "exportInTemplate",
560
+ isSignal: true,
561
+ isRequired: false,
562
+ transformFunction: null
563
+ },
564
+ pageView: {
565
+ classPropertyName: "pageView",
566
+ publicName: "pageView",
567
+ isSignal: true,
568
+ isRequired: false,
569
+ transformFunction: null
570
+ },
571
+ layoutOverride: {
572
+ classPropertyName: "layoutOverride",
573
+ publicName: "layout",
574
+ isSignal: true,
575
+ isRequired: false,
576
+ transformFunction: null
435
577
  }
436
578
  },
437
579
  outputs: {
@@ -439,7 +581,8 @@ var AsterEditorComponent = class AsterEditorComponent {
439
581
  changed: "changed",
440
582
  focused: "focused",
441
583
  blurred: "blurred",
442
- variablesChanged: "variablesChanged"
584
+ variablesChanged: "variablesChanged",
585
+ layoutChanged: "layoutChanged"
443
586
  },
444
587
  providers: [{
445
588
  provide: NG_VALUE_ACCESSOR,
@@ -593,6 +736,38 @@ i0.ɵɵngDeclareClassMetadata({
593
736
  required: false
594
737
  }]
595
738
  }],
739
+ importFidelity: [{
740
+ type: i0.Input,
741
+ args: [{
742
+ isSignal: true,
743
+ alias: "importFidelity",
744
+ required: false
745
+ }]
746
+ }],
747
+ exportInTemplate: [{
748
+ type: i0.Input,
749
+ args: [{
750
+ isSignal: true,
751
+ alias: "exportInTemplate",
752
+ required: false
753
+ }]
754
+ }],
755
+ pageView: [{
756
+ type: i0.Input,
757
+ args: [{
758
+ isSignal: true,
759
+ alias: "pageView",
760
+ required: false
761
+ }]
762
+ }],
763
+ layoutOverride: [{
764
+ type: i0.Input,
765
+ args: [{
766
+ isSignal: true,
767
+ alias: "layout",
768
+ required: false
769
+ }]
770
+ }],
596
771
  ready: [{
597
772
  type: i0.Output,
598
773
  args: ["ready"]
@@ -613,6 +788,10 @@ i0.ɵɵngDeclareClassMetadata({
613
788
  type: i0.Output,
614
789
  args: ["variablesChanged"]
615
790
  }],
791
+ layoutChanged: [{
792
+ type: i0.Output,
793
+ args: ["layoutChanged"]
794
+ }],
616
795
  host: [{
617
796
  type: i0.ViewChild,
618
797
  args: ["host", { isSignal: true }]
@@ -1 +1 @@
1
- {"version":3,"file":"aster-editor-angular.mjs","names":[],"sources":["../../src/lib/provide-aster.ts","../../src/lib/tokens.ts","../../src/lib/aster-editor.component.ts"],"sourcesContent":["import { InjectionToken, makeEnvironmentProviders } from '@angular/core';\nimport type { EnvironmentProviders } from '@angular/core';\nimport type { AsterUiOptions } from '@aster-editor/ui';\n\n/**\n * Configuration globale des éditeurs d'une application (ou d'une route, si fournie\n * dans ses `providers`). Le composant la fusionne avec l'input `config`, qui prime,\n * puis avec les inputs dédiés (`toolbar`, `theme`, `locale`, `placeholder`, `readonly`).\n */\nexport const ASTER_CONFIG = new InjectionToken<Partial<AsterUiOptions>>('ASTER_CONFIG');\n\n/**\n * Déclare la configuration globale d'Aster dans `ApplicationConfig.providers` ou dans\n * les `providers` d'une route. Fusion superficielle : une clé donnée ici est remplacée\n * en bloc par la même clé passée dans l'input `config` d'un composant.\n *\n * ```ts\n * provideAster({ locale: 'en', theme: 'night', linkPolicy: { defaultTarget: '_blank' } })\n * ```\n */\nexport function provideAster(config: Partial<AsterUiOptions>): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: ASTER_CONFIG, useValue: config }]);\n}\n","import { InjectionToken } from '@angular/core';\nimport type { UploadHandler } from '@aster-editor/core';\n\n/**\n * Hook d'upload d'image fourni par l'application (service HTTP, stockage, CDN…).\n * Optionnel : s'il est présent et qu'aucun `upload` n'est passé par `provideAster`\n * ni par l'input `config`, le composant le branche sur `AsterOptions.upload`.\n * Sans handler, les images sont insérées en data URL base64.\n */\nexport const ASTER_UPLOAD_HANDLER = new InjectionToken<UploadHandler>('ASTER_UPLOAD_HANDLER');\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n afterNextRender,\n computed,\n effect,\n forwardRef,\n inject,\n input,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport type { ElementRef, Signal } from '@angular/core';\nimport { NG_VALUE_ACCESSOR } from '@angular/forms';\nimport type { ControlValueAccessor } from '@angular/forms';\nimport type {\n AsterDocument,\n AsterEditor,\n AsterLocale,\n AsterTheme,\n AsterVariable,\n GetHtmlOptions,\n PasteTransformer,\n ToolbarConfig,\n Unsubscribe,\n VariableResolver,\n VariableSource,\n VariableValues,\n} from '@aster-editor/core';\nimport { createAster } from '@aster-editor/ui';\nimport type { AsterInstance, AsterUiOptions } from '@aster-editor/ui';\nimport type { DocxExportOptions, DocxImportResult } from '@aster-editor/word';\nimport { ASTER_CONFIG } from './provide-aster';\nimport { ASTER_UPLOAD_HANDLER } from './tokens';\n\n/** Vue minimale des options de l'extension Tiptap `Placeholder`, pour la changer à chaud. */\ninterface PlaceholderExtensionOptions {\n placeholder?: unknown;\n}\n\ntype TiptapEditor = AsterEditor['tiptap'];\ntype ProseMirrorPlugin = Parameters<TiptapEditor['registerPlugin']>[0];\n\n/** Signature de `addProseMirrorPlugins` d'une extension Tiptap (hors nœud et marque). */\ntype ExtensionPluginFactory = (this: {\n name: string;\n options: PlaceholderExtensionOptions;\n storage: unknown;\n editor: TiptapEditor;\n type: null;\n parent: undefined;\n}) => ProseMirrorPlugin[];\n\n/** Pose l'attribut quand une valeur est fournie, le retire sinon. */\nfunction setOrRemoveAttribute(element: HTMLElement, name: string, value: string | undefined): void {\n if (value === undefined || value === '') {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value);\n }\n}\n\n/** Égalité de deux listes de noms, pour ne pas notifier `variableNames` sans changement réel. */\nfunction sameNames(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((name, index) => name === b[index]);\n}\n\n/** État du magasin de variables à conserver au travers d'un remontage. */\ninterface VariableSnapshot {\n readonly declared: readonly AsterVariable[];\n readonly values: VariableValues;\n}\n\n/**\n * Composant Angular standalone autour de `createAster` (`@aster-editor/ui`).\n *\n * - `ControlValueAccessor` : utilisable avec `formControlName`, `[formControl]` et `ngModel`.\n * La valeur du formulaire est le HTML sémantique de `getHTML()`.\n * - Zoneless et `OnPush` : rien dans le template ne dépend de l'état, les sorties sont\n * des `output()` et l'éditeur est exposé en signal.\n * - SSR-safe : l'éditeur est monté dans `afterNextRender`, jamais dans le constructeur, et\n * le module Word n'est chargé qu'à partir du montage (donc jamais côté serveur).\n *\n * Configuration, par priorité croissante : `provideAster(config)` < input `config` <\n * inputs dédiés (`toolbar`, `theme`, `locale`, `placeholder`, `readonly`). Un input dédié\n * laissé à `undefined` n'écrase donc pas la valeur venue de la configuration.\n *\n * Changements à chaud : `theme`, `locale`, `readonly`, `placeholder`, `ariaLabel`,\n * `ariaLabelledBy`, `variables` et `variableValues` sont appliqués sur l'instance vivante.\n * `toolbar` remonte l'éditeur (le contenu, les déclarations et les valeurs de variables sont\n * conservés, l'historique d'annulation est perdu, `ready` est réémis avec la nouvelle\n * instance). Les autres clés de `config` (`extensions`, `commands`, `upload`…) ne sont lues\n * qu'au montage.\n *\n * Variables (champs de fusion) : les inputs `variables`, `variableValues`, `variableResolver`,\n * `allowUnknownVariables` et `variableSuggestion` se fusionnent dans `options.variables` et\n * `variableSuggestion` de `createAster`. `variableNames` expose les noms présents dans le\n * document, `variablesChanged` relaie `variablesChange`, `exportDocx` produit le `.docx` avec\n * les valeurs du magasin.\n */\n@Component({\n selector: 'aster-editor',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: '<div #host class=\"aster-editor__host\"></div>',\n styles: ':host { display: block; }',\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => AsterEditorComponent),\n multi: true,\n },\n ],\n})\nexport class AsterEditorComponent implements ControlValueAccessor {\n /** Preset, groupes déclaratifs, ou `false` pour aucune toolbar. Défaut effectif : `standard`. */\n readonly toolbar = input<ToolbarConfig | undefined>(undefined);\n /** Thème appliqué sur `.aster[data-theme]`. `light` et `night` sont fournis par `ui`. Défaut : `light`. */\n readonly theme = input<AsterTheme | undefined>(undefined);\n /** Locale de l'éditeur et de la toolbar. Défaut effectif : `fr`. */\n readonly locale = input<AsterLocale | undefined>(undefined);\n /** Texte affiché quand le document est vide. Sans valeur, la chaîne i18n `editor.placeholder`. */\n readonly placeholder = input<string | undefined>(undefined);\n /** Lecture seule. Le `disabled` d'un formulaire s'y ajoute (l'un ou l'autre suffit). Défaut : `false`. */\n readonly readonly = input<boolean | undefined>(undefined);\n /** Tout le reste des options (`extensions`, `commands`, `linkPolicy`, `upload`, `content`…). */\n readonly config = input<Partial<AsterUiOptions>>({});\n /**\n * Nettoyage automatique du HTML collé depuis Word et Google Docs via\n * `wordPasteTransformer()` de `@aster-editor/word`, chargé dynamiquement au montage.\n */\n readonly wordPaste = input<boolean>(true);\n /**\n * Nom accessible de la zone de saisie (`aria-label` sur le contenteditable). Un\n * contenteditable n'est pas associable à un `<label for>`, c'est le seul moyen de le nommer.\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n /** `id` (ou liste d'ids) de l'élément qui sert de libellé (`aria-labelledby` sur le contenteditable). */\n readonly ariaLabelledBy = input<string | undefined>(undefined);\n /**\n * Variables déclarées (libellé, description, valeur), proposées dans le menu d'insertion\n * même si absentes du document. À chaud : `editor.variables.define(...)`, fusion par nom.\n */\n readonly variables = input<readonly AsterVariable[] | undefined>(undefined);\n /**\n * Valeurs par nom. À chaud : `editor.variables.setValues(...)`, fusion avec les valeurs\n * connues (une clé absente n'efface rien, `undefined` efface).\n */\n readonly variableValues = input<VariableValues | undefined>(undefined);\n /** Résolveur asynchrone appelé par `resolveVariables()` pour les variables sans valeur. Lu au montage. */\n readonly variableResolver = input<VariableResolver | undefined>(undefined);\n /** Autoriser l'insertion d'une variable non déclarée. Défaut effectif : `true`. Lu au montage. */\n readonly allowUnknownVariables = input<boolean | undefined>(undefined);\n /** Menu de suggestion déclenché par `{{` dans le contenu. Défaut effectif : `true`. Lu au montage. */\n readonly variableSuggestion = input<boolean | undefined>(undefined);\n\n /** L'éditeur est monté et prêt. Réémis après un remontage (changement de `toolbar`). */\n readonly ready = output<AsterEditor>();\n /** Le document a changé : HTML de `getHTML()`. Pas émis sur `writeValue`. */\n readonly changed = output<string>();\n /** Le contenteditable a pris le focus. */\n readonly focused = output<void>();\n /**\n * Le contenteditable a perdu le focus au profit d'un élément extérieur à l'éditeur. Un\n * blur vers la toolbar ou un de ses menus n'est pas remonté : l'utilisateur est toujours\n * « dans » l'éditeur. C'est aussi ce qui marque le contrôle de formulaire `touched`.\n */\n readonly blurred = output<void>();\n /** Les valeurs ou déclarations de variables ont changé (`setValues`, `define`, `resolve`, import). */\n readonly variablesChanged = output<VariableValues>();\n\n private readonly editorState = signal<AsterEditor | null>(null);\n /** Éditeur courant, `null` avant le montage et après la destruction. */\n readonly editor: Signal<AsterEditor | null> = this.editorState.asReadonly();\n\n private readonly variableNamesState = signal<readonly string[]>([], { equal: sameNames });\n /**\n * Noms des variables réellement présentes dans le document (`editor.variables.getNames()`),\n * relus sur `change` et `variablesChange`. Vide avant le montage et après la destruction.\n */\n readonly variableNames: Signal<readonly string[]> = this.variableNamesState.asReadonly();\n\n private readonly host = viewChild.required<ElementRef<HTMLDivElement>>('host');\n private readonly globalConfig = inject(ASTER_CONFIG, { optional: true });\n private readonly uploadHandler = inject(ASTER_UPLOAD_HANDLER, { optional: true });\n private readonly formDisabled = signal(false);\n\n /** `ASTER_CONFIG` < `config`, fusion superficielle. */\n private readonly mergedConfig = computed<Partial<AsterUiOptions>>(() => ({\n ...(this.globalConfig ?? {}),\n ...this.config(),\n }));\n private readonly resolvedToolbar = computed<ToolbarConfig>(\n () => this.toolbar() ?? this.mergedConfig().toolbar ?? 'standard',\n );\n private readonly resolvedTheme = computed<AsterTheme>(\n () => this.theme() ?? this.mergedConfig().theme ?? 'light',\n );\n private readonly resolvedLocale = computed<AsterLocale>(\n () => this.locale() ?? this.mergedConfig().locale ?? 'fr',\n );\n private readonly resolvedPlaceholder = computed<string | undefined>(\n () => this.placeholder() ?? this.mergedConfig().placeholder,\n );\n private readonly resolvedReadOnly = computed<boolean>(\n () => (this.readonly() ?? this.mergedConfig().readOnly ?? false) || this.formDisabled(),\n );\n /** `config.variables` < inputs dédiés, clé par clé ; un input `undefined` ne masque rien. */\n private readonly resolvedVariableSource = computed<VariableSource | undefined>(() => {\n const base = this.mergedConfig().variables;\n const source: VariableSource = {\n ...base,\n ...(this.variables() !== undefined ? { variables: this.variables() } : {}),\n ...(this.variableValues() !== undefined ? { values: this.variableValues() } : {}),\n ...(this.variableResolver() !== undefined ? { resolve: this.variableResolver() } : {}),\n ...(this.allowUnknownVariables() !== undefined\n ? { allowUnknown: this.allowUnknownVariables() }\n : {}),\n };\n return Object.keys(source).length > 0 ? source : undefined;\n });\n private readonly resolvedVariableSuggestion = computed<boolean | undefined>(\n () => this.variableSuggestion() ?? this.mergedConfig().variableSuggestion,\n );\n\n private instance: AsterInstance | null = null;\n private mountedToolbar: ToolbarConfig | null = null;\n private subscriptions: Unsubscribe[] = [];\n /** Valeur reçue par `writeValue` avant le montage, appliquée comme contenu initial. */\n private pendingValue: string | null = null;\n private wordTransformer: PasteTransformer | null = null;\n private wordLoading: Promise<void> | null = null;\n private onChange: ((html: string) => void) | null = null;\n private onTouched: (() => void) | null = null;\n\n /**\n * Transformateur synchrone branché au montage ; il délègue au vrai transformateur Word\n * une fois le module chargé. Garde `@aster-editor/word` optionnel et hors du bundle\n * initial tout en respectant le contrat synchrone de `PasteTransformer`.\n */\n private readonly lazyWordTransformer: PasteTransformer = (html, context) =>\n this.wordTransformer && untracked(() => this.wordPaste())\n ? this.wordTransformer(html, context)\n : html;\n\n constructor() {\n afterNextRender(() => this.mount());\n inject(DestroyRef).onDestroy(() => this.unmount());\n\n effect(() => {\n const theme = this.resolvedTheme();\n untracked(() => this.instance?.setTheme(theme));\n });\n effect(() => {\n const locale = this.resolvedLocale();\n untracked(() => {\n const editor = this.instance?.editor;\n if (editor && editor.i18n.getLocale() !== locale) {\n editor.i18n.setLocale(locale);\n }\n });\n });\n effect(() => {\n const readOnly = this.resolvedReadOnly();\n untracked(() => this.instance?.editor.setReadOnly(readOnly));\n });\n effect(() => {\n const placeholder = this.resolvedPlaceholder();\n untracked(() => {\n if (this.instance) {\n this.applyPlaceholder(this.instance.editor, placeholder);\n }\n });\n });\n effect(() => {\n const label = this.ariaLabel();\n const labelledBy = this.ariaLabelledBy();\n untracked(() => {\n if (this.instance) {\n this.applyAriaAttributes(this.instance.editor, label, labelledBy);\n }\n });\n });\n effect(() => {\n const toolbar = this.resolvedToolbar();\n untracked(() => {\n if (this.instance && this.mountedToolbar !== toolbar) {\n this.remount();\n }\n });\n });\n // Le chargement initial du module Word part de `mount()` (jamais côté serveur) ; cet\n // effet ne couvre que le passage `false → true` d'un éditeur déjà monté.\n effect(() => {\n if (this.wordPaste()) {\n untracked(() => {\n if (this.instance) {\n this.loadWordPaste();\n }\n });\n }\n });\n // Au montage, déclarations et valeurs passent par `options.variables` ; ces deux effets\n // ne couvrent que les changements d'input sur un éditeur déjà monté.\n effect(() => {\n const declared = this.variables();\n untracked(() => {\n if (declared && this.instance) {\n this.instance.editor.variables.define(declared);\n }\n });\n });\n effect(() => {\n const values = this.variableValues();\n untracked(() => {\n if (values && this.instance) {\n this.instance.editor.variables.setValues(values);\n }\n });\n });\n }\n\n // --- API publique --------------------------------------------------------\n\n /**\n * Importe un `.docx` via `@aster-editor/word` (chargé à la demande, mammoth reste dans\n * un chunk séparé), remplace le contenu de l'éditeur en émettant `change` pour que le\n * formulaire voie la nouvelle valeur, et rend le résultat avec ses avertissements.\n * Le hook d'upload de l'éditeur est réutilisé pour les images embarquées. Si le\n * composant est détruit ou remonté pendant l'import, le résultat est rendu mais aucun\n * contenu n'est écrit : l'instance vivante est relue après chaque `await`.\n */\n async importDocx(file: File): Promise<DocxImportResult> {\n this.requireEditor('importDocx');\n const upload = untracked(() => this.resolvedOptions().upload);\n const { importDocx } = await import('@aster-editor/word');\n const result = await importDocx(file, upload ? { upload } : {});\n const editor = this.instance?.editor;\n if (editor && !editor.isDestroyed()) {\n editor.setHTML(result.html, true);\n this.declareImportedVariables(editor, result.variables);\n }\n return result;\n }\n\n /**\n * Convertit le document en `.docx` via `exportDocx` de `@aster-editor/word` (chargé à la\n * demande, la lib `docx` reste dans son chunk). Les valeurs du magasin de variables sont\n * transmises quand `options.variables.values` n'est pas fourni : `mode: 'resolve'` substitue\n * donc ce que l'utilisateur a saisi, `'fields'` produit des champs de fusion Word avec ces\n * valeurs comme résultat. Rend le `Blob`, à passer à `downloadDocx` ou à un upload.\n */\n async exportDocx(options: DocxExportOptions = {}): Promise<Blob> {\n const editor = this.requireEditor('exportDocx');\n const { exportDocx } = await import('@aster-editor/word');\n const variables = {\n ...options.variables,\n values: options.variables?.values ?? editor.variables.getValues(),\n };\n return exportDocx(editor.getHTML(), { ...options, variables });\n }\n\n /**\n * HTML du document, `{ variables: 'resolve' }` substitue les valeurs connues. Avant le\n * montage, rend la valeur reçue par `writeValue` (puces conservées) ou une chaîne vide.\n */\n getHTML(options?: GetHtmlOptions): string {\n return this.instance?.editor.getHTML(options) ?? this.pendingValue ?? '';\n }\n\n /**\n * Appelle le résolveur (`variableResolver` ou `config.variables.resolve`) pour les\n * variables présentes sans valeur, applique les valeurs obtenues et les rend toutes.\n */\n resolveVariables(): Promise<VariableValues> {\n return this.requireEditor('resolveVariables').variables.resolve();\n }\n\n // --- ControlValueAccessor ------------------------------------------------\n\n /**\n * Applique la valeur du formulaire sans émettre `change` ni entrer dans l'historique ;\n * mémorisée si l'éditeur n'est pas monté. Une valeur identique au HTML courant est\n * ignorée pour ne pas déplacer la sélection (les reactive forms réécrivent la valeur à\n * chaque `setValue`, y compris quand elle n'a pas changé).\n */\n writeValue(value: string | null | undefined): void {\n const html = value ?? '';\n const editor = this.instance?.editor;\n if (!editor) {\n this.pendingValue = html;\n return;\n }\n if (editor.getHTML() === html) {\n return;\n }\n editor.setHTML(html, false);\n }\n\n /** Enregistre le rappel appelé avec le HTML à chaque modification du document par l'utilisateur. */\n registerOnChange(fn: (html: string) => void): void {\n this.onChange = fn;\n }\n\n /** Enregistre le rappel appelé quand l'éditeur perd le focus vers l'extérieur (`touched`). */\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n /** `disabled` du formulaire → lecture seule, cumulé avec l'input `readonly`. */\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n this.instance?.editor.setReadOnly(untracked(() => this.resolvedReadOnly()));\n }\n\n // --- Cycle de vie --------------------------------------------------------\n\n /**\n * Monte l'éditeur. `content` force le contenu initial (remontage) et, dans ce cas,\n * `autofocus` est neutralisé : le focus est restauré explicitement par `remount()`.\n */\n private mount(content?: string, variables?: VariableSnapshot): void {\n if (this.instance) {\n return;\n }\n const options = untracked(() => this.resolvedOptions(content, variables));\n const instance = createAster(this.host().nativeElement, options);\n const editor = instance.editor;\n this.instance = instance;\n this.mountedToolbar = options.toolbar ?? 'standard';\n this.pendingValue = null;\n this.subscriptions = [\n editor.on('ready', ({ editor: ready }) => this.ready.emit(ready)),\n editor.on('change', ({ editor: changed }) => {\n const html = changed.getHTML();\n this.onChange?.(html);\n this.changed.emit(html);\n this.refreshVariableNames(changed);\n }),\n editor.on('variablesChange', ({ editor: source, values }) => {\n this.refreshVariableNames(source);\n this.variablesChanged.emit(values);\n }),\n editor.on('focus', () => this.focused.emit()),\n editor.on('blur', ({ event }) => {\n // Un blur vers la toolbar, un menu ou un dialogue de l'éditeur n'est pas une sortie.\n const related = event.relatedTarget;\n if (related instanceof Node && instance.element.contains(related)) {\n return;\n }\n this.onTouched?.();\n this.blurred.emit();\n }),\n ];\n untracked(() => this.applyAriaAttributes(editor, this.ariaLabel(), this.ariaLabelledBy()));\n if (untracked(() => this.wordPaste())) {\n this.loadWordPaste();\n }\n this.refreshVariableNames(editor);\n this.editorState.set(editor);\n }\n\n private unmount(): void {\n for (const unsubscribe of this.subscriptions) {\n unsubscribe();\n }\n this.subscriptions = [];\n this.instance?.destroy();\n this.instance = null;\n this.mountedToolbar = null;\n this.editorState.set(null);\n this.variableNamesState.set([]);\n }\n\n /**\n * Remonte l'éditeur en conservant le contenu, le focus, les déclarations et les valeurs\n * de variables ; l'historique est perdu.\n */\n private remount(): void {\n const current = this.instance;\n if (!current) {\n return;\n }\n const html = current.editor.getHTML();\n const focused = current.editor.isFocused();\n const variables: VariableSnapshot = {\n declared: current.editor.variables.list(),\n values: current.editor.variables.getValues(),\n };\n this.unmount();\n this.mount(html, variables);\n if (focused) {\n this.instance?.editor.focus('end');\n }\n }\n\n /**\n * Fusionne `ASTER_CONFIG` < `config` < inputs dédiés. Le transformateur Word est placé\n * en tête pour que les transformateurs de l'intégrateur reçoivent du HTML déjà nettoyé.\n * Avec `content` (remontage), `autofocus` est désactivé pour ne pas reprendre le focus et\n * `variables` réinjecte l'état du magasin précédent par-dessus la configuration.\n */\n private resolvedOptions(content?: string, variables?: VariableSnapshot): AsterUiOptions {\n const merged = this.mergedConfig();\n const initial: string | AsterDocument | undefined =\n content ?? this.pendingValue ?? merged.content;\n const source = this.resolvedVariableSource();\n const variableSource: VariableSource | undefined = variables\n ? {\n ...source,\n variables: [...(source?.variables ?? []), ...variables.declared],\n values: { ...source?.values, ...variables.values },\n }\n : source;\n return {\n ...merged,\n content: initial,\n autofocus: content === undefined ? merged.autofocus : false,\n toolbar: this.resolvedToolbar(),\n theme: this.resolvedTheme(),\n locale: this.resolvedLocale(),\n placeholder: this.resolvedPlaceholder(),\n readOnly: this.resolvedReadOnly(),\n pasteTransformers: [this.lazyWordTransformer, ...(merged.pasteTransformers ?? [])],\n upload: merged.upload ?? this.uploadHandler ?? undefined,\n variables: variableSource,\n variableSuggestion: this.resolvedVariableSuggestion(),\n };\n }\n\n /** Éditeur monté, sinon erreur explicite nommant la méthode appelée trop tôt. */\n private requireEditor(method: string): AsterEditor {\n const editor = this.instance?.editor;\n if (!editor) {\n throw new Error(`[aster-editor/angular] ${method}: editor is not mounted yet`);\n }\n return editor;\n }\n\n /** Relit `getNames()` ; le signal n'est notifié que si la liste change réellement. */\n private refreshVariableNames(editor: AsterEditor): void {\n this.variableNamesState.set(editor.variables.getNames());\n }\n\n /**\n * Après un import : déclare les variables trouvées dans le `.docx` (libellé et valeur des\n * contrôles de contenu compris), puis réapplique l'input `variableValues` pour les noms que\n * Word a lui-même valorisés, l'application restant la source de vérité des valeurs.\n */\n private declareImportedVariables(editor: AsterEditor, found: readonly AsterVariable[]): void {\n if (found.length === 0) {\n return;\n }\n editor.variables.define(found);\n const known = untracked(() => this.variableValues());\n if (!known) {\n return;\n }\n const overrides: Record<string, string> = {};\n for (const variable of found) {\n const value = known[variable.name];\n if (variable.value !== undefined && value !== undefined && value !== variable.value) {\n overrides[variable.name] = value;\n }\n }\n if (Object.keys(overrides).length > 0) {\n editor.variables.setValues(overrides);\n }\n }\n\n private loadWordPaste(): void {\n if (this.wordTransformer || this.wordLoading) {\n return;\n }\n this.wordLoading = import('@aster-editor/word')\n .then((word) => {\n this.wordTransformer = word.wordPasteTransformer();\n })\n .catch((error: unknown) => {\n this.wordLoading = null;\n console.warn(\n '[aster-editor/angular] @aster-editor/word unavailable, paste kept raw',\n error,\n );\n });\n }\n\n /** Nom accessible du contenteditable : `aria-label` et/ou `aria-labelledby`, retirés si vides. */\n private applyAriaAttributes(\n editor: AsterEditor,\n label: string | undefined,\n labelledBy: string | undefined,\n ): void {\n setOrRemoveAttribute(editor.contentElement, 'aria-label', label);\n setOrRemoveAttribute(editor.contentElement, 'aria-labelledby', labelledBy);\n }\n\n /**\n * Change le placeholder à chaud. L'extension `Placeholder` lit ses options au moment où\n * son plugin ProseMirror est créé (et `extension.options` est une copie à chaque accès),\n * donc on refabrique le plugin via `addProseMirrorPlugins` avec un `placeholder` surchargé\n * et on le substitue à l'ancien par `unregisterPlugin`/`registerPlugin`, API publiques de\n * Tiptap. Le repli sur la chaîne i18n `editor.placeholder` est conservé.\n */\n private applyPlaceholder(editor: AsterEditor, placeholder: string | undefined): void {\n const tiptap = editor.tiptap;\n const extension = tiptap.extensionManager.extensions.find(\n (candidate) => candidate.name === 'placeholder',\n );\n if (extension?.type !== 'extension') {\n return;\n }\n const factory = extension.config.addProseMirrorPlugins as ExtensionPluginFactory | undefined;\n if (!factory) {\n return;\n }\n const options: PlaceholderExtensionOptions = {\n ...extension.options,\n placeholder: (): string => placeholder ?? editor.i18n.t('editor.placeholder'),\n };\n const plugins = factory.call({\n name: extension.name,\n options,\n storage: extension.storage,\n editor: tiptap,\n type: null,\n parent: undefined,\n });\n for (const plugin of plugins) {\n tiptap.unregisterPlugin(plugin.spec.key ?? extension.name);\n tiptap.registerPlugin(plugin);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"aster-editor-angular.mjs","names":[],"sources":["../../src/lib/editor-dom.ts","../../src/lib/page-view.ts","../../src/lib/provide-aster.ts","../../src/lib/tokens.ts","../../src/lib/word.ts","../../src/lib/aster-editor.component.ts"],"sourcesContent":["import type { AsterEditor } from '@aster-editor/core';\n\n/**\n * Réglages appliqués à chaud sur l'éditeur monté (nom accessible, placeholder), hors de la\n * classe du composant pour la garder centrée sur le cycle de vie et les inputs.\n */\n\n/** Vue minimale des options de l'extension Tiptap `Placeholder`, pour la changer à chaud. */\ninterface PlaceholderExtensionOptions {\n placeholder?: unknown;\n}\n\ntype TiptapEditor = AsterEditor['tiptap'];\ntype ProseMirrorPlugin = Parameters<TiptapEditor['registerPlugin']>[0];\n\n/** Signature de `addProseMirrorPlugins` d'une extension Tiptap (hors nœud et marque). */\ntype ExtensionPluginFactory = (this: {\n name: string;\n options: PlaceholderExtensionOptions;\n storage: unknown;\n editor: TiptapEditor;\n type: null;\n parent: undefined;\n}) => ProseMirrorPlugin[];\n\n/** Pose l'attribut quand une valeur est fournie, le retire sinon. */\nfunction setOrRemoveAttribute(element: HTMLElement, name: string, value: string | undefined): void {\n if (value === undefined || value === '') {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value);\n }\n}\n\n/** Nom accessible du contenteditable : `aria-label` et/ou `aria-labelledby`, retirés si vides. */\nexport function applyAriaAttributes(\n editor: AsterEditor,\n label: string | undefined,\n labelledBy: string | undefined,\n): void {\n setOrRemoveAttribute(editor.contentElement, 'aria-label', label);\n setOrRemoveAttribute(editor.contentElement, 'aria-labelledby', labelledBy);\n}\n\n/**\n * Change le placeholder à chaud. L'extension `Placeholder` lit ses options au moment où\n * son plugin ProseMirror est créé (et `extension.options` est une copie à chaque accès),\n * donc on refabrique le plugin via `addProseMirrorPlugins` avec un `placeholder` surchargé\n * et on le substitue à l'ancien par `unregisterPlugin`/`registerPlugin`, API publiques de\n * Tiptap. Le repli sur la chaîne i18n `editor.placeholder` est conservé.\n */\nexport function applyPlaceholder(editor: AsterEditor, placeholder: string | undefined): void {\n const tiptap = editor.tiptap;\n const extension = tiptap.extensionManager.extensions.find(\n (candidate) => candidate.name === 'placeholder',\n );\n if (extension?.type !== 'extension') {\n return;\n }\n const factory = extension.config.addProseMirrorPlugins as ExtensionPluginFactory | undefined;\n if (!factory) {\n return;\n }\n const options: PlaceholderExtensionOptions = {\n ...extension.options,\n placeholder: (): string => placeholder ?? editor.i18n.t('editor.placeholder'),\n };\n const plugins = factory.call({\n name: extension.name,\n options,\n storage: extension.storage,\n editor: tiptap,\n type: null,\n parent: undefined,\n });\n for (const plugin of plugins) {\n tiptap.unregisterPlugin(plugin.spec.key ?? extension.name);\n tiptap.registerPlugin(plugin);\n }\n}\n","import { getActivePageView } from '@aster-editor/core';\nimport type { AsterEditor, DocumentLayout, PageViewOptions } from '@aster-editor/core';\nimport { pageViewApiOf } from '@aster-editor/ui';\n\n/**\n * Vue page du composant. Le core expose `setPageView` / `getLayout` hors contrat\n * (`api/editor.ts` ne les déclare pas encore) : on passe par `pageViewApiOf` de `ui`, qui\n * les détecte à l'exécution, et par `getActivePageView` du core pour relire les options\n * en vigueur (le dialogue « Mise en page » de la toolbar peut les avoir changées).\n */\n\n/** Valeur de l'input `pageView` du composant, identique à `AsterUiOptions.pageView`. */\nexport type PageViewInput = boolean | PageViewOptions | undefined;\n\n/**\n * Options de vue page à donner à `createAster` ou à `setPageView` : l'input (ou la\n * configuration) complété par la mise en page effective du composant, qui prime sur\n * `pageView.layout` quand elle existe. `undefined` et `false` passent tels quels.\n */\nexport function resolvePageViewOptions(\n pageView: PageViewInput,\n layout: DocumentLayout | null,\n): PageViewInput {\n if (pageView === undefined || pageView === false) {\n return pageView;\n }\n const base: PageViewOptions = pageView === true ? {} : pageView;\n return layout ? { ...base, layout } : base;\n}\n\n/** Active ou retire la vue page sur un éditeur monté ; sans effet si le core ne l'expose pas. */\nexport function setPageView(editor: AsterEditor, options: PageViewInput): void {\n const api = pageViewApiOf(editor);\n if (!api) {\n return;\n }\n if (options === undefined || options === false) {\n api.setPageView(false);\n } else {\n api.setPageView(options === true ? {} : options);\n }\n}\n\n/**\n * Mise en page de la vue page active, `null` si elle est inactive ou si le core ne l'expose\n * pas. L'activité est lue via `getActivePageView` : pendant la notification de retrait\n * (`setPageView` retire l'ancienne vue avant de poser la nouvelle), l'ancienne mise en page\n * est encore lisible par `getLayout` mais la vue n'est plus active, et doit être ignorée.\n */\nexport function readPageViewLayout(editor: AsterEditor): DocumentLayout | null {\n const active = getActivePageView(editor.contentElement);\n if (!active) {\n return null;\n }\n // Pendant la notification d'activation, `getLayout` ne connaît pas encore la nouvelle vue\n // (le core l'affecte au retour de `applyPageView`) : les options actives, elles, sont déjà\n // posées et portent la même référence de mise en page.\n return active.layout ?? pageViewApiOf(editor)?.getLayout() ?? null;\n}\n\n/**\n * Applique une mise en page à la vue page **si elle est active**, en conservant ses autres\n * options (pagination, affichage des en-têtes). Rien si la vue page est inactive ou si\n * elle montre déjà cette mise en page (même référence : c'est le cas juste après que le\n * dialogue « Mise en page » l'a posée). Rend vrai si la vue a été remontée.\n */\nexport function applyLayoutToPageView(editor: AsterEditor, layout: DocumentLayout): boolean {\n const api = pageViewApiOf(editor);\n const active = getActivePageView(editor.contentElement);\n if (!api || !active || api.getLayout() === layout) {\n return false;\n }\n api.setPageView({ ...active, layout });\n return true;\n}\n","import { InjectionToken, makeEnvironmentProviders } from '@angular/core';\nimport type { EnvironmentProviders } from '@angular/core';\nimport type { AsterUiOptions } from '@aster-editor/ui';\n\n/**\n * Configuration globale des éditeurs d'une application (ou d'une route, si fournie\n * dans ses `providers`). Le composant la fusionne avec l'input `config`, qui prime,\n * puis avec les inputs dédiés (`toolbar`, `theme`, `locale`, `placeholder`, `readonly`).\n */\nexport const ASTER_CONFIG = new InjectionToken<Partial<AsterUiOptions>>('ASTER_CONFIG');\n\n/**\n * Déclare la configuration globale d'Aster dans `ApplicationConfig.providers` ou dans\n * les `providers` d'une route. Fusion superficielle : une clé donnée ici est remplacée\n * en bloc par la même clé passée dans l'input `config` d'un composant.\n *\n * ```ts\n * provideAster({ locale: 'en', theme: 'night', linkPolicy: { defaultTarget: '_blank' } })\n * ```\n */\nexport function provideAster(config: Partial<AsterUiOptions>): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: ASTER_CONFIG, useValue: config }]);\n}\n","import { InjectionToken } from '@angular/core';\nimport type { UploadHandler } from '@aster-editor/core';\n\n/**\n * Hook d'upload d'image fourni par l'application (service HTTP, stockage, CDN…).\n * Optionnel : s'il est présent et qu'aucun `upload` n'est passé par `provideAster`\n * ni par l'input `config`, le composant le branche sur `AsterOptions.upload`.\n * Sans handler, les images sont insérées en data URL base64.\n */\nexport const ASTER_UPLOAD_HANDLER = new InjectionToken<UploadHandler>('ASTER_UPLOAD_HANDLER');\n","import { untracked } from '@angular/core';\nimport type {\n AsterEditor,\n AsterVariable,\n DocumentLayout,\n PasteTransformer,\n UploadHandler,\n VariableValues,\n} from '@aster-editor/core';\nimport type {\n DocxExportOptions,\n DocxImportOptions,\n DocxImportResult,\n FidelityReport,\n} from '@aster-editor/word';\n\n/**\n * Logique Word du composant, hors de la classe pour la garder lisible : chaque fonction\n * charge `@aster-editor/word` par `import()` au moment de l'appel, le paquet reste donc\n * optionnel et hors du bundle initial (mammoth, la lib `docx` et le comparateur ne sont\n * téléchargés qu'au premier usage).\n */\n\n/** Chemin de lecture d'un `.docx` : `styled` (lecteur OOXML d'Aster) ou `semantic` (mammoth). */\nexport type DocxImportFidelity = NonNullable<DocxImportOptions['fidelity']>;\n\n/** Objet Word non représentable signalé par l'import (`DocxImportResult.lost`). */\nexport type DocxLostObject = DocxImportResult['lost'][number];\n\n/** Ce que le composant sait au moment d'importer : hook d'upload et chemin de lecture. */\nexport interface WordImportDefaults {\n readonly upload: UploadHandler | undefined;\n readonly fidelity: DocxImportFidelity;\n}\n\n/** Import d'un fichier avec le hook d'upload de l'éditeur et le chemin de lecture demandé. */\nexport async function importWord(\n file: File,\n defaults: WordImportDefaults,\n): Promise<DocxImportResult> {\n const { importDocx } = await import('@aster-editor/word');\n return importDocx(file, {\n ...(defaults.upload ? { upload: defaults.upload } : {}),\n fidelity: defaults.fidelity,\n });\n}\n\n/** Ce que le composant conserve d'un import et qui complète les options d'export. */\nexport interface WordExportDefaults {\n /** Gabarit importé (`DocxImportResult.template`), `null` sans import. */\n readonly template: ArrayBuffer | null;\n /** Mise en page effective (import, input `layout` ou dialogue « Mise en page »). */\n readonly layout: DocumentLayout | null;\n /** Utiliser le gabarit importé quand `options.template` est absent. */\n readonly inTemplate: boolean;\n}\n\n/**\n * Complète les options d'export avec ce que le composant sait : les valeurs du magasin de\n * variables quand `options.variables.values` manque, le gabarit importé quand\n * `options.template` manque et que `inTemplate` l'autorise, la mise en page effective quand\n * `options.layout` manque. Avec un gabarit, `layout` ne sert qu'à régénérer un en-tête ou\n * un pied modifié (`layout.headers` / `footers` différents de ceux du gabarit) ; le reste\n * (format, marges, styles) vient du gabarit. Sans gabarit, `layout` pilote l'export neuf.\n */\nexport function resolveExportOptions(\n editor: AsterEditor,\n options: DocxExportOptions,\n defaults: WordExportDefaults,\n): DocxExportOptions {\n const variables = {\n ...options.variables,\n values: options.variables?.values ?? editor.variables.getValues(),\n };\n const template =\n options.template ?? (defaults.inTemplate && defaults.template ? defaults.template : undefined);\n const layout = options.layout ?? defaults.layout ?? undefined;\n return {\n ...options,\n variables,\n ...(template !== undefined ? { template } : {}),\n ...(layout !== undefined ? { layout } : {}),\n };\n}\n\n/** Export du document courant avec des options déjà résolues. */\nexport async function exportWord(editor: AsterEditor, options: DocxExportOptions): Promise<Blob> {\n const { exportDocx } = await import('@aster-editor/word');\n return exportDocx(editor.getHTML(), options);\n}\n\n/** Rapport de fidélité entre le gabarit importé et un export produit dans ce gabarit. */\nexport async function compareWithTemplate(\n template: ArrayBuffer,\n exported: Blob,\n): Promise<FidelityReport> {\n const { compareDocx } = await import('@aster-editor/word');\n return compareDocx(template, await exported.arrayBuffer());\n}\n\n/** Transformateur de collage Word, chargé à la demande. */\nexport async function loadWordPasteTransformer(): Promise<PasteTransformer> {\n const { wordPasteTransformer } = await import('@aster-editor/word');\n return wordPasteTransformer();\n}\n\n/**\n * Après un import : déclare les variables trouvées dans le `.docx` (libellé et valeur des\n * contrôles de contenu compris), puis réapplique les valeurs connues de l'application pour\n * les noms que Word a lui-même valorisés, l'application restant la source de vérité.\n */\nexport function declareImportedVariables(\n editor: AsterEditor,\n found: readonly AsterVariable[],\n known: () => VariableValues | undefined,\n): void {\n if (found.length === 0) {\n return;\n }\n editor.variables.define(found);\n const values = untracked(known);\n if (!values) {\n return;\n }\n const overrides: Record<string, string> = {};\n for (const variable of found) {\n const value = values[variable.name];\n if (variable.value !== undefined && value !== undefined && value !== variable.value) {\n overrides[variable.name] = value;\n }\n }\n if (Object.keys(overrides).length > 0) {\n editor.variables.setValues(overrides);\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n afterNextRender,\n computed,\n effect,\n forwardRef,\n inject,\n input,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport type { ElementRef, Signal } from '@angular/core';\nimport { NG_VALUE_ACCESSOR } from '@angular/forms';\nimport type { ControlValueAccessor } from '@angular/forms';\nimport { PAGE_VIEW_CHANGE_EVENT } from '@aster-editor/core';\nimport type {\n AsterDocument,\n AsterEditor,\n AsterLocale,\n AsterTheme,\n AsterVariable,\n DocumentLayout,\n GetHtmlOptions,\n PasteTransformer,\n ToolbarConfig,\n Unsubscribe,\n VariableResolver,\n VariableSource,\n VariableValues,\n} from '@aster-editor/core';\nimport { createAster } from '@aster-editor/ui';\nimport type { AsterInstance, AsterUiOptions } from '@aster-editor/ui';\nimport type { DocxExportOptions, DocxImportResult, FidelityReport } from '@aster-editor/word';\nimport { applyAriaAttributes, applyPlaceholder } from './editor-dom';\nimport {\n applyLayoutToPageView,\n readPageViewLayout,\n resolvePageViewOptions,\n setPageView,\n} from './page-view';\nimport type { PageViewInput } from './page-view';\nimport { ASTER_CONFIG } from './provide-aster';\nimport { ASTER_UPLOAD_HANDLER } from './tokens';\nimport {\n compareWithTemplate,\n declareImportedVariables,\n exportWord,\n importWord,\n loadWordPasteTransformer,\n resolveExportOptions,\n} from './word';\nimport type { DocxImportFidelity, DocxLostObject } from './word';\n\n/** Égalité de deux listes de noms, pour ne pas notifier `variableNames` sans changement réel. */\nfunction sameNames(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((name, index) => name === b[index]);\n}\n\n/** État du magasin de variables à conserver au travers d'un remontage. */\ninterface VariableSnapshot {\n readonly declared: readonly AsterVariable[];\n readonly values: VariableValues;\n}\n\n/**\n * Composant Angular standalone autour de `createAster` (`@aster-editor/ui`).\n *\n * - `ControlValueAccessor` : utilisable avec `formControlName`, `[formControl]` et `ngModel`.\n * La valeur du formulaire est le HTML sémantique de `getHTML()`.\n * - Zoneless et `OnPush` : rien dans le template ne dépend de l'état, les sorties sont\n * des `output()` et l'éditeur est exposé en signal.\n * - SSR-safe : l'éditeur est monté dans `afterNextRender`, jamais dans le constructeur, et\n * le module Word n'est chargé qu'à partir du montage (donc jamais côté serveur).\n *\n * Configuration, par priorité croissante : `provideAster(config)` < input `config` <\n * inputs dédiés (`toolbar`, `theme`, `locale`, `placeholder`, `readonly`). Un input dédié\n * laissé à `undefined` n'écrase donc pas la valeur venue de la configuration.\n *\n * Changements à chaud : `theme`, `locale`, `readonly`, `placeholder`, `ariaLabel`,\n * `ariaLabelledBy`, `variables` et `variableValues` sont appliqués sur l'instance vivante.\n * `toolbar` remonte l'éditeur (le contenu, les déclarations et les valeurs de variables sont\n * conservés, l'historique d'annulation est perdu, `ready` est réémis avec la nouvelle\n * instance). Les autres clés de `config` (`extensions`, `commands`, `upload`…) ne sont lues\n * qu'au montage.\n *\n * Variables (champs de fusion) : les inputs `variables`, `variableValues`, `variableResolver`,\n * `allowUnknownVariables` et `variableSuggestion` se fusionnent dans `options.variables` et\n * `variableSuggestion` de `createAster`. `variableNames` expose les noms présents dans le\n * document, `variablesChanged` relaie `variablesChange`, `exportDocx` produit le `.docx` avec\n * les valeurs du magasin.\n *\n * Fidélité Word (session 3) : `importDocx` lit le `.docx` en mode stylé et conserve le\n * gabarit (`importedTemplate`), la mise en page (`layout`) et les objets non représentables\n * (`lostObjects`) ; `exportDocx` réutilise le gabarit par défaut (`exportInTemplate`) et\n * transmet la mise en page ; `pageView` active la vue page, `layout` (input) impose une mise\n * en page, `layoutChanged` signale celle que montre la vue page (dialogue « Mise en page »\n * compris) ; `compareWithTemplate` mesure la fidélité de l'export dans le gabarit.\n */\n@Component({\n selector: 'aster-editor',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: '<div #host class=\"aster-editor__host\"></div>',\n styles: ':host { display: block; }',\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => AsterEditorComponent),\n multi: true,\n },\n ],\n})\nexport class AsterEditorComponent implements ControlValueAccessor {\n /** Preset, groupes déclaratifs, ou `false` pour aucune toolbar. Défaut effectif : `standard`. */\n readonly toolbar = input<ToolbarConfig | undefined>(undefined);\n /** Thème appliqué sur `.aster[data-theme]`. `light` et `night` sont fournis par `ui`. Défaut : `light`. */\n readonly theme = input<AsterTheme | undefined>(undefined);\n /** Locale de l'éditeur et de la toolbar. Défaut effectif : `fr`. */\n readonly locale = input<AsterLocale | undefined>(undefined);\n /** Texte affiché quand le document est vide. Sans valeur, la chaîne i18n `editor.placeholder`. */\n readonly placeholder = input<string | undefined>(undefined);\n /** Lecture seule. Le `disabled` d'un formulaire s'y ajoute (l'un ou l'autre suffit). Défaut : `false`. */\n readonly readonly = input<boolean | undefined>(undefined);\n /** Tout le reste des options (`extensions`, `commands`, `linkPolicy`, `upload`, `content`…). */\n readonly config = input<Partial<AsterUiOptions>>({});\n /**\n * Nettoyage automatique du HTML collé depuis Word et Google Docs via\n * `wordPasteTransformer()` de `@aster-editor/word`, chargé dynamiquement au montage.\n */\n readonly wordPaste = input<boolean>(true);\n /**\n * Nom accessible de la zone de saisie (`aria-label` sur le contenteditable). Un\n * contenteditable n'est pas associable à un `<label for>`, c'est le seul moyen de le nommer.\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n /** `id` (ou liste d'ids) de l'élément qui sert de libellé (`aria-labelledby` sur le contenteditable). */\n readonly ariaLabelledBy = input<string | undefined>(undefined);\n /**\n * Variables déclarées (libellé, description, valeur), proposées dans le menu d'insertion\n * même si absentes du document. À chaud : `editor.variables.define(...)`, fusion par nom.\n */\n readonly variables = input<readonly AsterVariable[] | undefined>(undefined);\n /**\n * Valeurs par nom. À chaud : `editor.variables.setValues(...)`, fusion avec les valeurs\n * connues (une clé absente n'efface rien, `undefined` efface).\n */\n readonly variableValues = input<VariableValues | undefined>(undefined);\n /** Résolveur asynchrone appelé par `resolveVariables()` pour les variables sans valeur. Lu au montage. */\n readonly variableResolver = input<VariableResolver | undefined>(undefined);\n /** Autoriser l'insertion d'une variable non déclarée. Défaut effectif : `true`. Lu au montage. */\n readonly allowUnknownVariables = input<boolean | undefined>(undefined);\n /** Menu de suggestion déclenché par `{{` dans le contenu. Défaut effectif : `true`. Lu au montage. */\n readonly variableSuggestion = input<boolean | undefined>(undefined);\n /**\n * Chemin de lecture d'`importDocx` : `styled` (lecteur OOXML d'Aster, HTML stylé, mise en\n * page et gabarit renseignés) ou `semantic` (mammoth, HTML sémantique, mise en page vide).\n * Défaut effectif : `styled`. Lu à chaque import.\n */\n readonly importFidelity = input<DocxImportFidelity | undefined>(undefined);\n /**\n * `exportDocx` sans `options.template` réutilise le gabarit du dernier import quand il\n * existe : tout ce qui n'est pas le corps ressort identique. `false` pour l'export neuf\n * (un `options.template` explicite reste honoré). Défaut : `true`. Lu à chaque export.\n */\n readonly exportInTemplate = input<boolean>(true);\n /**\n * Vue page (`AsterUiOptions.pageView`) : `true` pour les défauts d'Aster (A4 portrait), un\n * objet pour la mise en page, la pagination et l'affichage des en-têtes. La mise en page\n * effective du composant (`layout()`) prime sur `pageView.layout`. À chaud : la vue est\n * remontée. Le dialogue « Mise en page » de la toolbar peut aussi l'activer ou la modifier.\n */\n readonly pageView = input<PageViewInput>(undefined);\n /**\n * Mise en page imposée (input `layout`) : prime sur celle de l'import et sur celle posée\n * par le dialogue, se répercute sur la vue page active et sur `exportDocx`. Laisse\n * `undefined` pour suivre l'import ; avec une liaison, tiens-la à jour depuis\n * `layoutChanged` pour que le dialogue « Mise en page » reste pris en compte.\n */\n readonly layoutOverride = input<DocumentLayout | undefined>(undefined, { alias: 'layout' });\n\n /** L'éditeur est monté et prêt. Réémis après un remontage (changement de `toolbar`). */\n readonly ready = output<AsterEditor>();\n /** Le document a changé : HTML de `getHTML()`. Pas émis sur `writeValue`. */\n readonly changed = output<string>();\n /** Le contenteditable a pris le focus. */\n readonly focused = output<void>();\n /**\n * Le contenteditable a perdu le focus au profit d'un élément extérieur à l'éditeur. Un\n * blur vers la toolbar ou un de ses menus n'est pas remonté : l'utilisateur est toujours\n * « dans » l'éditeur. C'est aussi ce qui marque le contrôle de formulaire `touched`.\n */\n readonly blurred = output<void>();\n /** Les valeurs ou déclarations de variables ont changé (`setValues`, `define`, `resolve`, import). */\n readonly variablesChanged = output<VariableValues>();\n /**\n * La mise en page effective a changé : import, input `layout`, ou dialogue « Mise en page »\n * de la toolbar (la vue page est alors relue). Jamais émis pour `null` (vue page retirée).\n */\n readonly layoutChanged = output<DocumentLayout>();\n\n private readonly editorState = signal<AsterEditor | null>(null);\n /** Éditeur courant, `null` avant le montage et après la destruction. */\n readonly editor: Signal<AsterEditor | null> = this.editorState.asReadonly();\n\n private readonly importedTemplateState = signal<ArrayBuffer | null>(null);\n /** Le `.docx` du dernier import, intact, réutilisé comme gabarit à l'export. `null` sans import. */\n readonly importedTemplate: Signal<ArrayBuffer | null> = this.importedTemplateState.asReadonly();\n\n private readonly lostObjectsState = signal<readonly DocxLostObject[]>([]);\n /** Objets Word non représentables rencontrés par le dernier import (vide en mode `semantic`). */\n readonly lostObjects: Signal<readonly DocxLostObject[]> = this.lostObjectsState.asReadonly();\n\n /** Mise en page lue par l'import ou posée par le dialogue « Mise en page ». */\n private readonly layoutState = signal<DocumentLayout | null>(null);\n /**\n * Mise en page effective : l'input `layout` s'il est fourni, sinon celle du dernier import\n * ou du dialogue « Mise en page ». `null` avant tout import sans vue page.\n */\n readonly layout: Signal<DocumentLayout | null> = computed(\n () => this.layoutOverride() ?? this.layoutState(),\n );\n\n private readonly variableNamesState = signal<readonly string[]>([], { equal: sameNames });\n /**\n * Noms des variables réellement présentes dans le document (`editor.variables.getNames()`),\n * relus sur `change` et `variablesChange`. Vide avant le montage et après la destruction.\n */\n readonly variableNames: Signal<readonly string[]> = this.variableNamesState.asReadonly();\n\n private readonly host = viewChild.required<ElementRef<HTMLDivElement>>('host');\n private readonly globalConfig = inject(ASTER_CONFIG, { optional: true });\n private readonly uploadHandler = inject(ASTER_UPLOAD_HANDLER, { optional: true });\n private readonly formDisabled = signal(false);\n\n /** `ASTER_CONFIG` < `config`, fusion superficielle. */\n private readonly mergedConfig = computed<Partial<AsterUiOptions>>(() => ({\n ...(this.globalConfig ?? {}),\n ...this.config(),\n }));\n private readonly resolvedToolbar = computed<ToolbarConfig>(\n () => this.toolbar() ?? this.mergedConfig().toolbar ?? 'standard',\n );\n private readonly resolvedTheme = computed<AsterTheme>(\n () => this.theme() ?? this.mergedConfig().theme ?? 'light',\n );\n private readonly resolvedLocale = computed<AsterLocale>(\n () => this.locale() ?? this.mergedConfig().locale ?? 'fr',\n );\n private readonly resolvedPlaceholder = computed<string | undefined>(\n () => this.placeholder() ?? this.mergedConfig().placeholder,\n );\n private readonly resolvedReadOnly = computed<boolean>(\n () => (this.readonly() ?? this.mergedConfig().readOnly ?? false) || this.formDisabled(),\n );\n /** `config.variables` < inputs dédiés, clé par clé ; un input `undefined` ne masque rien. */\n private readonly resolvedVariableSource = computed<VariableSource | undefined>(() => {\n const base = this.mergedConfig().variables;\n const source: VariableSource = {\n ...base,\n ...(this.variables() !== undefined ? { variables: this.variables() } : {}),\n ...(this.variableValues() !== undefined ? { values: this.variableValues() } : {}),\n ...(this.variableResolver() !== undefined ? { resolve: this.variableResolver() } : {}),\n ...(this.allowUnknownVariables() !== undefined\n ? { allowUnknown: this.allowUnknownVariables() }\n : {}),\n };\n return Object.keys(source).length > 0 ? source : undefined;\n });\n private readonly resolvedVariableSuggestion = computed<boolean | undefined>(\n () => this.variableSuggestion() ?? this.mergedConfig().variableSuggestion,\n );\n private readonly resolvedPageView = computed<PageViewInput>(\n () => this.pageView() ?? this.mergedConfig().pageView,\n );\n\n private instance: AsterInstance | null = null;\n private mountedToolbar: ToolbarConfig | null = null;\n private mountedPageView: PageViewInput = undefined;\n /** Dernière mise en page émise par `layoutChanged`, pour ne pas la réémettre. */\n private emittedLayout: DocumentLayout | null = null;\n private subscriptions: Unsubscribe[] = [];\n /** Valeur reçue par `writeValue` avant le montage, appliquée comme contenu initial. */\n private pendingValue: string | null = null;\n private wordTransformer: PasteTransformer | null = null;\n private wordLoading: Promise<void> | null = null;\n private onChange: ((html: string) => void) | null = null;\n private onTouched: (() => void) | null = null;\n\n /**\n * Transformateur synchrone branché au montage ; il délègue au vrai transformateur Word\n * une fois le module chargé. Garde `@aster-editor/word` optionnel et hors du bundle\n * initial tout en respectant le contrat synchrone de `PasteTransformer`.\n */\n private readonly lazyWordTransformer: PasteTransformer = (html, context) =>\n this.wordTransformer && untracked(() => this.wordPaste())\n ? this.wordTransformer(html, context)\n : html;\n\n constructor() {\n afterNextRender(() => this.mount());\n inject(DestroyRef).onDestroy(() => this.unmount());\n\n effect(() => {\n const theme = this.resolvedTheme();\n untracked(() => this.instance?.setTheme(theme));\n });\n effect(() => {\n const locale = this.resolvedLocale();\n untracked(() => {\n const editor = this.instance?.editor;\n if (editor && editor.i18n.getLocale() !== locale) {\n editor.i18n.setLocale(locale);\n }\n });\n });\n effect(() => {\n const readOnly = this.resolvedReadOnly();\n untracked(() => this.instance?.editor.setReadOnly(readOnly));\n });\n effect(() => {\n const placeholder = this.resolvedPlaceholder();\n untracked(() => {\n if (this.instance) {\n applyPlaceholder(this.instance.editor, placeholder);\n }\n });\n });\n effect(() => {\n const label = this.ariaLabel();\n const labelledBy = this.ariaLabelledBy();\n untracked(() => {\n if (this.instance) {\n applyAriaAttributes(this.instance.editor, label, labelledBy);\n }\n });\n });\n effect(() => {\n const toolbar = this.resolvedToolbar();\n untracked(() => {\n if (this.instance && this.mountedToolbar !== toolbar) {\n this.remount();\n }\n });\n });\n // Le chargement initial du module Word part de `mount()` (jamais côté serveur) ; cet\n // effet ne couvre que le passage `false → true` d'un éditeur déjà monté.\n effect(() => {\n if (this.wordPaste()) {\n untracked(() => {\n if (this.instance) {\n this.loadWordPaste();\n }\n });\n }\n });\n // Au montage, déclarations et valeurs passent par `options.variables` ; ces deux effets\n // ne couvrent que les changements d'input sur un éditeur déjà monté.\n effect(() => {\n const declared = this.variables();\n untracked(() => {\n if (declared && this.instance) {\n this.instance.editor.variables.define(declared);\n }\n });\n });\n effect(() => {\n const values = this.variableValues();\n untracked(() => {\n if (values && this.instance) {\n this.instance.editor.variables.setValues(values);\n }\n });\n });\n // Au montage, la vue page passe par `options.pageView` ; cet effet ne couvre que les\n // changements d'input sur un éditeur déjà monté.\n effect(() => {\n const pageView = this.resolvedPageView();\n untracked(() => {\n if (this.instance && this.mountedPageView !== pageView) {\n this.mountedPageView = pageView;\n setPageView(this.instance.editor, resolvePageViewOptions(pageView, this.layout()));\n }\n });\n });\n // Mise en page effective : répercutée sur la vue page active, signalée par `layoutChanged`.\n effect(() => {\n const layout = this.layout();\n untracked(() => {\n if (layout && this.instance) {\n applyLayoutToPageView(this.instance.editor, layout);\n }\n this.notifyLayout(layout);\n });\n });\n }\n\n // --- API publique --------------------------------------------------------\n\n /**\n * Importe un `.docx` via `@aster-editor/word` (chargé à la demande, le lecteur reste dans\n * un chunk séparé), remplace le contenu de l'éditeur en émettant `change` pour que le\n * formulaire voie la nouvelle valeur, et rend le résultat avec ses avertissements.\n * Le hook d'upload de l'éditeur est réutilisé pour les images embarquées. En mode `styled`\n * (défaut, voir `importFidelity`), le gabarit, la mise en page et les objets non\n * représentables sont conservés dans `importedTemplate`, `layout` et `lostObjects`, et la\n * mise en page est appliquée à la vue page si elle est active. Si le composant est détruit\n * ou remonté pendant l'import, le résultat est rendu mais rien n'est écrit ni conservé :\n * l'instance vivante est relue après chaque `await`.\n */\n async importDocx(file: File): Promise<DocxImportResult> {\n this.requireEditor('importDocx');\n const defaults = untracked(() => ({\n upload: this.resolvedOptions().upload,\n fidelity: this.importFidelity() ?? 'styled',\n }));\n const result = await importWord(file, defaults);\n const editor = this.instance?.editor;\n if (editor && !editor.isDestroyed()) {\n editor.setHTML(result.html, true);\n declareImportedVariables(editor, result.variables, () => this.variableValues());\n this.importedTemplateState.set(result.template);\n this.lostObjectsState.set(result.lost);\n this.layoutState.set(result.layout);\n }\n return result;\n }\n\n /**\n * Convertit le document en `.docx` via `exportDocx` de `@aster-editor/word` (chargé à la\n * demande, la lib `docx` reste dans son chunk). Les valeurs du magasin de variables sont\n * transmises quand `options.variables.values` n'est pas fourni : `mode: 'resolve'` substitue\n * donc ce que l'utilisateur a saisi, `'fields'` produit des champs de fusion Word avec ces\n * valeurs comme résultat. Sans `options.template`, le gabarit du dernier import est utilisé\n * si `exportInTemplate` est vrai ; sans `options.layout`, la mise en page effective\n * (`layout()`) est transmise. Rend le `Blob`, à passer à `downloadDocx` ou à un upload.\n */\n async exportDocx(options: DocxExportOptions = {}): Promise<Blob> {\n const editor = this.requireEditor('exportDocx');\n const resolved = untracked(() =>\n resolveExportOptions(editor, options, {\n template: this.importedTemplate(),\n layout: this.layout(),\n inTemplate: this.exportInTemplate(),\n }),\n );\n return exportWord(editor, resolved);\n }\n\n /**\n * Rapport de fidélité du document courant : export dans le gabarit du dernier import\n * (valeurs du magasin de variables, mise en page effective) puis `compareDocx(gabarit,\n * export)`. `null` sans gabarit importé. Le comparateur est chargé à la demande.\n */\n async compareWithTemplate(): Promise<FidelityReport | null> {\n const template = this.importedTemplate();\n if (!template) {\n return null;\n }\n const exported = await this.exportDocx({ template });\n return compareWithTemplate(template, exported);\n }\n\n /**\n * HTML du document, `{ variables: 'resolve' }` substitue les valeurs connues. Avant le\n * montage, rend la valeur reçue par `writeValue` (puces conservées) ou une chaîne vide.\n */\n getHTML(options?: GetHtmlOptions): string {\n return this.instance?.editor.getHTML(options) ?? this.pendingValue ?? '';\n }\n\n /**\n * Appelle le résolveur (`variableResolver` ou `config.variables.resolve`) pour les\n * variables présentes sans valeur, applique les valeurs obtenues et les rend toutes.\n */\n resolveVariables(): Promise<VariableValues> {\n return this.requireEditor('resolveVariables').variables.resolve();\n }\n\n // --- ControlValueAccessor ------------------------------------------------\n\n /**\n * Applique la valeur du formulaire sans émettre `change` ni entrer dans l'historique ;\n * mémorisée si l'éditeur n'est pas monté. Une valeur identique au HTML courant est\n * ignorée pour ne pas déplacer la sélection (les reactive forms réécrivent la valeur à\n * chaque `setValue`, y compris quand elle n'a pas changé).\n */\n writeValue(value: string | null | undefined): void {\n const html = value ?? '';\n const editor = this.instance?.editor;\n if (!editor) {\n this.pendingValue = html;\n return;\n }\n if (editor.getHTML() === html) {\n return;\n }\n editor.setHTML(html, false);\n }\n\n /** Enregistre le rappel appelé avec le HTML à chaque modification du document par l'utilisateur. */\n registerOnChange(fn: (html: string) => void): void {\n this.onChange = fn;\n }\n\n /** Enregistre le rappel appelé quand l'éditeur perd le focus vers l'extérieur (`touched`). */\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n /** `disabled` du formulaire → lecture seule, cumulé avec l'input `readonly`. */\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n this.instance?.editor.setReadOnly(untracked(() => this.resolvedReadOnly()));\n }\n\n // --- Cycle de vie --------------------------------------------------------\n\n /**\n * Monte l'éditeur. `content` force le contenu initial (remontage) et, dans ce cas,\n * `autofocus` est neutralisé : le focus est restauré explicitement par `remount()`.\n */\n private mount(content?: string, variables?: VariableSnapshot): void {\n if (this.instance) {\n return;\n }\n const options = untracked(() => this.resolvedOptions(content, variables));\n const instance = createAster(this.host().nativeElement, options);\n const editor = instance.editor;\n this.instance = instance;\n this.mountedToolbar = options.toolbar ?? 'standard';\n this.mountedPageView = untracked(() => this.resolvedPageView());\n this.pendingValue = null;\n // Le dialogue « Mise en page » de la toolbar pose sa mise en page via `setPageView` sans\n // passer par le composant : le core signale chaque changement de vue page par un\n // événement DOM sur le contenteditable, on y relit la mise en page en vigueur.\n const onPageViewChange = (): void => this.readLayoutFromPageView(editor);\n editor.contentElement.addEventListener(PAGE_VIEW_CHANGE_EVENT, onPageViewChange);\n this.subscriptions = [\n () => editor.contentElement.removeEventListener(PAGE_VIEW_CHANGE_EVENT, onPageViewChange),\n ];\n this.subscriptions.push(\n editor.on('ready', ({ editor: ready }) => this.ready.emit(ready)),\n editor.on('change', ({ editor: changed }) => {\n const html = changed.getHTML();\n this.onChange?.(html);\n this.changed.emit(html);\n this.refreshVariableNames(changed);\n }),\n editor.on('variablesChange', ({ editor: source, values }) => {\n this.refreshVariableNames(source);\n this.variablesChanged.emit(values);\n }),\n editor.on('focus', () => this.focused.emit()),\n editor.on('blur', ({ event }) => {\n // Un blur vers la toolbar, un menu ou un dialogue de l'éditeur n'est pas une sortie.\n const related = event.relatedTarget;\n if (related instanceof Node && instance.element.contains(related)) {\n return;\n }\n this.onTouched?.();\n this.blurred.emit();\n }),\n );\n untracked(() => applyAriaAttributes(editor, this.ariaLabel(), this.ariaLabelledBy()));\n // Une vue page montée depuis `options.pageView` sans import : sa mise en page devient\n // celle du composant (le dialogue de la toolbar part de la même base).\n this.readLayoutFromPageView(editor);\n if (untracked(() => this.wordPaste())) {\n this.loadWordPaste();\n }\n this.refreshVariableNames(editor);\n this.editorState.set(editor);\n }\n\n private unmount(): void {\n for (const unsubscribe of this.subscriptions) {\n unsubscribe();\n }\n this.subscriptions = [];\n this.instance?.destroy();\n this.instance = null;\n this.mountedToolbar = null;\n this.mountedPageView = undefined;\n this.editorState.set(null);\n this.variableNamesState.set([]);\n }\n\n /**\n * Remonte l'éditeur en conservant le contenu, le focus, les déclarations et les valeurs\n * de variables ; l'historique est perdu.\n */\n private remount(): void {\n const current = this.instance;\n if (!current) {\n return;\n }\n const html = current.editor.getHTML();\n const focused = current.editor.isFocused();\n const variables: VariableSnapshot = {\n declared: current.editor.variables.list(),\n values: current.editor.variables.getValues(),\n };\n this.unmount();\n this.mount(html, variables);\n if (focused) {\n this.instance?.editor.focus('end');\n }\n }\n\n /**\n * Fusionne `ASTER_CONFIG` < `config` < inputs dédiés. Le transformateur Word est placé\n * en tête pour que les transformateurs de l'intégrateur reçoivent du HTML déjà nettoyé.\n * Avec `content` (remontage), `autofocus` est désactivé pour ne pas reprendre le focus et\n * `variables` réinjecte l'état du magasin précédent par-dessus la configuration.\n */\n private resolvedOptions(content?: string, variables?: VariableSnapshot): AsterUiOptions {\n const merged = this.mergedConfig();\n const initial: string | AsterDocument | undefined =\n content ?? this.pendingValue ?? merged.content;\n const source = this.resolvedVariableSource();\n const variableSource: VariableSource | undefined = variables\n ? {\n ...source,\n variables: [...(source?.variables ?? []), ...variables.declared],\n values: { ...source?.values, ...variables.values },\n }\n : source;\n return {\n ...merged,\n content: initial,\n autofocus: content === undefined ? merged.autofocus : false,\n toolbar: this.resolvedToolbar(),\n theme: this.resolvedTheme(),\n locale: this.resolvedLocale(),\n placeholder: this.resolvedPlaceholder(),\n readOnly: this.resolvedReadOnly(),\n pasteTransformers: [this.lazyWordTransformer, ...(merged.pasteTransformers ?? [])],\n upload: merged.upload ?? this.uploadHandler ?? undefined,\n variables: variableSource,\n variableSuggestion: this.resolvedVariableSuggestion(),\n pageView: resolvePageViewOptions(this.resolvedPageView(), this.layout()),\n };\n }\n\n /**\n * Relit la mise en page de la vue page active et l'adopte. Si l'input `layout` la masque,\n * `layoutChanged` est émis directement pour que l'application puisse l'adopter ; sinon\n * l'effet sur `layout()` s'en charge.\n */\n private readLayoutFromPageView(editor: AsterEditor): void {\n const current = readPageViewLayout(editor);\n // Rien à relire si la vue montre déjà l'état connu, ou l'input `layout` que le composant\n // vient lui-même de poser : l'état garde alors la mise en page de l'import, retrouvée\n // quand l'input repasse à `undefined`.\n if (\n !current ||\n current === untracked(() => this.layoutState()) ||\n current === untracked(() => this.layoutOverride())\n ) {\n return;\n }\n this.layoutState.set(current);\n if (untracked(() => this.layout()) !== current) {\n this.notifyLayout(current);\n }\n }\n\n /** Émet `layoutChanged` une seule fois par mise en page (même référence = déjà émise). */\n private notifyLayout(layout: DocumentLayout | null): void {\n if (layout && layout !== this.emittedLayout) {\n this.emittedLayout = layout;\n this.layoutChanged.emit(layout);\n }\n }\n\n /** Éditeur monté, sinon erreur explicite nommant la méthode appelée trop tôt. */\n private requireEditor(method: string): AsterEditor {\n const editor = this.instance?.editor;\n if (!editor) {\n throw new Error(`[aster-editor/angular] ${method}: editor is not mounted yet`);\n }\n return editor;\n }\n\n /** Relit `getNames()` ; le signal n'est notifié que si la liste change réellement. */\n private refreshVariableNames(editor: AsterEditor): void {\n this.variableNamesState.set(editor.variables.getNames());\n }\n\n private loadWordPaste(): void {\n if (this.wordTransformer || this.wordLoading) {\n return;\n }\n this.wordLoading = loadWordPasteTransformer()\n .then((transformer) => {\n this.wordTransformer = transformer;\n })\n .catch((error: unknown) => {\n this.wordLoading = null;\n console.warn(\n '[aster-editor/angular] @aster-editor/word unavailable, paste kept raw',\n error,\n );\n });\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aster-editor/angular",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "Composant Angular standalone pour Aster Editor : reactive forms, signals, zoneless",
5
5
  "license": "MIT",
6
6
  "author": "Joris Tremoulet",
@@ -30,9 +30,9 @@
30
30
  "@angular/common": ">=20.0.0",
31
31
  "@angular/core": ">=20.0.0",
32
32
  "@angular/forms": ">=20.0.0",
33
- "@aster-editor/core": "^0.4.2",
34
- "@aster-editor/ui": "^0.4.2",
35
- "@aster-editor/word": "^0.4.2"
33
+ "@aster-editor/core": "^0.5.0",
34
+ "@aster-editor/ui": "^0.5.0",
35
+ "@aster-editor/word": "^0.5.0"
36
36
  },
37
37
  "peerDependenciesMeta": {
38
38
  "@aster-editor/word": {
@@ -1,9 +1,86 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import { EnvironmentProviders, InjectionToken, Signal } from "@angular/core";
3
3
  import { ControlValueAccessor } from "@angular/forms";
4
- import { AsterCounts, AsterDocument, AsterEditor, AsterEditor as AsterEditor$1, AsterLocale, AsterLocale as AsterLocale$1, AsterTheme, AsterTheme as AsterTheme$1, AsterVariable, AsterVariable as AsterVariable$1, GetHtmlOptions, GetHtmlOptions as GetHtmlOptions$1, LinkPolicy, PasteTransformer, ToolbarConfig, ToolbarConfig as ToolbarConfig$1, ToolbarPreset, UploadHandler, UploadHandler as UploadHandler$1, VariableRenderMode, VariableResolver, VariableResolver as VariableResolver$1, VariableSource, VariableValues, VariableValues as VariableValues$1 } from "@aster-editor/core";
4
+ import { AsterCounts, AsterDocument, AsterEditor, AsterEditor as AsterEditor$1, AsterLocale, AsterLocale as AsterLocale$1, AsterTheme, AsterTheme as AsterTheme$1, AsterVariable, AsterVariable as AsterVariable$1, DocumentLayout, DocumentLayout as DocumentLayout$1, GetHtmlOptions, GetHtmlOptions as GetHtmlOptions$1, HeaderFooterContent, HeaderFooterSet, LinkPolicy, PageMargins, PageSetup, PageViewOptions, PageViewOptions as PageViewOptions$1, PasteTransformer, PasteTransformer as PasteTransformer$1, ToolbarConfig, ToolbarConfig as ToolbarConfig$1, ToolbarPreset, UploadHandler, UploadHandler as UploadHandler$1, VariableRenderMode, VariableResolver, VariableResolver as VariableResolver$1, VariableSource, VariableValues, VariableValues as VariableValues$1 } from "@aster-editor/core";
5
5
  import { AsterUiOptions, AsterUiOptions as AsterUiOptions$1 } from "@aster-editor/ui";
6
- import { DocxExportOptions, DocxExportOptions as DocxExportOptions$1, DocxExportVariableOptions, DocxExportWarning, DocxImportResult, DocxImportResult as DocxImportResult$1, DocxImportWarning, DocxVariableMode } from "@aster-editor/word";
6
+ import { DocxExportOptions, DocxExportOptions as DocxExportOptions$1, DocxExportVariableOptions, DocxExportWarning, DocxImportOptions, DocxImportResult, DocxImportResult as DocxImportResult$1, DocxImportWarning, DocxVariableMode, FidelityExample, FidelityProperty, FidelityPropertyGroup, FidelityReport, FidelityReport as FidelityReport$1 } from "@aster-editor/word";
7
+ /**
8
+ * Vue page du composant. Le core expose `setPageView` / `getLayout` hors contrat
9
+ * (`api/editor.ts` ne les déclare pas encore) : on passe par `pageViewApiOf` de `ui`, qui
10
+ * les détecte à l'exécution, et par `getActivePageView` du core pour relire les options
11
+ * en vigueur (le dialogue « Mise en page » de la toolbar peut les avoir changées).
12
+ */
13
+ /** Valeur de l'input `pageView` du composant, identique à `AsterUiOptions.pageView`. */
14
+ type PageViewInput = boolean | PageViewOptions$1 | undefined;
15
+ /**
16
+ * Options de vue page à donner à `createAster` ou à `setPageView` : l'input (ou la
17
+ * configuration) complété par la mise en page effective du composant, qui prime sur
18
+ * `pageView.layout` quand elle existe. `undefined` et `false` passent tels quels.
19
+ */
20
+ declare function resolvePageViewOptions(pageView: PageViewInput, layout: DocumentLayout$1 | null): PageViewInput;
21
+ /** Active ou retire la vue page sur un éditeur monté ; sans effet si le core ne l'expose pas. */
22
+ declare function setPageView(editor: AsterEditor$1, options: PageViewInput): void;
23
+ /**
24
+ * Mise en page de la vue page active, `null` si elle est inactive ou si le core ne l'expose
25
+ * pas. L'activité est lue via `getActivePageView` : pendant la notification de retrait
26
+ * (`setPageView` retire l'ancienne vue avant de poser la nouvelle), l'ancienne mise en page
27
+ * est encore lisible par `getLayout` mais la vue n'est plus active, et doit être ignorée.
28
+ */
29
+ declare function readPageViewLayout(editor: AsterEditor$1): DocumentLayout$1 | null;
30
+ /**
31
+ * Applique une mise en page à la vue page **si elle est active**, en conservant ses autres
32
+ * options (pagination, affichage des en-têtes). Rien si la vue page est inactive ou si
33
+ * elle montre déjà cette mise en page (même référence : c'est le cas juste après que le
34
+ * dialogue « Mise en page » l'a posée). Rend vrai si la vue a été remontée.
35
+ */
36
+ declare function applyLayoutToPageView(editor: AsterEditor$1, layout: DocumentLayout$1): boolean;
37
+ /**
38
+ * Logique Word du composant, hors de la classe pour la garder lisible : chaque fonction
39
+ * charge `@aster-editor/word` par `import()` au moment de l'appel, le paquet reste donc
40
+ * optionnel et hors du bundle initial (mammoth, la lib `docx` et le comparateur ne sont
41
+ * téléchargés qu'au premier usage).
42
+ */
43
+ /** Chemin de lecture d'un `.docx` : `styled` (lecteur OOXML d'Aster) ou `semantic` (mammoth). */
44
+ type DocxImportFidelity = NonNullable<DocxImportOptions['fidelity']>;
45
+ /** Objet Word non représentable signalé par l'import (`DocxImportResult.lost`). */
46
+ type DocxLostObject = DocxImportResult$1['lost'][number];
47
+ /** Ce que le composant sait au moment d'importer : hook d'upload et chemin de lecture. */
48
+ interface WordImportDefaults {
49
+ readonly upload: UploadHandler$1 | undefined;
50
+ readonly fidelity: DocxImportFidelity;
51
+ }
52
+ /** Import d'un fichier avec le hook d'upload de l'éditeur et le chemin de lecture demandé. */
53
+ declare function importWord(file: File, defaults: WordImportDefaults): Promise<DocxImportResult$1>;
54
+ /** Ce que le composant conserve d'un import et qui complète les options d'export. */
55
+ interface WordExportDefaults {
56
+ /** Gabarit importé (`DocxImportResult.template`), `null` sans import. */
57
+ readonly template: ArrayBuffer | null;
58
+ /** Mise en page effective (import, input `layout` ou dialogue « Mise en page »). */
59
+ readonly layout: DocumentLayout$1 | null;
60
+ /** Utiliser le gabarit importé quand `options.template` est absent. */
61
+ readonly inTemplate: boolean;
62
+ }
63
+ /**
64
+ * Complète les options d'export avec ce que le composant sait : les valeurs du magasin de
65
+ * variables quand `options.variables.values` manque, le gabarit importé quand
66
+ * `options.template` manque et que `inTemplate` l'autorise, la mise en page effective quand
67
+ * `options.layout` manque. Avec un gabarit, `layout` ne sert qu'à régénérer un en-tête ou
68
+ * un pied modifié (`layout.headers` / `footers` différents de ceux du gabarit) ; le reste
69
+ * (format, marges, styles) vient du gabarit. Sans gabarit, `layout` pilote l'export neuf.
70
+ */
71
+ declare function resolveExportOptions(editor: AsterEditor$1, options: DocxExportOptions$1, defaults: WordExportDefaults): DocxExportOptions$1;
72
+ /** Export du document courant avec des options déjà résolues. */
73
+ declare function exportWord(editor: AsterEditor$1, options: DocxExportOptions$1): Promise<Blob>;
74
+ /** Rapport de fidélité entre le gabarit importé et un export produit dans ce gabarit. */
75
+ declare function compareWithTemplate(template: ArrayBuffer, exported: Blob): Promise<FidelityReport$1>;
76
+ /** Transformateur de collage Word, chargé à la demande. */
77
+ declare function loadWordPasteTransformer(): Promise<PasteTransformer$1>;
78
+ /**
79
+ * Après un import : déclare les variables trouvées dans le `.docx` (libellé et valeur des
80
+ * contrôles de contenu compris), puis réapplique les valeurs connues de l'application pour
81
+ * les noms que Word a lui-même valorisés, l'application restant la source de vérité.
82
+ */
83
+ declare function declareImportedVariables(editor: AsterEditor$1, found: readonly AsterVariable$1[], known: () => VariableValues$1 | undefined): void;
7
84
  /**
8
85
  * Composant Angular standalone autour de `createAster` (`@aster-editor/ui`).
9
86
  *
@@ -30,6 +107,13 @@ import { DocxExportOptions, DocxExportOptions as DocxExportOptions$1, DocxExport
30
107
  * `variableSuggestion` de `createAster`. `variableNames` expose les noms présents dans le
31
108
  * document, `variablesChanged` relaie `variablesChange`, `exportDocx` produit le `.docx` avec
32
109
  * les valeurs du magasin.
110
+ *
111
+ * Fidélité Word (session 3) : `importDocx` lit le `.docx` en mode stylé et conserve le
112
+ * gabarit (`importedTemplate`), la mise en page (`layout`) et les objets non représentables
113
+ * (`lostObjects`) ; `exportDocx` réutilise le gabarit par défaut (`exportInTemplate`) et
114
+ * transmet la mise en page ; `pageView` active la vue page, `layout` (input) impose une mise
115
+ * en page, `layoutChanged` signale celle que montre la vue page (dialogue « Mise en page »
116
+ * compris) ; `compareWithTemplate` mesure la fidélité de l'export dans le gabarit.
33
117
  */
34
118
  export declare class AsterEditorComponent implements ControlValueAccessor {
35
119
  /** Preset, groupes déclaratifs, ou `false` pour aucune toolbar. Défaut effectif : `standard`. */
@@ -72,6 +156,32 @@ export declare class AsterEditorComponent implements ControlValueAccessor {
72
156
  readonly allowUnknownVariables: import("@angular/core").InputSignal<boolean | undefined>;
73
157
  /** Menu de suggestion déclenché par `{{` dans le contenu. Défaut effectif : `true`. Lu au montage. */
74
158
  readonly variableSuggestion: import("@angular/core").InputSignal<boolean | undefined>;
159
+ /**
160
+ * Chemin de lecture d'`importDocx` : `styled` (lecteur OOXML d'Aster, HTML stylé, mise en
161
+ * page et gabarit renseignés) ou `semantic` (mammoth, HTML sémantique, mise en page vide).
162
+ * Défaut effectif : `styled`. Lu à chaque import.
163
+ */
164
+ readonly importFidelity: import("@angular/core").InputSignal<DocxImportFidelity | undefined>;
165
+ /**
166
+ * `exportDocx` sans `options.template` réutilise le gabarit du dernier import quand il
167
+ * existe : tout ce qui n'est pas le corps ressort identique. `false` pour l'export neuf
168
+ * (un `options.template` explicite reste honoré). Défaut : `true`. Lu à chaque export.
169
+ */
170
+ readonly exportInTemplate: import("@angular/core").InputSignal<boolean>;
171
+ /**
172
+ * Vue page (`AsterUiOptions.pageView`) : `true` pour les défauts d'Aster (A4 portrait), un
173
+ * objet pour la mise en page, la pagination et l'affichage des en-têtes. La mise en page
174
+ * effective du composant (`layout()`) prime sur `pageView.layout`. À chaud : la vue est
175
+ * remontée. Le dialogue « Mise en page » de la toolbar peut aussi l'activer ou la modifier.
176
+ */
177
+ readonly pageView: import("@angular/core").InputSignal<PageViewInput>;
178
+ /**
179
+ * Mise en page imposée (input `layout`) : prime sur celle de l'import et sur celle posée
180
+ * par le dialogue, se répercute sur la vue page active et sur `exportDocx`. Laisse
181
+ * `undefined` pour suivre l'import ; avec une liaison, tiens-la à jour depuis
182
+ * `layoutChanged` pour que le dialogue « Mise en page » reste pris en compte.
183
+ */
184
+ readonly layoutOverride: import("@angular/core").InputSignal<DocumentLayout$1 | undefined>;
75
185
  /** L'éditeur est monté et prêt. Réémis après un remontage (changement de `toolbar`). */
76
186
  readonly ready: import("@angular/core").OutputEmitterRef<AsterEditor$1>;
77
187
  /** Le document a changé : HTML de `getHTML()`. Pas émis sur `writeValue`. */
@@ -86,9 +196,27 @@ export declare class AsterEditorComponent implements ControlValueAccessor {
86
196
  readonly blurred: import("@angular/core").OutputEmitterRef<void>;
87
197
  /** Les valeurs ou déclarations de variables ont changé (`setValues`, `define`, `resolve`, import). */
88
198
  readonly variablesChanged: import("@angular/core").OutputEmitterRef<Readonly<Record<string, string>>>;
199
+ /**
200
+ * La mise en page effective a changé : import, input `layout`, ou dialogue « Mise en page »
201
+ * de la toolbar (la vue page est alors relue). Jamais émis pour `null` (vue page retirée).
202
+ */
203
+ readonly layoutChanged: import("@angular/core").OutputEmitterRef<DocumentLayout$1>;
89
204
  private readonly editorState;
90
205
  /** Éditeur courant, `null` avant le montage et après la destruction. */
91
206
  readonly editor: Signal<AsterEditor$1 | null>;
207
+ private readonly importedTemplateState;
208
+ /** Le `.docx` du dernier import, intact, réutilisé comme gabarit à l'export. `null` sans import. */
209
+ readonly importedTemplate: Signal<ArrayBuffer | null>;
210
+ private readonly lostObjectsState;
211
+ /** Objets Word non représentables rencontrés par le dernier import (vide en mode `semantic`). */
212
+ readonly lostObjects: Signal<readonly DocxLostObject[]>;
213
+ /** Mise en page lue par l'import ou posée par le dialogue « Mise en page ». */
214
+ private readonly layoutState;
215
+ /**
216
+ * Mise en page effective : l'input `layout` s'il est fourni, sinon celle du dernier import
217
+ * ou du dialogue « Mise en page ». `null` avant tout import sans vue page.
218
+ */
219
+ readonly layout: Signal<DocumentLayout$1 | null>;
92
220
  private readonly variableNamesState;
93
221
  /**
94
222
  * Noms des variables réellement présentes dans le document (`editor.variables.getNames()`),
@@ -109,8 +237,12 @@ export declare class AsterEditorComponent implements ControlValueAccessor {
109
237
  /** `config.variables` < inputs dédiés, clé par clé ; un input `undefined` ne masque rien. */
110
238
  private readonly resolvedVariableSource;
111
239
  private readonly resolvedVariableSuggestion;
240
+ private readonly resolvedPageView;
112
241
  private instance;
113
242
  private mountedToolbar;
243
+ private mountedPageView;
244
+ /** Dernière mise en page émise par `layoutChanged`, pour ne pas la réémettre. */
245
+ private emittedLayout;
114
246
  private subscriptions;
115
247
  /** Valeur reçue par `writeValue` avant le montage, appliquée comme contenu initial. */
116
248
  private pendingValue;
@@ -126,12 +258,15 @@ export declare class AsterEditorComponent implements ControlValueAccessor {
126
258
  private readonly lazyWordTransformer;
127
259
  constructor();
128
260
  /**
129
- * Importe un `.docx` via `@aster-editor/word` (chargé à la demande, mammoth reste dans
261
+ * Importe un `.docx` via `@aster-editor/word` (chargé à la demande, le lecteur reste dans
130
262
  * un chunk séparé), remplace le contenu de l'éditeur en émettant `change` pour que le
131
263
  * formulaire voie la nouvelle valeur, et rend le résultat avec ses avertissements.
132
- * Le hook d'upload de l'éditeur est réutilisé pour les images embarquées. Si le
133
- * composant est détruit ou remonté pendant l'import, le résultat est rendu mais aucun
134
- * contenu n'est écrit : l'instance vivante est relue après chaque `await`.
264
+ * Le hook d'upload de l'éditeur est réutilisé pour les images embarquées. En mode `styled`
265
+ * (défaut, voir `importFidelity`), le gabarit, la mise en page et les objets non
266
+ * représentables sont conservés dans `importedTemplate`, `layout` et `lostObjects`, et la
267
+ * mise en page est appliquée à la vue page si elle est active. Si le composant est détruit
268
+ * ou remonté pendant l'import, le résultat est rendu mais rien n'est écrit ni conservé :
269
+ * l'instance vivante est relue après chaque `await`.
135
270
  */
136
271
  importDocx(file: File): Promise<DocxImportResult$1>;
137
272
  /**
@@ -139,9 +274,17 @@ export declare class AsterEditorComponent implements ControlValueAccessor {
139
274
  * demande, la lib `docx` reste dans son chunk). Les valeurs du magasin de variables sont
140
275
  * transmises quand `options.variables.values` n'est pas fourni : `mode: 'resolve'` substitue
141
276
  * donc ce que l'utilisateur a saisi, `'fields'` produit des champs de fusion Word avec ces
142
- * valeurs comme résultat. Rend le `Blob`, à passer à `downloadDocx` ou à un upload.
277
+ * valeurs comme résultat. Sans `options.template`, le gabarit du dernier import est utilisé
278
+ * si `exportInTemplate` est vrai ; sans `options.layout`, la mise en page effective
279
+ * (`layout()`) est transmise. Rend le `Blob`, à passer à `downloadDocx` ou à un upload.
143
280
  */
144
281
  exportDocx(options?: DocxExportOptions$1): Promise<Blob>;
282
+ /**
283
+ * Rapport de fidélité du document courant : export dans le gabarit du dernier import
284
+ * (valeurs du magasin de variables, mise en page effective) puis `compareDocx(gabarit,
285
+ * export)`. `null` sans gabarit importé. Le comparateur est chargé à la demande.
286
+ */
287
+ compareWithTemplate(): Promise<FidelityReport$1 | null>;
145
288
  /**
146
289
  * HTML du document, `{ variables: 'resolve' }` substitue les valeurs connues. Avant le
147
290
  * montage, rend la valeur reçue par `writeValue` (puces conservées) ou une chaîne vide.
@@ -183,27 +326,19 @@ export declare class AsterEditorComponent implements ControlValueAccessor {
183
326
  * `variables` réinjecte l'état du magasin précédent par-dessus la configuration.
184
327
  */
185
328
  private resolvedOptions;
329
+ /**
330
+ * Relit la mise en page de la vue page active et l'adopte. Si l'input `layout` la masque,
331
+ * `layoutChanged` est émis directement pour que l'application puisse l'adopter ; sinon
332
+ * l'effet sur `layout()` s'en charge.
333
+ */
334
+ private readLayoutFromPageView;
335
+ /** Émet `layoutChanged` une seule fois par mise en page (même référence = déjà émise). */
336
+ private notifyLayout;
186
337
  /** Éditeur monté, sinon erreur explicite nommant la méthode appelée trop tôt. */
187
338
  private requireEditor;
188
339
  /** Relit `getNames()` ; le signal n'est notifié que si la liste change réellement. */
189
340
  private refreshVariableNames;
190
- /**
191
- * Après un import : déclare les variables trouvées dans le `.docx` (libellé et valeur des
192
- * contrôles de contenu compris), puis réapplique l'input `variableValues` pour les noms que
193
- * Word a lui-même valorisés, l'application restant la source de vérité des valeurs.
194
- */
195
- private declareImportedVariables;
196
341
  private loadWordPaste;
197
- /** Nom accessible du contenteditable : `aria-label` et/ou `aria-labelledby`, retirés si vides. */
198
- private applyAriaAttributes;
199
- /**
200
- * Change le placeholder à chaud. L'extension `Placeholder` lit ses options au moment où
201
- * son plugin ProseMirror est créé (et `extension.options` est une copie à chaque accès),
202
- * donc on refabrique le plugin via `addProseMirrorPlugins` avec un `placeholder` surchargé
203
- * et on le substitue à l'ancien par `unregisterPlugin`/`registerPlugin`, API publiques de
204
- * Tiptap. Le repli sur la chaîne i18n `editor.placeholder` est conservé.
205
- */
206
- private applyPlaceholder;
207
342
  static ɵfac: i0.ɵɵFactoryDeclaration<AsterEditorComponent, never>;
208
343
  static ɵcmp: i0.ɵɵComponentDeclaration<AsterEditorComponent, "aster-editor", never, {
209
344
  "toolbar": {
@@ -276,12 +411,33 @@ export declare class AsterEditorComponent implements ControlValueAccessor {
276
411
  "required": false;
277
412
  "isSignal": true;
278
413
  };
414
+ "importFidelity": {
415
+ "alias": "importFidelity";
416
+ "required": false;
417
+ "isSignal": true;
418
+ };
419
+ "exportInTemplate": {
420
+ "alias": "exportInTemplate";
421
+ "required": false;
422
+ "isSignal": true;
423
+ };
424
+ "pageView": {
425
+ "alias": "pageView";
426
+ "required": false;
427
+ "isSignal": true;
428
+ };
429
+ "layoutOverride": {
430
+ "alias": "layout";
431
+ "required": false;
432
+ "isSignal": true;
433
+ };
279
434
  }, {
280
435
  "ready": "ready";
281
436
  "changed": "changed";
282
437
  "focused": "focused";
283
438
  "blurred": "blurred";
284
439
  "variablesChanged": "variablesChanged";
440
+ "layoutChanged": "layoutChanged";
285
441
  }, never, never, true, never>;
286
442
  }
287
443
  /**
@@ -307,4 +463,4 @@ export declare function provideAster(config: Partial<AsterUiOptions$1>): Environ
307
463
  * Sans handler, les images sont insérées en data URL base64.
308
464
  */
309
465
  export declare const ASTER_UPLOAD_HANDLER: InjectionToken<UploadHandler$1>;
310
- export type { AsterCounts, AsterDocument, AsterEditor, AsterLocale, AsterTheme, AsterUiOptions, AsterVariable, DocxExportOptions, DocxExportVariableOptions, DocxExportWarning, DocxImportResult, DocxImportWarning, DocxVariableMode, GetHtmlOptions, LinkPolicy, PasteTransformer, ToolbarConfig, ToolbarPreset, UploadHandler, VariableRenderMode, VariableResolver, VariableSource, VariableValues };
466
+ export type { AsterCounts, AsterDocument, AsterEditor, AsterLocale, AsterTheme, AsterUiOptions, AsterVariable, DocumentLayout, DocxExportOptions, DocxExportVariableOptions, DocxExportWarning, DocxImportFidelity, DocxImportResult, DocxImportWarning, DocxLostObject, DocxVariableMode, FidelityExample, FidelityProperty, FidelityPropertyGroup, FidelityReport, GetHtmlOptions, HeaderFooterContent, HeaderFooterSet, LinkPolicy, PageMargins, PageSetup, PageViewInput, PageViewOptions, PasteTransformer, ToolbarConfig, ToolbarPreset, UploadHandler, VariableRenderMode, VariableResolver, VariableSource, VariableValues };