@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.
- package/dist/bundle.js +1 -1
- package/dist/types/adapters/yasuniCauseAdapter.d.ts +31 -5
- package/dist/types/api.d.ts +5 -1
- package/dist/types/components/controller/YinYangController.d.ts +63 -679
- package/dist/types/components/controller/action-stack/ActionStackController.d.ts +35 -0
- package/dist/types/components/controller/action-stack/ActionStackManager.d.ts +9 -0
- package/dist/types/components/controller/action-stack/StackFocusController.d.ts +105 -0
- package/dist/types/components/controller/actions/ActionProjectionService.d.ts +32 -3
- package/dist/types/components/controller/actions/ChildActionMenuController.d.ts +8 -4
- package/dist/types/components/controller/actions/CoreEventMenuController.d.ts +13 -13
- package/dist/types/components/controller/actions/KeyEventController.d.ts +192 -0
- package/dist/types/components/controller/actions/radialItemMenu.d.ts +0 -9
- package/dist/types/components/controller/children/ChildrenBuilder.d.ts +95 -0
- package/dist/types/components/controller/children/ComponentSwitchCoordinator.d.ts +80 -0
- package/dist/types/components/controller/debug/ControllerDebugTools.d.ts +81 -0
- package/dist/types/components/controller/force-field/ForceFieldComputationService.d.ts +3 -15
- package/dist/types/components/controller/force-field/ForceFieldDetailsPanel.d.ts +120 -66
- package/dist/types/components/controller/force-field/ForceFieldDetailsPresenter.d.ts +139 -0
- package/dist/types/components/controller/force-field/ForceFieldRenderer.d.ts +0 -8
- package/dist/types/components/controller/force-field/IncomingForceFieldService.d.ts +53 -0
- package/dist/types/components/controller/force-field/PropagationAnimator.d.ts +56 -0
- package/dist/types/components/controller/force-field/edgeIdentity.d.ts +28 -0
- package/dist/types/components/controller/force-field/incomingContinuation.d.ts +22 -0
- package/dist/types/components/controller/force-field/propagation-viz/PropagationCometPlayer.d.ts +60 -0
- package/dist/types/components/controller/force-field/propagation-viz/propagationVizLists.d.ts +51 -0
- package/dist/types/components/controller/force-field/propagation-viz/propagationVizModel.d.ts +60 -0
- package/dist/types/components/controller/force-field/propagationTree.d.ts +32 -0
- package/dist/types/components/controller/force-field/shieldViewModel.d.ts +79 -0
- package/dist/types/components/controller/force-field/types.d.ts +37 -10
- package/dist/types/components/controller/labels/ComponentTitlePresenter.d.ts +99 -0
- package/dist/types/components/controller/navigation/DiagramNavigator.d.ts +64 -0
- package/dist/types/components/controller/odd/OddViewManager.d.ts +1 -1
- package/dist/types/components/controller/search/SearchPanelSynchronizer.d.ts +9 -0
- package/dist/types/components/controller/state/ControllerSession.d.ts +107 -0
- package/dist/types/components/controller/state/ControllerUiCallbacks.d.ts +60 -0
- package/dist/types/components/controller/state/YinYangControllerState.d.ts +4 -5
- package/dist/types/components/controller/types.d.ts +103 -0
- package/dist/types/components/controller/utils/actionCatalog.d.ts +15 -0
- package/dist/types/components/controller/utils/forceFieldPresentation.d.ts +14 -8
- package/dist/types/components/search/GlobalSearchController.d.ts +68 -9
- package/dist/types/components/view/BorderDrawer.d.ts +5 -0
- package/dist/types/components/workspace/workspaceTemplate.d.ts +1 -1
- package/dist/types/config/propagationCometConfig.d.ts +9 -36
- package/dist/types/config/propagationCometVizConfig.d.ts +34 -0
- package/dist/types/data/activeDiagram.d.ts +4 -6
- package/dist/types/data/adverse-action-planner.d.ts +22 -0
- package/dist/types/data/catalogue-coverage.d.ts +26 -0
- package/dist/types/data/combo-engine.d.ts +76 -21
- package/dist/types/data/contacts/buildContactSphere.d.ts +23 -4
- package/dist/types/data/contacts/index.d.ts +6 -3
- package/dist/types/data/propagation-graph.d.ts +16 -0
- package/dist/types/data/stability-shield.d.ts +21 -0
- package/dist/types/data/yasuni_actions.d.ts +38 -5
- package/dist/types/data/yasuni_cause.d.ts +7 -0
- package/dist/types/data/yasuni_key_events.d.ts +3 -2
- package/dist/types/interfaces/IPropagationGraph.d.ts +39 -0
- package/dist/types/interfaces/IYinYangController.d.ts +2 -2
- package/dist/types/utils/actionPropagation.d.ts +104 -32
- package/dist/types/utils/adverseMode.d.ts +14 -0
- package/package.json +4 -2
- package/dist/types/components/controller/utils/forceFieldMetadata.d.ts +0 -4
- package/dist/types/data/yasuni_graph.d.ts +0 -22
- package/dist/types/data/yasuni_propagation_layers.d.ts +0 -3
- package/dist/types/interfaces/ICauseGraph.d.ts +0 -9
- package/dist/types/interfaces/IPropagationLayers.d.ts +0 -27
- package/dist/types/utils/causeGraph.d.ts +0 -6
|
@@ -47,11 +47,46 @@ export declare class ActionStackController {
|
|
|
47
47
|
maxDeltaMultiplier?: number;
|
|
48
48
|
direction?: "forward" | "backward";
|
|
49
49
|
}): void;
|
|
50
|
+
/**
|
|
51
|
+
* Guide de placement d'un prérequis : un clic sur un prérequis absent de la
|
|
52
|
+
* pile (carte combo en mode STACK) ouvre RECHERCHE sur cette action et
|
|
53
|
+
* mémorise ici le contexte du combo. Dès que l'utilisateur glisse cette
|
|
54
|
+
* action vers la pile, les barres de position du combo réapparaissent —
|
|
55
|
+
* sans avoir à déposer puis recliquer sur la carte combo.
|
|
56
|
+
*/
|
|
57
|
+
private _prereqDragGuide;
|
|
58
|
+
/** Vrai pendant un glisser guidé : les re-rendus du panneau (bascule
|
|
59
|
+
* RECHERCHE → STACK) ne doivent pas effacer les barres en plein geste. */
|
|
60
|
+
private _prereqDragGuideActive;
|
|
61
|
+
setPrereqDragGuide(actionId: string, context: Parameters<ActionStackController["highlightComboContext"]>[0]): void;
|
|
62
|
+
/** Début du glisser de `actionId` vers la pile : affiche les barres du
|
|
63
|
+
* combo mémorisé si cette action en est le prérequis. Retourne l'item de
|
|
64
|
+
* pile portant le combo (pour réafficher son bloc), ou null. */
|
|
65
|
+
beginPrereqDragGuide(actionId: string): string | null;
|
|
66
|
+
/** Guide en cours de glisser : action glissée et item portant le combo. */
|
|
67
|
+
getActivePrereqDragGuide(): {
|
|
68
|
+
actionId: string;
|
|
69
|
+
sourceItemId: string;
|
|
70
|
+
} | null;
|
|
71
|
+
/**
|
|
72
|
+
* Historique slot-paddé (cf. getSlotPaddedActionIds) que verrait l'item
|
|
73
|
+
* `anchorItemId` si `insertedActionId` était déposé à l'emplacement
|
|
74
|
+
* actuellement survolé — même arithmétique d'insertion avec décalage que
|
|
75
|
+
* ActionStackState.addItem, sans muter la pile. null hors zone de dépôt.
|
|
76
|
+
*/
|
|
77
|
+
getPriorIdsIfInsertedAtPreview(anchorItemId: string, insertedActionId: string): string[] | null;
|
|
78
|
+
/** Fin du glisser (dépôt ou abandon). Les barres restent affichées ; un
|
|
79
|
+
* dépôt consomme le guide, un abandon le garde pour un nouvel essai. */
|
|
80
|
+
endPrereqDragGuide(dropped: boolean): void;
|
|
50
81
|
/** Efface le surlignage combo et restaure l'apparence normale du stack. */
|
|
51
82
|
clearComboHighlight(): void;
|
|
52
83
|
setBlockHighlightCallback(cb: (id: string | null) => void): void;
|
|
53
84
|
setSatelliteHighlightCallback(cb: (id: string | null) => void): void;
|
|
54
85
|
getItemById(id: string): ActionStackItem | undefined;
|
|
86
|
+
/** Même effet qu'un clic sur le libellé de l'item (selectSatelliteForItem) :
|
|
87
|
+
* sélection de son satellite ou de sa Facette, focus — ou défocus s'il
|
|
88
|
+
* était déjà en focus. Sert aux bulles du diagramme en mode STACK. */
|
|
89
|
+
selectItemAsFromLabel(stackItemId: string): void;
|
|
55
90
|
highlightByStackItemId(id: string | null): void;
|
|
56
91
|
/** Focus persistant (miroir du bloc en focus dans le panneau) — survit aux
|
|
57
92
|
* re-rendus, updateVisual relisant _focusedItemId. */
|
|
@@ -92,6 +92,15 @@ export declare class ActionStackManager {
|
|
|
92
92
|
getWeightDeltaByComponentOddCutting(): Map<string, number>;
|
|
93
93
|
clearWeightPreview(): void;
|
|
94
94
|
resetLastComboResults(): void;
|
|
95
|
+
/**
|
|
96
|
+
* Résultats combo d'une action. En mode STACK, ils tiennent compte de la
|
|
97
|
+
* pile (résultats de l'item s'il est empilé, sinon évaluation en haut de
|
|
98
|
+
* pile). En mode RECHERCHE, l'action est montrée BRUTE : la pile est
|
|
99
|
+
* ignorée (historique vide), ses prérequis apparaissent donc non joués,
|
|
100
|
+
* même s'ils sont empilés — seul le mode STACK fait jouer la pile.
|
|
101
|
+
* Exception : une sécurisation y est évaluée protecteurs supposés joués
|
|
102
|
+
* (×1), sinon elle serait toujours à ×0 et masquerait la propagation.
|
|
103
|
+
*/
|
|
95
104
|
computeComboResultsForAction(actionId: string): ComboResult[] | undefined;
|
|
96
105
|
validateActionSelection(childController: IYinYangController, actionId: string, label: string, insertAtVisibleIndex?: number | null, entryOrigin?: {
|
|
97
106
|
x: number;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { IYinYangController } from "../../../interfaces/IYinYangController";
|
|
2
|
+
import { YinYangInternalModel } from "../../../interfaces/IYinYangInternalModel";
|
|
3
|
+
import { ChildrenOrbitEntry } from "../utils/childrenOrbit";
|
|
4
|
+
import { ChildActionMenuController } from "../actions/ChildActionMenuController";
|
|
5
|
+
import { ActionStackController, ActionStackItem } from "./ActionStackController";
|
|
6
|
+
import { ForceFieldDetailsPanel } from "../force-field/ForceFieldDetailsPanel";
|
|
7
|
+
import { YinYangControllerState } from "../state/YinYangControllerState";
|
|
8
|
+
import { PropagationAnimator } from "../force-field/PropagationAnimator";
|
|
9
|
+
import { OddViewManager } from "../odd/OddViewManager";
|
|
10
|
+
export type StackFocusControllerDeps = {
|
|
11
|
+
actionStackController: ActionStackController;
|
|
12
|
+
buildChildrenOrbitData: () => ChildrenOrbitEntry[];
|
|
13
|
+
buildForceFieldSourceIndicesFromStackItems: (items: ActionStackItem[]) => number[];
|
|
14
|
+
childActionMenuController: ChildActionMenuController;
|
|
15
|
+
getChildControllers: () => IYinYangController[];
|
|
16
|
+
childOddMap: Map<string, {
|
|
17
|
+
oddId: string;
|
|
18
|
+
score: number;
|
|
19
|
+
cuttingIndex: number;
|
|
20
|
+
}>;
|
|
21
|
+
forceFieldDetailsPanel: ForceFieldDetailsPanel;
|
|
22
|
+
getAllComponents: () => YinYangInternalModel["components"];
|
|
23
|
+
getCurrentComponentOrUndefined: () => YinYangInternalModel["components"][number] | undefined;
|
|
24
|
+
oddViewManager: OddViewManager;
|
|
25
|
+
propagationAnimator: PropagationAnimator;
|
|
26
|
+
state: YinYangControllerState;
|
|
27
|
+
updateChildActionMenu: (orbitData: ChildrenOrbitEntry[]) => void;
|
|
28
|
+
};
|
|
29
|
+
/** Focus et emphase d'un élément de pile : satellite source mis en valeur,
|
|
30
|
+
* identité de la source pour l'atténuation du champ, bulle d'action en focus. */
|
|
31
|
+
export declare class StackFocusController {
|
|
32
|
+
private deps;
|
|
33
|
+
constructor(deps: StackFocusControllerDeps);
|
|
34
|
+
/** Focus persistant — null pour l'effacer. */
|
|
35
|
+
setFocusedStackItem(stackItemId: string | null): void;
|
|
36
|
+
/**
|
|
37
|
+
* Clic sur le libellé d'un item déjà en focus, alors que son bloc est
|
|
38
|
+
* visible dans le panneau (satellite porteur sélectionné) : désactive le
|
|
39
|
+
* focus et retourne true — l'appelant n'a alors ni navigation ni scroll à
|
|
40
|
+
* faire. Si le bloc n'est pas visible (l'utilisateur a navigué ailleurs
|
|
41
|
+
* entre-temps), le clic redevient une sélection normale : false.
|
|
42
|
+
*/
|
|
43
|
+
toggleStackItemFocusFromStack(stackItemId: string): boolean;
|
|
44
|
+
/** Aperçu par survol — null à la sortie, qui retombe sur le focus. */
|
|
45
|
+
setStackItemEmphasisPreview(stackItemId: string | null): void;
|
|
46
|
+
/**
|
|
47
|
+
* Point d'accroche unique de la mise en valeur du satellite source de
|
|
48
|
+
* l'action portant l'emphase (aperçu ?? focus). Réutilise pour l'instant
|
|
49
|
+
* le glow de highlightOddByStackItemId (ou le segment de bordure si la
|
|
50
|
+
* source est dans une autre facette) — l'anneau animé viendra ici.
|
|
51
|
+
* `clearIfNone` : sans emphase, efface la mise en valeur (sorties de
|
|
52
|
+
* survol, défocus) ; false pour les simples re-applications (satellites
|
|
53
|
+
* recréés, fin d'un survol de satellite) afin de ne pas écraser d'autres
|
|
54
|
+
* highlights en cours.
|
|
55
|
+
*/
|
|
56
|
+
applyFocusedSourceHighlight(clearIfNone?: boolean): void;
|
|
57
|
+
/** Memo à une entrée de resolveEmphasisSourceChildIndex (lu chaque frame). */
|
|
58
|
+
private _emphasisSourceMemo;
|
|
59
|
+
/**
|
|
60
|
+
* Index orbital du satellite source de l'action portant l'emphase, ou null
|
|
61
|
+
* si rien ne doit être atténué : hors mode STACK (un aperçu RECHERCHE ne
|
|
62
|
+
* doit pas hériter d'un focus STACK résiduel), item absent, Événement Clé
|
|
63
|
+
* (pas de champ de force), ou source dans une autre facette (tout reste
|
|
64
|
+
* plein, la bordure source est surlignée par highlightOddByStackItemId).
|
|
65
|
+
* Résolution par oddId + cuttingIndex (buildForceFieldSourceIndicesFromStackItems),
|
|
66
|
+
* robuste au rebuild de childOddMap ; la clé du memo suit la convention de
|
|
67
|
+
* ForceFieldLifecycleController._buildPropCacheKey.
|
|
68
|
+
*/
|
|
69
|
+
resolveEmphasisSourceChildIndex(): number | null;
|
|
70
|
+
/** Identité stable (sourceOriginKey) du satellite source d'un item de la
|
|
71
|
+
* pile — null pour un Événement Clé ou une facette introuvable. */
|
|
72
|
+
stackItemSourceOriginKey(item: ActionStackItem): string | null;
|
|
73
|
+
private _emphasisKeyMemo;
|
|
74
|
+
/** Clé de la source de l'action portant l'emphase (aperçu ?? focus), quelle
|
|
75
|
+
* que soit sa facette ; null hors STACK ou sans emphase. Lue à chaque frame. */
|
|
76
|
+
resolveEmphasisSourceOriginKey(): string | null;
|
|
77
|
+
/** Memo à une entrée de resolveFocusedActionSource (lu à chaque update du menu). */
|
|
78
|
+
private _focusSourceMemo;
|
|
79
|
+
/**
|
|
80
|
+
* Action en focus (focus persistant seulement, pas l'aperçu par survol —
|
|
81
|
+
* une bulle qui apparaît/disparaît au survol serait du bruit), résolue en
|
|
82
|
+
* (actionId, clé et index orbital du satellite source) dans la facette
|
|
83
|
+
* courante. null hors mode STACK, sans focus, pour un Événement Clé, ou si
|
|
84
|
+
* la source vit dans une autre facette.
|
|
85
|
+
*/
|
|
86
|
+
resolveFocusedActionSource(): {
|
|
87
|
+
actionId: string;
|
|
88
|
+
sourceKey: string;
|
|
89
|
+
sourceIndex: number;
|
|
90
|
+
} | null;
|
|
91
|
+
/**
|
|
92
|
+
* Point de départ « bulle » du champ de force de l'action en focus : la
|
|
93
|
+
* bulle de son action dans le menu radial si le satellite source est celui
|
|
94
|
+
* sélectionné, sinon la bulle détachée posée sur la source. null si
|
|
95
|
+
* aucune bulle n'est visible (le champ démarre alors au satellite).
|
|
96
|
+
*/
|
|
97
|
+
resolveFocusBubbleStub(): {
|
|
98
|
+
sourceChildIndex: number;
|
|
99
|
+
center: {
|
|
100
|
+
x: number;
|
|
101
|
+
y: number;
|
|
102
|
+
};
|
|
103
|
+
} | null;
|
|
104
|
+
highlightOddByStackItemId(stackItemId: string | null): void;
|
|
105
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { YinYangInternalModel } from "../../../interfaces/IYinYangInternalModel";
|
|
2
|
-
import { type PropagatedActionEdge } from "../../../utils/actionPropagation";
|
|
2
|
+
import { type PropagatedActionEdge, type PropagationTruncation } from "../../../utils/actionPropagation";
|
|
3
3
|
import { ForceFieldLink } from "../force-field/types";
|
|
4
4
|
export type ProjectedCuttingState = {
|
|
5
5
|
cuttingId: number;
|
|
@@ -17,6 +17,12 @@ export type GhostProjectionResult = {
|
|
|
17
17
|
export type SequentialActionProjectionInput = {
|
|
18
18
|
sourceOddId: string;
|
|
19
19
|
sourceCuttingIndex: number;
|
|
20
|
+
/** Bouclier de stabilité (points d'état) que cette action crée sur son
|
|
21
|
+
* satellite source une fois résolue — issu de ses slots de stabilisation
|
|
22
|
+
* déclenchés (voir stabilityShieldFromResults). Actif pour toutes les
|
|
23
|
+
* résolutions suivantes de la séquence, jamais consommé ; le plus fort
|
|
24
|
+
* remplace le précédent sur un même satellite. */
|
|
25
|
+
shield?: number;
|
|
20
26
|
};
|
|
21
27
|
export type EmptyGhostProjectionState = {
|
|
22
28
|
projectedGhostTensionByOddId: null;
|
|
@@ -30,10 +36,31 @@ export declare function projectGhostStateForIncomingLinks(params: {
|
|
|
30
36
|
incomingLinks: ForceFieldLink[];
|
|
31
37
|
}): GhostProjectionResult | null;
|
|
32
38
|
export type ActionSequenceStateSnapshot = Map<string, Map<number, number>>;
|
|
39
|
+
/** Réduction appliquée par un bouclier de stabilité lors d'une étape :
|
|
40
|
+
* le satellite recevait `aggregated` (total négatif direct + propagé),
|
|
41
|
+
* il ne reçoit finalement que `applied`. */
|
|
42
|
+
export type ShieldAbsorption = {
|
|
43
|
+
oddId: string;
|
|
44
|
+
cuttingId: number;
|
|
45
|
+
shield: number;
|
|
46
|
+
aggregated: number;
|
|
47
|
+
applied: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Bouclier de stabilité sur UNE résolution : pour chaque satellite protégé,
|
|
51
|
+
* la variation de toute l'étape (état projeté − état de départ) agrège déjà
|
|
52
|
+
* le delta direct et tous les chemins propagés ; le bouclier réduit ce
|
|
53
|
+
* total une seule fois — jamais chaque contribution séparément, jamais
|
|
54
|
+
* au-delà de 0. Mute `projectedStates` et rend les réductions appliquées.
|
|
55
|
+
*/
|
|
56
|
+
export declare function applyStabilityShieldsToResolution(startStates: Record<string, Record<number, number>>, projectedStates: Record<string, Record<number, number>>, activeShields: Map<string, Map<number, number>>): ShieldAbsorption[];
|
|
33
57
|
export type ActionSequenceStepInfo = {
|
|
34
58
|
actionIndex: number;
|
|
35
59
|
action: SequentialActionProjectionInput;
|
|
36
60
|
effectiveDelta: number;
|
|
61
|
+
/** Boucliers ayant réduit une contribution négative de cette étape — vide
|
|
62
|
+
* si aucun satellite protégé n'a été touché négativement. */
|
|
63
|
+
shieldAbsorptions: ShieldAbsorption[];
|
|
37
64
|
/** Clone of the fractional accumulator just before this step is applied. */
|
|
38
65
|
statesBefore: ActionSequenceStateSnapshot;
|
|
39
66
|
/** Clone of the fractional accumulator just after this step is applied. */
|
|
@@ -44,13 +71,16 @@ export type ActionSequenceStepInfo = {
|
|
|
44
71
|
* callers build a descriptive breakdown (e.g. UI badges) that's guaranteed
|
|
45
72
|
* consistent with the state diff, without re-running propagation. */
|
|
46
73
|
edges: PropagatedActionEdge[];
|
|
74
|
+
/** Passes locales interrompues par la garde technique pendant cette étape
|
|
75
|
+
* (PROP-01) — vide si la résolution est complète. Un appelant qui affiche
|
|
76
|
+
* l'étape doit signaler un résultat partiel plutôt que le taire. */
|
|
77
|
+
truncations: PropagationTruncation[];
|
|
47
78
|
};
|
|
48
79
|
export declare function projectGhostStateForActionSequence(params: {
|
|
49
80
|
component: YinYangInternalModel["components"][number] | undefined;
|
|
50
81
|
allComponents: YinYangInternalModel["components"] | undefined;
|
|
51
82
|
actions: SequentialActionProjectionInput[];
|
|
52
83
|
actionDelta: number;
|
|
53
|
-
actionPropagationFactor: number;
|
|
54
84
|
/** Delta effectif par action (index-aligné sur `actions`). Quand fourni,
|
|
55
85
|
* remplace `actionDelta` pour chaque action individuellement. */
|
|
56
86
|
actionDeltas?: number[];
|
|
@@ -67,7 +97,6 @@ export declare function projectGhostStateForComponent(params: {
|
|
|
67
97
|
sourceOddId: string | undefined;
|
|
68
98
|
sourceCuttingIndex: number;
|
|
69
99
|
actionDelta: number;
|
|
70
|
-
actionPropagationFactor: number;
|
|
71
100
|
}): GhostProjectionResult | null;
|
|
72
101
|
export declare function getOriginalComponentTension(component: YinYangInternalModel["components"][number] | undefined): number | null;
|
|
73
102
|
export declare function getOriginalOddTension(component: YinYangInternalModel["components"][number] | undefined, oddId: string): number | null;
|
|
@@ -23,14 +23,18 @@ type ChildActionMenuContext = {
|
|
|
23
23
|
childActionIconFontScale: number;
|
|
24
24
|
/** Actions filtrées pour le cutting actif (depuis yasuniCause + actionMap). */
|
|
25
25
|
actionsForActiveChild: ActionDefinition[];
|
|
26
|
+
/** Mode STACK : la seule bulle déployée est celle de l'item en focus, et
|
|
27
|
+
* son clic vaut clic sur le libellé de cet item dans la pile (ni aperçu,
|
|
28
|
+
* ni glisser). null hors STACK. */
|
|
29
|
+
onStackBubbleClick: (() => void) | null;
|
|
26
30
|
};
|
|
27
31
|
export declare class ChildActionMenuController {
|
|
28
32
|
private readonly view;
|
|
29
33
|
private readonly getChildRenderedCenter;
|
|
30
34
|
private readonly refreshActionStackVisual;
|
|
31
|
-
/** Aperçu —
|
|
35
|
+
/** Aperçu — clic sur une action : affiche sa carte, ne joue rien. */
|
|
32
36
|
private readonly activateActionFromChild;
|
|
33
|
-
/** Validation —
|
|
37
|
+
/** Validation — dépôt d'une bulle glissée sur la pile : l'y ajoute. */
|
|
34
38
|
private readonly validateActionSelection;
|
|
35
39
|
/** Glisser une bulle vers une position précise de la pile — cœur partagé
|
|
36
40
|
* avec le glisser-déposer depuis la hiérarchie RECHERCHE et depuis le
|
|
@@ -68,9 +72,9 @@ export declare class ChildActionMenuController {
|
|
|
68
72
|
/** Centre de la bulle détachée si elle porte `actionId`, sinon null. */
|
|
69
73
|
getDetachedCenter(actionId: string): Point | null;
|
|
70
74
|
constructor(view: IYinYangView, getChildRenderedCenter: (childController: IYinYangController) => Point | null, refreshActionStackVisual: () => void,
|
|
71
|
-
/** Aperçu —
|
|
75
|
+
/** Aperçu — clic sur une action : affiche sa carte, ne joue rien. */
|
|
72
76
|
activateActionFromChild: (childController: IYinYangController, actionId: string, label?: string) => void,
|
|
73
|
-
/** Validation —
|
|
77
|
+
/** Validation — dépôt d'une bulle glissée sur la pile : l'y ajoute. */
|
|
74
78
|
validateActionSelection: (childController: IYinYangController, actionId: string, label: string, insertAtVisibleIndex?: number | null, entryOrigin?: Point) => void,
|
|
75
79
|
/** Glisser une bulle vers une position précise de la pile — cœur partagé
|
|
76
80
|
* avec le glisser-déposer depuis la hiérarchie RECHERCHE et depuis le
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IYinYangView } from "../../../interfaces/IYinYangView";
|
|
2
|
-
import type
|
|
2
|
+
import { type KeyEventDefinition } from "../../../data/yasuni_key_events";
|
|
3
3
|
import { type Point } from "./radialItemMenu";
|
|
4
4
|
type CoreEventMenuContext = {
|
|
5
5
|
/** null/false ferme le menu (même logique que activeActionMenuChildKey côté satellite). */
|
|
@@ -30,18 +30,18 @@ type CoreEventMenuContext = {
|
|
|
30
30
|
* Menu radial des Événements Clés, déclenché par un clic sur le cercle
|
|
31
31
|
* central (yin-yang) de la facette active — même langage visuel et même
|
|
32
32
|
* sémantique de clic que ChildActionMenuController (bulles + icône,
|
|
33
|
-
* chorégraphie D3 en éventail
|
|
34
|
-
*
|
|
33
|
+
* chorégraphie D3 en éventail factorisée dans radialItemMenu.ts ; clic =
|
|
34
|
+
* aperçu, glisser vers la pile = validation), mais ancré sur
|
|
35
35
|
* le centre fixe de la facette plutôt que sur un satellite, et déployé à
|
|
36
36
|
* angle égal sur 360° plutôt que sur un axe source.
|
|
37
37
|
*/
|
|
38
38
|
export declare class CoreEventMenuController {
|
|
39
39
|
private readonly view;
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*
|
|
40
|
+
/** Clic sur une bulle — aperçu, ou focus de son item de pile en STACK
|
|
41
|
+
* (voir KeyEventController.onKeyEventBubbleClick). */
|
|
42
|
+
private readonly onKeyEventClick;
|
|
43
|
+
/** Validation — dépôt d'une bulle glissée sur la pile : l'y ajoute à
|
|
44
|
+
* insertAtVisibleIndex (voir startKeyEventDrag). */
|
|
45
45
|
private readonly validateKeyEventSelection;
|
|
46
46
|
/** Glisser une bulle vers une position précise de la pile — même cœur
|
|
47
47
|
* partagé que ChildActionMenuController.startActionDrag (voir
|
|
@@ -66,11 +66,11 @@ export declare class CoreEventMenuController {
|
|
|
66
66
|
* impulsion ne doit pas relancer toute la chorégraphie. */
|
|
67
67
|
private linkStyleGetter;
|
|
68
68
|
constructor(view: IYinYangView,
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
*
|
|
69
|
+
/** Clic sur une bulle — aperçu, ou focus de son item de pile en STACK
|
|
70
|
+
* (voir KeyEventController.onKeyEventBubbleClick). */
|
|
71
|
+
onKeyEventClick: (keyEvent: KeyEventDefinition) => void,
|
|
72
|
+
/** Validation — dépôt d'une bulle glissée sur la pile : l'y ajoute à
|
|
73
|
+
* insertAtVisibleIndex (voir startKeyEventDrag). */
|
|
74
74
|
validateKeyEventSelection: (keyEvent: KeyEventDefinition, insertAtVisibleIndex?: number | null, entryOrigin?: Point) => void,
|
|
75
75
|
/** Glisser une bulle vers une position précise de la pile — même cœur
|
|
76
76
|
* partagé que ChildActionMenuController.startActionDrag (voir
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { IYinYangView } from "../../../interfaces/IYinYangView";
|
|
2
|
+
import { YinYangInternalModel } from "../../../interfaces/IYinYangInternalModel";
|
|
3
|
+
import { type KeyEventDefinition } from "../../../data/yasuni_key_events";
|
|
4
|
+
import { ChildrenOrbitEntry } from "../utils/childrenOrbit";
|
|
5
|
+
import { CoreEventMenuController } from "./CoreEventMenuController";
|
|
6
|
+
import { ActionStackController } from "../action-stack/ActionStackController";
|
|
7
|
+
import { ForceFieldDetailsPanel } from "../force-field/ForceFieldDetailsPanel";
|
|
8
|
+
import { EventFieldRenderer } from "../force-field/EventFieldRenderer";
|
|
9
|
+
import { YinYangControllerState } from "../state/YinYangControllerState";
|
|
10
|
+
import { ComponentTitlePresenter } from "../labels/ComponentTitlePresenter";
|
|
11
|
+
import { ControllerSession } from "../state/ControllerSession";
|
|
12
|
+
import type { ControllerUiCallbacks } from "../state/ControllerUiCallbacks";
|
|
13
|
+
import { EventFieldLifecycleController } from "../force-field/EventFieldLifecycleController";
|
|
14
|
+
import { ActionStackManager } from "../action-stack/ActionStackManager";
|
|
15
|
+
export type KeyEventControllerDeps = {
|
|
16
|
+
actionStackController: ActionStackController;
|
|
17
|
+
actionStackManager: ActionStackManager;
|
|
18
|
+
animateChildrenHide: () => void;
|
|
19
|
+
buildChildrenOrbitData: () => ChildrenOrbitEntry[];
|
|
20
|
+
closeChildActionMenu: () => void;
|
|
21
|
+
coreEventMenuController: CoreEventMenuController;
|
|
22
|
+
eventFieldLifecycleController: EventFieldLifecycleController;
|
|
23
|
+
eventFieldRenderer: EventFieldRenderer;
|
|
24
|
+
forceFieldDetailsPanel: ForceFieldDetailsPanel;
|
|
25
|
+
getComponentBorderTargetPoint: (componentId: string) => {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
} | null;
|
|
29
|
+
getCurrentComponentOrUndefined: () => YinYangInternalModel["components"][number] | undefined;
|
|
30
|
+
navigateToPrereqAction: (actionId: string) => void;
|
|
31
|
+
prepareForComponentSwitch: (targetComponentId: string) => void;
|
|
32
|
+
session: ControllerSession;
|
|
33
|
+
state: YinYangControllerState;
|
|
34
|
+
titlePresenter: ComponentTitlePresenter;
|
|
35
|
+
ui: ControllerUiCallbacks;
|
|
36
|
+
view: IYinYangView;
|
|
37
|
+
};
|
|
38
|
+
/** Événements Clés : menu radial du cœur, aperçu de carte, champ
|
|
39
|
+
* d'événement et ajout à la pile. */
|
|
40
|
+
export declare class KeyEventController {
|
|
41
|
+
private deps;
|
|
42
|
+
constructor(deps: KeyEventControllerDeps);
|
|
43
|
+
/**
|
|
44
|
+
* Appelé par YinYangDrawer quand le petit cercle "œil" du lobe dominant
|
|
45
|
+
* (yin ou yang, selon Composante.orientation) est cliqué — jamais l'autre
|
|
46
|
+
* lobe, jamais un satellite (garde déjà appliquée côté YinYangDrawer, même
|
|
47
|
+
* principe que onDiagramOddArcClicked pour les arcs ODD). Ouvre/ferme le
|
|
48
|
+
* menu radial des Événements Clés de la facette active.
|
|
49
|
+
*/
|
|
50
|
+
onCoreEventNucleusClicked(): void;
|
|
51
|
+
notifyKeyEventMenuState(open: boolean): void;
|
|
52
|
+
private toggleCoreEventMenu;
|
|
53
|
+
/**
|
|
54
|
+
* Fermeture du Champ d'événement : l'Événement Clé en aperçu et les bulles
|
|
55
|
+
* du menu cœur — chemin unique partagé par la fermeture de facette
|
|
56
|
+
* (closeCurrentComposante) et par l'exclusivité action/événement
|
|
57
|
+
* (openActionMenuFromChild). No-op si rien n'est ouvert.
|
|
58
|
+
*
|
|
59
|
+
* hide() d'abord pour la rétraction immédiate du souffle (le geste
|
|
60
|
+
* d'ouverture joué à l'envers — cf. prepareForComponentSwitch),
|
|
61
|
+
* updateCoreEventMenu() ensuite pour replier les bulles et laisser
|
|
62
|
+
* refreshTargets constater qu'il n'y a plus rien à dessiner. La carte du
|
|
63
|
+
* panneau RECHERCHE part avec : elle décrit l'Événement Clé qu'on vient de
|
|
64
|
+
* retirer du diagramme, et rien ne garantit qu'un autre bloc prenne sa
|
|
65
|
+
* place (ouvrir un satellite n'affiche qu'un descriptif, pas un bloc).
|
|
66
|
+
*/
|
|
67
|
+
closeKeyEventField(): void;
|
|
68
|
+
updateCoreEventMenu(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Événements Clés qui pilotent le Champ d'événement en ce moment — source
|
|
71
|
+
* unique de vérité pour EventFieldLifecycleController (cibles) comme pour
|
|
72
|
+
* getEventFieldSource (point d'émission).
|
|
73
|
+
*
|
|
74
|
+
* Deux régimes, mêmes règles de priorité que le champ de force d'action :
|
|
75
|
+
* un APERÇU (clic sur une bulle du menu cœur ou sur l'entrée de l'arbre
|
|
76
|
+
* RECHERCHE) prend toujours la main — c'est le geste que l'utilisateur
|
|
77
|
+
* vient de faire, quel que soit l'onglet ; sinon, en mode STACK, ce sont
|
|
78
|
+
* les Événements Clés COCHÉS de la pile qui décident, exactement comme les
|
|
79
|
+
* actions cochées y décident des champs de force. En mode RECHERCHE sans
|
|
80
|
+
* aperçu, rien : la pile n'a pas voix au chapitre.
|
|
81
|
+
*
|
|
82
|
+
* Le renderer n'a qu'une source (le souffle part d'UN point, voir
|
|
83
|
+
* EventFieldRenderer), donc on ne renvoie jamais qu'un jeu d'événements
|
|
84
|
+
* partageant la même : ceux nés de la facette courante partent tous de son
|
|
85
|
+
* cœur et se cumulent ; à défaut, on retombe sur le plus récent des
|
|
86
|
+
* événements distants qui atteignent cette facette (mode entrant, source =
|
|
87
|
+
* l'arc de sa facette d'origine).
|
|
88
|
+
*/
|
|
89
|
+
getEventFieldKeyEvents(): KeyEventDefinition[];
|
|
90
|
+
/**
|
|
91
|
+
* Point d'émission du Champ d'événement : le CŒUR du yin/yang, c'est-à-dire
|
|
92
|
+
* le disque central du lobe correspondant à l'orientation de la facette
|
|
93
|
+
* courante — le cœur noir du yang sur une facette Yang, le cœur blanc du
|
|
94
|
+
* yin sur une facette Yin. Ce n'est PAS le centre géométrique du symbole :
|
|
95
|
+
* les deux lobes ont des rayons qui varient avec le score, donc le cœur se
|
|
96
|
+
* déplace le long de l'axe vertical au fil de la partie, d'où la
|
|
97
|
+
* relecture de la géométrie à chaque frame. Injecté dans
|
|
98
|
+
* EventFieldLifecycleController (getEventFieldSource), rappelé à chaque
|
|
99
|
+
* frame de son animation.
|
|
100
|
+
*
|
|
101
|
+
* `geometry.yin/yang.centerY` est la position CANONIQUE (pré-rotation) :
|
|
102
|
+
* pendant une rotation Yin/Yang (AnimationsMngr), le cœur visible se
|
|
103
|
+
* déplace via un `transform` écrit à même `graphElementGroup` à chaque
|
|
104
|
+
* frame, sans jamais toucher `geometry`. On lit donc la position réelle
|
|
105
|
+
* via getLiveLobeCoreCenter plutôt que la géométrie statique, pour que les
|
|
106
|
+
* anneaux du champ d'événement suivent le cœur qui tourne au lieu de
|
|
107
|
+
* naître à une origine figée.
|
|
108
|
+
*/
|
|
109
|
+
getEventFieldSource(): {
|
|
110
|
+
center: {
|
|
111
|
+
x: number;
|
|
112
|
+
y: number;
|
|
113
|
+
} | null;
|
|
114
|
+
radius: number;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Résout un point porté par `lobeGroup` (coordonnées locales, ici le
|
|
118
|
+
* centre canonique du cœur) dans le repère de globalGroup — celui où
|
|
119
|
+
* EventFieldRenderer dessine (voir EventFieldLifecycleController,
|
|
120
|
+
* getGlobalGroupNode). Passe par les CTM SVG plutôt que de reparser
|
|
121
|
+
* l'attribut `transform` (comme getChildRenderedCenter le fait pour une
|
|
122
|
+
* simple translation) : le transform posé sur graphElementGroup pendant
|
|
123
|
+
* une rotation combine rotate ET translate, et cette composition suit
|
|
124
|
+
* fidèlement AnimationsMngr sans dépendre de sa formule exacte — un
|
|
125
|
+
* changement futur de celle-ci n'a pas besoin d'être répercuté ici.
|
|
126
|
+
*/
|
|
127
|
+
private getLiveLobeCoreCenter;
|
|
128
|
+
/**
|
|
129
|
+
* Rejoue l'aperçu d'un Événement Clé depuis une navigation Recherche
|
|
130
|
+
* (historique précédent/suivant) — pendant minimal de searchNavigateToAction,
|
|
131
|
+
* sans mise au point du diagramme (pas de satellite/facette à recentrer,
|
|
132
|
+
* l'entrée d'arbre dédiée est hors scope pour l'instant).
|
|
133
|
+
*/
|
|
134
|
+
searchNavigateToKeyEvent(keyEventId: string): void;
|
|
135
|
+
/**
|
|
136
|
+
* Rétablit le Champ d'événement d'un Événement Clé DÉJÀ affiché à droite —
|
|
137
|
+
* pendant de restoreActionDiagramState pour les événements, utilisé au
|
|
138
|
+
* retour en mode RECHERCHE (voir PanelManager.resyncDiagramToMasterPanel).
|
|
139
|
+
*
|
|
140
|
+
* Volontairement plus étroit que previewKeyEvent : ni carte redessinée, ni
|
|
141
|
+
* notification de navigation (donc pas d'entrée d'historique en double) —
|
|
142
|
+
* le panneau montre déjà cet événement, c'est le diagramme qui le rattrape.
|
|
143
|
+
* On garde en revanche l'exclusivité action/événement : les deux champs ne
|
|
144
|
+
* cohabitent jamais.
|
|
145
|
+
*
|
|
146
|
+
* Si la facette courante n'est plus celle de l'événement (l'utilisateur a
|
|
147
|
+
* navigué ailleurs pendant le mode STACK), on revient d'abord sur sa facette
|
|
148
|
+
* d'origine — mêmes gestes que searchSetKeyEventMenuOpen : l'aperçu survit
|
|
149
|
+
* au switch (prepareForComponentSwitch le garde vivant, destination =
|
|
150
|
+
* origine) et le menu cœur se redéploie à l'arrivée avec sa bulle active.
|
|
151
|
+
*/
|
|
152
|
+
restoreKeyEventDiagramState(keyEventId: string): void;
|
|
153
|
+
/**
|
|
154
|
+
* Dépli/repli du groupe "Événements Clés" depuis la hiérarchie RECHERCHE —
|
|
155
|
+
* pendant exact du clic sur le cœur du yin/yang (onCoreEventNucleusClicked),
|
|
156
|
+
* pour que l'arbre et le diagramme montrent le même menu déployé : ouvrir le
|
|
157
|
+
* groupe déploie les bulles de la facette, le refermer les rétracte (même
|
|
158
|
+
* règle que le dépli d'un Satellite, qui déploie ses boutons d'Action).
|
|
159
|
+
*
|
|
160
|
+
* Le repli passe par closeKeyEventField plutôt que par le toggle : il doit
|
|
161
|
+
* aussi emporter l'Événement Clé en aperçu (et sa carte), sinon une bulle
|
|
162
|
+
* validée resterait allumée sous un groupe replié.
|
|
163
|
+
*/
|
|
164
|
+
searchSetKeyEventMenuOpen(componentIndex: number, open: boolean): void;
|
|
165
|
+
/** Ouverture idempotente du menu cœur — no-op s'il est déjà déployé (le
|
|
166
|
+
* toggle le refermerait). */
|
|
167
|
+
openCoreEventMenu(): void;
|
|
168
|
+
/** Seul point de mutation de activeKeyEventId — resynchronise la ligne
|
|
169
|
+
* Événement Clé du titre (voir getCurrentSatelliteTitle) à chaque
|
|
170
|
+
* changement, exactement comme setActiveChildKey le fait pour le
|
|
171
|
+
* satellite. */
|
|
172
|
+
setActiveKeyEventId(keyEventId: string | null): void;
|
|
173
|
+
/**
|
|
174
|
+
* Clic sur une bulle du menu cœur. En STACK : clic sur le libellé de son
|
|
175
|
+
* item de pile — celui en focus s'il s'agit de cet événement, sinon le
|
|
176
|
+
* plus récent ; rien s'il n'est pas dans la pile. Ailleurs : aperçu.
|
|
177
|
+
*/
|
|
178
|
+
onKeyEventBubbleClick(keyEvent: KeyEventDefinition): void;
|
|
179
|
+
/** Aperçu — 1er clic sur un Événement Clé : affiche sa carte descriptive
|
|
180
|
+
* dans le panneau Recherche, ne joue rien (même principe que
|
|
181
|
+
* activateActionFromChild côté satellite). */
|
|
182
|
+
previewKeyEvent(keyEvent: KeyEventDefinition): void;
|
|
183
|
+
/** Validation — glisser une bulle (menu radial ou arbre RECHERCHE)
|
|
184
|
+
* jusqu'à une position précise de la pile (voir startKeyEventDrag, même
|
|
185
|
+
* mécanisme que validateActionSelection côté satellite). Sans
|
|
186
|
+
* insertAtVisibleIndex, l'item est ajouté au sommet — le menu radial
|
|
187
|
+
* reste ouvert, pour enchaîner d'autres choix. */
|
|
188
|
+
validateKeyEventSelection(keyEvent: KeyEventDefinition, insertAtVisibleIndex?: number | null, entryOrigin?: {
|
|
189
|
+
x: number;
|
|
190
|
+
y: number;
|
|
191
|
+
}): void;
|
|
192
|
+
}
|
|
@@ -106,12 +106,3 @@ export declare function renderRadialItemLinks<T extends {
|
|
|
106
106
|
startRadius?: number;
|
|
107
107
|
getStyle?: (d: RadialMenuItemPosition<T>) => RadialItemLinkStyle;
|
|
108
108
|
}): void;
|
|
109
|
-
/**
|
|
110
|
-
* Sémantique de clic partagée par les deux menus radiaux : un premier
|
|
111
|
-
* clic sur un item prévisualise (affiche sa carte, ne joue rien) ; un
|
|
112
|
-
* second clic sur ce même item déjà actif valide (l'ajoute à la
|
|
113
|
-
* pile). Cliquer un autre item pendant qu'un aperçu est actif bascule
|
|
114
|
-
* l'aperçu sans valider — c'est simplement le cas "isAlreadyActive
|
|
115
|
-
* === false" pour ce nouvel item.
|
|
116
|
-
*/
|
|
117
|
-
export declare function handleRadialItemClick(isAlreadyActive: boolean, onPreview: () => void, onValidate: () => void): void;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { IYinYangView } from "../../../interfaces/IYinYangView";
|
|
2
|
+
import { IYinYangController } from "../../../interfaces/IYinYangController";
|
|
3
|
+
import { IYinYangAppFactory } from "../../../interfaces/IYinYangAppFactory";
|
|
4
|
+
import { YinYangInternalModel } from "../../../interfaces/IYinYangInternalModel";
|
|
5
|
+
import { type ActionDefinition } from "../../../data/yasuni_actions";
|
|
6
|
+
import { ChildrenOrbitEntry } from "../utils/childrenOrbit";
|
|
7
|
+
import { YinYangControllerState } from "../state/YinYangControllerState";
|
|
8
|
+
import { StackFocusController } from "../action-stack/StackFocusController";
|
|
9
|
+
import { ComponentTitlePresenter } from "../labels/ComponentTitlePresenter";
|
|
10
|
+
import type { ControllerUiCallbacks } from "../state/ControllerUiCallbacks";
|
|
11
|
+
import { ChildrenOrbitManager } from "../odd/ChildrenOrbitManager";
|
|
12
|
+
export type ChildrenBuilderDeps = {
|
|
13
|
+
animateChildren: (show: boolean) => Promise<void>;
|
|
14
|
+
applyChildrenOrbitTransforms: (angleOffset: number, orbitData?: ChildrenOrbitEntry[]) => void;
|
|
15
|
+
attachBackgroundClickHandler: () => void;
|
|
16
|
+
attachChildHoverHandler: (childController: IYinYangController) => void;
|
|
17
|
+
attachChildToggleHandler: (childController: IYinYangController) => void;
|
|
18
|
+
getChildControllers: () => IYinYangController[];
|
|
19
|
+
childOddMap: Map<string, {
|
|
20
|
+
oddId: string;
|
|
21
|
+
score: number;
|
|
22
|
+
cuttingIndex: number;
|
|
23
|
+
}>;
|
|
24
|
+
childrenOrbitManager: ChildrenOrbitManager;
|
|
25
|
+
clearChildren: () => void;
|
|
26
|
+
factory: IYinYangAppFactory;
|
|
27
|
+
getAllComponents: () => YinYangInternalModel["components"];
|
|
28
|
+
getCurrentComponent: () => YinYangInternalModel["components"][number] | null;
|
|
29
|
+
getCurrentComponentOrUndefined: () => YinYangInternalModel["components"][number] | undefined;
|
|
30
|
+
getKey: () => string;
|
|
31
|
+
renderOppositeChildrenForceField: (orbitData?: ChildrenOrbitEntry[], angleOffset?: number) => void;
|
|
32
|
+
getRotationState: () => {
|
|
33
|
+
clockWise: boolean;
|
|
34
|
+
durationMs: number;
|
|
35
|
+
rampMs: number;
|
|
36
|
+
} | null;
|
|
37
|
+
setChildrenHiddenState: (hidden: boolean) => void;
|
|
38
|
+
stackFocus: StackFocusController;
|
|
39
|
+
startChildrenOrbit: (durationMs: number) => void;
|
|
40
|
+
state: YinYangControllerState;
|
|
41
|
+
titlePresenter: ComponentTitlePresenter;
|
|
42
|
+
ui: ControllerUiCallbacks;
|
|
43
|
+
view: IYinYangView;
|
|
44
|
+
};
|
|
45
|
+
/** Création des satellites (contrôleurs enfants) d'une facette, mise à
|
|
46
|
+
* l'échelle pour tenir dans le cercle, et actions proposées par satellite. */
|
|
47
|
+
export declare class ChildrenBuilder {
|
|
48
|
+
private deps;
|
|
49
|
+
constructor(deps: ChildrenBuilderDeps);
|
|
50
|
+
/**
|
|
51
|
+
* Creates child instances of the YinYang pattern using the model's data.
|
|
52
|
+
* Each child is generated based on the small circle data.
|
|
53
|
+
*/
|
|
54
|
+
createYinYangChildren(): void;
|
|
55
|
+
/** Both distance and size are fixed relative to the facette's uniform
|
|
56
|
+
* baseline radius, independent of any satellite's own weight-scaled
|
|
57
|
+
* radius — mirrors ChildActionMenuController's action cluster geometry. */
|
|
58
|
+
private getChildActionClusterReach;
|
|
59
|
+
/** Décalage constant appliqué au poids ET à sa moyenne avant de calculer le
|
|
60
|
+
* ratio de taille d'un satellite (voir weightToSizeRatio) : resserre la
|
|
61
|
+
* fourchette de tailles (poids min moins minuscule, poids max un peu
|
|
62
|
+
* moins dominant) sans changer la taille d'un satellite au poids moyen
|
|
63
|
+
* exact (ratio toujours 1 dans ce cas), et sans dépendre du poids moyen
|
|
64
|
+
* de la fratrie pour l'ampleur du resserrement. */
|
|
65
|
+
private static readonly WEIGHT_SIZE_FLOOR_OFFSET;
|
|
66
|
+
/** Ratio de taille d'un satellite (rayon relatif à la baseline uniforme de
|
|
67
|
+
* sa facette) à partir de son poids et du poids moyen de sa fratrie —
|
|
68
|
+
* voir WEIGHT_SIZE_FLOOR_OFFSET pour le resserrement. */
|
|
69
|
+
private static weightToSizeRatio;
|
|
70
|
+
/** Ratio of a component's heaviest satellite radius to its own uniform
|
|
71
|
+
* baseline radius. Mirrors the per-cutting weight-based scaling applied
|
|
72
|
+
* in createYinYangChildren(). */
|
|
73
|
+
private getMaxWeightRatio;
|
|
74
|
+
/** The container-fit shrink ratio only depends on borderOuterRadius/
|
|
75
|
+
* smallCircleRadius/distanceFromChild, which are fixed for the whole
|
|
76
|
+
* session once this top-level view is first initialized (they don't get
|
|
77
|
+
* recomputed on facette switch) — so this is computed once (on the worst
|
|
78
|
+
* case weight ratio across every facette) and cached. That's what keeps
|
|
79
|
+
* the whole diagram's size from visibly changing every time the user
|
|
80
|
+
* switches facette. */
|
|
81
|
+
private cachedGlobalFitShrinkRatio?;
|
|
82
|
+
private computeGlobalFitShrinkRatio;
|
|
83
|
+
applyChildrenFitScale(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Retourne les actions applicables au cutting associé à `childKey`,
|
|
86
|
+
* en consultant `activeComposantes` via `actionMap` (lookup O(1)).
|
|
87
|
+
*
|
|
88
|
+
* Les actions adverses vivent sous le même satellite (l'invariant "une
|
|
89
|
+
* action vit sous un satellite" tient) mais ne sont proposées au joueur
|
|
90
|
+
* qu'en mode adverse (outil de debug, voir adverseMode.ts), où elles
|
|
91
|
+
* remplacent les actions ordinaires — d'où le filtre "mode" par défaut.
|
|
92
|
+
* Hors de ce mode, c'est le système qui les place lui-même dans la pile.
|
|
93
|
+
*/
|
|
94
|
+
getActionsForChild(childKey: string, filter?: "mode" | "playable" | "adverse" | "all"): ActionDefinition[];
|
|
95
|
+
}
|