Fix: StripOverlayLayer initialization timing - proper architecture

Resolved the 'ScryingPoolStrip not found, appending to body' warning by
restructuring the initialization flow:

1. ScryingPoolStrip now creates its own StripOverlayLayer lazily via getter
2. ScryingPoolStrip.stripOverlayLayer returns the layer instance
3. ConfirmationBar accepts ScryingPoolStrip/RoleRenderer and extracts stripOverlayLayer
4. RoleRenderer exposes public .strip getter for ScryingPoolStrip access
5. All components only initialized for GM users (where ScryingPoolStrip exists)

This ensures:
- StripOverlayLayer is created AFTER ScryingPoolStrip DOM element exists
- ConfirmationBar renders correctly positioned within the strip
- No fallback to document.body needed
- Proper separation of concerns (strip owns its overlay layer)

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-05-24 00:56:19 +02:00
parent a06e504183
commit 6f07e48e54
4 changed files with 45 additions and 10 deletions
+8
View File
@@ -24,6 +24,14 @@ export class RoleRenderer {
this._strip = null;
}
/**
* Returns the ScryingPoolStrip instance (GM only).
* @returns {ScryingPoolStrip|null} The strip instance.
*/
get strip() {
return this._strip;
}
/**
* Registers Hooks listeners. Must be called once during module ready.
*/
+20 -4
View File
@@ -25,14 +25,30 @@ export class ConfirmationBar {
* Injected VisibilityManager for reverting matrix on undo.
* @param {import('../../core/SocketHandler.js').SocketHandler} socketHandler
* Injected SocketHandler (for potential future use).
* @param {import('../shared/StripOverlayLayer.js').StripOverlayLayer} stripOverlayLayer
* Injected StripOverlayLayer for rendering.
* @param {import('./ScryingPoolStrip.js').ScryingPoolStrip|import('../shared/StripOverlayLayer.js').StripOverlayLayer} stripOverlayLayerOrStrip
* Injected ScryingPoolStrip (which provides stripOverlayLayer) or StripOverlayLayer directly.
*/
constructor(adapter, visibilityManager, socketHandler, stripOverlayLayer) {
constructor(adapter, visibilityManager, socketHandler, stripOverlayLayerOrStrip) {
this._adapter = adapter;
this._visibilityManager = visibilityManager;
this._socketHandler = socketHandler;
this._stripOverlayLayer = stripOverlayLayer;
// Extract StripOverlayLayer from the provided source
// Can be: ScryingPoolStrip, RoleRenderer (with .strip), or StripOverlayLayer directly
let source = stripOverlayLayerOrStrip;
// If it's a RoleRenderer, get the strip from it
if (source && source.strip && source.strip?.stripOverlayLayer) {
source = source.strip;
}
// If it's a ScryingPoolStrip, get its stripOverlayLayer
if (source && source.stripOverlayLayer) {
this._stripOverlayLayer = source.stripOverlayLayer;
} else {
// Direct StripOverlayLayer
this._stripOverlayLayer = source;
}
// State
/** @type {object|null} */
+15
View File
@@ -1,6 +1,7 @@
// @ts-nocheck
/* global Application, directorsBoard */
import { generateOpId } from '../../utils/uuid.js';
import { StripOverlayLayer } from '../shared/StripOverlayLayer.js';
/**
* Canonical action labels — never use inline string literals.
@@ -117,6 +118,20 @@ export class ScryingPoolStrip extends _AppBase {
this._isExpanded = true;
/** @type {ActionPopover|null} */
this._activePopover = null;
/** @type {StripOverlayLayer|null} */
this._stripOverlayLayer = null;
}
/**
* Returns the StripOverlayLayer instance, creating it lazily if needed.
* @returns {StripOverlayLayer} The overlay layer instance.
*/
get stripOverlayLayer() {
if (!this._stripOverlayLayer) {
this._stripOverlayLayer = new StripOverlayLayer(this._adapter);
this._stripOverlayLayer.init();
}
return this._stripOverlayLayer;
}
/** @inheritdoc */