@sinequa/atomic-angular 1.17.0 → 2.0.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.
Files changed (77) hide show
  1. package/README.md +23 -18
  2. package/components/navbar-tabs/i18n/de.json +4 -2
  3. package/components/navbar-tabs/i18n/en.json +4 -2
  4. package/components/navbar-tabs/i18n/fr.json +5 -3
  5. package/components/preview/i18n/de.json +12 -0
  6. package/components/preview/i18n/en.json +12 -0
  7. package/components/preview/i18n/fr.json +12 -0
  8. package/components/sort-selector/i18n/de.json +1 -0
  9. package/components/sort-selector/i18n/en.json +1 -0
  10. package/components/sort-selector/i18n/fr.json +1 -0
  11. package/components/sponsored-results/i18n/de.json +3 -0
  12. package/components/sponsored-results/i18n/en.json +3 -0
  13. package/components/sponsored-results/i18n/fr.json +3 -0
  14. package/document-workspaces/i18n/de.json +2 -0
  15. package/document-workspaces/i18n/en.json +2 -0
  16. package/document-workspaces/i18n/fr.json +2 -0
  17. package/document-workspaces/i18n/ja.json +2 -0
  18. package/features/{drawer → advanced-search}/i18n/de.json +12 -1
  19. package/features/{drawer → advanced-search}/i18n/en.json +12 -1
  20. package/features/{drawer → advanced-search}/i18n/fr.json +13 -2
  21. package/features/alerts/i18n/de.json +7 -1
  22. package/features/alerts/i18n/en.json +7 -1
  23. package/features/alerts/i18n/fr.json +7 -1
  24. package/features/auth/i18n/de.json +6 -0
  25. package/features/auth/i18n/en.json +6 -0
  26. package/features/auth/i18n/fr.json +6 -1
  27. package/features/collections/i18n/de.json +4 -1
  28. package/features/collections/i18n/en.json +4 -1
  29. package/features/collections/i18n/fr.json +4 -1
  30. package/features/dialogs/i18n/de.json +11 -1
  31. package/features/dialogs/i18n/en.json +11 -1
  32. package/features/dialogs/i18n/fr.json +11 -1
  33. package/features/export/i18n/de.json +5 -1
  34. package/features/export/i18n/en.json +5 -1
  35. package/features/export/i18n/fr.json +5 -1
  36. package/features/feedback/i18n/de.json +2 -1
  37. package/features/feedback/i18n/en.json +2 -1
  38. package/features/feedback/i18n/fr.json +2 -1
  39. package/features/filters/i18n/de.json +10 -3
  40. package/features/filters/i18n/en.json +10 -3
  41. package/features/filters/i18n/fr.json +11 -4
  42. package/features/labels/i18n/de.json +5 -1
  43. package/features/labels/i18n/en.json +5 -1
  44. package/features/labels/i18n/fr.json +5 -1
  45. package/features/list-panel/i18n/de.json +4 -0
  46. package/features/list-panel/i18n/en.json +4 -0
  47. package/features/list-panel/i18n/fr.json +4 -0
  48. package/features/searches/i18n/de.json +2 -1
  49. package/features/searches/i18n/en.json +2 -1
  50. package/features/searches/i18n/fr.json +3 -2
  51. package/features/sheet/i18n/de.json +3 -0
  52. package/features/sheet/i18n/en.json +3 -0
  53. package/features/sheet/i18n/fr.json +3 -0
  54. package/features/user-profile/i18n/de.json +22 -1
  55. package/features/user-profile/i18n/en.json +22 -1
  56. package/features/user-profile/i18n/fr.json +22 -1
  57. package/fesm2022/sinequa-atomic-angular-charts-heatmap.mjs +294 -0
  58. package/fesm2022/sinequa-atomic-angular-charts-heatmap.mjs.map +1 -0
  59. package/fesm2022/sinequa-atomic-angular-charts.mjs +969 -0
  60. package/fesm2022/sinequa-atomic-angular-charts.mjs.map +1 -0
  61. package/fesm2022/sinequa-atomic-angular-document-workspaces.mjs +11197 -7899
  62. package/fesm2022/sinequa-atomic-angular-document-workspaces.mjs.map +1 -1
  63. package/fesm2022/sinequa-atomic-angular-workspace-elements.mjs +85 -152
  64. package/fesm2022/sinequa-atomic-angular-workspace-elements.mjs.map +1 -1
  65. package/fesm2022/sinequa-atomic-angular.mjs +30683 -17302
  66. package/fesm2022/sinequa-atomic-angular.mjs.map +1 -1
  67. package/package.json +60 -19
  68. package/styles/calendar.css +88 -0
  69. package/types/sinequa-atomic-angular-charts-heatmap.d.ts +154 -0
  70. package/types/sinequa-atomic-angular-charts.d.ts +462 -0
  71. package/types/sinequa-atomic-angular-document-workspaces.d.ts +2527 -0
  72. package/types/sinequa-atomic-angular-workspace-elements.d.ts +49 -0
  73. package/types/sinequa-atomic-angular.d.ts +19918 -0
  74. package/workspace-elements/styles/lexiq-workspaces.css +7310 -4010
  75. package/document-workspaces/index.d.ts +0 -2159
  76. package/index.d.ts +0 -16119
  77. package/workspace-elements/index.d.ts +0 -37
@@ -8,20 +8,27 @@
8
8
  "clearBasket": "Auswahlkorb leeren",
9
9
  "dateFilter": "Datumsfilter",
10
10
  "moreFilters": "Weitere Filter",
11
+ "asideFilters": "Seitliche Filter",
11
12
  "noFiltersAvailable": "Keine Filter verfügbar",
12
- "noFilterMatch": "Kein Filter entspricht Ihrer Suche",
13
- "searchFilters": "Filter nach Namen durchsuchen",
14
13
  "openFilter": "Öffne{filter, select, other { {filter} } undefined { Filter } }",
15
14
  "selectionInvalid": "Auswahl ungültig",
16
15
  "customRangeInvalid": "Benutzerdefinierter Bereich ungültig",
17
16
  "filterInvalid": "Filter ungültig",
18
17
  "aggregationNotFound": "Aggregation nicht gefunden",
19
18
  "filter": "Filter",
19
+ "filterControls": "Filtersteuerung",
20
+ "filterList": "Filter",
20
21
  "addFilter": "Filter hinzufügen",
21
22
  "removeFilter": "Filter entfernen",
22
23
  "selectDateRange": "Wählen Sie einen Zeitraum aus",
23
24
  "customRange": "Benutzerdefinierter Bereich",
24
25
  "validate": "Bestätigen",
25
26
  "from": "Von",
26
- "to": "Bis"
27
+ "to": "Bis",
28
+ "searchInFacet": "In {facet} suchen",
29
+ "toggle": "Diesen Filter ein- oder ausblenden",
30
+ "searchFilters": "Filter nach Namen durchsuchen",
31
+ "noFilterMatch": "Kein Filter entspricht Ihrer Suche",
32
+ "close": "Schließen",
33
+ "clearSearch": "Suche löschen"
27
34
  }
@@ -8,20 +8,27 @@
8
8
  "clearBasket": "Clear basket selection",
9
9
  "dateFilter": "Date filter",
10
10
  "moreFilters": "More filters",
11
+ "asideFilters": "Side filters",
11
12
  "noFiltersAvailable": "No filters available",
12
- "noFilterMatch": "No filter matches your search",
13
- "searchFilters": "Search filters by name",
14
13
  "openFilter": "Open{filter, select, other { {filter} } undefined { filter } }",
15
14
  "selectionInvalid": "Selection invalid",
16
15
  "customRangeInvalid": "Custom range invalid",
17
16
  "filterInvalid": "Filter invalid",
18
17
  "aggregationNotFound": "Aggregation not found",
19
18
  "filter": "Filter",
19
+ "filterControls": "Filter controls",
20
+ "filterList": "Filters",
20
21
  "addFilter": "Add filter",
21
22
  "removeFilter": "Remove filter",
22
23
  "selectDateRange": "Select a range",
23
24
  "customRange": "Custom Range",
24
25
  "validate": "Validate",
25
26
  "from": "From",
26
- "to": "To"
27
+ "to": "To",
28
+ "searchInFacet": "Search in {facet}",
29
+ "toggle": "Show or hide this filter",
30
+ "searchFilters": "Search filters by name",
31
+ "noFilterMatch": "No filter matches your search",
32
+ "close": "Close",
33
+ "clearSearch": "Clear search"
27
34
  }
@@ -1,27 +1,34 @@
1
1
  {
2
2
  "applyFilters": "Appliquer les filtres",
3
3
  "apply": "Appliquer",
4
- "clearAllFilters": "Effacer tout les filtres",
4
+ "clearAllFilters": "Effacer tous les filtres",
5
5
  "clearFilters": "Effacer les filtres",
6
6
  "selectAllFilters": "Sélectionner tous les filtres",
7
7
  "unselectAllFilters": "Désélectionner tous les filtres",
8
8
  "clearBasket": "Effacer la sélection du panier",
9
9
  "dateFilter": "Filtre de date",
10
10
  "moreFilters": "Plus de filtres",
11
+ "asideFilters": "Filtres latéraux",
11
12
  "noFiltersAvailable": "Aucun filtre disponible",
12
- "noFilterMatch": "Aucun filtre ne correspond à votre recherche",
13
- "searchFilters": "Rechercher un filtre par son nom",
14
13
  "openFilter": "Ouvrir{filter, select, other { {filter} } undefined { filter } }",
15
14
  "selectionInvalid": "Sélection invalide",
16
15
  "customRangeInvalid": "Plage personnalisée invalide",
17
16
  "filterInvalid": "Filtre invalide",
18
17
  "aggregationNotFound": "Aggregation non trouvée",
19
18
  "filter": "Filtrer",
19
+ "filterControls": "Commandes de filtrage",
20
+ "filterList": "Filtres",
20
21
  "addFilter": "Ajouter le filtre",
21
22
  "removeFilter": "Retirer le filtre",
22
23
  "selectDateRange": "Choisir une plage",
23
24
  "customRange": "Plage personnalisée",
24
25
  "validate": "Valider",
25
26
  "from": "Début",
26
- "to": "Fin"
27
+ "to": "Fin",
28
+ "searchInFacet": "Rechercher dans {facet}",
29
+ "toggle": "Afficher ou masquer ce filtre",
30
+ "searchFilters": "Rechercher un filtre par son nom",
31
+ "noFilterMatch": "Aucun filtre ne correspond à votre recherche",
32
+ "close": "Fermer",
33
+ "clearSearch": "Effacer la recherche"
27
34
  }
@@ -5,5 +5,9 @@
5
5
  "publicLabels": "Öffentliche Labels",
6
6
  "privateLabels": "Private Labels",
7
7
  "close": "Schließen",
8
- "error": "Es ist ein Fehler aufgetreten. Bitte stellen Sie sicher, dass der Webdienst für Etiketten korrekt konfiguriert ist, und versuchen Sie es erneut."
8
+ "noResults": "Keine passenden Labels",
9
+ "error": "Es ist ein Fehler aufgetreten. Bitte stellen Sie sicher, dass der Webdienst für Etiketten korrekt konfiguriert ist, und versuchen Sie es erneut.",
10
+ "searching": "Suche läuft…",
11
+ "searchFailed": "Die Suche ist fehlgeschlagen",
12
+ "removeLabel": "{label} entfernen"
9
13
  }
@@ -5,5 +5,9 @@
5
5
  "publicLabels": "Public labels",
6
6
  "privateLabels": "Private labels",
7
7
  "close": "Close",
8
- "error": "An error happened. Please make sure the labels web service is correctly configured and try again."
8
+ "noResults": "No matching labels",
9
+ "error": "An error happened. Please make sure the labels web service is correctly configured and try again.",
10
+ "searching": "Searching…",
11
+ "searchFailed": "Search failed",
12
+ "removeLabel": "Remove {label}"
9
13
  }
@@ -5,5 +5,9 @@
5
5
  "publicLabels": "Labels publics",
6
6
  "privateLabels": "Labels privés",
7
7
  "close": "Fermer",
8
- "error": "Une erreur est survenue. Veuillez s'il vous plaît vous assurer que le web service des labels est bien configuré et réessayez."
8
+ "noResults": "Aucun label correspondant",
9
+ "error": "Une erreur est survenue. Veuillez s'il vous plaît vous assurer que le web service des labels est bien configuré et réessayez.",
10
+ "searching": "Recherche en cours…",
11
+ "searchFailed": "La recherche a échoué",
12
+ "removeLabel": "Retirer {label}"
9
13
  }
@@ -0,0 +1,4 @@
1
+ {
2
+ "loadMore": "Mehr laden",
3
+ "seeMore": "Alle anzeigen"
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "loadMore": "Load more",
3
+ "seeMore": "See all"
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "loadMore": "Charger plus",
3
+ "seeMore": "Voir plus"
4
+ }
@@ -20,5 +20,6 @@
20
20
  "selection": {
21
21
  "selectAll": "Aktuelle Ergebnisse auswählen",
22
22
  "unselectAll": "Aktuelle Ergebnisse abwählen"
23
- }
23
+ },
24
+ "close": "Schließen"
24
25
  }
@@ -20,5 +20,6 @@
20
20
  "selection": {
21
21
  "selectAll": "Select current results",
22
22
  "unselectAll": "Unselect current results"
23
- }
23
+ },
24
+ "close": "Close"
24
25
  }
@@ -9,7 +9,7 @@
9
9
  "saved": "Recherche sauvegardée",
10
10
  "saveName": "Nom de la sauvegarde",
11
11
  "saveYourSearch": "Sauvegardez votre recherche",
12
- "deleted": "Recherche enregistree supprimée"
12
+ "deleted": "Recherche enregistrée supprimée"
13
13
  },
14
14
  "recent": {
15
15
  "label": "Recherches récentes",
@@ -20,5 +20,6 @@
20
20
  "selection": {
21
21
  "selectAll": "Sélectionner les résultats actuels",
22
22
  "unselectAll": "Désélectionner les résultats actuels"
23
- }
23
+ },
24
+ "close": "Fermer"
24
25
  }
@@ -0,0 +1,3 @@
1
+ {
2
+ "back": "Zurück"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "back": "Back"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "back": "Retour"
3
+ }
@@ -1,8 +1,28 @@
1
1
  {
2
2
  "title": "Benutzerprofil",
3
3
  "notDefined": "Nicht definiert",
4
+ "language": "Sprache",
5
+ "profileFields": "Profilfelder",
6
+ "changePhoto": "Profilfoto ändern",
7
+ "loading": "Ihr Profil wird geladen…",
8
+ "loadError": "Bitte wenden Sie sich an einen Administrator, um Ihr Benutzerprofil zu erstellen.",
4
9
  "deleteProperty": "Eigenschaft löschen",
5
10
  "editProperty": "Eigenschaft bearbeiten",
11
+ "saveProperty": "Eigenschaft speichern",
12
+ "cancelEdit": "Bearbeitung abbrechen",
13
+ "deletePropertyNamed": "{{property}} löschen",
14
+ "editPropertyNamed": "{{property}} bearbeiten",
15
+ "savePropertyNamed": "{{property}} speichern",
16
+ "cancelEditNamed": "Bearbeitung von {{property}} abbrechen",
17
+ "status": {
18
+ "editing": "{{property}} wird bearbeitet. Zum Abbrechen Esc drücken.",
19
+ "saved": "{{property}} gespeichert.",
20
+ "editCancelled": "Bearbeitung von {{property}} abgebrochen.",
21
+ "deleted": "{{property}} gelöscht."
22
+ },
23
+ "errors": {
24
+ "required": "Dieses Feld ist erforderlich."
25
+ },
6
26
  "data": {
7
27
  "mail": "E-Mail",
8
28
  "fullName": "Vollständiger Name",
@@ -12,5 +32,6 @@
12
32
  "location": "Standort",
13
33
  "profilePhoto": "Profilfoto",
14
34
  "skills": "Fähigkeiten"
15
- }
35
+ },
36
+ "close": "Schließen"
16
37
  }
@@ -1,8 +1,28 @@
1
1
  {
2
2
  "title": "User Profile",
3
3
  "notDefined": "Not defined",
4
+ "language": "Language",
5
+ "profileFields": "Profile fields",
6
+ "changePhoto": "Change profile photo",
7
+ "loading": "Loading your profile…",
8
+ "loadError": "Please contact an administrator to create your user profile.",
4
9
  "deleteProperty": "Delete property",
5
10
  "editProperty": "Edit property",
11
+ "saveProperty": "Save property",
12
+ "cancelEdit": "Cancel editing",
13
+ "deletePropertyNamed": "Delete {{property}}",
14
+ "editPropertyNamed": "Edit {{property}}",
15
+ "savePropertyNamed": "Save {{property}}",
16
+ "cancelEditNamed": "Cancel editing {{property}}",
17
+ "status": {
18
+ "editing": "Editing {{property}}. Press Escape to cancel.",
19
+ "saved": "{{property}} saved.",
20
+ "editCancelled": "Editing {{property}} cancelled.",
21
+ "deleted": "{{property}} deleted."
22
+ },
23
+ "errors": {
24
+ "required": "This field is required."
25
+ },
6
26
  "data": {
7
27
  "mail": "Mail",
8
28
  "fullName": "Full name",
@@ -12,5 +32,6 @@
12
32
  "location": "Location",
13
33
  "profilePhoto": "Profile photo",
14
34
  "skills": "Skills"
15
- }
35
+ },
36
+ "close": "Close"
16
37
  }
@@ -1,8 +1,28 @@
1
1
  {
2
2
  "title": "Profil Utilisateur",
3
3
  "notDefined": "Non défini",
4
+ "language": "Langue",
5
+ "profileFields": "Champs du profil",
6
+ "changePhoto": "Changer la photo de profil",
7
+ "loading": "Chargement de votre profil…",
8
+ "loadError": "Veuillez contacter un administrateur pour créer votre profil utilisateur.",
4
9
  "deleteProperty": "Supprimer le champ",
5
10
  "editProperty": "Modifier le champ",
11
+ "saveProperty": "Enregistrer le champ",
12
+ "cancelEdit": "Annuler la modification",
13
+ "deletePropertyNamed": "Supprimer {{property}}",
14
+ "editPropertyNamed": "Modifier {{property}}",
15
+ "savePropertyNamed": "Enregistrer {{property}}",
16
+ "cancelEditNamed": "Annuler la modification de {{property}}",
17
+ "status": {
18
+ "editing": "Modification de {{property}}. Appuyez sur Échap pour annuler.",
19
+ "saved": "{{property}} enregistré.",
20
+ "editCancelled": "Modification de {{property}} annulée.",
21
+ "deleted": "{{property}} supprimé."
22
+ },
23
+ "errors": {
24
+ "required": "Ce champ est obligatoire."
25
+ },
6
26
  "data": {
7
27
  "mail": "E-mail",
8
28
  "fullName": "Nom complet",
@@ -12,5 +32,6 @@
12
32
  "location": "Lieu",
13
33
  "profilePhoto": "Photo de profil",
14
34
  "skills": "Compétences"
15
- }
35
+ },
36
+ "close": "Fermer"
16
37
  }
@@ -0,0 +1,294 @@
1
+ import { Chart } from "chart.js";
2
+ import { MatrixController, MatrixElement } from "chartjs-chart-matrix";
3
+ import * as i0 from "@angular/core";
4
+ import { Component, afterNextRender, computed, input, output, signal } from "@angular/core";
5
+ import { cn } from "cn";
6
+ import { buildHeatmap, galactikPrimitive, quantileScale, withAlpha } from "@sinequa/atomic-angular";
7
+ import { ChartCanvasComponent, createAxisClickPlugin } from "@sinequa/atomic-angular/charts";
8
+ let registered = false;
9
+ function setupMatrixChart() {
10
+ if (registered) return;
11
+ Chart.register(MatrixController, MatrixElement);
12
+ registered = true;
13
+ }
14
+ var AggregationHeatmapComponent = class AggregationHeatmapComponent {
15
+ cn = cn;
16
+ class = input("", ...ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []);
17
+ aggregation = input(void 0, ...ngDevMode ? [{ debugName: "aggregation" }] : /* istanbul ignore next */ []);
18
+ encoding = input({
19
+ kind: "separator",
20
+ separator: "$@$"
21
+ }, ...ngDevMode ? [{ debugName: "encoding" }] : /* istanbul ignore next */ []);
22
+ maxX = input(20, ...ngDevMode ? [{ debugName: "maxX" }] : /* istanbul ignore next */ []);
23
+ maxY = input(20, ...ngDevMode ? [{ debugName: "maxY" }] : /* istanbul ignore next */ []);
24
+ emptyLabel = input("No data", ...ngDevMode ? [{ debugName: "emptyLabel" }] : /* istanbul ignore next */ []);
25
+ enableAxisSelection = input(true, ...ngDevMode ? [{ debugName: "enableAxisSelection" }] : /* istanbul ignore next */ []);
26
+ cellSelected = output();
27
+ axisSelected = output();
28
+ axisClick = createAxisClickPlugin((hit) => this.selectAxis(hit.axis, hit.label));
29
+ rampColor = signal(galactikPrimitive("blue-500"), ...ngDevMode ? [{ debugName: "rampColor" }] : /* istanbul ignore next */ []);
30
+ constructor() {
31
+ setupMatrixChart();
32
+ afterNextRender(() => this.rampColor.set(galactikPrimitive("blue-500")));
33
+ }
34
+ plugins = computed(() => this.enableAxisSelection() ? [this.axisClick] : [], ...ngDevMode ? [{ debugName: "plugins" }] : /* istanbul ignore next */ []);
35
+ heatmap = computed(() => buildHeatmap(this.aggregation(), {
36
+ encoding: this.encoding(),
37
+ maxX: this.maxX(),
38
+ maxY: this.maxY()
39
+ }), ...ngDevMode ? [{ debugName: "heatmap" }] : /* istanbul ignore next */ []);
40
+ isEmpty = computed(() => this.heatmap().cells.length === 0, ...ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []);
41
+ selectAxis(axis, label) {
42
+ const heatmap = this.heatmap();
43
+ const value = (axis === "x" ? heatmap.xValues : heatmap.yValues).get(label) ?? label;
44
+ this.axisSelected.emit({
45
+ axis,
46
+ label,
47
+ value
48
+ });
49
+ }
50
+ config = computed(() => {
51
+ const { cells, xLabels, yLabels } = this.heatmap();
52
+ const intensity = quantileScale(cells.map((cell) => cell.v));
53
+ const ramp = this.rampColor();
54
+ return {
55
+ type: "matrix",
56
+ data: { datasets: [{
57
+ data: cells.map((cell) => ({
58
+ x: cell.x,
59
+ y: cell.y,
60
+ v: cell.v
61
+ })),
62
+ backgroundColor: (ctx) => {
63
+ const point = ctx.raw;
64
+ return withAlpha(ramp, .12 + .88 * intensity(point?.v ?? 0));
65
+ },
66
+ borderColor: withAlpha(galactikPrimitive("grey-500"), .25),
67
+ borderWidth: 1,
68
+ width: (ctx) => (ctx.chart.chartArea?.width ?? 0) / Math.max(1, xLabels.length) - 2,
69
+ height: (ctx) => (ctx.chart.chartArea?.height ?? 0) / Math.max(1, yLabels.length) - 2
70
+ }] },
71
+ options: {
72
+ scales: {
73
+ x: {
74
+ type: "category",
75
+ labels: xLabels,
76
+ offset: true,
77
+ grid: { display: false },
78
+ ticks: { autoSkip: false }
79
+ },
80
+ y: {
81
+ type: "category",
82
+ labels: yLabels,
83
+ offset: true,
84
+ grid: { display: false },
85
+ ticks: { autoSkip: false }
86
+ }
87
+ },
88
+ plugins: {
89
+ legend: { display: false },
90
+ tooltip: { callbacks: {
91
+ title: () => "",
92
+ label: (ctx) => {
93
+ const point = ctx.raw;
94
+ return `${String(point?.x ?? "")} / ${String(point?.y ?? "")}: ${point?.v ?? 0}`;
95
+ }
96
+ } }
97
+ },
98
+ onClick: (_event, elements) => {
99
+ const first = elements[0];
100
+ if (!first) return;
101
+ const cell = cells[first.index];
102
+ if (cell) this.cellSelected.emit({
103
+ x: cell.x,
104
+ y: cell.y,
105
+ xValue: cell.xValue,
106
+ yValue: cell.yValue,
107
+ count: cell.v
108
+ });
109
+ }
110
+ }
111
+ };
112
+ }, ...ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []);
113
+ static ɵfac = i0.ɵɵngDeclareFactory({
114
+ minVersion: "12.0.0",
115
+ version: "22.2.1",
116
+ ngImport: i0,
117
+ type: AggregationHeatmapComponent,
118
+ deps: [],
119
+ target: i0.ɵɵFactoryTarget.Component
120
+ });
121
+ static ɵcmp = i0.ɵɵngDeclareComponent({
122
+ minVersion: "17.0.0",
123
+ version: "22.2.1",
124
+ type: AggregationHeatmapComponent,
125
+ isStandalone: true,
126
+ selector: "AggregationHeatmap, aggregation-heatmap, aggregationheatmap",
127
+ inputs: {
128
+ class: {
129
+ classPropertyName: "class",
130
+ publicName: "class",
131
+ isSignal: true,
132
+ isRequired: false,
133
+ transformFunction: null
134
+ },
135
+ aggregation: {
136
+ classPropertyName: "aggregation",
137
+ publicName: "aggregation",
138
+ isSignal: true,
139
+ isRequired: false,
140
+ transformFunction: null
141
+ },
142
+ encoding: {
143
+ classPropertyName: "encoding",
144
+ publicName: "encoding",
145
+ isSignal: true,
146
+ isRequired: false,
147
+ transformFunction: null
148
+ },
149
+ maxX: {
150
+ classPropertyName: "maxX",
151
+ publicName: "maxX",
152
+ isSignal: true,
153
+ isRequired: false,
154
+ transformFunction: null
155
+ },
156
+ maxY: {
157
+ classPropertyName: "maxY",
158
+ publicName: "maxY",
159
+ isSignal: true,
160
+ isRequired: false,
161
+ transformFunction: null
162
+ },
163
+ emptyLabel: {
164
+ classPropertyName: "emptyLabel",
165
+ publicName: "emptyLabel",
166
+ isSignal: true,
167
+ isRequired: false,
168
+ transformFunction: null
169
+ },
170
+ enableAxisSelection: {
171
+ classPropertyName: "enableAxisSelection",
172
+ publicName: "enableAxisSelection",
173
+ isSignal: true,
174
+ isRequired: false,
175
+ transformFunction: null
176
+ }
177
+ },
178
+ outputs: {
179
+ cellSelected: "cellSelected",
180
+ axisSelected: "axisSelected"
181
+ },
182
+ host: { properties: { "class": "cn(\"block h-full w-full\", class())" } },
183
+ ngImport: i0,
184
+ template: `
185
+ @if (isEmpty()) {
186
+ <p class="flex h-full items-center justify-center text-sm text-(--font-neutral-muted)">{{ emptyLabel() }}</p>
187
+ } @else {
188
+ <ChartCanvas [config]="config()" [plugins]="plugins()" />
189
+ }
190
+ `,
191
+ isInline: true,
192
+ dependencies: [{
193
+ kind: "component",
194
+ type: ChartCanvasComponent,
195
+ selector: "ChartCanvas, chart-canvas, chartcanvas",
196
+ inputs: [
197
+ "class",
198
+ "config",
199
+ "plugins"
200
+ ]
201
+ }]
202
+ });
203
+ };
204
+ i0.ɵɵngDeclareClassMetadata({
205
+ minVersion: "12.0.0",
206
+ version: "22.2.1",
207
+ ngImport: i0,
208
+ type: AggregationHeatmapComponent,
209
+ decorators: [{
210
+ type: Component,
211
+ args: [{
212
+ selector: "AggregationHeatmap, aggregation-heatmap, aggregationheatmap",
213
+ imports: [ChartCanvasComponent],
214
+ template: `
215
+ @if (isEmpty()) {
216
+ <p class="flex h-full items-center justify-center text-sm text-(--font-neutral-muted)">{{ emptyLabel() }}</p>
217
+ } @else {
218
+ <ChartCanvas [config]="config()" [plugins]="plugins()" />
219
+ }
220
+ `,
221
+ host: { "[class]": "cn(\"block h-full w-full\", class())" }
222
+ }]
223
+ }],
224
+ ctorParameters: () => [],
225
+ propDecorators: {
226
+ class: [{
227
+ type: i0.Input,
228
+ args: [{
229
+ isSignal: true,
230
+ alias: "class",
231
+ required: false
232
+ }]
233
+ }],
234
+ aggregation: [{
235
+ type: i0.Input,
236
+ args: [{
237
+ isSignal: true,
238
+ alias: "aggregation",
239
+ required: false
240
+ }]
241
+ }],
242
+ encoding: [{
243
+ type: i0.Input,
244
+ args: [{
245
+ isSignal: true,
246
+ alias: "encoding",
247
+ required: false
248
+ }]
249
+ }],
250
+ maxX: [{
251
+ type: i0.Input,
252
+ args: [{
253
+ isSignal: true,
254
+ alias: "maxX",
255
+ required: false
256
+ }]
257
+ }],
258
+ maxY: [{
259
+ type: i0.Input,
260
+ args: [{
261
+ isSignal: true,
262
+ alias: "maxY",
263
+ required: false
264
+ }]
265
+ }],
266
+ emptyLabel: [{
267
+ type: i0.Input,
268
+ args: [{
269
+ isSignal: true,
270
+ alias: "emptyLabel",
271
+ required: false
272
+ }]
273
+ }],
274
+ enableAxisSelection: [{
275
+ type: i0.Input,
276
+ args: [{
277
+ isSignal: true,
278
+ alias: "enableAxisSelection",
279
+ required: false
280
+ }]
281
+ }],
282
+ cellSelected: [{
283
+ type: i0.Output,
284
+ args: ["cellSelected"]
285
+ }],
286
+ axisSelected: [{
287
+ type: i0.Output,
288
+ args: ["axisSelected"]
289
+ }]
290
+ }
291
+ });
292
+ export { AggregationHeatmapComponent, setupMatrixChart };
293
+
294
+ //# sourceMappingURL=sinequa-atomic-angular-charts-heatmap.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sinequa-atomic-angular-charts-heatmap.mjs","names":[],"sources":["../../../projects/atomic-angular/charts/heatmap/matrix-setup.ts","../../../projects/atomic-angular/charts/heatmap/aggregation-heatmap.ts"],"sourcesContent":["import { Chart } from \"chart.js\";\nimport { MatrixController, MatrixElement } from \"chartjs-chart-matrix\";\n\nlet registered = false;\n\n/**\n * Registers the `matrix` controller and element that `<AggregationHeatmap>` draws with.\n *\n * Chart.js has no matrix controller of its own; `chartjs-chart-matrix` adds one. Idempotent on\n * purpose: it is called from the constructor of every `<AggregationHeatmap>`, so it must be safe to\n * call many times. Registering from the component rather than from application bootstrap is what\n * keeps the entry point self-contained — an application that never imports\n * `@sinequa/atomic-angular/charts/heatmap` never runs this, and never needs `chartjs-chart-matrix`\n * installed.\n *\n * This import must stay a VALUE import. A `import type` would be elided at compile time, and with\n * it the `declare module \"chart.js\"` augmentation the package ships — `\"matrix\"` would stop being a\n * known chart type and the configuration below would no longer type-check.\n */\nexport function setupMatrixChart(): void {\n if (registered) return;\n Chart.register(MatrixController, MatrixElement);\n registered = true;\n}\n","import { afterNextRender, Component, computed, input, output, signal, type Signal } from \"@angular/core\";\nimport type { ChartConfiguration, Plugin, ScriptableContext } from \"chart.js\";\nimport type { MatrixDataPoint } from \"chartjs-chart-matrix\";\n\nimport { cn } from \"cn\";\n\nimport {\n buildHeatmap,\n galactikPrimitive,\n quantileScale,\n withAlpha,\n type AggregationLike,\n type HeatmapAxisSelection,\n type HeatmapCell,\n type HeatmapCellSelection,\n type HeatmapEncoding\n} from \"@sinequa/atomic-angular\";\nimport { ChartCanvasComponent, createAxisClickPlugin } from \"@sinequa/atomic-angular/charts\";\n\nimport { setupMatrixChart } from \"./matrix-setup\";\n\n/**\n * A two-dimensional distribution rendered as a canvas heatmap, on Chart.js.\n *\n * **`<Heatmap>` from the main entry point is the one to reach for first.** It renders a CSS grid,\n * needs no dependency at all, is accessible and selectable, and its axis labels are real buttons.\n * This component exists for the case that one cannot serve: a matrix large enough that hundreds of\n * DOM nodes become the bottleneck. Canvas rendering is flat in the cell count; a DOM grid is not.\n *\n * What it costs, and what it does not:\n *\n * - **it costs a dependency** — `chartjs-chart-matrix`, which is why this is its own entry point.\n * See the note in `public-api.ts`;\n * - **it costs accessibility** — a canvas is opaque to screen readers and to text selection, and\n * nothing brings that back. Weigh this before choosing it over `<Heatmap>`;\n * - **it does NOT cost the axis click.** Clicking a label to filter a whole row or column works\n * here too, through `createAxisClickPlugin()`. SBA v2's canvas heatmap had to hit-test painted\n * pixels for this and this component does the same, but the hit test is written once, in the\n * plugin, and `(axisSelected)` emits the same payload as `<Heatmap>`.\n *\n * The API is deliberately the same as `<Heatmap>`'s, so the two are interchangeable: same inputs,\n * same `(cellSelected)` and `(axisSelected)` payloads. Swapping one for the other is an import\n * change.\n *\n * **The host must have a resolved height** — see `<ChartCanvas>`.\n */\n@Component({\n selector: \"AggregationHeatmap, aggregation-heatmap, aggregationheatmap\",\n imports: [ChartCanvasComponent],\n template: `\n @if (isEmpty()) {\n <p class=\"flex h-full items-center justify-center text-sm text-(--font-neutral-muted)\">{{ emptyLabel() }}</p>\n } @else {\n <ChartCanvas [config]=\"config()\" [plugins]=\"plugins()\" />\n }\n `,\n host: {\n \"[class]\": 'cn(\"block h-full w-full\", class())'\n }\n})\nexport class AggregationHeatmapComponent {\n cn = cn;\n\n /**\n * Extra classes for the host element.\n * @default \"\"\n */\n readonly class = input(\"\");\n\n /**\n * The two-dimensional aggregation to render.\n * @default undefined\n */\n readonly aggregation = input<AggregationLike | undefined>(undefined);\n\n /**\n * How the two dimensions are encoded in `item.value`. Sinequa uses three different encodings\n * depending on how the aggregation was configured; see `heatmap-data.ts`.\n * @default { kind: \"separator\", separator: \"$@$\" }\n */\n readonly encoding = input<HeatmapEncoding>({ kind: \"separator\", separator: \"$@$\" });\n\n /**\n * Maximum number of columns kept, ranked by total weight.\n * @default 20\n */\n readonly maxX = input(20);\n\n /**\n * Maximum number of rows kept, ranked by total weight.\n * @default 20\n */\n readonly maxY = input(20);\n\n /**\n * Text shown when there is nothing to display.\n * @default \"No data\"\n */\n readonly emptyLabel = input(\"No data\");\n\n /**\n * Makes the axis labels clickable. Turn it off when nothing is wired to `(axisSelected)`: on a\n * canvas the pointer cursor is the only affordance a label can offer, and an affordance that\n * filters nothing is worse than none.\n * @default true\n */\n readonly enableAxisSelection = input(true);\n\n /** Emitted when a cell is clicked. */\n readonly cellSelected = output<HeatmapCellSelection>();\n\n /** Emitted when an axis label is clicked — filter a whole row or column. */\n readonly axisSelected = output<HeatmapAxisSelection>();\n\n /**\n * Built ONCE, as a field, never inside a `computed()` — the same rule as the timeline brush. The\n * plugin keeps hover state in its closure, and `<ChartCanvas>` only reads `plugins` when it builds\n * the Chart.js instance; a fresh object on every recompute would be both pointless and stateless.\n */\n private readonly axisClick: Plugin = createAxisClickPlugin(hit => this.selectAxis(hit.axis, hit.label));\n\n /**\n * Base colour of the intensity ramp, resolved once the DOM exists.\n *\n * Read after the first render rather than in a field initialiser: `getComputedStyle` returns\n * nothing useful before styles have applied, and the fallback would silently win. A *primitive*\n * ramp, so the heatmap keeps its identity when the theme flips.\n */\n private readonly rampColor = signal(galactikPrimitive(\"blue-500\"));\n\n constructor() {\n setupMatrixChart();\n afterNextRender(() => this.rampColor.set(galactikPrimitive(\"blue-500\")));\n }\n\n // Annotated rather than inferred, exactly as in `<ChartCanvas>`: the inferred type would have to\n // name chart.js' internal `AnyObject` by path, which is not portable in an emitted .d.ts.\n protected readonly plugins: Signal<Plugin[]> = computed(() => (this.enableAxisSelection() ? [this.axisClick] : []));\n\n private readonly heatmap = computed(() => buildHeatmap(this.aggregation(), { encoding: this.encoding(), maxX: this.maxX(), maxY: this.maxY() }));\n\n protected readonly isEmpty = computed(() => this.heatmap().cells.length === 0);\n\n /**\n * The plugin can only report what is painted — the label. The caller needs the filterable value,\n * which `buildHeatmap()` indexes per axis; they differ under the \"cross\" encoding.\n */\n private selectAxis(axis: \"x\" | \"y\", label: string): void {\n const heatmap = this.heatmap();\n const value = (axis === \"x\" ? heatmap.xValues : heatmap.yValues).get(label) ?? label;\n this.axisSelected.emit({ axis, label, value });\n }\n\n protected readonly config: Signal<ChartConfiguration> = computed(() => {\n const { cells, xLabels, yLabels } = this.heatmap();\n\n // Quantile scale rather than count/max: see the rationale in `heatmap-data.ts`.\n const intensity = quantileScale(cells.map(cell => cell.v));\n const ramp = this.rampColor();\n\n /*\n * Typed as `ChartConfiguration<\"matrix\">`, then cast ONCE on the final expression.\n *\n * Casting the whole literal — which is what most matrix examples do, Sinequa's usage-analytics\n * included — switches off type checking for every scriptable callback inside it, so a wrong\n * `ctx` shape or a misspelled option passes silently. The friction is only at the boundary:\n * `ChartConfiguration` without a type argument is a union over every chart type and TypeScript\n * will not narrow into it. Everything above the cast stays checked.\n */\n const config: ChartConfiguration<\"matrix\"> = {\n type: \"matrix\",\n data: {\n datasets: [\n {\n data: cells.map(cell => ({ x: cell.x, y: cell.y, v: cell.v })),\n backgroundColor: (ctx: ScriptableContext<\"matrix\">) => {\n // `raw` is typed `unknown` under strict mode; narrow it explicitly.\n const point = ctx.raw as MatrixDataPoint | undefined;\n // Floor at 0.12 so the lightest non-empty cell is still visibly a cell.\n return withAlpha(ramp, 0.12 + 0.88 * intensity(point?.v ?? 0));\n },\n borderColor: withAlpha(galactikPrimitive(\"grey-500\"), 0.25),\n borderWidth: 1,\n // Divide the plot area by the number of categories, minus a hairline gap. Both are\n // natively scriptable on a matrix dataset, so no hand-written callback types are needed.\n width: ctx => (ctx.chart.chartArea?.width ?? 0) / Math.max(1, xLabels.length) - 2,\n height: ctx => (ctx.chart.chartArea?.height ?? 0) / Math.max(1, yLabels.length) - 2\n }\n ]\n },\n options: {\n scales: {\n // `offset: true` puts categories BETWEEN gridlines rather than on them, which is what\n // centres each tile under its label. `autoSkip: false` keeps every label: on a heatmap a\n // hidden label makes its whole row unreadable — and, labels being click targets, a\n // skipped one would also be an unreachable filter.\n x: { type: \"category\", labels: xLabels, offset: true, grid: { display: false }, ticks: { autoSkip: false } },\n y: { type: \"category\", labels: yLabels, offset: true, grid: { display: false }, ticks: { autoSkip: false } }\n },\n plugins: {\n legend: { display: false },\n tooltip: {\n callbacks: {\n // The default title would be the raw index; blank it and put everything in the label.\n title: () => \"\",\n label: ctx => {\n const point = ctx.raw as MatrixDataPoint | undefined;\n return `${String(point?.x ?? \"\")} / ${String(point?.y ?? \"\")}: ${point?.v ?? 0}`;\n }\n }\n }\n },\n onClick: (_event, elements) => {\n const first = elements[0];\n if (!first) return;\n const cell: HeatmapCell | undefined = cells[first.index];\n if (cell) this.cellSelected.emit({ x: cell.x, y: cell.y, xValue: cell.xValue, yValue: cell.yValue, count: cell.v });\n }\n }\n };\n\n return config as unknown as ChartConfiguration;\n });\n}\n"],"mappings":"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"}