@vforsh/phaser-dev-ui 0.1.0 → 0.2.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/README.md +9 -0
- package/dist/anchorToViewport.d.ts +51 -0
- package/dist/anchorToViewport.d.ts.map +1 -0
- package/dist/anchorToViewport.js +200 -0
- package/dist/anchorToViewport.js.map +1 -0
- package/dist/bindDebugControl.d.ts +42 -0
- package/dist/bindDebugControl.d.ts.map +1 -0
- package/dist/bindDebugControl.js +254 -0
- package/dist/bindDebugControl.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/layoutAuto.d.ts +25 -0
- package/dist/layoutAuto.d.ts.map +1 -0
- package/dist/layoutAuto.js +76 -0
- package/dist/layoutAuto.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,6 +70,15 @@ The system is designed with a fluent, chainable API and dark-theme defaults matc
|
|
|
70
70
|
- **`createGridContainer`**: Arranges children in a grid with configurable columns, cell size, and spacing.
|
|
71
71
|
- **Usage**: Group related UI elements. After adding items via `addItem()` or `addItems()`, call `.layout()` to reposition children. Containers are invisible positioning helpers and can be nested.
|
|
72
72
|
|
|
73
|
+
### Utility Helpers
|
|
74
|
+
|
|
75
|
+
- **`bindDebugControl`**: Two-way model binding helper for debug controls.
|
|
76
|
+
- Supports model access via object path (`target` + `path`) or custom getter/setter.
|
|
77
|
+
- Polls model on `preupdate` and pushes control changes back through control events.
|
|
78
|
+
- **`anchorToViewport`**: Anchors any game object to viewport edges/corners/center with optional safe-area insets and resize updates.
|
|
79
|
+
- **`getSafeAreaInsets`**: Resolves safe-area insets in game units (CSS env insets + optional extra insets).
|
|
80
|
+
- **`layoutAuto`**: Dirty layout scheduler; batches `.layout()` calls and flushes once per frame.
|
|
81
|
+
|
|
73
82
|
## Example: Creating a Settings Popup
|
|
74
83
|
|
|
75
84
|
```typescript
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export type ViewportAnchor = "top-left" | "top-center" | "top-right" | "center-left" | "center" | "center-right" | "bottom-left" | "bottom-center" | "bottom-right";
|
|
2
|
+
export interface SafeAreaInsets {
|
|
3
|
+
left: number;
|
|
4
|
+
right: number;
|
|
5
|
+
top: number;
|
|
6
|
+
bottom: number;
|
|
7
|
+
}
|
|
8
|
+
export interface SafeAreaOptions {
|
|
9
|
+
/** Merge extra insets in game units. */
|
|
10
|
+
extraInsets?: Partial<SafeAreaInsets>;
|
|
11
|
+
/** Read CSS env(safe-area-inset-*) values from the browser (default: true). */
|
|
12
|
+
useCssEnvInsets?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface AnchorToViewportOptions {
|
|
15
|
+
/** Scene object for scale/resize events (auto-detected from target.scene when omitted). */
|
|
16
|
+
scene?: Phaser.Scene;
|
|
17
|
+
/** Target object to place in viewport coordinates. */
|
|
18
|
+
target: Phaser.GameObjects.GameObject;
|
|
19
|
+
/** Anchor point in viewport (default: "top-left"). */
|
|
20
|
+
anchor?: ViewportAnchor;
|
|
21
|
+
/** Offset from anchor in game units (default: 0). */
|
|
22
|
+
offsetX?: number;
|
|
23
|
+
offsetY?: number;
|
|
24
|
+
/** Apply safe-area insets (default: true). */
|
|
25
|
+
useSafeArea?: boolean;
|
|
26
|
+
/** Safe-area options (extra insets + css env toggle). */
|
|
27
|
+
safeArea?: SafeAreaOptions;
|
|
28
|
+
/** Update automatically on scale resize (default: true). */
|
|
29
|
+
autoResize?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface ViewportAnchorHandle {
|
|
32
|
+
update(): void;
|
|
33
|
+
destroy(): void;
|
|
34
|
+
isDestroyed(): boolean;
|
|
35
|
+
getSafeAreaInsets(): SafeAreaInsets;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Anchor a game object to a viewport corner/edge/center.
|
|
39
|
+
*
|
|
40
|
+
* Position is computed in game coordinates and updated on resize.
|
|
41
|
+
* Assumes centered origin for best results (0.5, 0.5).
|
|
42
|
+
*/
|
|
43
|
+
export declare function anchorToViewport(options: AnchorToViewportOptions): ViewportAnchorHandle;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve safe-area insets in game units.
|
|
46
|
+
*
|
|
47
|
+
* Uses browser CSS env(safe-area-inset-*) values when available,
|
|
48
|
+
* then applies optional caller-provided extra insets.
|
|
49
|
+
*/
|
|
50
|
+
export declare function getSafeAreaInsets(scene: Phaser.Scene, options?: SafeAreaOptions): SafeAreaInsets;
|
|
51
|
+
//# sourceMappingURL=anchorToViewport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchorToViewport.d.ts","sourceRoot":"","sources":["../src/anchorToViewport.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GACvB,UAAU,GACV,YAAY,GACZ,WAAW,GACX,aAAa,GACb,QAAQ,GACR,cAAc,GACd,aAAa,GACb,eAAe,GACf,cAAc,CAAA;AAEjB,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,eAAe;IAC/B,wCAAwC;IACxC,WAAW,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IACrC,+EAA+E;IAC/E,eAAe,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,uBAAuB;IACvC,2FAA2F;IAC3F,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,CAAA;IACpB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,UAAU,CAAA;IACrC,sDAAsD;IACtD,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,4DAA4D;IAC5D,UAAU,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,oBAAoB;IACpC,MAAM,IAAI,IAAI,CAAA;IACd,OAAO,IAAI,IAAI,CAAA;IACf,WAAW,IAAI,OAAO,CAAA;IACtB,iBAAiB,IAAI,cAAc,CAAA;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,oBAAoB,CAwEvF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,GAAE,eAAoB,GAAG,cAAc,CAWpG"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor a game object to a viewport corner/edge/center.
|
|
3
|
+
*
|
|
4
|
+
* Position is computed in game coordinates and updated on resize.
|
|
5
|
+
* Assumes centered origin for best results (0.5, 0.5).
|
|
6
|
+
*/
|
|
7
|
+
export function anchorToViewport(options) {
|
|
8
|
+
const { target, scene: sceneFromOptions, anchor = "top-left", offsetX = 0, offsetY = 0, useSafeArea = true, safeArea, autoResize = true, } = options;
|
|
9
|
+
const scene = sceneFromOptions ?? target.scene;
|
|
10
|
+
if (!scene) {
|
|
11
|
+
throw new Error("anchorToViewport: scene not found. Pass options.scene or use a scene-owned target.");
|
|
12
|
+
}
|
|
13
|
+
let destroyed = false;
|
|
14
|
+
const placeTarget = () => {
|
|
15
|
+
if (destroyed)
|
|
16
|
+
return;
|
|
17
|
+
const viewport = getViewportRect(scene);
|
|
18
|
+
const insets = useSafeArea ? getSafeAreaInsets(scene, safeArea) : zeroInsets();
|
|
19
|
+
const left = viewport.x + insets.left;
|
|
20
|
+
const right = viewport.x + viewport.width - insets.right;
|
|
21
|
+
const top = viewport.y + insets.top;
|
|
22
|
+
const bottom = viewport.y + viewport.height - insets.bottom;
|
|
23
|
+
const availableWidth = Math.max(0, right - left);
|
|
24
|
+
const availableHeight = Math.max(0, bottom - top);
|
|
25
|
+
const size = getDisplaySize(target);
|
|
26
|
+
const halfW = size.width / 2;
|
|
27
|
+
const halfH = size.height / 2;
|
|
28
|
+
const x = computeAnchoredX(anchor, left, availableWidth, right, halfW) + offsetX;
|
|
29
|
+
const y = computeAnchoredY(anchor, top, availableHeight, bottom, halfH) + offsetY;
|
|
30
|
+
setTargetPosition(target, x, y);
|
|
31
|
+
};
|
|
32
|
+
const onResize = () => {
|
|
33
|
+
placeTarget();
|
|
34
|
+
};
|
|
35
|
+
if (autoResize) {
|
|
36
|
+
scene.scale.on("resize", onResize);
|
|
37
|
+
}
|
|
38
|
+
scene.events.once("shutdown", destroyHandle);
|
|
39
|
+
attachAutoDestroy(target, () => {
|
|
40
|
+
destroyHandle();
|
|
41
|
+
});
|
|
42
|
+
placeTarget();
|
|
43
|
+
function destroyHandle() {
|
|
44
|
+
if (destroyed)
|
|
45
|
+
return;
|
|
46
|
+
destroyed = true;
|
|
47
|
+
if (autoResize) {
|
|
48
|
+
scene.scale.off("resize", onResize);
|
|
49
|
+
}
|
|
50
|
+
scene.events.off("shutdown", destroyHandle);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
update: placeTarget,
|
|
54
|
+
destroy: destroyHandle,
|
|
55
|
+
isDestroyed: () => destroyed,
|
|
56
|
+
getSafeAreaInsets: () => (useSafeArea ? getSafeAreaInsets(scene, safeArea) : zeroInsets()),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Resolve safe-area insets in game units.
|
|
61
|
+
*
|
|
62
|
+
* Uses browser CSS env(safe-area-inset-*) values when available,
|
|
63
|
+
* then applies optional caller-provided extra insets.
|
|
64
|
+
*/
|
|
65
|
+
export function getSafeAreaInsets(scene, options = {}) {
|
|
66
|
+
const { extraInsets, useCssEnvInsets = true } = options;
|
|
67
|
+
const cssInsetsPx = useCssEnvInsets ? getCssSafeAreaInsetsPx() : zeroInsets();
|
|
68
|
+
const scale = getCanvasToGameScale(scene);
|
|
69
|
+
return {
|
|
70
|
+
left: Math.max(0, cssInsetsPx.left * scale.x + (extraInsets?.left ?? 0)),
|
|
71
|
+
right: Math.max(0, cssInsetsPx.right * scale.x + (extraInsets?.right ?? 0)),
|
|
72
|
+
top: Math.max(0, cssInsetsPx.top * scale.y + (extraInsets?.top ?? 0)),
|
|
73
|
+
bottom: Math.max(0, cssInsetsPx.bottom * scale.y + (extraInsets?.bottom ?? 0)),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
let safeAreaProbe = null;
|
|
77
|
+
function getCssSafeAreaInsetsPx() {
|
|
78
|
+
if (typeof document === "undefined")
|
|
79
|
+
return zeroInsets();
|
|
80
|
+
if (!safeAreaProbe) {
|
|
81
|
+
safeAreaProbe = document.createElement("div");
|
|
82
|
+
safeAreaProbe.style.position = "fixed";
|
|
83
|
+
safeAreaProbe.style.left = "0";
|
|
84
|
+
safeAreaProbe.style.top = "0";
|
|
85
|
+
safeAreaProbe.style.width = "0";
|
|
86
|
+
safeAreaProbe.style.height = "0";
|
|
87
|
+
safeAreaProbe.style.paddingLeft = "env(safe-area-inset-left)";
|
|
88
|
+
safeAreaProbe.style.paddingRight = "env(safe-area-inset-right)";
|
|
89
|
+
safeAreaProbe.style.paddingTop = "env(safe-area-inset-top)";
|
|
90
|
+
safeAreaProbe.style.paddingBottom = "env(safe-area-inset-bottom)";
|
|
91
|
+
safeAreaProbe.style.pointerEvents = "none";
|
|
92
|
+
safeAreaProbe.style.visibility = "hidden";
|
|
93
|
+
document.body.appendChild(safeAreaProbe);
|
|
94
|
+
}
|
|
95
|
+
const styles = getComputedStyle(safeAreaProbe);
|
|
96
|
+
return {
|
|
97
|
+
left: toFiniteNumber(styles.paddingLeft),
|
|
98
|
+
right: toFiniteNumber(styles.paddingRight),
|
|
99
|
+
top: toFiniteNumber(styles.paddingTop),
|
|
100
|
+
bottom: toFiniteNumber(styles.paddingBottom),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function getCanvasToGameScale(scene) {
|
|
104
|
+
const canvas = scene.game.canvas;
|
|
105
|
+
if (!canvas || typeof canvas.getBoundingClientRect !== "function")
|
|
106
|
+
return { x: 1, y: 1 };
|
|
107
|
+
const rect = canvas.getBoundingClientRect();
|
|
108
|
+
if (rect.width <= 0 || rect.height <= 0)
|
|
109
|
+
return { x: 1, y: 1 };
|
|
110
|
+
return {
|
|
111
|
+
x: scene.scale.width / rect.width,
|
|
112
|
+
y: scene.scale.height / rect.height,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function getViewportRect(scene) {
|
|
116
|
+
if (typeof scene.scale.getViewPort === "function") {
|
|
117
|
+
const out = scene.scale.getViewPort(scene.cameras.main);
|
|
118
|
+
if (out)
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
return new Phaser.Geom.Rectangle(0, 0, scene.scale.width, scene.scale.height);
|
|
122
|
+
}
|
|
123
|
+
function getDisplaySize(target) {
|
|
124
|
+
const withDisplay = target;
|
|
125
|
+
if (typeof withDisplay.displayWidth === "number" || typeof withDisplay.displayHeight === "number") {
|
|
126
|
+
return {
|
|
127
|
+
width: Math.max(0, withDisplay.displayWidth ?? 0),
|
|
128
|
+
height: Math.max(0, withDisplay.displayHeight ?? 0),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const withSize = target;
|
|
132
|
+
if (typeof withSize.width === "number" || typeof withSize.height === "number") {
|
|
133
|
+
return {
|
|
134
|
+
width: Math.max(0, withSize.width ?? 0),
|
|
135
|
+
height: Math.max(0, withSize.height ?? 0),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (typeof target.getBounds === "function") {
|
|
139
|
+
const bounds = target.getBounds();
|
|
140
|
+
return { width: Math.max(0, bounds.width), height: Math.max(0, bounds.height) };
|
|
141
|
+
}
|
|
142
|
+
return { width: 0, height: 0 };
|
|
143
|
+
}
|
|
144
|
+
function setTargetPosition(target, x, y) {
|
|
145
|
+
const transform = target;
|
|
146
|
+
if (typeof transform.setPosition !== "function") {
|
|
147
|
+
throw new Error("anchorToViewport: target does not support setPosition(x, y)");
|
|
148
|
+
}
|
|
149
|
+
transform.setPosition(x, y);
|
|
150
|
+
}
|
|
151
|
+
function attachAutoDestroy(target, onDestroy) {
|
|
152
|
+
const emitter = target;
|
|
153
|
+
if (typeof emitter.once !== "function")
|
|
154
|
+
return;
|
|
155
|
+
emitter.once("destroy", onDestroy);
|
|
156
|
+
}
|
|
157
|
+
function computeAnchoredX(anchor, left, availableWidth, right, halfWidth) {
|
|
158
|
+
switch (anchor) {
|
|
159
|
+
case "top-left":
|
|
160
|
+
case "center-left":
|
|
161
|
+
case "bottom-left":
|
|
162
|
+
return left + halfWidth;
|
|
163
|
+
case "top-center":
|
|
164
|
+
case "center":
|
|
165
|
+
case "bottom-center":
|
|
166
|
+
return left + availableWidth / 2;
|
|
167
|
+
case "top-right":
|
|
168
|
+
case "center-right":
|
|
169
|
+
case "bottom-right":
|
|
170
|
+
return right - halfWidth;
|
|
171
|
+
default:
|
|
172
|
+
return left + halfWidth;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function computeAnchoredY(anchor, top, availableHeight, bottom, halfHeight) {
|
|
176
|
+
switch (anchor) {
|
|
177
|
+
case "top-left":
|
|
178
|
+
case "top-center":
|
|
179
|
+
case "top-right":
|
|
180
|
+
return top + halfHeight;
|
|
181
|
+
case "center-left":
|
|
182
|
+
case "center":
|
|
183
|
+
case "center-right":
|
|
184
|
+
return top + availableHeight / 2;
|
|
185
|
+
case "bottom-left":
|
|
186
|
+
case "bottom-center":
|
|
187
|
+
case "bottom-right":
|
|
188
|
+
return bottom - halfHeight;
|
|
189
|
+
default:
|
|
190
|
+
return top + halfHeight;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function toFiniteNumber(value) {
|
|
194
|
+
const parsed = Number.parseFloat(value);
|
|
195
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
196
|
+
}
|
|
197
|
+
function zeroInsets() {
|
|
198
|
+
return { left: 0, right: 0, top: 0, bottom: 0 };
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=anchorToViewport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchorToViewport.js","sourceRoot":"","sources":["../src/anchorToViewport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface DebugControlAdapter<TControl, TValue> {
|
|
2
|
+
read(control: TControl): TValue;
|
|
3
|
+
write(control: TControl, value: TValue): void;
|
|
4
|
+
subscribe?(control: TControl, onValue: (value: TValue) => void): (() => void) | void;
|
|
5
|
+
}
|
|
6
|
+
export interface BindDebugControlOptions<TControl, TValue> {
|
|
7
|
+
/** UI control instance to bind. */
|
|
8
|
+
control: TControl;
|
|
9
|
+
/** Optional explicit scene (auto-detected from control.scene when omitted). */
|
|
10
|
+
scene?: Phaser.Scene;
|
|
11
|
+
/** Model object used with `path` for get/set. */
|
|
12
|
+
target?: Record<string, unknown>;
|
|
13
|
+
/** Dot/bracket path (e.g. "player.speed" / "items[0].enabled"). */
|
|
14
|
+
path?: string;
|
|
15
|
+
/** Custom model getter (alternative to `target` + `path`). */
|
|
16
|
+
getValue?: () => TValue;
|
|
17
|
+
/** Custom model setter (alternative to `target` + `path`). */
|
|
18
|
+
setValue?: (value: TValue) => void;
|
|
19
|
+
/** Optional control adapter; inferred for known controls when omitted. */
|
|
20
|
+
adapter?: Partial<DebugControlAdapter<TControl, TValue>>;
|
|
21
|
+
/** Compare model/control values (default: Object.is). */
|
|
22
|
+
equals?: (a: TValue, b: TValue) => boolean;
|
|
23
|
+
/** Sync model -> control once at bind time (default: true). */
|
|
24
|
+
syncFromModelOnBind?: boolean;
|
|
25
|
+
/** Poll model each frame and push updates to control (default: true). */
|
|
26
|
+
syncFromModelEachFrame?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface DebugControlBinding<TValue> {
|
|
29
|
+
syncFromModel(): void;
|
|
30
|
+
syncFromControl(): void;
|
|
31
|
+
getModelValue(): TValue;
|
|
32
|
+
destroy(): void;
|
|
33
|
+
isDestroyed(): boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Two-way data binding between a debug control and a model source.
|
|
37
|
+
*
|
|
38
|
+
* Control -> model updates happen via control events.
|
|
39
|
+
* Model -> control updates happen on preupdate polling (or manual sync).
|
|
40
|
+
*/
|
|
41
|
+
export declare function bindDebugControl<TControl, TValue>(options: BindDebugControlOptions<TControl, TValue>): DebugControlBinding<TValue>;
|
|
42
|
+
//# sourceMappingURL=bindDebugControl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bindDebugControl.d.ts","sourceRoot":"","sources":["../src/bindDebugControl.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB,CAAC,QAAQ,EAAE,MAAM;IACpD,IAAI,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAA;IAC/B,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7C,SAAS,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;CACpF;AAED,MAAM,WAAW,uBAAuB,CAAC,QAAQ,EAAE,MAAM;IACxD,mCAAmC;IACnC,OAAO,EAAE,QAAQ,CAAA;IACjB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,CAAA;IACpB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAA;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;IACxD,yDAAyD;IACzD,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;IAC1C,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,yEAAyE;IACzE,sBAAsB,CAAC,EAAE,OAAO,CAAA;CAChC;AAED,MAAM,WAAW,mBAAmB,CAAC,MAAM;IAC1C,aAAa,IAAI,IAAI,CAAA;IACrB,eAAe,IAAI,IAAI,CAAA;IACvB,aAAa,IAAI,MAAM,CAAA;IACvB,OAAO,IAAI,IAAI,CAAA;IACf,WAAW,IAAI,OAAO,CAAA;CACtB;AAOD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAChD,OAAO,EAAE,uBAAuB,CAAC,QAAQ,EAAE,MAAM,CAAC,GAChD,mBAAmB,CAAC,MAAM,CAAC,CAuG7B"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two-way data binding between a debug control and a model source.
|
|
3
|
+
*
|
|
4
|
+
* Control -> model updates happen via control events.
|
|
5
|
+
* Model -> control updates happen on preupdate polling (or manual sync).
|
|
6
|
+
*/
|
|
7
|
+
export function bindDebugControl(options) {
|
|
8
|
+
const { control, scene: sceneFromOptions, equals = Object.is, syncFromModelOnBind = true, syncFromModelEachFrame = true, } = options;
|
|
9
|
+
const scene = sceneFromOptions ?? getSceneFromControl(control);
|
|
10
|
+
const model = resolveModelAccess(options);
|
|
11
|
+
const adapter = resolveControlAdapter(control, options.adapter);
|
|
12
|
+
let destroyed = false;
|
|
13
|
+
let pushingModelToControl = false;
|
|
14
|
+
let pushingControlToModel = false;
|
|
15
|
+
let hasLastModelValue = false;
|
|
16
|
+
let lastModelValue = null;
|
|
17
|
+
let unsubscribeControl = null;
|
|
18
|
+
const syncModelIntoControl = () => {
|
|
19
|
+
if (destroyed || pushingControlToModel)
|
|
20
|
+
return;
|
|
21
|
+
const modelValue = model.get();
|
|
22
|
+
if (hasLastModelValue && equals(modelValue, lastModelValue))
|
|
23
|
+
return;
|
|
24
|
+
pushingModelToControl = true;
|
|
25
|
+
adapter.write(control, modelValue);
|
|
26
|
+
pushingModelToControl = false;
|
|
27
|
+
lastModelValue = modelValue;
|
|
28
|
+
hasLastModelValue = true;
|
|
29
|
+
};
|
|
30
|
+
const syncControlIntoModel = () => {
|
|
31
|
+
if (destroyed || pushingModelToControl)
|
|
32
|
+
return;
|
|
33
|
+
const controlValue = adapter.read(control);
|
|
34
|
+
if (hasLastModelValue && equals(controlValue, lastModelValue))
|
|
35
|
+
return;
|
|
36
|
+
pushingControlToModel = true;
|
|
37
|
+
model.set(controlValue);
|
|
38
|
+
pushingControlToModel = false;
|
|
39
|
+
lastModelValue = controlValue;
|
|
40
|
+
hasLastModelValue = true;
|
|
41
|
+
};
|
|
42
|
+
if (adapter.subscribe) {
|
|
43
|
+
const maybeUnsub = adapter.subscribe(control, (value) => {
|
|
44
|
+
if (destroyed || pushingModelToControl)
|
|
45
|
+
return;
|
|
46
|
+
if (hasLastModelValue && equals(value, lastModelValue))
|
|
47
|
+
return;
|
|
48
|
+
pushingControlToModel = true;
|
|
49
|
+
model.set(value);
|
|
50
|
+
pushingControlToModel = false;
|
|
51
|
+
lastModelValue = value;
|
|
52
|
+
hasLastModelValue = true;
|
|
53
|
+
});
|
|
54
|
+
if (typeof maybeUnsub === "function") {
|
|
55
|
+
unsubscribeControl = maybeUnsub;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const preupdate = () => {
|
|
59
|
+
if (!syncFromModelEachFrame)
|
|
60
|
+
return;
|
|
61
|
+
syncModelIntoControl();
|
|
62
|
+
};
|
|
63
|
+
if (scene) {
|
|
64
|
+
scene.events.on("preupdate", preupdate);
|
|
65
|
+
scene.events.once("shutdown", destroyBinding);
|
|
66
|
+
}
|
|
67
|
+
attachAutoDestroy(control, () => {
|
|
68
|
+
destroyBinding();
|
|
69
|
+
});
|
|
70
|
+
if (syncFromModelOnBind) {
|
|
71
|
+
syncModelIntoControl();
|
|
72
|
+
}
|
|
73
|
+
function destroyBinding() {
|
|
74
|
+
if (destroyed)
|
|
75
|
+
return;
|
|
76
|
+
destroyed = true;
|
|
77
|
+
if (scene) {
|
|
78
|
+
scene.events.off("preupdate", preupdate);
|
|
79
|
+
scene.events.off("shutdown", destroyBinding);
|
|
80
|
+
}
|
|
81
|
+
if (unsubscribeControl) {
|
|
82
|
+
unsubscribeControl();
|
|
83
|
+
unsubscribeControl = null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
syncFromModel: syncModelIntoControl,
|
|
88
|
+
syncFromControl: syncControlIntoModel,
|
|
89
|
+
getModelValue: model.get,
|
|
90
|
+
destroy: destroyBinding,
|
|
91
|
+
isDestroyed: () => destroyed,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function resolveModelAccess(options) {
|
|
95
|
+
if (options.getValue && options.setValue) {
|
|
96
|
+
return {
|
|
97
|
+
get: options.getValue,
|
|
98
|
+
set: options.setValue,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const { target, path } = options;
|
|
102
|
+
if (!target || !path) {
|
|
103
|
+
throw new Error('bindDebugControl: provide either `getValue`+`setValue` or `target`+`path`');
|
|
104
|
+
}
|
|
105
|
+
const tokens = parsePath(path);
|
|
106
|
+
if (tokens.length === 0) {
|
|
107
|
+
throw new Error("bindDebugControl: path cannot be empty");
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
get: () => getValueAtPath(target, tokens),
|
|
111
|
+
set: (value) => {
|
|
112
|
+
setValueAtPath(target, tokens, value);
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function resolveControlAdapter(control, partial) {
|
|
117
|
+
const inferred = inferAdapter(control);
|
|
118
|
+
const read = (partial?.read ?? inferred?.read);
|
|
119
|
+
const write = (partial?.write ?? inferred?.write);
|
|
120
|
+
const subscribe = (partial?.subscribe ?? inferred?.subscribe);
|
|
121
|
+
if (!read || !write) {
|
|
122
|
+
throw new Error("bindDebugControl: could not infer control adapter. Provide adapter.read + adapter.write (and adapter.subscribe for two-way).");
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
read,
|
|
126
|
+
write,
|
|
127
|
+
subscribe,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function inferAdapter(control) {
|
|
131
|
+
const anyControl = control;
|
|
132
|
+
const hasSwitchApi = typeof anyControl.getCurrentOption === "function" &&
|
|
133
|
+
typeof anyControl.setOptionByKey === "function" &&
|
|
134
|
+
typeof anyControl.on === "function" &&
|
|
135
|
+
typeof anyControl.off === "function";
|
|
136
|
+
if (hasSwitchApi) {
|
|
137
|
+
return {
|
|
138
|
+
read: (ctrl) => {
|
|
139
|
+
const c = ctrl;
|
|
140
|
+
return (c.getCurrentOption()?.key ?? null);
|
|
141
|
+
},
|
|
142
|
+
write: (ctrl, value) => {
|
|
143
|
+
const c = ctrl;
|
|
144
|
+
if (typeof c.setOptionByKey === "function") {
|
|
145
|
+
c.setOptionByKey(value);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (typeof c.setOptionIndex === "function" && typeof value === "number") {
|
|
149
|
+
c.setOptionIndex(value);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
subscribe: (ctrl, onValue) => {
|
|
153
|
+
const c = ctrl;
|
|
154
|
+
const handler = (option) => onValue(option.key);
|
|
155
|
+
c.on("option-changed", handler);
|
|
156
|
+
return () => c.off("option-changed", handler);
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const hasValueApi = typeof anyControl.getValue === "function" && typeof anyControl.setValue === "function";
|
|
161
|
+
if (hasValueApi) {
|
|
162
|
+
return {
|
|
163
|
+
read: (ctrl) => {
|
|
164
|
+
const c = ctrl;
|
|
165
|
+
return c.getValue();
|
|
166
|
+
},
|
|
167
|
+
write: (ctrl, value) => {
|
|
168
|
+
const c = ctrl;
|
|
169
|
+
c.setValue(value);
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
function attachAutoDestroy(control, onDestroy) {
|
|
176
|
+
const maybeEmitter = control;
|
|
177
|
+
if (typeof maybeEmitter.once !== "function")
|
|
178
|
+
return;
|
|
179
|
+
maybeEmitter.once("destroy", onDestroy);
|
|
180
|
+
}
|
|
181
|
+
function getSceneFromControl(control) {
|
|
182
|
+
const maybeScene = control.scene;
|
|
183
|
+
return maybeScene ?? null;
|
|
184
|
+
}
|
|
185
|
+
function parsePath(path) {
|
|
186
|
+
const tokens = [];
|
|
187
|
+
const re = /[^.[\]]+|\[(\d+)\]/g;
|
|
188
|
+
let match;
|
|
189
|
+
while ((match = re.exec(path)) !== null) {
|
|
190
|
+
const indexValue = match[1];
|
|
191
|
+
if (indexValue !== undefined) {
|
|
192
|
+
tokens.push(Number(indexValue));
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
const key = match[0];
|
|
196
|
+
if (key)
|
|
197
|
+
tokens.push(key);
|
|
198
|
+
}
|
|
199
|
+
return tokens;
|
|
200
|
+
}
|
|
201
|
+
function getValueAtPath(obj, tokens) {
|
|
202
|
+
let cursor = obj;
|
|
203
|
+
for (const token of tokens) {
|
|
204
|
+
if (cursor === null || cursor === undefined)
|
|
205
|
+
return undefined;
|
|
206
|
+
if (typeof token === "number") {
|
|
207
|
+
if (!Array.isArray(cursor))
|
|
208
|
+
return undefined;
|
|
209
|
+
cursor = cursor[token];
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
cursor = cursor[token];
|
|
213
|
+
}
|
|
214
|
+
return cursor;
|
|
215
|
+
}
|
|
216
|
+
function setValueAtPath(obj, tokens, value) {
|
|
217
|
+
if (tokens.length === 0)
|
|
218
|
+
return;
|
|
219
|
+
let cursor = obj;
|
|
220
|
+
for (let i = 0; i < tokens.length - 1; i++) {
|
|
221
|
+
const token = tokens[i];
|
|
222
|
+
const nextToken = tokens[i + 1];
|
|
223
|
+
if (token === undefined || nextToken === undefined)
|
|
224
|
+
return;
|
|
225
|
+
if (typeof token === "number") {
|
|
226
|
+
if (!Array.isArray(cursor))
|
|
227
|
+
return;
|
|
228
|
+
const nextValue = cursor[token];
|
|
229
|
+
if (nextValue === null || nextValue === undefined) {
|
|
230
|
+
cursor[token] = typeof nextToken === "number" ? [] : {};
|
|
231
|
+
}
|
|
232
|
+
cursor = cursor[token];
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const record = cursor;
|
|
236
|
+
const nextValue = record[token];
|
|
237
|
+
if (nextValue === null || nextValue === undefined) {
|
|
238
|
+
record[token] = typeof nextToken === "number" ? [] : {};
|
|
239
|
+
}
|
|
240
|
+
cursor = record[token];
|
|
241
|
+
}
|
|
242
|
+
const lastToken = tokens[tokens.length - 1];
|
|
243
|
+
if (lastToken === undefined)
|
|
244
|
+
return;
|
|
245
|
+
if (typeof lastToken === "number") {
|
|
246
|
+
if (!Array.isArray(cursor))
|
|
247
|
+
return;
|
|
248
|
+
cursor[lastToken] = value;
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
;
|
|
252
|
+
cursor[lastToken] = value;
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=bindDebugControl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bindDebugControl.js","sourceRoot":"","sources":["../src/bindDebugControl.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export type { HexColor, Position, Size, ClickHandler, DebugImageIconOptions, IconSide } from "./types.js";
|
|
2
2
|
export { parseHex, toColorInt, dimHex, hexToColorAlpha, estimateTextWidth, getDevicePixelRatio } from "./utils.js";
|
|
3
|
+
export { bindDebugControl } from "./bindDebugControl.js";
|
|
4
|
+
export type { BindDebugControlOptions, DebugControlAdapter, DebugControlBinding } from "./bindDebugControl.js";
|
|
5
|
+
export { anchorToViewport, getSafeAreaInsets } from "./anchorToViewport.js";
|
|
6
|
+
export type { AnchorToViewportOptions, SafeAreaInsets, SafeAreaOptions, ViewportAnchor, ViewportAnchorHandle } from "./anchorToViewport.js";
|
|
7
|
+
export { layoutAuto } from "./layoutAuto.js";
|
|
8
|
+
export type { LayoutAutoOptions, LayoutAutoScheduler, LayoutAutoTarget } from "./layoutAuto.js";
|
|
3
9
|
export { DebugPanel, createDebugPanel } from "./DebugPanel.js";
|
|
4
10
|
export type { CreateDebugPanelOptions } from "./DebugPanel.js";
|
|
5
11
|
export { DebugLabel, createDebugLabel } from "./DebugLabel.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAGzG,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAGzG,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAClH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,YAAY,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC9G,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAC3E,YAAY,EAAE,uBAAuB,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAC3I,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAG/F,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAC9D,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAG9D,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAC9D,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAG9D,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACjE,YAAY,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAGhE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAC9D,YAAY,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAGtF,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAChF,YAAY,EAAE,6BAA6B,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAA;AAGxG,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AACnF,YAAY,EAAE,8BAA8B,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAG/G,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC9E,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAA;AAEvE,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACvF,YAAY,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAA;AAE7E,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AACjF,YAAY,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAA;AAEzE,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAA;AAC5F,YAAY,EAAE,iCAAiC,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// Utilities
|
|
2
2
|
export { parseHex, toColorInt, dimHex, hexToColorAlpha, estimateTextWidth, getDevicePixelRatio } from "./utils.js";
|
|
3
|
+
export { bindDebugControl } from "./bindDebugControl.js";
|
|
4
|
+
export { anchorToViewport, getSafeAreaInsets } from "./anchorToViewport.js";
|
|
5
|
+
export { layoutAuto } from "./layoutAuto.js";
|
|
3
6
|
// Panel
|
|
4
7
|
export { DebugPanel, createDebugPanel } from "./DebugPanel.js";
|
|
5
8
|
// Label
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY;AACZ,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY;AACZ,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAClH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAE3E,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,QAAQ;AACR,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAG9D,QAAQ;AACR,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAG9D,SAAS;AACT,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAGjE,QAAQ;AACR,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAG9D,eAAe;AACf,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAGhF,gBAAgB;AAChB,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAGnF,oBAAoB;AACpB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAG9E,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAGvF,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAGjF,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface LayoutAutoTarget {
|
|
2
|
+
layout(): unknown;
|
|
3
|
+
}
|
|
4
|
+
export interface LayoutAutoOptions {
|
|
5
|
+
/** Scene event used for flushing dirty targets (default: "preupdate"). */
|
|
6
|
+
flushEvent?: "preupdate" | "postupdate";
|
|
7
|
+
}
|
|
8
|
+
export interface LayoutAutoScheduler {
|
|
9
|
+
markDirty(target: LayoutAutoTarget): this;
|
|
10
|
+
markDirtyMany(targets: LayoutAutoTarget[]): this;
|
|
11
|
+
remove(target: LayoutAutoTarget): this;
|
|
12
|
+
clear(): this;
|
|
13
|
+
flush(): this;
|
|
14
|
+
destroy(): void;
|
|
15
|
+
isDestroyed(): boolean;
|
|
16
|
+
getDirtyCount(): number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Frame-batched layout scheduler for row/column/grid/scroll containers.
|
|
20
|
+
*
|
|
21
|
+
* Call `markDirty(...)` after mutating children/options.
|
|
22
|
+
* Pending targets are laid out once per frame.
|
|
23
|
+
*/
|
|
24
|
+
export declare function layoutAuto(scene: Phaser.Scene, options?: LayoutAutoOptions): LayoutAutoScheduler;
|
|
25
|
+
//# sourceMappingURL=layoutAuto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layoutAuto.d.ts","sourceRoot":"","sources":["../src/layoutAuto.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAChC,MAAM,IAAI,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IACjC,0EAA0E;IAC1E,UAAU,CAAC,EAAE,WAAW,GAAG,YAAY,CAAA;CACvC;AAED,MAAM,WAAW,mBAAmB;IACnC,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACzC,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAA;IAChD,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACtC,KAAK,IAAI,IAAI,CAAA;IACb,KAAK,IAAI,IAAI,CAAA;IACb,OAAO,IAAI,IAAI,CAAA;IACf,WAAW,IAAI,OAAO,CAAA;IACtB,aAAa,IAAI,MAAM,CAAA;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,GAAE,iBAAsB,GAAG,mBAAmB,CAmEpG"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frame-batched layout scheduler for row/column/grid/scroll containers.
|
|
3
|
+
*
|
|
4
|
+
* Call `markDirty(...)` after mutating children/options.
|
|
5
|
+
* Pending targets are laid out once per frame.
|
|
6
|
+
*/
|
|
7
|
+
export function layoutAuto(scene, options = {}) {
|
|
8
|
+
const { flushEvent = "preupdate" } = options;
|
|
9
|
+
const dirty = new Set();
|
|
10
|
+
let destroyed = false;
|
|
11
|
+
let isFlushing = false;
|
|
12
|
+
const onFlushEvent = () => {
|
|
13
|
+
if (destroyed || dirty.size === 0)
|
|
14
|
+
return;
|
|
15
|
+
flushNow();
|
|
16
|
+
};
|
|
17
|
+
scene.events.on(flushEvent, onFlushEvent);
|
|
18
|
+
scene.events.once("shutdown", () => {
|
|
19
|
+
destroyScheduler();
|
|
20
|
+
});
|
|
21
|
+
const flushNow = () => {
|
|
22
|
+
if (destroyed || dirty.size === 0 || isFlushing)
|
|
23
|
+
return;
|
|
24
|
+
isFlushing = true;
|
|
25
|
+
const queue = Array.from(dirty);
|
|
26
|
+
dirty.clear();
|
|
27
|
+
for (const target of queue) {
|
|
28
|
+
if (destroyed)
|
|
29
|
+
break;
|
|
30
|
+
target.layout();
|
|
31
|
+
}
|
|
32
|
+
isFlushing = false;
|
|
33
|
+
};
|
|
34
|
+
const destroyScheduler = () => {
|
|
35
|
+
if (destroyed)
|
|
36
|
+
return;
|
|
37
|
+
destroyed = true;
|
|
38
|
+
dirty.clear();
|
|
39
|
+
scene.events.off(flushEvent, onFlushEvent);
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
markDirty(target) {
|
|
43
|
+
if (destroyed)
|
|
44
|
+
return this;
|
|
45
|
+
dirty.add(target);
|
|
46
|
+
return this;
|
|
47
|
+
},
|
|
48
|
+
markDirtyMany(targets) {
|
|
49
|
+
if (destroyed || targets.length === 0)
|
|
50
|
+
return this;
|
|
51
|
+
for (const target of targets)
|
|
52
|
+
dirty.add(target);
|
|
53
|
+
return this;
|
|
54
|
+
},
|
|
55
|
+
remove(target) {
|
|
56
|
+
if (destroyed)
|
|
57
|
+
return this;
|
|
58
|
+
dirty.delete(target);
|
|
59
|
+
return this;
|
|
60
|
+
},
|
|
61
|
+
clear() {
|
|
62
|
+
if (destroyed)
|
|
63
|
+
return this;
|
|
64
|
+
dirty.clear();
|
|
65
|
+
return this;
|
|
66
|
+
},
|
|
67
|
+
flush() {
|
|
68
|
+
flushNow();
|
|
69
|
+
return this;
|
|
70
|
+
},
|
|
71
|
+
destroy: destroyScheduler,
|
|
72
|
+
isDestroyed: () => destroyed,
|
|
73
|
+
getDirtyCount: () => dirty.size,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=layoutAuto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layoutAuto.js","sourceRoot":"","sources":["../src/layoutAuto.ts"],"names":[],"mappings":"AAoBA;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,KAAmB,EAAE,UAA6B,EAAE;IAC9E,MAAM,EAAE,UAAU,GAAG,WAAW,EAAE,GAAG,OAAO,CAAA;IAC5C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAA;IACzC,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,IAAI,UAAU,GAAG,KAAK,CAAA;IAEtB,MAAM,YAAY,GAAG,GAAS,EAAE;QAC/B,IAAI,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;YAAE,OAAM;QACzC,QAAQ,EAAE,CAAA;IACX,CAAC,CAAA;IAED,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;IACzC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE;QAClC,gBAAgB,EAAE,CAAA;IACnB,CAAC,CAAC,CAAA;IAEF,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC3B,IAAI,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,UAAU;YAAE,OAAM;QACvD,UAAU,GAAG,IAAI,CAAA;QAEjB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC/B,KAAK,CAAC,KAAK,EAAE,CAAA;QAEb,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;YAC5B,IAAI,SAAS;gBAAE,MAAK;YACpB,MAAM,CAAC,MAAM,EAAE,CAAA;QAChB,CAAC;QAED,UAAU,GAAG,KAAK,CAAA;IACnB,CAAC,CAAA;IAED,MAAM,gBAAgB,GAAG,GAAS,EAAE;QACnC,IAAI,SAAS;YAAE,OAAM;QACrB,SAAS,GAAG,IAAI,CAAA;QAChB,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;IAC3C,CAAC,CAAA;IAED,OAAO;QACN,SAAS,CAAC,MAAwB;YACjC,IAAI,SAAS;gBAAE,OAAO,IAAI,CAAA;YAC1B,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACjB,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,aAAa,CAAC,OAA2B;YACxC,IAAI,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAA;YAClD,KAAK,MAAM,MAAM,IAAI,OAAO;gBAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YAC/C,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,MAAM,CAAC,MAAwB;YAC9B,IAAI,SAAS;gBAAE,OAAO,IAAI,CAAA;YAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACpB,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,KAAK;YACJ,IAAI,SAAS;gBAAE,OAAO,IAAI,CAAA;YAC1B,KAAK,CAAC,KAAK,EAAE,CAAA;YACb,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,KAAK;YACJ,QAAQ,EAAE,CAAA;YACV,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,OAAO,EAAE,gBAAgB;QACzB,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS;QAC5B,aAAa,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI;KAC/B,CAAA;AACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vforsh/phaser-dev-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Pure-code debug UI primitives for Phaser 3 games — panels, buttons, labels, badges, progress bars, switch buttons, and layout containers. No assets required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|