@micheeeeel/yinyangapp 2.5.1 → 2.6.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 (66) hide show
  1. package/dist/bundle.js +1 -1
  2. package/dist/types/adapters/yasuniCauseAdapter.d.ts +31 -5
  3. package/dist/types/api.d.ts +5 -1
  4. package/dist/types/components/controller/YinYangController.d.ts +63 -679
  5. package/dist/types/components/controller/action-stack/ActionStackController.d.ts +35 -0
  6. package/dist/types/components/controller/action-stack/ActionStackManager.d.ts +9 -0
  7. package/dist/types/components/controller/action-stack/StackFocusController.d.ts +105 -0
  8. package/dist/types/components/controller/actions/ActionProjectionService.d.ts +32 -3
  9. package/dist/types/components/controller/actions/ChildActionMenuController.d.ts +8 -4
  10. package/dist/types/components/controller/actions/CoreEventMenuController.d.ts +13 -13
  11. package/dist/types/components/controller/actions/KeyEventController.d.ts +192 -0
  12. package/dist/types/components/controller/actions/radialItemMenu.d.ts +0 -9
  13. package/dist/types/components/controller/children/ChildrenBuilder.d.ts +95 -0
  14. package/dist/types/components/controller/children/ComponentSwitchCoordinator.d.ts +80 -0
  15. package/dist/types/components/controller/debug/ControllerDebugTools.d.ts +81 -0
  16. package/dist/types/components/controller/force-field/ForceFieldComputationService.d.ts +3 -15
  17. package/dist/types/components/controller/force-field/ForceFieldDetailsPanel.d.ts +120 -66
  18. package/dist/types/components/controller/force-field/ForceFieldDetailsPresenter.d.ts +139 -0
  19. package/dist/types/components/controller/force-field/ForceFieldRenderer.d.ts +0 -8
  20. package/dist/types/components/controller/force-field/IncomingForceFieldService.d.ts +53 -0
  21. package/dist/types/components/controller/force-field/PropagationAnimator.d.ts +56 -0
  22. package/dist/types/components/controller/force-field/edgeIdentity.d.ts +28 -0
  23. package/dist/types/components/controller/force-field/incomingContinuation.d.ts +22 -0
  24. package/dist/types/components/controller/force-field/propagation-viz/PropagationCometPlayer.d.ts +60 -0
  25. package/dist/types/components/controller/force-field/propagation-viz/propagationVizLists.d.ts +51 -0
  26. package/dist/types/components/controller/force-field/propagation-viz/propagationVizModel.d.ts +60 -0
  27. package/dist/types/components/controller/force-field/propagationTree.d.ts +32 -0
  28. package/dist/types/components/controller/force-field/shieldViewModel.d.ts +79 -0
  29. package/dist/types/components/controller/force-field/types.d.ts +37 -10
  30. package/dist/types/components/controller/labels/ComponentTitlePresenter.d.ts +99 -0
  31. package/dist/types/components/controller/navigation/DiagramNavigator.d.ts +64 -0
  32. package/dist/types/components/controller/odd/OddViewManager.d.ts +1 -1
  33. package/dist/types/components/controller/search/SearchPanelSynchronizer.d.ts +9 -0
  34. package/dist/types/components/controller/state/ControllerSession.d.ts +107 -0
  35. package/dist/types/components/controller/state/ControllerUiCallbacks.d.ts +60 -0
  36. package/dist/types/components/controller/state/YinYangControllerState.d.ts +4 -5
  37. package/dist/types/components/controller/types.d.ts +103 -0
  38. package/dist/types/components/controller/utils/actionCatalog.d.ts +15 -0
  39. package/dist/types/components/controller/utils/forceFieldPresentation.d.ts +14 -8
  40. package/dist/types/components/search/GlobalSearchController.d.ts +68 -9
  41. package/dist/types/components/view/BorderDrawer.d.ts +5 -0
  42. package/dist/types/components/workspace/workspaceTemplate.d.ts +1 -1
  43. package/dist/types/config/propagationCometConfig.d.ts +9 -36
  44. package/dist/types/config/propagationCometVizConfig.d.ts +34 -0
  45. package/dist/types/data/activeDiagram.d.ts +4 -6
  46. package/dist/types/data/adverse-action-planner.d.ts +22 -0
  47. package/dist/types/data/catalogue-coverage.d.ts +26 -0
  48. package/dist/types/data/combo-engine.d.ts +76 -21
  49. package/dist/types/data/contacts/buildContactSphere.d.ts +23 -4
  50. package/dist/types/data/contacts/index.d.ts +6 -3
  51. package/dist/types/data/propagation-graph.d.ts +16 -0
  52. package/dist/types/data/stability-shield.d.ts +21 -0
  53. package/dist/types/data/yasuni_actions.d.ts +38 -5
  54. package/dist/types/data/yasuni_cause.d.ts +7 -0
  55. package/dist/types/data/yasuni_key_events.d.ts +3 -2
  56. package/dist/types/interfaces/IPropagationGraph.d.ts +39 -0
  57. package/dist/types/interfaces/IYinYangController.d.ts +2 -2
  58. package/dist/types/utils/actionPropagation.d.ts +104 -32
  59. package/dist/types/utils/adverseMode.d.ts +14 -0
  60. package/package.json +4 -2
  61. package/dist/types/components/controller/utils/forceFieldMetadata.d.ts +0 -4
  62. package/dist/types/data/yasuni_graph.d.ts +0 -22
  63. package/dist/types/data/yasuni_propagation_layers.d.ts +0 -3
  64. package/dist/types/interfaces/ICauseGraph.d.ts +0 -9
  65. package/dist/types/interfaces/IPropagationLayers.d.ts +0 -27
  66. package/dist/types/utils/causeGraph.d.ts +0 -6
@@ -1,26 +1,43 @@
1
+ import type { PropagationScope } from "../../../interfaces/IPropagationGraph";
2
+ /**
3
+ * Une arrivée de propagation prête pour l'affichage : un saut du graphe
4
+ * unifié, d'un satellite à un autre, issu d'une résolution précise.
5
+ *
6
+ * Identité (PROP-GRAPH-04) : `edgeId` est unique dans tout ensemble de
7
+ * lignes affichées, même après filtrage, transformation ou fusion de
8
+ * plusieurs actions de la pile ; `parentEdgeId` désigne l'arrivée qui a
9
+ * porté le budget de ce saut. Ensemble, ils forment l'arbre des arrivées
10
+ * (voir propagationTree.ts) : embranchements, convergences et retours
11
+ * cycliques s'y lisent sans cas particulier. Deux actions qui produisent la
12
+ * même relation gardent des identités distinctes (`resolutionId`).
13
+ */
1
14
  export type ForceFieldLinkDetail = {
15
+ /** Résolution d'origine : un bloc de pile, ou le satellite source d'un
16
+ * champ de force. Toutes les arêtes d'une résolution le partagent. */
17
+ resolutionId: string;
18
+ edgeId: string;
19
+ /** Absent pour une sortie du point de départ de la résolution. Peut
20
+ * désigner une arrivée absente des lignes affichées (sautée dans une autre
21
+ * facette) : la ligne est alors une racine pour cet affichage. */
22
+ parentEdgeId?: string;
23
+ scope: PropagationScope;
2
24
  fromComponentId: string;
3
25
  toComponentId: string;
4
26
  fromOddId: string;
5
27
  toOddId: string;
6
- fromCuttingId?: number;
7
- toCuttingId?: number;
28
+ fromCuttingId: number;
29
+ toCuttingId: number;
8
30
  baseDelta: number;
9
31
  weight: number;
10
32
  strategicWeight: number;
11
- layerType: "inter" | "intra" | "bridge";
12
- propagationFactor: number;
13
33
  absorption: number;
14
34
  gap: number;
15
35
  fromState: number;
16
36
  toState: number;
17
37
  deltaTo: number;
18
38
  rationale?: string;
19
- /** Entry cutting in the target ODD's intra chain (from yasuniInterconnectionGraph edge). */
20
- targetedCutting?: number;
21
- layersInvolved: string[];
22
- localLayerWeights: string | null;
23
- bridgeLayerWeights: string | null;
39
+ /** Chemin causal de l'arrivée (PropagatedActionEdge.path). */
40
+ path?: readonly string[];
24
41
  };
25
42
  export type ForceFieldLink = {
26
43
  startIndex?: number;
@@ -29,7 +46,8 @@ export type ForceFieldLink = {
29
46
  targetComponentId?: string;
30
47
  thickness: number;
31
48
  potentialGain: number;
32
- /** Delay before revealing this link, used for chained intra-ODD propagation. */
49
+ /** Delay before revealing this link: its depth in the arrival tree times the
50
+ * reveal step, whatever its scope. */
33
51
  revealDelayMs?: number;
34
52
  /** Index orbital du satellite source racine ayant produit ce lien (posé par
35
53
  * ForceFieldComputationService.build, un appel par source). Pour un segment
@@ -56,3 +74,12 @@ export declare function buildSourceOriginKey(componentId: string, oddId: string,
56
74
  * sans impacter la logique de propagation.
57
75
  */
58
76
  export type ForceFieldSegment = Omit<ForceFieldLink, "detail">;
77
+ /**
78
+ * Clé d'une entrée de liens entrants (contexte "incoming" d'un changement de
79
+ * facette) : l'identité de l'arrivée elle-même (PROP-GRAPH-04). Deux
80
+ * arrivées distinctes — autre action, autre satellite de départ, autre
81
+ * satellite cible, autre chemin — restent deux entrées, sans qu'aucune ne
82
+ * soit écartée au profit de la plus forte ; une même arrivée vue deux fois
83
+ * (état courant et recalcul) n'en fait qu'une.
84
+ */
85
+ export declare function buildIncomingLinkKey(detail: Pick<ForceFieldLinkDetail, "edgeId">): string;
@@ -0,0 +1,99 @@
1
+ import { IYinYangView } from "../../../interfaces/IYinYangView";
2
+ import { IYinYangController } from "../../../interfaces/IYinYangController";
3
+ import { YinYangInternalModel } from "../../../interfaces/IYinYangInternalModel";
4
+ import { ChildrenOrbitEntry } from "../utils/childrenOrbit";
5
+ import { ForceFieldDetailsPanel } from "../force-field/ForceFieldDetailsPanel";
6
+ import { YinYangControllerState } from "../state/YinYangControllerState";
7
+ import { ControllerSession } from "../state/ControllerSession";
8
+ import { ChildScoresDeltaRenderer } from "./ChildScoresDeltaRenderer";
9
+ import { WeightPreviewRingRenderer } from "./WeightPreviewRingRenderer";
10
+ import { ContextLabelsRenderer } from "./ContextLabelsRenderer";
11
+ import { ActionStackManager } from "../action-stack/ActionStackManager";
12
+ import type { CumulativeBlock } from "../types";
13
+ export type ComponentTitlePresenterDeps = {
14
+ actionStackManager: ActionStackManager;
15
+ buildChildrenOrbitData: () => ChildrenOrbitEntry[];
16
+ buildKeyEventBlocksForComponent: (component: {
17
+ id: string;
18
+ }) => CumulativeBlock[];
19
+ childOddMap: Map<string, {
20
+ oddId: string;
21
+ score: number;
22
+ cuttingIndex: number;
23
+ }>;
24
+ childScoresDeltaRenderer: ChildScoresDeltaRenderer;
25
+ contextLabelsRenderer: ContextLabelsRenderer;
26
+ forceFieldDetailsPanel: ForceFieldDetailsPanel;
27
+ getActiveChildMeta: () => {
28
+ oddId: string;
29
+ cuttingIndex: number;
30
+ componentId: string;
31
+ } | null;
32
+ getAllComponents: () => YinYangInternalModel["components"];
33
+ getChildRenderedCenter: (childController: IYinYangController) => {
34
+ x: number;
35
+ y: number;
36
+ } | null;
37
+ getCurrentComponent: () => YinYangInternalModel["components"][number] | null;
38
+ getInternalModel: () => YinYangInternalModel;
39
+ navigateToPrereqAction: (actionId: string) => void;
40
+ session: ControllerSession;
41
+ showComposanteInfo: () => void;
42
+ state: YinYangControllerState;
43
+ view: IYinYangView;
44
+ weightPreviewRingRenderer: WeightPreviewRingRenderer;
45
+ };
46
+ /** Titre de composante (facette / satellite / action), étiquettes de
47
+ * contexte, deltas de score des satellites et anneau d'aperçu de poids. */
48
+ export declare class ComponentTitlePresenter {
49
+ private deps;
50
+ constructor(deps: ComponentTitlePresenterDeps);
51
+ private getCurrentComponentTitle;
52
+ /** Second (et, le cas échéant, troisième) niveau du titre : libellé + couleur
53
+ * ODD du satellite actif sous la facette courante (menu ouvert, ou
54
+ * sélection en lecture seule — voir getActiveChildMeta), avec le libellé
55
+ * de son action active le cas échéant. Un Événement Clé actif (frère du
56
+ * Satellite, jamais les deux à la fois côté menu — voir activeKeyEventId)
57
+ * prend la priorité et occupe cette même ligne, sans action associée
58
+ * (targetedActionIds sont des renvois, pas une Action propre). Null hors
59
+ * facette / sans satellite ni Événement Clé actif. */
60
+ private getCurrentSatelliteTitle;
61
+ /** Troisième niveau du titre : libellé de l'action actuellement active,
62
+ * seulement si elle appartient bien au satellite affiché (oddId,
63
+ * cuttingIndex) — actionSourceChildKey peut différer du satellite affiché
64
+ * quand l'utilisateur navigue vers un autre satellite en lecture seule
65
+ * (recherche/STACK) pendant qu'une action reste techniquement active sur
66
+ * le précédent (voir le commentaire sur actionSourceChildKey). Sans ce
67
+ * contrôle, le titre affichait le libellé de l'ancienne action sous le
68
+ * nouveau satellite. */
69
+ private getCurrentActionTitle;
70
+ /** Refreshes just the top-left title's satellite line against the current
71
+ * state — cheap, idempotent DOM diffing — from every code path that can
72
+ * change which satellite is active (menu open/close, force-field link
73
+ * click, hierarchy/search navigation, cumulative view). */
74
+ refreshComponentTitle(): void;
75
+ /** Cross-fades the top-left component-title label to `componentIndex`'s
76
+ * name immediately, without waiting for the full updateContextLabels()
77
+ * pass (orbit data, legend, etc.) that only runs once the diagram's
78
+ * component-switch animation completes. A facette switch always starts
79
+ * with no active satellite (createYinYangChildren() resets it), so the
80
+ * satellite line is cleared here rather than read from state mid-switch. */
81
+ updateComponentTitleLabelImmediate(componentIndex: number): void;
82
+ updateContextLabels(orbitData: ChildrenOrbitEntry[]): void;
83
+ renderChildScoresDeltas(orbitData: ChildrenOrbitEntry[]): void;
84
+ /** Re-syncs the weightDelta ghost/wave/pulse against the current
85
+ * ViewInitializer settings (basePulseEnabled, ghostPulseDurationSec,
86
+ * pulseMorphRatio) without waiting for the next natural preview change.
87
+ * Needed because toggling "Pulsation rayons activée" only calls
88
+ * redrawBothGhosts() (VizControlsPanel), which refreshes the facette's own
89
+ * score ghost but has no reason to know about the weightDelta preview. */
90
+ refreshWeightPreviewPulse(): void;
91
+ /** Draws the weightDelta ghost + traveling wave for every satellite
92
+ * targeted by a currently-previewed action — see
93
+ * ActionStackManager.getWeightDeltaByChildKey. The satellite's own circle
94
+ * never resizes, same as the facette ghost never resizes the real
95
+ * yin-yang circle; WeightPreviewRingRenderer resyncs every child each
96
+ * call (no delta = no ghost/wave), same "recompute the full desired
97
+ * state" pattern as highlightOddInChildren. */
98
+ applyWeightPreview(orbitData: ChildrenOrbitEntry[], globalGroupNode: SVGGElement | null): void;
99
+ }
@@ -0,0 +1,64 @@
1
+ import { IYinYangView } from "../../../interfaces/IYinYangView";
2
+ import { IYinYangController } from "../../../interfaces/IYinYangController";
3
+ import { YinYangComponentNode, YinYangInternalModel } from "../../../interfaces/IYinYangInternalModel";
4
+ import { type ComboResult } from "../../../data/combo-engine";
5
+ import { ChildrenOrbitEntry } from "../utils/childrenOrbit";
6
+ import { ForceFieldDetailsPanel } from "../force-field/ForceFieldDetailsPanel";
7
+ import { YinYangControllerState } from "../state/YinYangControllerState";
8
+ import { ComponentTitlePresenter } from "../labels/ComponentTitlePresenter";
9
+ import { ControllerSession } from "../state/ControllerSession";
10
+ import type { ControllerUiCallbacks } from "../state/ControllerUiCallbacks";
11
+ import { ForceFieldComputationService } from "../force-field/ForceFieldComputationService";
12
+ export type DiagramNavigatorDeps = {
13
+ computeComboResultsForAction: (actionId: string) => ComboResult[] | undefined;
14
+ animateChildrenHide: () => void;
15
+ buildChildrenOrbitData: () => ChildrenOrbitEntry[];
16
+ getChildControllers: () => IYinYangController[];
17
+ childOddMap: Map<string, {
18
+ oddId: string;
19
+ score: number;
20
+ cuttingIndex: number;
21
+ }>;
22
+ forceFieldComputationService: ForceFieldComputationService;
23
+ forceFieldDetailsPanel: ForceFieldDetailsPanel;
24
+ getAllComponents: () => YinYangInternalModel["components"];
25
+ getCurrentComponent: () => YinYangInternalModel["components"][number] | null;
26
+ getCurrentComponentOrUndefined: () => YinYangInternalModel["components"][number] | undefined;
27
+ renderCumulativeDetailsForCutting: (oddId: string, cuttingId: number | undefined) => boolean;
28
+ renderForceFieldDetails: (linkIndex: number) => void;
29
+ renderSourceActionDetailsForCurrentSource: (opts?: {
30
+ deltaOverride?: number;
31
+ comboResults?: ComboResult[];
32
+ }) => void;
33
+ session: ControllerSession;
34
+ state: YinYangControllerState;
35
+ titlePresenter: ComponentTitlePresenter;
36
+ ui: ControllerUiCallbacks;
37
+ view: IYinYangView;
38
+ };
39
+ /** Navigation dans le diagramme depuis les panneaux (source d'une action,
40
+ * prérequis, découpe ciblée, clic sur une étiquette de découpe) et fantôme
41
+ * HTML affiché pendant un glisser d'action. */
42
+ export declare class DiagramNavigator {
43
+ private deps;
44
+ constructor(deps: DiagramNavigatorDeps);
45
+ private htmlDragGhost;
46
+ navigateToSource(fromOddId: string, fromCuttingId: number | undefined, fromComponentId: string | undefined): void;
47
+ navigateToPrereqAction(actionId: string): void;
48
+ navigateToCutting(toOddId: string, toCuttingId: number | undefined, toComponentId: string | undefined): void;
49
+ /** Index (position dans l'ODD) d'un cutting à partir de son id — inverse
50
+ * de resolveOddCuttingId ; undefined si l'ODD ou l'id est inconnu. */
51
+ resolveCuttingIndex(component: YinYangInternalModel["components"][number], oddId: string, cuttingId: number): number | undefined;
52
+ notifyCuttingNavigated(oddId: string, cuttingId: number | undefined): void;
53
+ clientPointToGlobalGroup(clientX: number, clientY: number): {
54
+ x: number;
55
+ y: number;
56
+ } | null;
57
+ renderDragGhost(clientX: number, clientY: number, iconUrl: string): void;
58
+ removeDragGhost(): void;
59
+ onCuttingLabelClick(oddId: string, cuttingId: number | undefined): void;
60
+ resolveActionSource(component: YinYangComponentNode | undefined): {
61
+ oddId: string;
62
+ cuttingId: number | undefined;
63
+ } | undefined;
64
+ }
@@ -4,7 +4,7 @@ import { YinYangInternalModel } from "../../../interfaces/IYinYangInternalModel"
4
4
  import { ForceFieldDetailsPanel } from "../force-field/ForceFieldDetailsPanel";
5
5
  import { ActionStackController } from "../action-stack/ActionStackController";
6
6
  import { OddHighlightIntensity, ChildHighlightState } from "./childHighlightStyles";
7
- import type { CumulativeBlock } from "../YinYangController";
7
+ import type { CumulativeBlock } from "../types";
8
8
  type ChildOddMeta = {
9
9
  oddId: string;
10
10
  score: number;
@@ -83,6 +83,15 @@ type SearchPanelSynchronizerDeps = {
83
83
  x: number;
84
84
  y: number;
85
85
  } | null;
86
+ /** Glisser guidé d'un prérequis : réaffiche dans le panneau STACK les
87
+ * blocs de l'item de pile portant le combo. */
88
+ showStackItemBlocksForDrag: (stackItemId: string) => void;
89
+ /** Glisser guidé : aperçu en direct des cartes combo selon l'emplacement
90
+ * survolé (restaure le contenu d'origine hors glisser guidé). */
91
+ refreshGuidedComboPreview: () => void;
92
+ /** Sélectionne le satellite d'un item de pile et centre son bloc — même
93
+ * chemin qu'un clic sur le libellé de l'item dans la pile. */
94
+ focusStackItemSatellite: (stackItemId: string) => void;
86
95
  };
87
96
  /**
88
97
  * Coordonne le panneau RECHERCHE avec le diagramme — et héberge aussi le
@@ -0,0 +1,107 @@
1
+ import type { ForceFieldLink, ForceFieldLinkDetail } from "../force-field/types";
2
+ /** Contexte "incoming" préparé avant un changement de facette (voir
3
+ * ComponentSwitchContext). */
4
+ export type IncomingLinksByOddId = Map<string, {
5
+ toOddId: string;
6
+ thickness: number;
7
+ potentialGain: number;
8
+ detail: ForceFieldLinkDetail;
9
+ sourceOriginKey?: string;
10
+ }>;
11
+ /**
12
+ * Prepared by prepareForComponentSwitch() before children are hidden.
13
+ * undefined = not yet prepared (fallback path)
14
+ * null = prepared but no action applies to target component
15
+ * { type: 'incoming', ... } = show incoming force fields on arrival
16
+ * { type: 'reactivate' } = re-activate the source action on arrival
17
+ */
18
+ export type ComponentSwitchContext = undefined | null | {
19
+ type: "incoming";
20
+ sourceComponentId: string;
21
+ /** Keyed by the arrival's own identity (edgeId) — voir
22
+ * buildIncomingLinkKey — so that every arrival is preserved as a
23
+ * separate entry. `toOddId` is also stored in the value since the key
24
+ * is not the plain ODD id. */
25
+ linksByOddId: IncomingLinksByOddId;
26
+ } | {
27
+ type: "reactivate";
28
+ } | {
29
+ type: "searchCutting";
30
+ oddId: string;
31
+ cuttingIndex: number;
32
+ forceOpen?: boolean;
33
+ } | {
34
+ type: "searchOdd";
35
+ oddId: string;
36
+ } | {
37
+ type: "searchOddHighlight";
38
+ oddId: string;
39
+ } | {
40
+ type: "searchAction";
41
+ oddId: string;
42
+ cuttingIndex: number;
43
+ actionId: string;
44
+ } | {
45
+ type: "restoreAction";
46
+ oddId: string;
47
+ cuttingIndex: number;
48
+ actionId: string;
49
+ };
50
+ export type PersistentActionContext = {
51
+ sourceComponentId: string;
52
+ sourceOddId: string;
53
+ sourceCuttingIndex: number;
54
+ actionId: string;
55
+ actionLabel?: string;
56
+ links: ForceFieldLink[];
57
+ };
58
+ export type SourceFocus = {
59
+ oddId: string;
60
+ cuttingId: number | undefined;
61
+ };
62
+ /**
63
+ * État de navigation mutable partagé entre YinYangController et ses
64
+ * collaborateurs (bascule de facette, navigation, panneau de détails,
65
+ * Événements Clés). Regroupé ici pour que chacun lise et écrive la même
66
+ * instance plutôt que de passer par des getters/setters du contrôleur.
67
+ */
68
+ export declare class ControllerSession {
69
+ /**
70
+ * Persists the active action across component switches.
71
+ * Cleared only when the user explicitly deselects the action.
72
+ */
73
+ persistentActionContext: PersistentActionContext | null;
74
+ pendingComponentSwitchContext: ComponentSwitchContext;
75
+ selectedSourceFocus: SourceFocus | null;
76
+ /** Focus saved just before switching away from the source component, so returning
77
+ * to the source component restores the same highlighted cutting (multi-action). */
78
+ focusBeforeComponentSwitch: SourceFocus | null;
79
+ /** Cross-component force-field links from the source component, saved when
80
+ * switching away to a target component. Used to recompute the incoming view
81
+ * when a checkbox toggle fires while already on the target component. */
82
+ savedSourceComponentLinks: ForceFieldLink[];
83
+ /** Set by navigateToCutting for cross-component nav: after the switch the
84
+ * incoming force field context is established, then onCuttingLabelClick is
85
+ * called for this cutting to show its propagated card. */
86
+ pendingCuttingFocusAfterSwitch: SourceFocus | null;
87
+ pendingOddHighlightAfterSwitch: string | null;
88
+ /** Set by SearchPanelSynchronizer.searchNavigateToCutting when a stack-item
89
+ * click switches facette while an action is active: prepareForComponentSwitch
90
+ * owns pendingComponentSwitchContext for the incoming force field, so this
91
+ * navigation is applied separately once the switch completes. */
92
+ pendingCuttingNavigationAfterSwitch: {
93
+ oddId: string;
94
+ cuttingIndex: number;
95
+ forceOpen: boolean;
96
+ } | null;
97
+ /** Menu cœur à déployer à l'arrivée sur la facette (voir searchSetKeyEventMenuOpen). */
98
+ pendingKeyEventMenuAfterSwitch: boolean;
99
+ isCoreEventMenuOpen: boolean;
100
+ /** Id de l'Événement Clé actuellement en aperçu (carte affichée), ou null. */
101
+ activeKeyEventId: string | null;
102
+ /** Quand vrai, le prochain appel à onShowDirectActionBlock est routé vers le panneau B. */
103
+ routeNextDirectActionBlockToPanelB: boolean;
104
+ /** Quand vrai, renderSourceActionDetailsForCurrentSource ne re-rend pas le bloc Panel A.
105
+ * Utilisé pendant reactivatePersistentAction pour préserver l'état des <details> ouverts. */
106
+ suppressDirectActionBlockRender: boolean;
107
+ }
@@ -0,0 +1,60 @@
1
+ import type { DiagramNavEvent } from "../types";
2
+ type DirectActionBlockCallback = (compId: string, oddId: string, cutIdx: number, actionId: string, cardsHtml: string, attachHandlers: (container: HTMLElement) => void) => void;
3
+ /**
4
+ * Callbacks UI branchés depuis l'extérieur (main.ts, PanelManager,
5
+ * DiagramPanelBridge…) via les setOn* de YinYangController. Partagé tel quel
6
+ * avec les collaborateurs qui doivent notifier les panneaux.
7
+ */
8
+ export type ControllerUiCallbacks = {
9
+ /** Callback to open the search tab and set a query — wired from main.ts. */
10
+ openSearchWithQuery?: (query: string) => void;
11
+ /** Injecte le bloc d'impact d'action directe dans l'onglet Recherche. */
12
+ onShowDirectActionBlock?: DirectActionBlockCallback;
13
+ /** Affiche le bloc d'action directe d'un prérequis dans le panneau B. */
14
+ onShowDirectActionBlockPanelB?: DirectActionBlockCallback;
15
+ /** Efface le bloc d'impact d'action directe de l'onglet Recherche. */
16
+ onClearDirectActionBlock?: () => void;
17
+ /** Injecte la carte descriptive d'un Événement Clé dans l'onglet Recherche. */
18
+ onShowKeyEventBlock?: (compId: string, keyEventId: string, cardsHtml: string, attachHandlers: (container: HTMLElement) => void) => void;
19
+ /** Efface la carte d'Événement Clé de l'onglet Recherche. */
20
+ onClearKeyEventBlock?: () => void;
21
+ /** Notifie la hiérarchie RECHERCHE de l'état du menu radial des Événements
22
+ * Clés (diagramme → arbre), pour que le groupe "Événements Clés" reste le
23
+ * reflet exact des bulles réellement déployées. */
24
+ onKeyEventMenuStateChange?: (componentIndex: number, open: boolean) => void;
25
+ /** Injecte le bloc d'action propagée dans l'onglet Recherche. */
26
+ onShowPropagationBlock?: (compId: string, oddId: string, cutIdx: number, html: string, attachHandlers: (container: HTMLElement) => void, sourceDesc: {
27
+ breadcrumb: string;
28
+ title: string;
29
+ description: string;
30
+ }, rationale?: string) => void;
31
+ /** Efface le bloc d'action propagée de l'onglet Recherche. */
32
+ onClearPropagationBlock?: () => void;
33
+ onDiagramActionDragIntent?: () => void;
34
+ onActiveChildChange?: () => void;
35
+ onOuterSparkAutoToggle?: (enabled: boolean) => void;
36
+ /** Fired unconditionally at the end of onCuttingLabelClick (both the cumulative and
37
+ * the normal branch), regardless of which internal path handled the click, so that
38
+ * DiagramPanelBridge can keep the STACK hierarchy (chip + history) in sync even when
39
+ * the cumulative view intercepts the click before renderForceFieldDetails /
40
+ * onShowPropagationBlock is reached. Signature mirrors setOnPropagationBlock's
41
+ * (compId, oddId, cuttingIndex) shape so the same STACK-sync handler can be reused. */
42
+ onCuttingNavigated?: (compId: string, oddId: string, cuttingIndex: number) => void;
43
+ onDiagramOddChange?: (componentIndex: number, oddId: string, mode: "highlight") => void;
44
+ onDiagramNavChange?: (event: DiagramNavEvent) => void;
45
+ /** Fired when the user re-clicks the active satellite in the diagram (toggle-to-close),
46
+ * or when an ODD-level interaction deselects it — componentIndex lets the listener
47
+ * restore its detail panel to the facette view rather than clearing it entirely. */
48
+ onDiagramSatelliteDeselect?: (componentIndex: number) => void;
49
+ /** Fired when the user clicks the current composante's border arc to hide its satellites. */
50
+ onDiagramComposanteDeselect?: () => void;
51
+ /** Vers le panneau Recherche quand la souris entre/sort d'un satellite dans le diagramme. */
52
+ onDiagramChildHover?: ((componentIndex: number | null, oddId: string | null, cuttingIndex?: number) => void) | null;
53
+ /** Vers le panneau Recherche quand la souris entre/sort d'un arc de bordure (composante). */
54
+ onDiagramComposanteHover?: ((componentIndex: number | null) => void) | null;
55
+ /** Vers le panneau Recherche quand la souris entre/sort d'un cercle d'action dans le menu radial. */
56
+ onDiagramActionHover?: ((componentIndex: number | null, oddId: string | null, cuttingIndex: number | null, actionId: string | null) => void) | null;
57
+ /** Panneau RECHERCHE : la souris entre/sort d'un arc ODD dans le diagramme. */
58
+ onDiagramOddArcHover?: ((oddId: string | null) => void) | null;
59
+ };
60
+ export {};
@@ -47,7 +47,6 @@ export declare class YinYangControllerState {
47
47
  coreEventIconFontScale: number;
48
48
  };
49
49
  action: {
50
- propagationFactor: number;
51
50
  delta: number;
52
51
  };
53
52
  visibility: {
@@ -59,14 +58,14 @@ export declare class YinYangControllerState {
59
58
  * chaque plafond levé. Bornés (false) par défaut : comportement actuel. */
60
59
  combos: {
61
60
  /** Lève le plafond à 1 sur le ratio de performance des prérequis
62
- * DÉCLENCHEURS (combos non dangereux), ce qui autorise une cascade de
61
+ * DÉCLENCHEURS (exploitations éligibles), ce qui autorise une cascade de
63
62
  * combos à dépasser ×2. N'affecte pas les prérequis PROTECTEURS d'un
64
- * combo dangereux (voir dangerousComboCanBecomeBonus). */
63
+ * sécurisation (voir dangerousComboCanBecomeBonus). */
65
64
  uncappedChainedPerformance: boolean;
66
65
  /** Lève le plafond à 1 sur le ratio de performance des prérequis
67
- * PROTECTEURS d'un combo dangereux, ce qui permet à m = avgRatio de
66
+ * PROTECTEURS d'une sécurisation, ce qui permet à m = avgRatio de
68
67
  * dépasser ×1 (le risque devient un bonus net). N'affecte pas les
69
- * combos non dangereux (voir uncappedChainedPerformance). */
68
+ * exploitations éligibles (voir uncappedChainedPerformance). */
70
69
  dangerousComboCanBecomeBonus: boolean;
71
70
  };
72
71
  labels: {
@@ -0,0 +1,103 @@
1
+ import type { ForceFieldLinkDetail } from "./force-field/types";
2
+ import type { ComboResult } from "../../data/combo-engine";
3
+ import type { AmplifierResult, AmplifierTargetBreakdown } from "../../data/amplifier-engine";
4
+ import type { AbsorptionBreakdown, ActiveShield } from "./force-field/shieldViewModel";
5
+ /**
6
+ * Bloc "action" de la vue cumulative (mode STACK) : "source" = action jouée
7
+ * sur le satellite ciblé, "propagation" = effet indirect qui l'atteint depuis
8
+ * un autre satellite.
9
+ */
10
+ export type ActionCumulativeBlock = {
11
+ type: "source" | "propagation";
12
+ actionId?: string;
13
+ actionName: string;
14
+ actionDescription: string;
15
+ sourceComponentName?: string;
16
+ sourceOddName?: string;
17
+ /** Facette du satellite qui porte l'action (peut différer de la facette
18
+ * affichée pour un bloc de propagation). */
19
+ sourceComponentId?: string;
20
+ sourceOddId: string;
21
+ sourceCuttingId: number | undefined;
22
+ totalDelta: number;
23
+ rawDelta?: number;
24
+ baseDelta?: number;
25
+ weightDelta?: number;
26
+ weightDeltaBase?: number;
27
+ detailRows: ForceFieldLinkDetail[];
28
+ comboResults?: ComboResult[];
29
+ amplifierResults?: AmplifierResult[];
30
+ stackItemId?: string;
31
+ color?: string;
32
+ /** This item's own propagation edges from the real sequential
33
+ * simulation (see computeSequentialStackContributionsAtFocus) — lets
34
+ * the panel build this block's descriptive breakdown (cascade,
35
+ * absorption/gap badges, "satellites touchés" list) from data that
36
+ * exactly matches totalDelta, instead of the shared isolated pool. */
37
+ sequentialDetailPool?: ForceFieldLinkDetail[];
38
+ /** Arrivées de la seule résolution de ce bloc : pool séquentiel quand il
39
+ * existe, sinon les lignes de la résolution de cet item. Lues par les
40
+ * listes Source / Bilan et la comète (PROP-VIZ-01). */
41
+ resolutionPool?: ForceFieldLinkDetail[];
42
+ /** Position dans la pile (ActionStackItem.slotIndex) — permet de fusionner
43
+ * et trier les blocs "keyEvent" avec les blocs action dans leur ordre
44
+ * naturel de pile (voir renderCumulativeDetailsForCutting). */
45
+ slotIndex?: number;
46
+ /** Bouclier de stabilité déjà actif sur le satellite en focus quand ce
47
+ * bloc s'est résolu (bloc "source" uniquement). */
48
+ activeShield?: ActiveShield;
49
+ /** Bouclier créé par cette action (slots de stabilisation déclenchés). */
50
+ createdShield?: number;
51
+ /** Réduction appliquée par le bouclier du satellite en focus à la
52
+ * contribution négative de ce bloc — journal de résolution. */
53
+ shieldAbsorption?: AbsorptionBreakdown;
54
+ };
55
+ /**
56
+ * Bloc "keyEvent" de la vue cumulative : un Événement Clé joué (kind="keyEvent"
57
+ * dans la pile), toujours affiché dès que sa Facette d'origine correspond à
58
+ * celle affichée — voir buildKeyEventBlocksForComponent. `active` distingue
59
+ * visuellement "amplifie actuellement une action ciblée" de "présent mais
60
+ * rien ne l'active encore" (voir isKeyEventCurrentlyActive) ; l'existence du
61
+ * bloc, elle, ne dépend jamais de cette condition.
62
+ */
63
+ export type KeyEventCumulativeBlock = {
64
+ type: "keyEvent";
65
+ keyEventId: string;
66
+ active: boolean;
67
+ totalDelta: number;
68
+ slotIndex?: number;
69
+ stackItemId?: string;
70
+ color?: string;
71
+ targetedActions: Array<{
72
+ id: string;
73
+ name: string;
74
+ }>;
75
+ breakdowns?: AmplifierTargetBreakdown[];
76
+ };
77
+ /**
78
+ * Un bloc de la vue cumulative (mode STACK). Hissé au niveau module (au lieu
79
+ * d'un type local à renderCumulativeDetailsForCutting) pour être partagé avec
80
+ * buildKeyEventBlocksForComponent, réutilisé aussi par renderComposanteInfo
81
+ * quand aucun satellite n'est sélectionné.
82
+ */
83
+ export type CumulativeBlock = ActionCumulativeBlock | KeyEventCumulativeBlock;
84
+ /** Navigation diagramme → panneau RECHERCHE (voir setOnDiagramNavChange). */
85
+ export type DiagramNavEvent = {
86
+ type: "composante";
87
+ componentIndex: number;
88
+ } | {
89
+ type: "cutting";
90
+ componentIndex: number;
91
+ oddId: string;
92
+ cuttingIndex: number;
93
+ } | {
94
+ type: "action";
95
+ componentIndex: number;
96
+ oddId: string;
97
+ cuttingIndex: number;
98
+ actionId: string;
99
+ } | {
100
+ type: "keyEvent";
101
+ componentIndex: number;
102
+ keyEventId: string;
103
+ };
@@ -0,0 +1,15 @@
1
+ import type { ActionDefinition } from "../../../data/yasuni_actions";
2
+ import type { KeyEventDefinition } from "../../../data/yasuni_key_events";
3
+ /** Catalogue indexé par ID — instancié une seule fois au chargement du module. */
4
+ export declare const actionMap: Map<string, ActionDefinition>;
5
+ /**
6
+ * Cibles d'un Événement Clé prêtes pour buildKeyEventCardHtml : id + nom,
7
+ * la carte affichant pour chacune le seul bonus ajouté par l'effet (pas de
8
+ * deltas du catalogue à charrier jusque-là). Les deux points d'appel (clic
9
+ * sur le cercle central, cartes cumulées du panneau) passent par ici — une
10
+ * seule définition de la forme attendue.
11
+ */
12
+ export declare function buildKeyEventTargets(keyEvent: KeyEventDefinition): Array<{
13
+ id: string;
14
+ name: string;
15
+ }>;
@@ -1,9 +1,15 @@
1
- export type ForceFieldLayerType = "inter" | "intra" | "bridge";
2
- export type ForceFieldDeltaDetail = {
3
- layerType: ForceFieldLayerType;
1
+ import type { PropagationScope } from "../../../interfaces/IPropagationGraph";
2
+ /** Libellé de la portée réelle d'une arête du graphe unifié (PROP-GRAPH-04) :
3
+ * la même mécanique, seule la destination change. */
4
+ export declare function getScopeDisplayName(scope: PropagationScope): string;
5
+ /** Classe CSS d'une ligne selon sa portée (voir details-panel.css). */
6
+ export declare function getScopeCssClass(scope: PropagationScope): string;
7
+ /**
8
+ * Delta affiché sur un lien du champ de force qui regroupe plusieurs
9
+ * arrivées le long du même trajet (même satellite de départ, même cible) :
10
+ * leur somme, c'est-à-dire tout ce que ce trajet apporte réellement à la
11
+ * cible dans la résolution.
12
+ */
13
+ export declare function calculateDisplayedDelta(details: readonly {
4
14
  deltaTo: number;
5
- };
6
- export declare function getForceFieldWeightLabel(layerType: ForceFieldLayerType): string;
7
- export declare function getLayerDisplayName(layerType: ForceFieldLayerType): string;
8
- export declare function getPropagationCardTitle(layerType: ForceFieldLayerType): string;
9
- export declare function calculateDisplayedDelta(details: ForceFieldDeltaDetail[]): number;
15
+ }[]): number;