@micheeeeel/yinyangapp 1.0.5 → 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 (122) hide show
  1. package/README.md +105 -0
  2. package/dist/bundle.js +2 -0
  3. package/dist/bundle.js.LICENSE.txt +1 -0
  4. package/dist/types/adapters/yinYangAdapter.d.ts +10 -0
  5. package/dist/types/animations/AnimationsMngr.d.ts +14 -0
  6. package/dist/types/api-film.d.ts +22 -0
  7. package/dist/types/api.d.ts +48 -0
  8. package/dist/types/benchmark/runner.d.ts +5 -0
  9. package/dist/types/benchmark/scenarios.d.ts +118 -0
  10. package/dist/types/components/action-image/ActionImageModal.d.ts +42 -0
  11. package/dist/types/components/controller/YinYangController.d.ts +987 -0
  12. package/dist/types/components/controller/action-stack/ActionStackController.d.ts +149 -0
  13. package/dist/types/components/controller/action-stack/ActionStackDragHandler.d.ts +111 -0
  14. package/dist/types/components/controller/action-stack/ActionStackManager.d.ts +118 -0
  15. package/dist/types/components/controller/action-stack/ActionStackState.d.ts +169 -0
  16. package/dist/types/components/controller/actions/ActionProjectionService.d.ts +73 -0
  17. package/dist/types/components/controller/actions/ChildActionMenuController.d.ts +83 -0
  18. package/dist/types/components/controller/actions/CoreEventMenuController.d.ts +90 -0
  19. package/dist/types/components/controller/actions/radialItemMenu.d.ts +117 -0
  20. package/dist/types/components/controller/children/ChildInteractionController.d.ts +38 -0
  21. package/dist/types/components/controller/children/ChildrenOrbitService.d.ts +14 -0
  22. package/dist/types/components/controller/force-field/EventFieldLifecycleController.d.ts +104 -0
  23. package/dist/types/components/controller/force-field/EventFieldRenderer.d.ts +86 -0
  24. package/dist/types/components/controller/force-field/ForceFieldComputationService.d.ts +50 -0
  25. package/dist/types/components/controller/force-field/ForceFieldDetailsPanel.d.ts +639 -0
  26. package/dist/types/components/controller/force-field/ForceFieldLifecycleController.d.ts +53 -0
  27. package/dist/types/components/controller/force-field/ForceFieldRenderer.d.ts +67 -0
  28. package/dist/types/components/controller/force-field/types.d.ts +42 -0
  29. package/dist/types/components/controller/labels/ChildScoresDeltaRenderer.d.ts +33 -0
  30. package/dist/types/components/controller/labels/ContextLabelsRenderer.d.ts +155 -0
  31. package/dist/types/components/controller/labels/WeightPreviewRingRenderer.d.ts +61 -0
  32. package/dist/types/components/controller/odd/ChildrenOrbitManager.d.ts +25 -0
  33. package/dist/types/components/controller/odd/OddViewManager.d.ts +44 -0
  34. package/dist/types/components/controller/search/SearchPanelSynchronizer.d.ts +125 -0
  35. package/dist/types/components/controller/settings/ControllerSettingsApplier.d.ts +50 -0
  36. package/dist/types/components/controller/state/BlockingAnimationTracker.d.ts +17 -0
  37. package/dist/types/components/controller/state/YinYangControllerState.d.ts +176 -0
  38. package/dist/types/components/controller/utils/actionStackMath.d.ts +13 -0
  39. package/dist/types/components/controller/utils/actionStackReorder.d.ts +7 -0
  40. package/dist/types/components/controller/utils/childrenOrbit.d.ts +18 -0
  41. package/dist/types/components/controller/utils/cuttingLabels.d.ts +9 -0
  42. package/dist/types/components/controller/utils/eventFieldStyle.d.ts +13 -0
  43. package/dist/types/components/controller/utils/eventFieldTargets.d.ts +47 -0
  44. package/dist/types/components/controller/utils/forceFieldMetadata.d.ts +4 -0
  45. package/dist/types/components/controller/utils/forceFieldPresentation.d.ts +9 -0
  46. package/dist/types/components/controller/utils/forceFieldStyle.d.ts +10 -0
  47. package/dist/types/components/controller/utils/labelGeometry.d.ts +5 -0
  48. package/dist/types/components/controller/utils/oddCutting.d.ts +2 -0
  49. package/dist/types/components/controller/utils/svgCoordinates.d.ts +9 -0
  50. package/dist/types/components/controller/utils/svgTransform.d.ts +5 -0
  51. package/dist/types/components/controller/utils/textLayout.d.ts +2 -0
  52. package/dist/types/components/controls/VizControlsPanel.d.ts +14 -0
  53. package/dist/types/components/factory/YinYangAppFactory.d.ts +60 -0
  54. package/dist/types/components/model/YinYangModel.d.ts +15 -0
  55. package/dist/types/components/panel/DiagramPanelBridge.d.ts +34 -0
  56. package/dist/types/components/panel/PanelManager.d.ts +150 -0
  57. package/dist/types/components/search/GlobalSearchController.d.ts +396 -0
  58. package/dist/types/components/stack-nav/StackNavOverlay.d.ts +82 -0
  59. package/dist/types/components/view/BorderDrawer.d.ts +232 -0
  60. package/dist/types/components/view/SpikeDrawer.d.ts +60 -0
  61. package/dist/types/components/view/ViewInitializer.d.ts +527 -0
  62. package/dist/types/components/view/YinYangDrawer.d.ts +460 -0
  63. package/dist/types/components/view/YinYangView.d.ts +52 -0
  64. package/dist/types/config/animationConfig.d.ts +37 -0
  65. package/dist/types/config/deltaColors.d.ts +64 -0
  66. package/dist/types/config/labelStyleConfig.d.ts +50 -0
  67. package/dist/types/data/OddCategoryColors.d.ts +13 -0
  68. package/dist/types/data/adverse-action-planner.d.ts +51 -0
  69. package/dist/types/data/adverse-action-planner.test.d.ts +1 -0
  70. package/dist/types/data/amplifier-engine.d.ts +107 -0
  71. package/dist/types/data/amplifier-engine.test.d.ts +1 -0
  72. package/dist/types/data/combo-engine.d.ts +94 -0
  73. package/dist/types/data/combo-engine.test.d.ts +1 -0
  74. package/dist/types/data/odd_generic_descriptions.d.ts +4 -0
  75. package/dist/types/data/odd_labels.d.ts +5 -0
  76. package/dist/types/data/yasuni_actions.d.ts +47 -0
  77. package/dist/types/data/yasuni_adverse_actions.d.ts +2 -0
  78. package/dist/types/data/yasuni_adverse_key_events.d.ts +2 -0
  79. package/dist/types/data/yasuni_cause.d.ts +33 -0
  80. package/dist/types/data/yasuni_graph.d.ts +22 -0
  81. package/dist/types/data/yasuni_key_events.d.ts +61 -0
  82. package/dist/types/data/yasuni_propagation_layers.d.ts +3 -0
  83. package/dist/types/interfaces/IActions.d.ts +1 -0
  84. package/dist/types/interfaces/IAnimator.d.ts +3 -0
  85. package/dist/types/interfaces/ICategory.d.ts +9 -0
  86. package/dist/types/interfaces/ICauseGraph.d.ts +9 -0
  87. package/dist/types/interfaces/ICauseModel.d.ts +33 -0
  88. package/dist/types/interfaces/ICircleManager.d.ts +8 -0
  89. package/dist/types/interfaces/IGradientStop.d.ts +5 -0
  90. package/dist/types/interfaces/IGraphicElement.d.ts +15 -0
  91. package/dist/types/interfaces/IGraphicsStrategy.d.ts +27 -0
  92. package/dist/types/interfaces/IPropagationLayers.d.ts +27 -0
  93. package/dist/types/interfaces/ISpikeManager.d.ts +4 -0
  94. package/dist/types/interfaces/IViewData.d.ts +17 -0
  95. package/dist/types/interfaces/IYinOrYangPattern.d.ts +8 -0
  96. package/dist/types/interfaces/IYinYangAppFactory.d.ts +17 -0
  97. package/dist/types/interfaces/IYinYangController.d.ts +317 -0
  98. package/dist/types/interfaces/IYinYangGeometry.d.ts +43 -0
  99. package/dist/types/interfaces/IYinYangInternalModel.d.ts +34 -0
  100. package/dist/types/interfaces/IYinYangModel.d.ts +10 -0
  101. package/dist/types/interfaces/IYinYangView.d.ts +19 -0
  102. package/dist/types/main.d.ts +9 -0
  103. package/dist/types/utils/actionImages.d.ts +14 -0
  104. package/dist/types/utils/actionPropagation.d.ts +74 -0
  105. package/dist/types/utils/appMode.d.ts +5 -0
  106. package/dist/types/utils/causeGraph.d.ts +6 -0
  107. package/dist/types/utils/causeMetrics.d.ts +26 -0
  108. package/dist/types/utils/chainCardHeight.d.ts +27 -0
  109. package/dist/types/utils/d3/D3Animator.d.ts +4 -0
  110. package/dist/types/utils/d3/D3Element.d.ts +20 -0
  111. package/dist/types/utils/d3/D3GraphicsStrategy.d.ts +78 -0
  112. package/dist/types/utils/deltaChips.d.ts +15 -0
  113. package/dist/types/utils/deltaLabels.d.ts +54 -0
  114. package/dist/types/utils/facetteImages.d.ts +1 -0
  115. package/dist/types/utils/geometryUtils.d.ts +3 -0
  116. package/dist/types/utils/hierBadge.d.ts +44 -0
  117. package/dist/types/utils/idleSphereImage.d.ts +8 -0
  118. package/dist/types/utils/keyEventImages.d.ts +41 -0
  119. package/dist/types/utils/oddLegend.d.ts +30 -0
  120. package/dist/types/utils/positionalEfficiency.d.ts +16 -0
  121. package/dist/types/utils/yinYangWatermark.d.ts +29 -0
  122. package/package.json +27 -12
@@ -0,0 +1,639 @@
1
+ import { YinYangComponentNode, YinYangInternalModel } from "../../../interfaces/IYinYangInternalModel";
2
+ import { ForceFieldLink, ForceFieldLinkDetail } from "./types";
3
+ import type { ComboResult } from "../../../data/combo-engine";
4
+ import type { AmplifierResult, AmplifierTargetBreakdown } from "../../../data/amplifier-engine";
5
+ import { type KeyEventDefinition } from "../../../data/yasuni_key_events";
6
+ import type { Composante, ODD } from "../../../data/yasuni_cause";
7
+ /** Contexte combo (backward) ou amplificateur (forward) transmis au clic
8
+ * d'un tag d'action, d'une ligne de prérequis, ou de la carte/du bloc. */
9
+ type ActionTagComboContext = {
10
+ requires: string[];
11
+ withinLastN?: number;
12
+ type: string;
13
+ comboName?: string;
14
+ sourceItemId?: string;
15
+ deltaMultiplier?: number;
16
+ maxDeltaMultiplier?: number;
17
+ direction?: "forward" | "backward";
18
+ };
19
+ type ActionCumulativeBlockViewModel = {
20
+ type: "source" | "propagation";
21
+ actionId?: string;
22
+ actionName: string;
23
+ actionDescription: string;
24
+ sourceComponentName?: string;
25
+ sourceOddName?: string;
26
+ sourceOddId: string;
27
+ sourceCuttingId: number | undefined;
28
+ totalDelta: number;
29
+ rawDelta?: number;
30
+ baseDelta?: number;
31
+ /** Variation de poids du satellite ciblé, amplificateurs inclus — uniquement
32
+ * peuplé pour type "source" (le poids ne se propage jamais), depuis
33
+ * ActionDefinition.weightDelta. Affiché sur la carte bilan. */
34
+ weightDelta?: number;
35
+ /** Même variation de poids, mais avant application des amplificateurs —
36
+ * affichée sur le chip de la carte source, en écho au badge de delta de
37
+ * score qui montre lui aussi la valeur de base (le montant amplifié
38
+ * n'apparaît que dans la carte bilan, cf. weightDelta ci-dessus). */
39
+ weightDeltaBase?: number;
40
+ detailRows: ForceFieldLinkDetail[];
41
+ comboResults?: ComboResult[];
42
+ amplifierResults?: AmplifierResult[];
43
+ stackItemId?: string;
44
+ color?: string;
45
+ sequentialDetailPool?: ForceFieldLinkDetail[];
46
+ /** Position dans la pile (ActionStackItem.slotIndex) — permet de fusionner
47
+ * et trier les blocs "keyEvent" (voir ci-dessous) avec les blocs action
48
+ * dans leur ordre naturel de pile. */
49
+ slotIndex?: number;
50
+ };
51
+ /** Bloc "keyEvent" : un Événement Clé joué, toujours affiché dès que sa
52
+ * Facette d'origine correspond à celle affichée (voir YinYangController.
53
+ * buildKeyEventBlocksForComponent) — `active` ne conditionne que le style
54
+ * (voir _buildKeyEventBlockHtml), jamais l'existence du bloc. */
55
+ type KeyEventCumulativeBlockViewModel = {
56
+ type: "keyEvent";
57
+ keyEventId: string;
58
+ active: boolean;
59
+ totalDelta: number;
60
+ slotIndex?: number;
61
+ stackItemId?: string;
62
+ color?: string;
63
+ targetedActions: Array<{
64
+ id: string;
65
+ name: string;
66
+ }>;
67
+ breakdowns?: AmplifierTargetBreakdown[];
68
+ };
69
+ type CumulativeBlockViewModel = ActionCumulativeBlockViewModel | KeyEventCumulativeBlockViewModel;
70
+ export declare class ForceFieldDetailsPanel {
71
+ private onComboHighlight?;
72
+ private onComboClear?;
73
+ /** Key of the currently active (clicked) combo card — persists across re-renders. */
74
+ private activeComboCardKey;
75
+ /** Resolves an action ID to its display name for combo rules. Defaults to identity. */
76
+ private resolveActionName;
77
+ /** Called when the user clicks an action rule tag.
78
+ * Second argument is the combo context of the card containing the tag (if any). */
79
+ private onActionTagClick?;
80
+ /** Cached propagation index, invalidated when force-field data changes. */
81
+ private _cachedPropagationIndex;
82
+ /** When non-null, clearForceFieldDetails is a no-op (panel frozen during component switch). */
83
+ private _frozenHtml;
84
+ /**
85
+ * Persistent set of expanded card keys, for cards whose DOM position isn't
86
+ * stable across re-renders — combo cards (can disappear temporarily during
87
+ * drag preview when the slot reorder invalidates the combo condition) and
88
+ * Événement Clé / action adverse cards (.ff-chain-keyevent-detail,
89
+ * .ff-chain-keyevent-targets — their grid can shift position when a new
90
+ * block is inserted elsewhere in the cumulative view, see
91
+ * _hasStableCardKey). Keyed via _getCardKey, which already derives a
92
+ * content-based key for both families rather than relying on the
93
+ * positional pos:${gi}:${ci} key used for everything else.
94
+ */
95
+ private _expandedComboKeys;
96
+ /**
97
+ * Every _getCardKey a stable-keyed card (combo or Événement Clé/action
98
+ * adverse) has ever been processed under, regardless of expanded state.
99
+ * Distinguishes "first appearance" (key absent here) from "already seen,
100
+ * deliberately left collapsed" (key present but not in _expandedComboKeys)
101
+ * — both look identical to _expandedComboKeys alone, but only the former
102
+ * should default to expanded when a live-update render (a card inserted
103
+ * while other, already-restored cards are on screen — see
104
+ * _initCardRailState) has no snapshot entry for it yet.
105
+ */
106
+ private _seenCardKeys;
107
+ /** Timer set during a user card interaction — prevents ResizeObserver from
108
+ * running _applyAutoFitToGrids while a card is animating. */
109
+ private _userInteractingTimer;
110
+ /** Set during a live-update _initCardRailState call. _applyAutoFitToGrids skips
111
+ * this container until the timer fires (covering both the initial DOM-insertion
112
+ * resize and the gs-block-open animation resize that follows). */
113
+ private _suppressAutoFitContainer;
114
+ private _suppressAutoFitTimer;
115
+ /** Top-level sphere name & description shown in the empty (nothing-selected) state. */
116
+ private _sphereName;
117
+ /** Per-render registry mapping navKey → onNavigateToSource callback for source card steps. */
118
+ private readonly _sourceNavCallbacks;
119
+ /** Monotonic counter to generate unique nav keys per render. */
120
+ private _sourceNavCounter;
121
+ private _sphereDescription;
122
+ /** Called on hover enter/leave over a navigable step — used to highlight the corresponding diagram element. */
123
+ private _onDiagramElementHover?;
124
+ /** Called when hovering a cumulative block — notifies the stack to highlight the matching item. */
125
+ private _onStackItemHighlightCb?;
126
+ /** Id d'un bloc "Effets cumulés" à centrer (scroll animé) dès qu'il apparaît
127
+ * dans le panneau — voir requestScrollToStackItemBlock. Le rendu déclencheur
128
+ * (renderComposanteInfo / renderCumulativeActionDetails) peut survenir de
129
+ * façon asynchrone après la demande (ouverture animée du satellite). */
130
+ private _pendingBlockScrollStackItemId;
131
+ private _pendingBlockScrollTimeout;
132
+ /** Notifie le header (chip STACK) du badge + nom de l'élément affiché par les
133
+ * cartes d'info minimales (Sphère, ODD) — ces cartes ne répètent plus ce
134
+ * titre dans leur corps. Facette et Satellite restent gérés par leurs
135
+ * mécanismes dédiés existants (voir renderComposanteInfo/renderCuttingInfo). */
136
+ private _onHeaderUpdate?;
137
+ setOnHeaderUpdate(cb: (badge: {
138
+ label: string;
139
+ cssClass: string;
140
+ } | undefined, name: string | undefined) => void): void;
141
+ setSphereInfo(name: string, description: string): void;
142
+ setActionNameResolver(resolver: (id: string) => string): void;
143
+ setActionTagClickCallback(cb: (actionId: string, comboContext?: ActionTagComboContext) => void): void;
144
+ /**
145
+ * Enregistre les callbacks de surlignage combo.
146
+ * Doit être appelé une seule fois depuis YinYangController après instanciation.
147
+ */
148
+ setOnDiagramElementHover(cb: ((target: {
149
+ oddId: string;
150
+ cuttingId: number | undefined;
151
+ componentId?: string;
152
+ } | null) => void) | undefined): void;
153
+ setComboHighlightCallbacks(onHighlight: (params: ActionTagComboContext) => void, onClear: () => void): void;
154
+ /** Clé stable identifiant la carte/le bloc pour le suivi "actif" — combo,
155
+ * ou Événement Clé (carte événement ET carte actions ciblées partagent la
156
+ * même clé via data-keyevent-item-id : deux éléments DOM, un seul bloc
157
+ * logique). */
158
+ private _getCardKey;
159
+ /** True pour une carte dont l'état déplié/replié doit être suivi via
160
+ * _getCardKey (contenu) plutôt que via sa position dans la grid — combo,
161
+ * ou Événement Clé/action adverse (.ff-chain-keyevent-detail,
162
+ * .ff-chain-keyevent-targets). Sans ça, une carte ainsi insérée au milieu
163
+ * d'une vue cumulative déjà rendue (ex. : valider un Événement Clé pendant
164
+ * que d'autres blocs sont affichés) déciderait son repli/dépli sur une clé
165
+ * positionnelle pos:${gi}:${ci} décalée par l'insertion — potentiellement
166
+ * celle d'une tout autre carte, ou une position absente du snapshot
167
+ * précédent, ce qui la replierait par défaut au lieu de suivre l'auto-fit. */
168
+ private _hasStableCardKey;
169
+ /** Un clic "replier" (par opposition à un clic qui ouvre/surligne) — sur le
170
+ * badge delta habituel, ou sur le header pour une carte qui n'en a plus :
171
+ * la carte source Événement Clé n'a aucun delta à elle (celui de l'effet
172
+ * vit désormais uniquement sur la carte "Actions amplifiées" sœur), donc
173
+ * aucun badge à cliquer — le header sert de poignée de repli à sa place. */
174
+ private _isCardCollapseTrigger;
175
+ private _attachComboHighlightHandlers;
176
+ /** Contexte combo (backward) ou amplificateur (forward) déduit de
177
+ * l'ancêtre le plus proche de `el` — même forme pour un clic sur un tag
178
+ * de règle, une ligne de prérequis, ou la carte/le bloc entier.
179
+ * `undefined` si `el` ne vit dans aucune carte combo/Événement Clé (ex.
180
+ * tag de règle dans une description hors contexte). */
181
+ private _extractTagComboContext;
182
+ private _buildComboSectionHtml;
183
+ /**
184
+ * Média d'une carte Événement Clé : l'illustration si l'événement est
185
+ * débloqué, sinon un cartouche verrouillé. Voir isKeyEventUnlocked —
186
+ * le verrou simule la progression de l'aventure, absente du POC, et évite
187
+ * surtout d'afficher une image cassée pour les événements pas encore
188
+ * illustrés. Le cartouche ne porte ni data-full-src ni .ff-zoom-thumb :
189
+ * pas de modale HD à ouvrir sur une image qui n'existe pas.
190
+ */
191
+ private _buildKeyEventMediaHtml;
192
+ /**
193
+ * Construit la (les) carte(s) "amplificateur" — un Événement Clé actif qui
194
+ * renforce le delta effectif de cette action (bonus additif en points, voir
195
+ * amplifier-engine.ts). Contrairement à une carte combo, elle affiche
196
+ * l'illustration de l'ÉVÉNEMENT (pas de l'action) et se relie au reste du
197
+ * rail par un connecteur "⚡" plutôt que "⊕", pour signaler un renfort
198
+ * événementiel plutôt qu'une synergie entre actions.
199
+ *
200
+ * Description et coefficients sont EN SURIMPRESSION sur l'illustration
201
+ * (.ff-card-steps-overlay), comme sur une carte action illustrée : posés à
202
+ * côté, ils amputaient le cadre de l'image, qui ne pouvait alors plus la
203
+ * montrer entière (voir --ff-card-image-ratio).
204
+ */
205
+ private _buildAmplifierSectionHtml;
206
+ /**
207
+ * Carte descriptive autonome d'un Événement Clé — affichée dans le
208
+ * panneau Recherche quand l'utilisateur prévisualise l'événement lui-même
209
+ * (1er clic sur une bulle du menu radial du cercle central), pas quand il
210
+ * amplifie une action (voir _buildAmplifierSectionHtml pour cette carte-là).
211
+ * Reprend délibérément le langage visuel de la carte action "source" (voir
212
+ * _renderChainCardHtml/isSourceCard) — illustration plein cadre — mais SANS
213
+ * badge de score ni chip de poids : ce sont des deltas d'effet différé, ils
214
+ * ne vivent que sur la carte "Actions amplifiées" sœur
215
+ * (_buildDelayedTargetsCardHtml), pas ici, pour ne pas dupliquer la même
216
+ * valeur sur deux cartes. N'ayant plus aucune valeur à porter, cette carte
217
+ * n'a pas de badge du tout (pas de bouton vide) — le header sert de
218
+ * poignée de repli à sa place (voir _isCardCollapseTrigger). Jamais de
219
+ * section combo ni de carte Bilan, l'événement n'a pas de delta propre.
220
+ * Repliable comme n'importe quelle carte de la famille — priorité
221
+ * d'expansion maximale dans l'auto-fit du rail (première carte non-combo,
222
+ * voir _applyAutoFitToGrids), donc repliée seulement si l'espace manque
223
+ * vraiment.
224
+ *
225
+ * La liste des Actions amplifiées vit dans une SECONDE carte du même rail
226
+ * (.ff-chain-keyevent-targets, voir _buildDelayedTargetsCardHtml), séparée
227
+ * par un .ff-chain-separator — même traitement qu'un bloc combo/amplificateur
228
+ * vis-à-vis de sa carte source, pour que ce bloc-ci ne fasse pas exception.
229
+ * Même gabarit standard que le reste de la famille de cartes — les noms
230
+ * d'action y passent à la ligne plutôt que d'exiger une largeur
231
+ * dérogatoire.
232
+ */
233
+ buildKeyEventCardHtml(params: {
234
+ keyEvent: KeyEventDefinition;
235
+ targetedActions: Array<{
236
+ id: string;
237
+ name: string;
238
+ }>;
239
+ /** Répartition par action ciblée (position dans la fenêtre, bonus
240
+ * effectif déjà réduit) — absente en aperçu avant validation, où
241
+ * l'événement n'a pas encore de slot depuis lequel compter une position.
242
+ * Une entrée par targetedActions quand présente (voir
243
+ * getAmplifierTargetBreakdown). */
244
+ breakdowns?: AmplifierTargetBreakdown[];
245
+ /** Id de l'item "keyEvent" actif dans la pile (absent en aperçu avant
246
+ * validation) — active le clic "barres de gain par slot" sur la carte
247
+ * et sa section d'actions ciblées (voir _attachComboHighlightHandlers),
248
+ * même mécanisme que le clic sur une carte combo. */
249
+ sourceItemId?: string;
250
+ onNavigateToAction?: (actionId: string) => void;
251
+ }): {
252
+ html: string;
253
+ attachHandlers: (container: HTMLElement) => void;
254
+ };
255
+ /**
256
+ * Carte "actions ciblées" d'une source d'effet différé — la liste des
257
+ * actions qu'un Événement Clé amplifie ("Actions amplifiées") ou qu'une
258
+ * action adverse entrave ("Actions entravées"), avec pour chacune le seul
259
+ * delta AJOUTÉ (ou retiré) par l'effet — pas le résultat final combiné au
260
+ * delta de base de l'action, qui deviendrait faux dès qu'un combo entre
261
+ * en jeu ailleurs sur la même action. Même grammaire que la chip de bonus
262
+ * de la carte Événement Clé sœur (buildKeyEventChipsHtml) : rester simple
263
+ * et lisible plutôt que reconstituer un calcul complet ici.
264
+ *
265
+ * Le bonus du catalogue est le PLAFOND — atteint seulement quand l'action
266
+ * est jouée au pic de la fenêtre. Une fois la source placée (breakdowns
267
+ * disponibles), chaque ligne affiche le bonus EFFECTIF (réduit selon la
268
+ * position) plutôt que ce plafond nominal — sinon la chip mentirait sur ce
269
+ * que l'action rapporte réellement. Sans breakdowns, le plafond reste la
270
+ * meilleure estimation disponible.
271
+ *
272
+ * Porte le même jeu d'attributs data-keyevent-* que la carte source
273
+ * (Événement Clé ou action adverse) pour que _attachComboHighlightHandlers
274
+ * et _extractTagComboContext y lisent la fenêtre "en avant" : un clic
275
+ * affiche les barres de gain par slot pour toute la fenêtre withinNextN.
276
+ *
277
+ * Badge et tableau repris à l'identique du gabarit carte combo (voir
278
+ * _buildComboSectionHtml/_buildPrereqBreakdownHtml) plutôt qu'un format ad
279
+ * hoc : le badge affiche le bonus/malus plafond du catalogue, accompagné
280
+ * d'un chip de poids (même paire badge+chip que portait la carte source
281
+ * avant que ces deltas n'emménagent ici, voir buildKeyEventCardHtml —
282
+ * absent si l'effet ne touche pas le poids), et le tableau réutilise les
283
+ * colonnes ff-pt-name/ff-pt-val de
284
+ * .ff-combo-prereq-table (les noms passent à la ligne plutôt que d'exiger
285
+ * une largeur de carte dérogatoire). Repliable comme n'importe quelle autre
286
+ * carte de la famille (le garde-fou qui la forçait dépliée a été retiré de
287
+ * _handleCardRailClick/_applyAutoFitToGrids) et précédée d'un séparateur
288
+ * .ff-chain-separator — même traitement que la carte source vis-à-vis d'un
289
+ * bloc combo/amplificateur, pour que ce bloc-ci ne fasse pas exception.
290
+ */
291
+ private _buildDelayedTargetsCardHtml;
292
+ /** Badge et note de provenance d'un bloc action de la vue cumulative :
293
+ * propagée (depuis son satellite source), adverse (son acteur d'origine)
294
+ * ou directe. */
295
+ private _pickActionBlockBadge;
296
+ /**
297
+ * En-tête générique et repliable d'un .ff-cumulative-block — icône, badge
298
+ * de type, nom, note de provenance optionnelle ("rationale"), et une
299
+ * valeur phare à droite (delta, coefficient…). Un seul gabarit pour tous
300
+ * les types de bloc (action directe/propagée, Événement Clé…) : le clic
301
+ * replie/déplie via le délégué déjà installé une seule fois sur le
302
+ * conteneur (voir getForceFieldDetailsContainer, qui toggle
303
+ * .ff-action-expanded sur le .ff-cumulative-block ancêtre au clic sur
304
+ * .ff-block-header) — aucun câblage supplémentaire à ajouter pour qu'un
305
+ * nouveau type de bloc devienne repliable, tant qu'il réutilise cette
306
+ * structure.
307
+ */
308
+ private _buildBlockHeaderHtml;
309
+ /**
310
+ * Bloc "keyEvent" de la vue cumulative (mode STACK) et de renderComposanteInfo
311
+ * — même structure que les blocs action (_buildBlockHeaderHtml + description
312
+ * courte + rail de cartes dans .ff-action-body), pour que ce bloc s'apparente
313
+ * visuellement au reste de la famille plutôt que de n'être qu'une carte brute.
314
+ * Un Événement Clé joué (kind="keyEvent" dans la pile) reste toujours visible,
315
+ * qu'une de ses actions ciblées soit effectivement amplifiée ou non ; seules
316
+ * la classe modificatrice --keyevent-active/--keyevent-inactive et la couleur
317
+ * du coefficient dans l'en-tête changent (voir isKeyEventCurrentlyActive côté
318
+ * YinYangController). attachHandlers n'est délibérément pas invoqué ici,
319
+ * comme pour l'aperçu (voir commentaire de buildKeyEventCardHtml) : les
320
+ * gestionnaires délégués au conteneur (_attachPrereqNavHandlers/
321
+ * _attachComboHighlightHandlers) couvrent déjà les attributs data-keyevent-*.
322
+ */
323
+ private _buildKeyEventBlockHtml;
324
+ /**
325
+ * Construit le bloc de détail d'un combo : valeur héro (multiplicateur
326
+ * effectif), tableau de répartition par prérequis/protecteur (avec
327
+ * mini-barre de remplissage sur Score), et conseil conditionnel listant
328
+ * les prérequis jamais joués. Structure alignée sur les cartes Absorption
329
+ * et Écart (state-row héro + détail + tip).
330
+ *
331
+ * Chaque ligne du tableau montre :
332
+ * - Nom du prérequis (tronqué si besoin)
333
+ * - Perf. : ratio effectif/base (100% = nominal)
334
+ * - Pos. : efficacité positionnelle Beta(t) (100% = position optimale)
335
+ * - Score : contribution combinée Perf × Pos (avec mini-barre)
336
+ * Les lignes "jamais joué" (played=false) affichent "—" plutôt que des
337
+ * pourcentages sans signification réelle.
338
+ */
339
+ private _buildPrereqBreakdownHtml;
340
+ /** Ratio de performance du Bilan (% du delta nominal obtenu), généralisé aux
341
+ * blocs source (combos vs baseDelta) ET propagation (Abs/Gap vs rawDelta) —
342
+ * même sémantique des deux côtés, juste un nominal différent. */
343
+ private _computeBlockOptimizationRatio;
344
+ private _buildTotalCardHtml;
345
+ /** Delta "brut" d'une ligne de propagation, avant application d'Absorption
346
+ * et Gap — sert à la fois à décomposer leur contribution (cartes Abs/Gap)
347
+ * et à calculer le ratio de performance du Bilan (% du nominal obtenu). */
348
+ private _rawDeltaForRow;
349
+ /** Barre de zones générique (piste B) partagée entre Absorption et Écart :
350
+ * une piste de zones colorées (largeurs fixées en CSS) + un marqueur
351
+ * positionné à markerPct. Seules les classes de zones et l'échelle du
352
+ * marqueur diffèrent selon la carte appelante. */
353
+ private _buildZoneBarHtml;
354
+ private _buildPropagationModifiersSectionHtml;
355
+ private _buildWeightInfluenceHint;
356
+ /**
357
+ * Anime tous les badges numériques d'un container après un innerHTML update.
358
+ * Une seule boucle rAF partagée remplace N boucles indépendantes (une par badge),
359
+ * ce qui évite N appels requestAnimationFrame simultanés à 60fps pendant 600ms.
360
+ */
361
+ private _animateContainerCounters;
362
+ private _wrapChainGrid;
363
+ /** Renders the same crosshair/reticle "navigate to" icon used by the action-stack
364
+ * items (ActionStackController.ts, ring + 4 orthogonal ticks), as a clickable span
365
+ * carrying the given nav data attributes. This is the sole navigation trigger for a
366
+ * listed element — clicking the label itself now animates instead of navigating. */
367
+ private _buildNavTargetIconHtml;
368
+ /** Steps HTML for the propagation source card: one line per sortedDirect row,
369
+ * each clickable to navigate back to the source satellite. */
370
+ private _buildPropSourceStepsHtml;
371
+ /** Flat list of cascade targets (satellites X sends to) for the bilan card. */
372
+ /** Reconstructs the forward path origin → ... → (toOddId, toCuttingId) by walking
373
+ * cascadeRows backward via fromCuttingId (picking one contributing row per hop when
374
+ * several exist, same simplification as _getBranchLabel's "first cascade" pick).
375
+ * Used to give each cascade-list entry its own isolated flash sequence. */
376
+ private _buildCascadeFlashPath;
377
+ private _buildCascadeListHtml;
378
+ /** Simple chain-steps HTML from TargetChainData — used in the collapsible section
379
+ * when no flash-target context is available (cumulative panel). */
380
+ private _buildPropChainStepsHtml;
381
+ private _buildDetailDisclosureHtml;
382
+ private _snapshotCardExpansion;
383
+ /**
384
+ * Expand all cards in a grid and measure if they fit.
385
+ * If they fit → keep all expanded. Otherwise → collapse all.
386
+ * Called on fresh mount and on ResizeObserver triggers.
387
+ */
388
+ private _applyAutoFitToGrids;
389
+ /**
390
+ * Installs a ResizeObserver on the container the first time this is called
391
+ * for a given container element (guard via data attribute). The observer
392
+ * re-runs the auto-fit measurement whenever the container changes size.
393
+ */
394
+ private _ensureResizeObserver;
395
+ private _initCardRailState;
396
+ private _handleCardRailClick;
397
+ private _triggerHighlightFromCard;
398
+ /** Maps every row within a target chain's chainCards (trigger + steps) to that card's
399
+ * own flash sequence — the diagram nodes lit up when isolating just that one
400
+ * propagation path (a bridge hop, an inter-ODD hop, or a pure-intra chain). Shared by
401
+ * every panel that offers a "flash all paths combined" header plus a per-path,
402
+ * badge-isolated flash (buildPropagatedActionHtml and renderCumulativeActionDetails). */
403
+ private _computeChainCardFlashes;
404
+ /** Builds a chain-card's final flash sequence: `source` first, then `cardFlash` in its
405
+ * own (causally correct) order, deduped by node so the same satellite never flashes
406
+ * twice. `target` (the currently focused satellite) is only force-inserted right after
407
+ * `source` when `cardFlash` wouldn't otherwise reach it at all — e.g. an inter trigger
408
+ * whose own BFS didn't resolve to this exact cutting. When `cardFlash` DOES naturally
409
+ * include `target` (the common case), it's left at its true causal position instead of
410
+ * being jumped to the front: for a chainCard like "Maladies de peau → Populations
411
+ * exposées", forcing the focused satellite (Populations exposées) to position 2 would
412
+ * make it flash *before* the intermediate ancestor that actually causes it. Shared by
413
+ * every panel presenting a propagation-path flash (buildPropagatedActionHtml,
414
+ * renderCumulativeActionDetails) so their animations never diverge. */
415
+ private _finalizeFlashSequence;
416
+ private _buildBranchFlashSequence;
417
+ private _getBranchLabel;
418
+ private _handleCardRailClickPrelude;
419
+ private _resolveDetailPool;
420
+ private _ensurePropagationIndex;
421
+ invalidatePropagationIndex(): void;
422
+ private static _buildTargetChainKey;
423
+ private static _buildSourceChainKey;
424
+ /** Whether this chain's own satellite is the direct target of a bridge (cross-component)
425
+ * edge — an intrinsic property of the chain, independent of which upstream source is
426
+ * asking. Chains only reached *indirectly* through an intermediate node that itself
427
+ * received a bridge (e.g. one more intra hop downstream) don't qualify: the bridge
428
+ * badge should mark the satellite the bridge actually lands on, not everything
429
+ * downstream of it. */
430
+ private static _chainHasDirectBridgeEdge;
431
+ private _buildTargetChainData;
432
+ /** Builds one TargetChainData per distinct cutting reached within a
433
+ * self-contained, single-source pool (e.g. one stack item's own
434
+ * sequential-step edges) — the per-item equivalent of
435
+ * propagationIndex.sourceToTargetChains, without needing the shared
436
+ * cross-item index since the pool already belongs to exactly one action. */
437
+ private _buildBranchesFromPool;
438
+ private _buildDetailRowKey;
439
+ private _buildTargetGroupKey;
440
+ private _renderChainCardHtml;
441
+ private _selectPropagationTableViewModel;
442
+ private _selectCumulativeViewModel;
443
+ private _selectTargetChainCards;
444
+ renderCumulativeActionDetails(params: {
445
+ focusOddId: string;
446
+ focusCuttingId: number | undefined;
447
+ currentComponent?: YinYangComponentNode;
448
+ /** All components in the model, used to resolve cutting labels for cross-component targets. */
449
+ allComponents?: YinYangComponentNode[];
450
+ forceFieldLinks: ForceFieldLink[];
451
+ allForceFieldLinkDetails: ForceFieldLinkDetail[];
452
+ onCardElementFlash?: (targets: Array<{
453
+ oddId: string;
454
+ cuttingId: number | undefined;
455
+ componentId?: string;
456
+ }>) => void;
457
+ onNavigateToCutting?: (toOddId: string, toCuttingId: number | undefined, toComponentId: string | undefined) => void;
458
+ onNavigateToAction?: (actionId: string) => void;
459
+ blocks: CumulativeBlockViewModel[];
460
+ onNavigateToSatellite?: (oddId: string, cuttingId: number | undefined, componentId?: string) => void;
461
+ }): void;
462
+ private _attachBlockLinkedHoverHandlers;
463
+ setStackItemHighlightCallback(cb: (id: string | null) => void): void;
464
+ highlightBlockByStackItemId(id: string | null): void;
465
+ /**
466
+ * Demande de centrer (scroll animé) le bloc "Effets cumulés" de cet item de
467
+ * pile dès qu'il apparaît dans le panneau — déclenché par le clic sur le
468
+ * libellé d'un item de la pile (sélection auto du satellite/facette porteur,
469
+ * cf. DiagramPanelBridge.setOnSelectStackItemSatellite). Le rendu qui produit
470
+ * le bloc correspondant peut arriver de façon asynchrone (ouverture animée du
471
+ * satellite) : on retente immédiatement puis on laisse chaque prochain rendu
472
+ * de blocs (renderComposanteInfo / renderCumulativeActionDetails) consommer
473
+ * la demande via _consumePendingBlockScroll. Abandonnée après 1s si aucun
474
+ * bloc correspondant n'apparaît (item hors de tout bloc affiché).
475
+ */
476
+ requestScrollToStackItemBlock(stackItemId: string): void;
477
+ private _consumePendingBlockScroll;
478
+ private getTargetName;
479
+ private getGhostDetailsContainer;
480
+ private getForceFieldDetailsContainer;
481
+ /** Ouvre/ferme la description de cet ODD sous le descriptif actuellement
482
+ * affiché (sphère/facette/satellite), comme un clic direct sur son chip
483
+ * de légende. Retourne `null` si aucun chip pour cet ODD n'est visible
484
+ * dans le contexte courant (no-op), sinon le nouvel état (ouvert/fermé). */
485
+ toggleOddLegendChipById(oddId: string): boolean | null;
486
+ clearGhostDetails(): void;
487
+ /** Freeze the panel during a component switch so clearForceFieldDetails is a no-op. */
488
+ freezeForSwitch(html: string): void;
489
+ /** Unfreeze and optionally restore the preserved HTML. */
490
+ unfreezeForSwitch(): void;
491
+ clearForceFieldDetails(): void;
492
+ /** Shows the sphere intro card in the empty (nothing-selected) state.
493
+ * Falls back to clearing the container if no sphere info is set.
494
+ * Badge + nom ne sont plus répétés ici : ils remontent au header du panneau
495
+ * (chip STACK / titre de panneau RECHERCHE) via _onHeaderUpdate, à l'identique
496
+ * du fonctionnement déjà en place côté RECHERCHE (setOnTitleUpdate).
497
+ */
498
+ private _renderSphereIntroOrClear;
499
+ /** Callback vers le diagramme quand la souris entre/sort d'un chip de la
500
+ * légende ODD (lien visuel bidirectionnel — voir aussi highlightOddLegendChip
501
+ * pour le sens inverse, arc du diagramme → chip). */
502
+ private _onOddLegendHoverCb;
503
+ setOddLegendHoverCallback(cb: (oddId: string | null) => void): void;
504
+ /** Callback vers le diagramme quand un chip de la légende ODD est
505
+ * déplié/replié par un clic direct dans le panneau (sens panneau →
506
+ * diagramme — voir onDiagramOddArcClicked pour le sens inverse). */
507
+ private _onOddLegendActiveChangeCb;
508
+ setOddLegendActiveChangeCallback(cb: (oddId: string, isOpen: boolean) => void): void;
509
+ /** Surligne (ou éteint si `oddId` est `null`) le chip de la légende ODD
510
+ * correspondant à l'arc actuellement survolé dans le diagramme. */
511
+ highlightOddLegendChip(oddId: string | null): void;
512
+ /**
513
+ * Displays a minimal ODD info card with its parent Facette (collapsed).
514
+ * Called when the user clicks an ODD arc in the diagram. Badge + nom
515
+ * remontent au header via _onHeaderUpdate (voir _renderSphereIntroOrClear).
516
+ */
517
+ renderOddInfo(oddName: string, description?: string): void;
518
+ /**
519
+ * Displays a minimal Composante info card.
520
+ * Called when the user clicks the component title or a legend label — y compris
521
+ * une seconde fois après le rebuild post-animation d'un switch de composante, qui
522
+ * repasse d'abord par un clearForceFieldDetails() transitoire (état Sphère). C'est
523
+ * pourquoi _onHeaderUpdate est notifié ici plutôt que laissé au seul mécanisme
524
+ * diagramme-vers-chip : cet appel est fiablement le dernier de la séquence.
525
+ */
526
+ renderComposanteInfo(composante: Composante, keyEventBlocks?: CumulativeBlockViewModel[], onNavigateToAction?: (actionId: string) => void): void;
527
+ /**
528
+ * Displays a simple satellite info card.
529
+ * Used when the clicked cutting has no direct or indirect impact from the current action(s).
530
+ * Badge + nom ne sont pas répétés ici : notifyCuttingNavigated (déclenché par
531
+ * le même appelant, onCuttingLabelClick) tient déjà le chip STACK à jour.
532
+ */
533
+ renderCuttingInfo(cuttingName: string, description?: string, odd?: ODD, composanteId?: string): void;
534
+ /**
535
+ * empty placeholder), null otherwise. Used to preserve the panel across a
536
+ * component switch (save before children are rebuilt, restore after).
537
+ */
538
+ snapshotPanelHtml(): string | null;
539
+ /**
540
+ * Restores previously snapshotted panel HTML. The old click listener
541
+ * (captured in its closure) is still attached to the container from the
542
+ * previous render, so interactivity is fully preserved.
543
+ */
544
+ private restorePanelHtml;
545
+ renderGhostDetailsForActiveAction(params: {
546
+ isInOddMode: boolean;
547
+ displayingOddId?: string;
548
+ currentComponent?: YinYangInternalModel["components"][number];
549
+ projectedGhostTensionByOddId: Map<string, number> | null;
550
+ projectedGhostComponentTension: number | null;
551
+ projectedGhostCuttingStatesByOddId: Map<string, Array<{
552
+ cuttingId: number;
553
+ originalTension: number;
554
+ projectedTension: number;
555
+ originalState: number;
556
+ projectedState: number;
557
+ }>> | null;
558
+ }): void;
559
+ renderActionPropagationTable(params: {
560
+ forceFieldLinks: ForceFieldLink[];
561
+ allForceFieldLinkDetails: ForceFieldLinkDetail[];
562
+ }): void;
563
+ /**
564
+ * Builds only the chain-rail HTML (cards row) for a direct action on a source cutting.
565
+ * Used by the Recherche tab to inject the impact block inline below the cutting element.
566
+ * No interactive flash handlers or nav buttons are attached.
567
+ */
568
+ buildDirectActionCardsHtml(params: {
569
+ oddId: string;
570
+ cuttingId: number | undefined;
571
+ actionDelta: number;
572
+ actionBaseDelta?: number;
573
+ projectionDelta?: number;
574
+ actionId?: string;
575
+ actionName?: string;
576
+ /** Variation de poids du satellite ciblé, amplificateurs inclus — affichée
577
+ * sur la carte bilan (ActionDefinition.weightDelta). */
578
+ weightDelta?: number;
579
+ /** Même variation, avant amplificateurs — affichée sur le chip de la
580
+ * carte source (voir ActionCumulativeBlockViewModel.weightDeltaBase). */
581
+ weightDeltaBase?: number;
582
+ forceFieldLinks: ForceFieldLink[];
583
+ allForceFieldLinkDetails: ForceFieldLinkDetail[];
584
+ currentComponent?: YinYangComponentNode;
585
+ allComponents?: YinYangComponentNode[];
586
+ comboResults?: ComboResult[];
587
+ amplifierResults?: AmplifierResult[];
588
+ stackItemId?: string;
589
+ onCardElementFlash?: (targets: Array<{
590
+ oddId: string;
591
+ cuttingId: number | undefined;
592
+ componentId?: string;
593
+ }>) => void;
594
+ onNavigateToCutting?: (toOddId: string, toCuttingId: number | undefined, toComponentId: string | undefined) => void;
595
+ onNavigateToAction?: (actionId: string) => void;
596
+ }): {
597
+ html: string;
598
+ attachHandlers: (container: HTMLElement) => void;
599
+ };
600
+ /**
601
+ * Builds the full propagated-action analysis block HTML for a target cutting.
602
+ * Returns `{ html, attachHandlers }` so the caller (Recherche tab) can inject
603
+ * and wire it inline under the cutting row — identical rendering to the Analyse tab panel.
604
+ * Returns `null` when the link or chain data is unavailable.
605
+ */
606
+ buildPropagatedActionHtml(params: {
607
+ linkIndex: number;
608
+ forceFieldLinks: ForceFieldLink[];
609
+ allForceFieldLinkDetails: ForceFieldLinkDetail[];
610
+ onCardElementFlash?: (targets: Array<{
611
+ oddId: string;
612
+ cuttingId: number | undefined;
613
+ componentId?: string;
614
+ }>) => void;
615
+ onNavigateToCutting?: (toOddId: string, toCuttingId: number | undefined, toComponentId: string | undefined) => void;
616
+ actionSource?: {
617
+ oddId: string;
618
+ cuttingId: number | undefined;
619
+ };
620
+ incomingMode?: boolean;
621
+ incomingSourceName?: string;
622
+ currentComponent?: YinYangComponentNode;
623
+ actionId?: string;
624
+ actionName?: string;
625
+ actionDescription?: string;
626
+ sourceOddName?: string;
627
+ onNavigateToSatellite?: (oddId: string, cuttingId: number | undefined, componentId?: string) => void;
628
+ }): {
629
+ html: string;
630
+ attachHandlers: (container: HTMLElement) => void;
631
+ } | null;
632
+ /** Attaches the standard card↔table click handler used by detail panels with a disclosure table. */
633
+ private _attachDetailPanelClickHandler;
634
+ private _installClickHandler;
635
+ private _buildMultiFlashClickHandler;
636
+ private _attachNavBtnHandlers;
637
+ private _attachPrereqNavHandlers;
638
+ }
639
+ export {};