gedcom-ts 2026.5.2 → 2026.5.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes of gedcom-ts
4
4
 
5
+ ## [2026.5.3] - 2026-05-16
6
+
7
+ ### Added
8
+
9
+ - **Module `gedcom-ts/booklet`** : génération de livrets généalogiques en PDF (collecte des personnes, récits en français, frises chronologiques, estimation de taille, `generateGenealogyBookletPdf`, `downloadBookletPdf`). Dépendance `pdf-lib` incluse dans ce sous-paquet.
10
+ - **Logo couverture** : chemins SVG `GEDCOM_TS_LOGO_PATHS` / `GEDCOM_TS_LOGO_VIEWBOX` et `drawGedcomTsLogoOnPage` exportés ; logo gedcom-ts sur la couverture par défaut (`coverLogo` dans `BookletPdfOptions`).
11
+ - **Tests** : `tests/booklet/` (date/lieu/genre, logo, PDF smoke).
12
+ - **README** : guide `gedcom-ts/booklet`, double point d’entrée npm.
13
+
14
+ ### Changed
15
+
16
+ - **`findHarmonizationClustersFromActs`** : si plusieurs libellés similaires partagent une seule position GPS et que tous les actes ont des coordonnées, unifie automatiquement le libellé (libellé le plus long) sans cluster d’harmonisation manuel.
17
+ - Critère d’harmonisation : ne signale plus les seules variantes d’orthographe lorsque les coordonnées sont déjà identiques.
18
+
5
19
  ## [2026.5.2] - 2026-05-16
6
20
 
7
21
  ### Added
@@ -113,7 +127,7 @@ Les entrées historiques du changelog conservent leurs numéros semver d’origi
113
127
 
114
128
  - Major GEDCOM 7 coverage push: round-trip preservation (`preservedTopLevelRecords`, label-keyed FAM / NOTE xrefs, level-0 `OBJE`), richer `HEAD` export options, full P1.4 dates and places (INT/EST/CAL, `3 PHRASE`, `3 TIME`, `2 SDATE`, `2 PHRASE` event-level, ISO date input, verbatim fallback).
115
129
  - New **fluent edit layer** (`editPerson`, `editAct`, `editActs`, `editDateAct`, `editPlace`, `editNotes` + `*Edit` classes) for in-place model mutations with chainable APIs.
116
- - **README fully rewritten** with a complete public-API reference and a link to the live graphical demo at **[https://gedcomts.jaunet.me](https://gedcomts.jaunet.me)**.
130
+ - **README fully rewritten** with a complete public-API reference and a link to the live graphical demo at **[https://gedcomts.com](https://gedcomts.com)**.
117
131
 
118
132
  ### Added
119
133
 
@@ -174,7 +188,7 @@ Les entrées historiques du changelog conservent leurs numéros semver d’origi
174
188
  #### Documentation
175
189
 
176
190
  - **README intégralement réécrit** : référence complète de l’API publique (un sous-titre par export de `src/index.ts`), tables synthétiques pour `ReadGed`, `GedcomExportOptions` et la couche `*Edit`, exemples mis à jour pour chaque type / classe / fonction exposés.
177
- - Mention en tête du README du **site de démo graphique** : **[https://gedcomts.jaunet.me](https://gedcomts.jaunet.me)**.
191
+ - Mention en tête du README du **site de démo graphique** : **[https://gedcomts.com](https://gedcomts.com)**.
178
192
 
179
193
  ### Changed
180
194
 
package/README.md CHANGED
@@ -6,23 +6,29 @@
6
6
  - work with a typed JSON model (persons, acts, dates, places, notes, media, name variants, attributes)
7
7
  - edit the model in-place through a fluent, chainable API (`editPerson`, `editAct`, …)
8
8
  - export data back to GEDCOM (`.ged`) or GEDZIP (`.zip`)
9
+ - geocode event places (OpenStreetMap / Nominatim) and group similar city names
10
+ - generate a **genealogy booklet** as PDF (`gedcom-ts/booklet`, French narratives)
9
11
 
10
12
  ## Live demo
11
13
 
12
- A graphical demo showcasing the public API (import a `.ged` / `.zip`, browse the typed model, export back) is available at **[https://gedcomts.jaunet.me](https://gedcomts.jaunet.me)**
14
+ A graphical demo showcasing the public API (import a `.ged` / `.zip`, browse the typed model, export back) is available at **[https://gedcomts.com](https://gedcomts.com)**
13
15
 
14
16
  ## Contents
15
17
 
16
18
  - [Installation](#installation)
17
19
  - [Quick start](#quick-start)
18
20
  - [Geocoding places](#geocoding-places)
21
+ - [Genealogy booklet (PDF)](#genealogy-booklet-pdf)
19
22
  - [API reference](#api-reference)
20
23
  - [Error handling](#error-handling)
21
24
 
22
25
  ## Package
23
26
 
24
27
  - NPM: [gedcom-ts](https://www.npmjs.com/package/gedcom-ts)
25
- - Version format **CalVer** `AAAA.M.micro` (e.g. `2026.5.2` = May 2026). See [CHANGELOG.md](CHANGELOG.md).
28
+ - Version format **CalVer** `AAAA.M.micro` (e.g. `2026.5.3` = May 2026). See [CHANGELOG.md](CHANGELOG.md).
29
+ - Entry points:
30
+ - **`gedcom-ts`** — import, model, edit layer, export, geocoding
31
+ - **`gedcom-ts/booklet`** — PDF livret (`pdf-lib` bundled in that chunk)
26
32
 
27
33
  ## Installation
28
34
 
@@ -30,6 +36,8 @@ A graphical demo showcasing the public API (import a `.ged` / `.zip`, browse the
30
36
  npm install gedcom-ts
31
37
  ```
32
38
 
39
+ Both entry points come from the same package; no extra install for the booklet.
40
+
33
41
  ## Runtime Requirements
34
42
 
35
43
  - modern browser runtime (`File`, `Blob`, `XMLHttpRequest`, `URL.createObjectURL`)
@@ -183,9 +191,118 @@ Network: `GET https://nominatim.openstreetmap.org/search?q=…&format=jsonv2` wi
183
191
 
184
192
  The legacy callback `getCityCoordinates` is deprecated — use the flow above.
185
193
 
194
+ ## Genealogy booklet (PDF)
195
+
196
+ The **`gedcom-ts/booklet`** subpath builds a printable family booklet: cover page, table of contents, chapters by generation (Sosa), family sheets, and French narrative text from GEDCOM acts (birth, marriage, death, …). Optional generation timelines are rasterized for PDF.
197
+
198
+ ### Workflow
199
+
200
+ 1. Import with `importGedFile` (`gedcom-ts`).
201
+ 2. Collect persons with `collectBookletPersons` (`gedcom-ts/booklet`).
202
+ 3. Optionally preview size with `estimateBookletSize` + `groupBookletIntoChapters`.
203
+ 4. Build bytes with `generateGenealogyBookletPdf`, then `downloadBookletPdf` (browser).
204
+
205
+ ```ts
206
+ import { importGedFile } from "gedcom-ts";
207
+ import {
208
+ collectBookletPersons,
209
+ groupBookletIntoChapters,
210
+ estimateBookletSize,
211
+ generateGenealogyBookletPdf,
212
+ downloadBookletPdf,
213
+ personDisplayName,
214
+ } from "gedcom-ts/booklet";
215
+
216
+ async function exportBooklet(file: File) {
217
+ const ged = await importGedFile(file);
218
+ const root = ged.persons[0] ?? null;
219
+
220
+ const entries = collectBookletPersons({
221
+ ged,
222
+ scope: "from-reference",
223
+ referencePerson: root,
224
+ maxGeneration: 6,
225
+ });
226
+
227
+ const chapters = groupBookletIntoChapters(entries);
228
+ const families = chapters.reduce((n, ch) => n + ch.families.length, 0);
229
+ const size = estimateBookletSize(chapters, entries.length, families, "summary", "canvas");
230
+ console.log(size.label);
231
+
232
+ const pdf = await generateGenealogyBookletPdf(
233
+ entries,
234
+ {
235
+ title: "Livret familial",
236
+ scopeLabel: "Ancêtres et descendance",
237
+ personCount: entries.length,
238
+ referenceName: root ? personDisplayName(root) : undefined,
239
+ },
240
+ {
241
+ detailLevel: "summary",
242
+ timelineStyle: "canvas",
243
+ coverLogo: true,
244
+ },
245
+ );
246
+
247
+ downloadBookletPdf(pdf, "livret.pdf");
248
+ }
249
+ ```
250
+
251
+ Use `scope: "all"` and `referencePerson: null` to include every individual in the file.
252
+
253
+ ### `collectBookletPersons` options
254
+
255
+ | Option | Role |
256
+ | --- | --- |
257
+ | `ged` | `ReadGed` after import |
258
+ | `scope` | `"all"` or `"from-reference"` (Sosa from `referencePerson`) |
259
+ | `referencePerson` | Root person for `"from-reference"`; `null` if scope is `"all"` |
260
+ | `maxGeneration` | Max Sosa generation (e.g. `6`); ignored when `scope === "all"` |
261
+
262
+ Helpers: `personDisplayName`, `buildBookletPersonEntry`, `sortBookletEntries`, `bookletSexFromPerson`.
263
+
264
+ ### `generateGenealogyBookletPdf` options
265
+
266
+ | Option | Values | Effect |
267
+ | --- | --- | --- |
268
+ | `detailLevel` | `"summary"` \| `"detailed"` | Short prose per person vs longer biographies |
269
+ | `timelineStyle` | `"off"` \| `"canvas"` | Generation timeline pages per chapter |
270
+ | `coverLogo` | `true` (default), `false`, or `DrawGedcomTsLogoOptions` | gedcom-ts vector logo on the cover |
271
+
272
+ `BookletPdfMeta`: `title`, `scopeLabel`, `personCount`, optional `referenceName`.
273
+
274
+ ### Cover logo
275
+
276
+ The cover draws the **gedcom-ts logo** from paths shipped in the package (`GEDCOM_TS_LOGO_PATHS`, `GEDCOM_TS_LOGO_VIEWBOX`). Reuse on custom PDF pages:
277
+
278
+ ```ts
279
+ import { PDFDocument } from "pdf-lib";
280
+ import {
281
+ drawGedcomTsLogoOnPage,
282
+ defaultCoverLogoOptions,
283
+ BOOKLET_BRAND_RGB,
284
+ } from "gedcom-ts/booklet";
285
+
286
+ const doc = await PDFDocument.create();
287
+ const page = doc.addPage();
288
+ drawGedcomTsLogoOnPage(page, defaultCoverLogoOptions());
289
+ ```
290
+
291
+ ### Booklet API cheat sheet
292
+
293
+ | Goal | Export |
294
+ | --- | --- |
295
+ | Persons for the booklet | `collectBookletPersons` |
296
+ | Chapters / families | `groupBookletIntoChapters`, `partnerNamesLabel` |
297
+ | French narratives (custom UI) | `buildPersonSummaryNarrative`, `buildPersonDetailedNarratives`, `buildFamilyNarrative`, `buildChapterIntroNarrative` |
298
+ | Page estimate | `estimateBookletSize`, `bookletSizeAdvice` |
299
+ | Timeline data / PNG | `buildGenerationTimeline`, `rasterizeGenerationTimelinePng` |
300
+ | PDF output | `generateGenealogyBookletPdf`, `downloadBookletPdf`, `toPdfText` |
301
+ | Logo | `drawGedcomTsLogoOnPage`, `defaultCoverLogoOptions`, `GEDCOM_TS_LOGO_PATHS` |
302
+
186
303
  ## API reference
187
304
 
188
- Short description and a minimal snippet for each public export.
305
+ Short description and a minimal snippet for each export of **`gedcom-ts`**. For the PDF booklet, see [Genealogy booklet (PDF)](#genealogy-booklet-pdf) (`gedcom-ts/booklet`).
189
306
 
190
307
  ### Importing a file
191
308
 
@@ -0,0 +1,8 @@
1
+ /** Date réduite à une année (éventuellement avec qualificateur GEDCOM). */
2
+ export declare function isYearOnlyDate(dateLabel: string): boolean;
3
+ /** « le 15 mars 1991 », « en 1991 », « vers 1700 », « avant 1800 »… */
4
+ export declare function onDate(dateLabel: string): string;
5
+ /** « De 1700 à 1850 » ou « Du 15 mars 1700 au 3 janvier 1850 ». */
6
+ export declare function lifeDateRange(from: string, to: string): string;
7
+ /** « voit le jour en 1991 » ou « voit le jour le 15 mars 1991 ». */
8
+ export declare function seesDayOn(dateLabel: string): string;
@@ -0,0 +1,11 @@
1
+ import type { BookletTimelineStyle } from './booklet-timeline';
2
+ import type { BookletChapter, BookletDetailLevel } from './booklet-structure';
3
+ export interface BookletSizeEstimate {
4
+ readonly pages: number;
5
+ readonly label: string;
6
+ }
7
+ /** Nombre de pages frise estimé pour un chapitre (tranches dynamiques). */
8
+ export declare function estimateTimelineSliceCount(rowCount: number): number;
9
+ /** Estimation grossière du nombre de pages pour orienter l’utilisateur. */
10
+ export declare function estimateBookletSize(chapters: readonly BookletChapter[], personCount: number, familyCount: number, detailLevel: BookletDetailLevel, timelineStyle?: BookletTimelineStyle): BookletSizeEstimate;
11
+ export declare function bookletSizeAdvice(personCount: number, detailLevel: BookletDetailLevel): string | null;
@@ -0,0 +1,23 @@
1
+ /** Sexe GEDCOM exploité pour les accords du livret (M, F, U, X). */
2
+ export type BookletSex = 'M' | 'F' | 'U' | 'X';
3
+ export interface PersonGenderWords {
4
+ readonly born: string;
5
+ readonly died: string;
6
+ readonly baptized: string;
7
+ readonly present: string;
8
+ readonly linked: string;
9
+ readonly offspring: string;
10
+ readonly descendant: string;
11
+ readonly childOf: string;
12
+ readonly parentOf: string;
13
+ }
14
+ /** Participes / noms accordés au genre de la personne. U et X → formes neutres. */
15
+ export declare function personGenderWords(sex: BookletSex): PersonGenderWords;
16
+ /** Suffixe pluriel français (0 ou 1 → singulier). */
17
+ export declare function pluralS(count: number): string;
18
+ /** Choisit la forme singulier / pluriel. */
19
+ export declare function pluralPick<T>(count: number, one: T, many: T): T;
20
+ /** « 1 enfant recensé » / « N enfants recensés ». */
21
+ export declare function recensedChildrenPhrase(count: number): string;
22
+ /** « 1 autre union citée… » / « N autres unions citées… ». */
23
+ export declare function otherUnionsPhrase(count: number): string;
@@ -0,0 +1,19 @@
1
+ import { type PDFPage, type RGB } from 'pdf-lib';
2
+ export { GEDCOM_TS_LOGO_PATHS, GEDCOM_TS_LOGO_VIEWBOX } from "./gedcom-ts-logo.paths";
3
+ /** Couleur de marque gedcom-ts (#19196f), pour pdf-lib `rgb(...)`. */
4
+ export declare const BOOKLET_BRAND_RGB: RGB;
5
+ export interface GedcomTsLogoLayout {
6
+ /** Ordonnée PDF du bas du logo (pour placer texte et barre en dessous). */
7
+ readonly bottomY: number;
8
+ readonly height: number;
9
+ }
10
+ export interface DrawGedcomTsLogoOptions {
11
+ readonly pageWidth?: number;
12
+ readonly maxWidth?: number;
13
+ readonly bottomY?: number;
14
+ readonly color?: RGB;
15
+ }
16
+ /** Options par défaut du logo sur une page A4 (couverture du livret). */
17
+ export declare function defaultCoverLogoOptions(pageWidth?: number, pageHeight?: number): DrawGedcomTsLogoOptions;
18
+ /** Dessine le logo gedcom-ts en vecteur SVG sur la page (pdf-lib drawSvgPath). */
19
+ export declare function drawGedcomTsLogoOnPage(page: PDFPage, options?: DrawGedcomTsLogoOptions): GedcomTsLogoLayout;
@@ -0,0 +1,10 @@
1
+ import type { BookletPersonEntry } from './booklet-person';
2
+ import type { BookletChapter, BookletDetailLevel, BookletFamilyUnit } from './booklet-structure';
3
+ /** Chapitre : phrase d'ouverture narrative. */
4
+ export declare function buildChapterIntroNarrative(chapter: BookletChapter): string;
5
+ /** Fiche famille en récit. */
6
+ export declare function buildFamilyNarrative(family: BookletFamilyUnit, detailLevel: BookletDetailLevel): readonly string[];
7
+ /** Portrait condensé : un paragraphe fluide, nom cité une fois. */
8
+ export declare function buildPersonSummaryNarrative(entry: BookletPersonEntry): string;
9
+ /** Portrait détaillé : peu de paragraphes, sans redondance naissance/décès. */
10
+ export declare function buildPersonDetailedNarratives(entry: BookletPersonEntry): readonly string[];
@@ -0,0 +1,22 @@
1
+ import { type DrawGedcomTsLogoOptions } from './booklet-logo';
2
+ import type { BookletPersonEntry } from './booklet-person';
3
+ import { type BookletTimelineStyle } from './booklet-timeline';
4
+ import { type BookletDetailLevel } from './booklet-structure';
5
+ export interface BookletPdfMeta {
6
+ readonly title: string;
7
+ readonly scopeLabel: string;
8
+ readonly personCount: number;
9
+ readonly referenceName?: string;
10
+ }
11
+ export interface BookletPdfOptions {
12
+ readonly detailLevel: BookletDetailLevel;
13
+ readonly timelineStyle: BookletTimelineStyle;
14
+ /**
15
+ * Logo gedcom-ts sur la page de couverture (vecteur, inclus dans le paquet).
16
+ * Défaut : affiché. `false` pour masquer ; sinon options passées à `drawGedcomTsLogoOnPage`.
17
+ */
18
+ readonly coverLogo?: boolean | DrawGedcomTsLogoOptions;
19
+ }
20
+ export declare function toPdfText(text: string): string;
21
+ export declare function generateGenealogyBookletPdf(entries: readonly BookletPersonEntry[], meta: BookletPdfMeta, options: BookletPdfOptions): Promise<Uint8Array>;
22
+ export declare function downloadBookletPdf(bytes: Uint8Array, filename: string): void;
@@ -0,0 +1,48 @@
1
+ import { type Person } from "../commons/Person";
2
+ import type { ReadGed } from "../import/ReadGed";
3
+ import type { BookletSex } from './booklet-gender';
4
+ export type { BookletSex } from './booklet-gender';
5
+ export interface BookletRelationRef {
6
+ readonly indi: number;
7
+ readonly name: string;
8
+ readonly datesLabel: string;
9
+ readonly sex: BookletSex;
10
+ }
11
+ export interface BookletEventLine {
12
+ readonly kind: string;
13
+ readonly label: string;
14
+ readonly date: string;
15
+ readonly place: string;
16
+ }
17
+ export interface BookletUnionEntry {
18
+ readonly familyId: number;
19
+ readonly coParent: BookletRelationRef;
20
+ readonly children: readonly BookletRelationRef[];
21
+ readonly marriageLabel: string | null;
22
+ }
23
+ export interface BookletPersonEntry {
24
+ readonly indi: number;
25
+ readonly name: string;
26
+ readonly sex: BookletSex;
27
+ readonly datesLabel: string;
28
+ readonly sosa: number | null;
29
+ readonly generation: number | null;
30
+ readonly events: readonly BookletEventLine[];
31
+ readonly notesPreview: string | null;
32
+ readonly parents: readonly BookletRelationRef[];
33
+ readonly unions: readonly BookletUnionEntry[];
34
+ }
35
+ export declare function personDisplayName(person: Person): string;
36
+ export declare function personDatesLabel(person: Person): string;
37
+ export declare function bookletSexFromPerson(person: Person): BookletSex;
38
+ export declare function buildBookletPersonEntry(person: Person, ged: ReadGed, sosa: number | null): BookletPersonEntry;
39
+ export declare function sortBookletEntries(entries: BookletPersonEntry[]): BookletPersonEntry[];
40
+ export type BookletScope = 'all' | 'from-reference';
41
+ export interface BookletCollectOptions {
42
+ readonly scope: BookletScope;
43
+ readonly ged: ReadGed;
44
+ readonly referencePerson: Person | null;
45
+ /** Limite de génération SOSA (1 = racine seulement). Ignoré si « tout l’arbre ». */
46
+ readonly maxGeneration?: number | null;
47
+ }
48
+ export declare function collectBookletPersons(options: BookletCollectOptions): BookletPersonEntry[];
@@ -0,0 +1,24 @@
1
+ export interface ParsedPlace {
2
+ readonly city: string | null;
3
+ readonly country: string | null;
4
+ readonly raw: string;
5
+ }
6
+ /** Découpe « ville, pays » issu de actPlaceLabel. */
7
+ export declare function parsePlaceLabel(label: string): ParsedPlace | null;
8
+ /** Noyau du lieu sans préposition initiale : « Poissy », « Poissy, en France », « en France ». */
9
+ export declare function placeCore(label: string): string;
10
+ /** Lieu après une date ou un événement : « à Poissy », « en France », « , à Poissy » si date = année. */
11
+ export declare function afterDateLocation(dateLabel: string, placeLabel: string): string;
12
+ /** Lieu seul (sans date avant) : « à Poissy, en France ». */
13
+ export declare function atLocation(placeLabel: string): string;
14
+ /** Lieu de naissance et de décès : évite de répéter le lieu si identique. */
15
+ export declare function birthDeathLocationPhrases(birthDate: string, birthPlace: string, deathDate: string, deathPlace: string): {
16
+ readonly birth: string;
17
+ readonly death: string;
18
+ };
19
+ /** Lieu(x) après une fourchette de dates de vie. */
20
+ export declare function lifeRangeLocation(birthPlace: string, deathPlace: string): string;
21
+ /** « en 1991, à Poissy, en France » — date et lieu pour un mariage. */
22
+ export declare function marriageWhenWhere(dateLabel: string, placeLabel: string): string | null;
23
+ /** Espace + fragment mariage pour l’insérer après un verbe (« se marient en 1991… »). */
24
+ export declare function embedMarriageWhenWhere(label: string | null | undefined): string;
@@ -0,0 +1,23 @@
1
+ import type { BookletPersonEntry, BookletRelationRef } from './booklet-person';
2
+ export type BookletDetailLevel = 'summary' | 'detailed';
3
+ export type { BookletRelationRef };
4
+ export interface BookletFamilyUnit {
5
+ readonly familyId: number;
6
+ readonly partners: readonly BookletRelationRef[];
7
+ readonly children: readonly BookletRelationRef[];
8
+ readonly marriageLabel: string | null;
9
+ }
10
+ export interface BookletChapter {
11
+ readonly key: string;
12
+ readonly title: string;
13
+ readonly subtitle: string;
14
+ readonly entries: readonly BookletPersonEntry[];
15
+ readonly families: readonly BookletFamilyUnit[];
16
+ }
17
+ export interface BookletTocEntry {
18
+ readonly title: string;
19
+ readonly page: number;
20
+ }
21
+ export declare function groupBookletIntoChapters(entries: readonly BookletPersonEntry[]): BookletChapter[];
22
+ export declare function partnerNamesLabel(partners: readonly BookletRelationRef[]): string;
23
+ export declare function childrenNamesLabel(children: readonly BookletRelationRef[], max?: number): string;
@@ -0,0 +1,9 @@
1
+ import { type GenerationTimelineLayout } from './booklet-timeline';
2
+ export declare const TIMELINE_CANVAS_WIDTH = 920;
3
+ /** Hauteur du PNG (px) pour N lignes de frise. */
4
+ export declare function timelineCanvasHeightPx(rowCount: number, continuationNote?: boolean): number;
5
+ /** Hauteur en points PDF après mise à l'échelle dans le livret. */
6
+ export declare function timelineScaledPdfHeight(rowCount: number, pdfMaxWidth: number, continuationNote?: boolean): number;
7
+ /** Nombre maximal de lignes dont la frise tient dans la hauteur PDF disponible. */
8
+ export declare function maxTimelineRowsForPdfHeight(availablePt: number, pdfMaxWidth: number, continuationNote?: boolean): number;
9
+ export declare function rasterizeGenerationTimelinePng(layout: GenerationTimelineLayout, pageNote?: string): Promise<Uint8Array>;
@@ -0,0 +1,31 @@
1
+ import type { BookletChapter } from './booklet-structure';
2
+ export type BookletTimelineStyle = 'off' | 'canvas';
3
+ export type TimelineMarkerKind = 'birth' | 'death' | 'marriage';
4
+ export interface TimelineMarker {
5
+ readonly year: number;
6
+ readonly kind: TimelineMarkerKind;
7
+ }
8
+ export interface TimelineRow {
9
+ readonly name: string;
10
+ readonly shortName: string;
11
+ readonly birthYear: number | null;
12
+ readonly deathYear: number | null;
13
+ readonly markers: readonly TimelineMarker[];
14
+ readonly hasLifeSpan: boolean;
15
+ }
16
+ export interface GenerationTimelineLayout {
17
+ readonly chapterTitle: string;
18
+ readonly yearMin: number;
19
+ readonly yearMax: number;
20
+ readonly tickStep: number;
21
+ readonly tickYears: readonly number[];
22
+ readonly rows: readonly TimelineRow[];
23
+ readonly overflowCount: number;
24
+ readonly pageCount: number;
25
+ }
26
+ export declare function chapterSupportsTimeline(chapter: BookletChapter): boolean;
27
+ export declare function parseYearFromDate(date: string): number | null;
28
+ export declare function timelineRowCount(chapter: BookletChapter): number;
29
+ export declare function buildGenerationTimeline(chapter: BookletChapter, rowStart?: number, rowCount?: number): GenerationTimelineLayout | null;
30
+ /** Position X normalisée 0–1 dans la plage [yearMin, yearMax]. */
31
+ export declare function timelineXNorm(year: number, yearMin: number, yearMax: number): number;
@@ -0,0 +1,3 @@
1
+ /** Chemins du logo gedcom-ts (viewBox commun). */
2
+ export declare const GEDCOM_TS_LOGO_VIEWBOX = "28.136896362304697 238.4370489501953 1352.32712890625 293.0861376953125";
3
+ export declare const GEDCOM_TS_LOGO_PATHS: readonly ["M 1305.159,272.478 C 1306.112,274.485 1307.065,276.493 1308.018,278.500 C 1308.932,313.833 1307.845,349.167 1307.759,384.500 C 1307.673,419.833 1307.586,455.167 1307.500,490.500 C 1306.736,491.932 1305.971,493.363 1305.207,494.795 C 1301.672,501.415 1296.377,506.667 1290.161,509.720 C 1288.274,510.647 1286.387,511.573 1284.500,512.500 C 1249.167,512.500 1213.833,512.500 1178.500,512.500 C 1143.167,512.500 1107.833,512.500 1072.500,512.500 C 1070.833,511.677 1069.167,510.855 1067.500,510.032 C 1060.247,506.452 1053.705,499.501 1051.143,492.653 C 1049.003,486.933 1049,486.781 1049,383.500 C 1049,281.958 1049.037,279.976 1051.033,274.640 C 1053.622,267.719 1059.317,261.248 1066.145,257.466 C 1067.930,256.477 1069.715,255.489 1071.500,254.500 C 1106.646,254.411 1141.792,254.321 1176.938,254.232 C 1271.064,253.993 1282.889,254.135 1287.158,255.553 C 1293.887,257.788 1301.651,265.088 1305.159,272.478 ZM 1148.500,369 C 1134,369 1119.500,369 1105,369 C 1105,372.500 1105,376 1105,379.500 C 1105,383 1105,386.500 1105,390 C 1110.333,390 1115.667,390 1121,390 C 1126.333,390 1131.667,390 1137,390 C 1137,405.833 1137,421.667 1137,437.500 C 1137,453.333 1137,469.167 1137,485 C 1140.833,485 1144.667,485 1148.500,485 C 1152.333,485 1156.167,485 1160,485 C 1160,469.167 1160,453.333 1160,437.500 C 1160,421.667 1160,405.833 1160,390 C 1165.333,390 1170.667,390 1176,390 C 1181.333,390 1186.667,390 1192,390 C 1192,386.500 1192,383 1192,379.500 C 1192,376 1192,372.500 1192,369 C 1177.500,369 1163,369 1148.500,369 ZM 1203.739,460.228 C 1200.990,462.143 1200.986,462.167 1202.739,465.168 C 1211.828,480.727 1230.452,488.669 1251.571,485.991 C 1265.570,484.216 1274.010,478.789 1279.215,468.214 C 1282.177,462.198 1282.494,460.702 1282.434,453.020 C 1282.293,434.845 1274.476,425.946 1249.377,415.384 C 1235.916,409.720 1231.345,406.356 1230.423,401.441 C 1228.911,393.378 1234.308,388.492 1243.956,389.190 C 1249.947,389.623 1253.327,391.486 1256.673,396.196 C 1257.314,397.098 1257.954,398 1258.595,398.902 C 1261.489,397.002 1264.384,395.101 1267.279,393.201 C 1272.055,390.065 1275.971,386.844 1275.981,386.043 C 1275.991,385.242 1273.176,381.831 1269.725,378.464 C 1262.318,371.237 1257.195,369.096 1245.369,368.288 C 1229.582,367.210 1216.149,373.886 1210.351,385.693 C 1207.842,390.803 1207.505,392.580 1207.542,400.500 C 1207.578,408.209 1207.960,410.223 1210.203,414.540 C 1214.235,422.301 1220.653,427.492 1233.837,433.652 C 1240.251,436.649 1247.525,440.157 1250,441.448 C 1262.500,447.967 1261.922,461.901 1249.023,464.995 C 1243.341,466.358 1237.206,465.625 1231.932,462.953 C 1228.390,461.159 1221.668,454.505 1220.817,451.951 C 1220.493,450.977 1218.507,451.654 1213.437,454.462 C 1209.622,456.575 1205.258,459.170 1203.739,460.228 Z", "M 225.380,335.713 C 225.772,336.105 225.942,365.918 225.759,401.963 C 225.461,460.487 225.241,468.142 223.695,473.500 C 215.587,501.606 191.466,517.459 159.500,515.688 C 147.674,515.033 139.874,513.136 131,508.756 C 123.005,504.810 112.315,494.528 108.616,487.228 C 107.728,485.475 106.839,483.722 105.951,481.969 C 106.782,481.653 107.613,481.337 108.444,481.021 C 109.815,480.500 114.203,478.684 118.194,476.985 C 126.258,473.553 125.247,473.202 130,481.096 C 133.139,486.309 139.532,491.270 146.847,494.169 C 151.547,496.032 154.438,496.410 164,496.410 C 179.109,496.410 184.874,494.302 193.588,485.588 C 202.242,476.934 204.180,471.495 204.776,454.201 C 204.929,449.768 205.081,445.336 205.234,440.903 C 203.339,442.890 201.444,444.876 199.549,446.863 C 183.362,463.834 157.572,467.618 134.090,456.466 C 123.991,451.670 112.996,440.613 107.772,430 C 102.187,418.653 100.588,411.423 100.583,397.500 C 100.576,376.858 105.878,363.166 119,349.939 C 127.108,341.766 136.428,336.423 147,333.887 C 153.967,332.216 167.851,332.242 175,333.939 C 183.154,335.875 193.353,341.580 199.534,347.663 C 201.356,349.456 203.178,351.249 205,353.042 C 205.003,351.785 205.006,350.528 205.009,349.271 C 205.014,347.197 205.301,343.138 205.648,340.250 C 205.858,338.500 206.069,336.750 206.279,335 C 209.344,335 212.408,335 215.473,335 C 220.530,335 224.988,335.321 225.380,335.713 ZM 122.022,389.200 C 120.892,396.956 120.930,398.721 122.415,407.042 C 125.883,426.478 138.872,440.098 156.884,443.187 C 178.669,446.923 199.317,432.057 204.057,409.224 C 205.748,401.078 204.781,385.847 202.140,379.023 C 197.584,367.254 188.711,358.051 177.780,353.757 C 170.193,350.777 156.539,350.809 149,353.827 C 134.233,359.738 124.444,372.573 122.022,389.200 Z", "M 508,286 C 511.333,286 514.667,286 518,286 C 518,315.333 518,344.667 518,374 C 518,403.333 518,432.667 518,462 C 514.667,462 511.333,462 508,462 C 504.667,462 501.333,462 498,462 C 498,458.811 498,455.622 498,452.433 C 498,449.244 498,446.055 498,442.866 C 495.875,445.022 493.751,447.179 491.626,449.335 C 474.540,466.675 446.501,470.165 422.906,457.890 C 408.340,450.312 396.391,434.668 391.972,417.391 C 388.015,401.918 389.862,381.623 396.507,367.577 C 400.385,359.380 408.939,349.034 415.841,344.192 C 427.939,335.706 438.526,332.467 453.542,332.658 C 469.877,332.865 483.504,338.894 493.518,350.342 C 495.012,352.050 496.506,353.758 498,355.466 C 498,343.888 498,332.311 498,320.733 C 498,309.155 498,297.578 498,286 C 501.333,286 504.667,286 508,286 ZM 412.082,387.108 C 407.475,410.565 417.567,433.256 436.808,442.705 C 442.038,445.273 443.434,445.500 454,445.500 C 465.062,445.500 465.756,445.371 472.210,442.132 C 495.351,430.518 504.420,400.706 492.324,376.013 C 481.485,353.887 457.114,345.306 435.411,355.974 C 424.494,361.340 414.531,374.636 412.082,387.108 Z", "M 805.897,388.107 C 807.087,395.930 806.409,408.990 804.410,416.736 C 799.555,435.549 786.507,451.242 769.077,459.232 C 745.708,469.945 715.450,465.632 696.694,448.915 C 689.676,442.660 681.914,431.161 679.116,422.876 C 673.975,407.652 674.080,389.135 679.392,374.501 C 686.555,354.768 703.236,339.744 724,334.324 C 734.342,331.625 751.409,332.097 761.500,335.361 C 772.424,338.895 781.049,344.251 788.454,352.100 C 798.280,362.514 803.708,373.720 805.897,388.107 ZM 697.009,389.528 C 695.771,396.453 696.744,408.291 699.139,415.462 C 703.243,427.747 711.279,436.868 722.820,442.335 C 729.114,445.317 730.163,445.500 741,445.500 C 751.817,445.500 752.893,445.314 759.123,442.362 C 775.696,434.509 785.195,418.938 785.270,399.500 C 785.328,384.498 780.452,372.423 770.416,362.710 C 761.762,354.334 746.457,349.659 734.435,351.718 C 726.976,352.996 718.387,356.734 712.871,361.102 C 705.470,366.964 698.956,378.639 697.009,389.528 Z", "M 1012.963,373.810 C 1013.395,377.489 1013.692,398.725 1013.624,421 C 1013.583,434.500 1013.541,448 1013.500,461.500 C 1010.108,461.595 1006.717,461.689 1003.325,461.784 C 999.933,461.879 996.542,461.973 993.150,462.068 C 993.020,447.640 992.891,433.212 992.761,418.784 C 992.331,370.854 992.138,369.271 985.715,360.849 C 980.815,354.425 974.329,351.515 965.052,351.578 C 959.350,351.617 956.364,352.178 952.864,353.871 C 946.122,357.131 940.271,362.531 937.452,368.095 C 932.317,378.228 932,381.430 932,423.210 C 932,436.140 932,449.070 932,462 C 928.525,462 925.050,462 921.575,462 C 918.100,462 914.624,462 911.149,462 C 911.032,447.583 910.917,433.167 910.800,418.750 C 910.467,377.548 910.349,375.230 908.322,369.810 C 905.317,361.776 901.672,357.478 895.150,354.275 C 876.725,345.227 855.437,358.603 850.996,382.020 C 850.446,384.921 850,404.004 850,424.636 C 850,437.091 850,449.546 850,462 C 846.500,462 843,462 839.500,462 C 836,462 832.500,462 829,462 C 829,440.821 829,419.643 829,398.464 C 829,377.285 829,356.107 829,334.928 C 832.250,335.023 835.500,335.119 838.750,335.214 C 842,335.309 845.250,335.405 848.500,335.500 C 848.667,338.436 848.833,341.371 849,344.307 C 849.167,347.243 849.333,350.177 849.500,353.113 C 850.536,351.762 851.571,350.412 852.607,349.061 C 862.146,336.620 877.850,330.621 894.731,332.969 C 907.103,334.690 916.916,340.693 922.924,350.218 C 924.065,352.028 925.208,353.837 926.349,355.647 C 927.727,353.956 929.105,352.264 930.483,350.573 C 941.697,336.811 957.957,330.521 975.954,332.982 C 997.187,335.886 1010.194,350.235 1012.963,373.810 Z", "M 370.503,382.500 C 371.227,386.350 371.860,392.763 371.910,396.750 C 371.940,399.167 371.970,401.583 372,404 C 354.953,404 337.907,404 320.860,404 C 303.813,404 286.767,404 269.720,404 C 269.911,405.853 270.103,407.707 270.294,409.560 C 271.046,416.849 276.054,427.420 281.304,432.801 C 291.031,442.771 300.809,446.451 315.887,445.818 C 324.320,445.464 326.327,445.005 332.234,442.078 C 339.025,438.713 346.918,431.468 349.164,426.539 C 349.800,425.143 350.636,424 351.022,424 C 352.590,424 369,432.158 369,432.938 C 369,434.517 360.340,445.489 355.851,449.598 C 350.204,454.767 343.577,458.665 335.120,461.788 C 325.969,465.168 308.541,465.988 297.603,463.555 C 267.364,456.827 248,431.474 248,398.608 C 248,366.704 267.142,340.922 296,333.958 C 303.636,332.115 320.091,332.296 327.725,334.306 C 350.643,340.342 365.780,357.394 370.503,382.500 ZM 272.456,378.727 C 271.175,382.394 270.349,385.757 270.622,386.198 C 270.895,386.639 288.866,387 310.559,387 C 343.627,387 350,386.774 350,385.605 C 350,384.838 349.111,381.332 348.024,377.813 C 344.295,365.739 337.509,358.326 326.048,353.804 C 321.697,352.087 318.343,351.604 310.500,351.563 C 301.680,351.517 299.823,351.827 294.765,354.193 C 283.347,359.534 276.552,367.006 272.456,378.727 Z", "M 660.250,429.675 C 661.292,430.291 661.220,430.668 659.367,434.300 C 656.179,440.550 647.510,450.122 641.029,454.550 C 631.093,461.339 621.848,464.224 608.217,464.788 C 587.580,465.642 573.088,460.230 559.429,446.571 C 550.521,437.663 545.570,429.081 542.352,416.968 C 540.042,408.273 540.027,389.837 542.322,381 C 548.423,357.512 565.289,340.301 588,334.388 C 596.625,332.143 613.350,332.135 621.928,334.373 C 631.105,336.767 640.468,341.661 646.611,347.275 C 652.865,352.991 660.217,363.569 659.796,366.247 C 659.594,367.534 656.997,369.216 651.583,371.565 C 647.229,373.454 643.178,375 642.581,375 C 641.984,375 640.422,372.975 639.109,370.499 C 634.163,361.177 623.375,354.023 610.963,351.837 C 594.304,348.903 576.137,357.886 568.051,373.056 C 563.539,381.521 562.026,387.907 562.012,398.540 C 561.991,414.722 566.382,425.510 576.990,435.331 C 584.699,442.468 591.621,445.227 603.201,445.780 C 618.135,446.493 630.041,440.788 638.282,428.971 C 640.380,425.962 642.530,423.348 643.061,423.162 C 643.849,422.886 657.542,428.075 660.250,429.675 Z"];
@@ -0,0 +1,9 @@
1
+ export { buildBookletPersonEntry, bookletSexFromPerson, collectBookletPersons, personDisplayName, sortBookletEntries, type BookletCollectOptions, type BookletPersonEntry, type BookletRelationRef, type BookletScope, type BookletSex, type BookletUnionEntry, } from './booklet-person';
2
+ export { personGenderWords, pluralS, pluralPick } from './booklet-gender';
3
+ export { buildChapterIntroNarrative, buildFamilyNarrative, buildPersonDetailedNarratives, buildPersonSummaryNarrative, } from './booklet-narrative';
4
+ export { buildGenerationTimeline, chapterSupportsTimeline, timelineRowCount, type BookletTimelineStyle, type GenerationTimelineLayout, } from './booklet-timeline';
5
+ export { bookletSizeAdvice, estimateBookletSize, estimateTimelineSliceCount } from './booklet-estimate';
6
+ export { rasterizeGenerationTimelinePng } from './booklet-timeline-canvas';
7
+ export { BOOKLET_BRAND_RGB, defaultCoverLogoOptions, drawGedcomTsLogoOnPage, GEDCOM_TS_LOGO_PATHS, GEDCOM_TS_LOGO_VIEWBOX, type DrawGedcomTsLogoOptions, type GedcomTsLogoLayout, } from './booklet-logo';
8
+ export { groupBookletIntoChapters, partnerNamesLabel, type BookletChapter, type BookletDetailLevel, type BookletFamilyUnit, type BookletTocEntry, } from './booklet-structure';
9
+ export { downloadBookletPdf, generateGenealogyBookletPdf, toPdfText, type BookletPdfMeta, type BookletPdfOptions, } from './booklet-pdf';