@energy8platform/game-engine 0.2.1 → 0.4.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 +400 -35
- package/dist/animation.cjs.js +191 -1
- package/dist/animation.cjs.js.map +1 -1
- package/dist/animation.d.ts +117 -1
- package/dist/animation.esm.js +192 -3
- package/dist/animation.esm.js.map +1 -1
- package/dist/audio.cjs.js +66 -16
- package/dist/audio.cjs.js.map +1 -1
- package/dist/audio.d.ts +4 -0
- package/dist/audio.esm.js +66 -16
- package/dist/audio.esm.js.map +1 -1
- package/dist/core.cjs.js +307 -85
- package/dist/core.cjs.js.map +1 -1
- package/dist/core.d.ts +60 -1
- package/dist/core.esm.js +308 -86
- package/dist/core.esm.js.map +1 -1
- package/dist/debug.cjs.js +36 -68
- package/dist/debug.cjs.js.map +1 -1
- package/dist/debug.d.ts +4 -6
- package/dist/debug.esm.js +36 -68
- package/dist/debug.esm.js.map +1 -1
- package/dist/index.cjs.js +997 -475
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +356 -79
- package/dist/index.esm.js +983 -478
- package/dist/index.esm.js.map +1 -1
- package/dist/ui.cjs.js +816 -529
- package/dist/ui.cjs.js.map +1 -1
- package/dist/ui.d.ts +179 -41
- package/dist/ui.esm.js +798 -531
- package/dist/ui.esm.js.map +1 -1
- package/dist/vite.cjs.js +85 -68
- package/dist/vite.cjs.js.map +1 -1
- package/dist/vite.d.ts +17 -23
- package/dist/vite.esm.js +86 -68
- package/dist/vite.esm.js.map +1 -1
- package/package.json +19 -5
- package/src/animation/SpriteAnimation.ts +210 -0
- package/src/animation/Tween.ts +27 -1
- package/src/animation/index.ts +2 -0
- package/src/audio/AudioManager.ts +64 -15
- package/src/core/EventEmitter.ts +7 -1
- package/src/core/GameApplication.ts +19 -7
- package/src/core/SceneManager.ts +3 -1
- package/src/debug/DevBridge.ts +49 -80
- package/src/index.ts +22 -0
- package/src/input/InputManager.ts +26 -0
- package/src/loading/CSSPreloader.ts +7 -33
- package/src/loading/LoadingScene.ts +17 -41
- package/src/loading/index.ts +1 -0
- package/src/loading/logo.ts +95 -0
- package/src/types.ts +4 -0
- package/src/ui/BalanceDisplay.ts +12 -1
- package/src/ui/Button.ts +71 -130
- package/src/ui/Layout.ts +286 -0
- package/src/ui/Modal.ts +6 -5
- package/src/ui/Panel.ts +52 -55
- package/src/ui/ProgressBar.ts +52 -57
- package/src/ui/ScrollContainer.ts +126 -0
- package/src/ui/Toast.ts +19 -13
- package/src/ui/index.ts +17 -0
- package/src/viewport/ViewportManager.ts +2 -0
- package/src/vite/index.ts +103 -83
package/src/ui/Panel.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { Container,
|
|
1
|
+
import { Container, NineSliceSprite, Texture } from 'pixi.js';
|
|
2
|
+
import { LayoutContainer } from '@pixi/layout/components';
|
|
3
|
+
import type { LayoutStyles } from '@pixi/layout';
|
|
2
4
|
|
|
3
5
|
export interface PanelConfig {
|
|
4
6
|
/** Width */
|
|
@@ -24,7 +26,10 @@ export interface PanelConfig {
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
|
-
* Background panel
|
|
29
|
+
* Background panel powered by `@pixi/layout` LayoutContainer.
|
|
30
|
+
*
|
|
31
|
+
* Supports both Graphics-based (color + border) and 9-slice sprite backgrounds.
|
|
32
|
+
* Children added to `content` participate in flexbox layout automatically.
|
|
28
33
|
*
|
|
29
34
|
* @example
|
|
30
35
|
* ```ts
|
|
@@ -39,87 +44,79 @@ export interface PanelConfig {
|
|
|
39
44
|
* });
|
|
40
45
|
* ```
|
|
41
46
|
*/
|
|
42
|
-
export class Panel extends
|
|
43
|
-
private
|
|
44
|
-
private _content: Container;
|
|
45
|
-
private _config: Required<
|
|
47
|
+
export class Panel extends LayoutContainer {
|
|
48
|
+
private _panelConfig: Required<
|
|
46
49
|
Pick<PanelConfig, 'width' | 'height' | 'padding' | 'backgroundAlpha'>
|
|
47
50
|
> & PanelConfig;
|
|
48
51
|
|
|
49
52
|
constructor(config: PanelConfig = {}) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
padding: 16,
|
|
56
|
-
backgroundAlpha: 1,
|
|
53
|
+
const resolvedConfig = {
|
|
54
|
+
width: config.width ?? 400,
|
|
55
|
+
height: config.height ?? 300,
|
|
56
|
+
padding: config.padding ?? 16,
|
|
57
|
+
backgroundAlpha: config.backgroundAlpha ?? 1,
|
|
57
58
|
...config,
|
|
58
59
|
};
|
|
59
60
|
|
|
60
|
-
//
|
|
61
|
+
// If using a 9-slice texture, pass it as a custom background
|
|
62
|
+
let customBackground: Container | undefined;
|
|
61
63
|
if (config.nineSliceTexture) {
|
|
62
64
|
const texture =
|
|
63
65
|
typeof config.nineSliceTexture === 'string'
|
|
64
66
|
? Texture.from(config.nineSliceTexture)
|
|
65
67
|
: config.nineSliceTexture;
|
|
66
|
-
|
|
67
68
|
const [left, top, right, bottom] = config.nineSliceBorders ?? [10, 10, 10, 10];
|
|
68
|
-
|
|
69
|
-
this._bg = new NineSliceSprite({
|
|
69
|
+
const nineSlice = new NineSliceSprite({
|
|
70
70
|
texture,
|
|
71
71
|
leftWidth: left,
|
|
72
72
|
topHeight: top,
|
|
73
73
|
rightWidth: right,
|
|
74
74
|
bottomHeight: bottom,
|
|
75
75
|
});
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
this.drawGraphicsBg();
|
|
76
|
+
nineSlice.width = resolvedConfig.width;
|
|
77
|
+
nineSlice.height = resolvedConfig.height;
|
|
78
|
+
nineSlice.alpha = resolvedConfig.backgroundAlpha;
|
|
79
|
+
customBackground = nineSlice;
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
|
|
84
|
-
this.addChild(this._bg);
|
|
82
|
+
super(customBackground ? { background: customBackground } : undefined);
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
this._content = new Container();
|
|
88
|
-
this._content.x = this._config.padding;
|
|
89
|
-
this._content.y = this._config.padding;
|
|
90
|
-
this.addChild(this._content);
|
|
91
|
-
}
|
|
84
|
+
this._panelConfig = resolvedConfig;
|
|
92
85
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
// Apply layout styles
|
|
87
|
+
const layoutStyles: LayoutStyles = {
|
|
88
|
+
width: resolvedConfig.width,
|
|
89
|
+
height: resolvedConfig.height,
|
|
90
|
+
padding: resolvedConfig.padding,
|
|
91
|
+
flexDirection: 'column',
|
|
92
|
+
};
|
|
97
93
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
// Graphics-based background via layout styles
|
|
95
|
+
if (!config.nineSliceTexture) {
|
|
96
|
+
layoutStyles.backgroundColor = config.backgroundColor ?? 0x1a1a2e;
|
|
97
|
+
layoutStyles.borderRadius = config.borderRadius ?? 0;
|
|
98
|
+
if (config.borderColor !== undefined && config.borderWidth) {
|
|
99
|
+
layoutStyles.borderColor = config.borderColor;
|
|
100
|
+
layoutStyles.borderWidth = config.borderWidth;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.layout = layoutStyles;
|
|
102
105
|
|
|
103
|
-
if (
|
|
104
|
-
this.
|
|
105
|
-
} else {
|
|
106
|
-
this._bg.width = width;
|
|
107
|
-
this._bg.height = height;
|
|
106
|
+
if (!config.nineSliceTexture) {
|
|
107
|
+
this.background.alpha = resolvedConfig.backgroundAlpha;
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
} = this._config;
|
|
116
|
-
|
|
117
|
-
bg.clear();
|
|
118
|
-
bg.roundRect(0, 0, width!, height!, borderRadius ?? 0).fill(backgroundColor ?? 0x1a1a2e);
|
|
111
|
+
/** Access the content container (children added here participate in layout) */
|
|
112
|
+
get content(): Container {
|
|
113
|
+
return this.overflowContainer;
|
|
114
|
+
}
|
|
119
115
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
116
|
+
/** Resize the panel */
|
|
117
|
+
setSize(width: number, height: number): void {
|
|
118
|
+
this._panelConfig.width = width;
|
|
119
|
+
this._panelConfig.height = height;
|
|
120
|
+
this._layout?.setStyle({ width, height });
|
|
124
121
|
}
|
|
125
122
|
}
|
package/src/ui/ProgressBar.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Container, Graphics } from 'pixi.js';
|
|
2
|
+
import { ProgressBar as PixiProgressBar } from '@pixi/ui';
|
|
3
|
+
import type { ProgressBarOptions } from '@pixi/ui';
|
|
2
4
|
|
|
3
5
|
export interface ProgressBarConfig {
|
|
4
6
|
width?: number;
|
|
@@ -14,8 +16,16 @@ export interface ProgressBarConfig {
|
|
|
14
16
|
animationSpeed?: number;
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
function makeBarGraphics(
|
|
20
|
+
w: number, h: number, radius: number, color: number,
|
|
21
|
+
): Graphics {
|
|
22
|
+
return new Graphics().roundRect(0, 0, w, h, radius).fill(color);
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
/**
|
|
18
|
-
* Horizontal progress bar
|
|
26
|
+
* Horizontal progress bar powered by `@pixi/ui` ProgressBar.
|
|
27
|
+
*
|
|
28
|
+
* Provides optional smooth animated fill via per-frame `update()`.
|
|
19
29
|
*
|
|
20
30
|
* @example
|
|
21
31
|
* ```ts
|
|
@@ -25,9 +35,8 @@ export interface ProgressBarConfig {
|
|
|
25
35
|
* ```
|
|
26
36
|
*/
|
|
27
37
|
export class ProgressBar extends Container {
|
|
28
|
-
private
|
|
29
|
-
private
|
|
30
|
-
private _border: Graphics;
|
|
38
|
+
private _bar: PixiProgressBar;
|
|
39
|
+
private _borderGfx: Graphics;
|
|
31
40
|
private _config: Required<ProgressBarConfig>;
|
|
32
41
|
private _progress = 0;
|
|
33
42
|
private _displayedProgress = 0;
|
|
@@ -36,26 +45,45 @@ export class ProgressBar extends Container {
|
|
|
36
45
|
super();
|
|
37
46
|
|
|
38
47
|
this._config = {
|
|
39
|
-
width: 300,
|
|
40
|
-
height: 16,
|
|
41
|
-
borderRadius: 8,
|
|
42
|
-
fillColor: 0xffd700,
|
|
43
|
-
trackColor: 0x333333,
|
|
44
|
-
borderColor: 0x555555,
|
|
45
|
-
borderWidth: 1,
|
|
46
|
-
animated: true,
|
|
47
|
-
animationSpeed: 0.1,
|
|
48
|
-
...config,
|
|
48
|
+
width: config.width ?? 300,
|
|
49
|
+
height: config.height ?? 16,
|
|
50
|
+
borderRadius: config.borderRadius ?? 8,
|
|
51
|
+
fillColor: config.fillColor ?? 0xffd700,
|
|
52
|
+
trackColor: config.trackColor ?? 0x333333,
|
|
53
|
+
borderColor: config.borderColor ?? 0x555555,
|
|
54
|
+
borderWidth: config.borderWidth ?? 1,
|
|
55
|
+
animated: config.animated ?? true,
|
|
56
|
+
animationSpeed: config.animationSpeed ?? 0.1,
|
|
49
57
|
};
|
|
50
58
|
|
|
51
|
-
|
|
52
|
-
this._fill = new Graphics();
|
|
53
|
-
this._border = new Graphics();
|
|
59
|
+
const { width, height, borderRadius, fillColor, trackColor, borderColor, borderWidth } = this._config;
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
const bgGraphics = makeBarGraphics(width, height, borderRadius, trackColor);
|
|
62
|
+
const fillGraphics = makeBarGraphics(width - borderWidth * 2, height - borderWidth * 2, Math.max(0, borderRadius - 1), fillColor);
|
|
63
|
+
|
|
64
|
+
const options: ProgressBarOptions = {
|
|
65
|
+
bg: bgGraphics,
|
|
66
|
+
fill: fillGraphics,
|
|
67
|
+
fillPaddings: {
|
|
68
|
+
top: borderWidth,
|
|
69
|
+
right: borderWidth,
|
|
70
|
+
bottom: borderWidth,
|
|
71
|
+
left: borderWidth,
|
|
72
|
+
},
|
|
73
|
+
progress: 0,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
this._bar = new PixiProgressBar(options);
|
|
77
|
+
this.addChild(this._bar);
|
|
78
|
+
|
|
79
|
+
// Border overlay
|
|
80
|
+
this._borderGfx = new Graphics();
|
|
81
|
+
if (borderColor !== undefined && borderWidth > 0) {
|
|
82
|
+
this._borderGfx
|
|
83
|
+
.roundRect(0, 0, width, height, borderRadius)
|
|
84
|
+
.stroke({ color: borderColor, width: borderWidth });
|
|
85
|
+
}
|
|
86
|
+
this.addChild(this._borderGfx);
|
|
59
87
|
}
|
|
60
88
|
|
|
61
89
|
/** Get/set progress (0..1) */
|
|
@@ -67,14 +95,14 @@ export class ProgressBar extends Container {
|
|
|
67
95
|
this._progress = Math.max(0, Math.min(1, value));
|
|
68
96
|
if (!this._config.animated) {
|
|
69
97
|
this._displayedProgress = this._progress;
|
|
70
|
-
this.
|
|
98
|
+
this._bar.progress = this._displayedProgress * 100;
|
|
71
99
|
}
|
|
72
100
|
}
|
|
73
101
|
|
|
74
102
|
/**
|
|
75
103
|
* Call each frame if animated is true.
|
|
76
104
|
*/
|
|
77
|
-
update(
|
|
105
|
+
update(_dt: number): void {
|
|
78
106
|
if (!this._config.animated) return;
|
|
79
107
|
if (Math.abs(this._displayedProgress - this._progress) < 0.001) {
|
|
80
108
|
this._displayedProgress = this._progress;
|
|
@@ -83,39 +111,6 @@ export class ProgressBar extends Container {
|
|
|
83
111
|
|
|
84
112
|
this._displayedProgress +=
|
|
85
113
|
(this._progress - this._displayedProgress) * this._config.animationSpeed;
|
|
86
|
-
this.
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private drawTrack(): void {
|
|
90
|
-
const { width, height, borderRadius, trackColor } = this._config;
|
|
91
|
-
this._track.clear();
|
|
92
|
-
this._track.roundRect(0, 0, width, height, borderRadius).fill(trackColor);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
private drawBorder(): void {
|
|
96
|
-
const { width, height, borderRadius, borderColor, borderWidth } = this._config;
|
|
97
|
-
this._border.clear();
|
|
98
|
-
this._border
|
|
99
|
-
.roundRect(0, 0, width, height, borderRadius)
|
|
100
|
-
.stroke({ color: borderColor, width: borderWidth });
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private drawFill(progress: number): void {
|
|
104
|
-
const { width, height, borderRadius, fillColor, borderWidth } = this._config;
|
|
105
|
-
const innerWidth = width - borderWidth * 2;
|
|
106
|
-
const innerHeight = height - borderWidth * 2;
|
|
107
|
-
const fillWidth = Math.max(0, innerWidth * progress);
|
|
108
|
-
|
|
109
|
-
this._fill.clear();
|
|
110
|
-
if (fillWidth > 0) {
|
|
111
|
-
this._fill.x = borderWidth;
|
|
112
|
-
this._fill.y = borderWidth;
|
|
113
|
-
this._fill.roundRect(0, 0, fillWidth, innerHeight, borderRadius - 1).fill(fillColor);
|
|
114
|
-
|
|
115
|
-
// Highlight
|
|
116
|
-
this._fill
|
|
117
|
-
.roundRect(0, 0, fillWidth, innerHeight * 0.4, borderRadius - 1)
|
|
118
|
-
.fill({ color: 0xffffff, alpha: 0.15 });
|
|
119
|
-
}
|
|
114
|
+
this._bar.progress = this._displayedProgress * 100;
|
|
120
115
|
}
|
|
121
116
|
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Container, type ColorSource } from 'pixi.js';
|
|
2
|
+
import { ScrollBox as PixiScrollBox } from '@pixi/ui';
|
|
3
|
+
import type { ScrollBoxOptions } from '@pixi/ui';
|
|
4
|
+
|
|
5
|
+
// ─── Types ───────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
export type ScrollDirection = 'vertical' | 'horizontal' | 'both';
|
|
8
|
+
|
|
9
|
+
export interface ScrollContainerConfig {
|
|
10
|
+
/** Visible viewport width */
|
|
11
|
+
width: number;
|
|
12
|
+
|
|
13
|
+
/** Visible viewport height */
|
|
14
|
+
height: number;
|
|
15
|
+
|
|
16
|
+
/** Scroll direction (default: 'vertical') */
|
|
17
|
+
direction?: ScrollDirection;
|
|
18
|
+
|
|
19
|
+
/** Background color (undefined = transparent) */
|
|
20
|
+
backgroundColor?: ColorSource;
|
|
21
|
+
|
|
22
|
+
/** Border radius for the mask (default: 0) */
|
|
23
|
+
borderRadius?: number;
|
|
24
|
+
|
|
25
|
+
/** Gap between items (default: 0) */
|
|
26
|
+
elementsMargin?: number;
|
|
27
|
+
|
|
28
|
+
/** Padding */
|
|
29
|
+
padding?: number;
|
|
30
|
+
|
|
31
|
+
/** Disable dynamic rendering (render all items even when offscreen) */
|
|
32
|
+
disableDynamicRendering?: boolean;
|
|
33
|
+
|
|
34
|
+
/** Disable easing/inertia */
|
|
35
|
+
disableEasing?: boolean;
|
|
36
|
+
|
|
37
|
+
/** Global scroll — scroll even when mouse is not over the component */
|
|
38
|
+
globalScroll?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const DIRECTION_MAP: Record<ScrollDirection, 'vertical' | 'horizontal' | 'bidirectional'> = {
|
|
42
|
+
vertical: 'vertical',
|
|
43
|
+
horizontal: 'horizontal',
|
|
44
|
+
both: 'bidirectional',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Scrollable container powered by `@pixi/ui` ScrollBox.
|
|
49
|
+
*
|
|
50
|
+
* Provides touch/drag scrolling, mouse wheel support, inertia, and
|
|
51
|
+
* dynamic rendering optimization for off-screen items.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const scroll = new ScrollContainer({
|
|
56
|
+
* width: 600,
|
|
57
|
+
* height: 400,
|
|
58
|
+
* direction: 'vertical',
|
|
59
|
+
* elementsMargin: 8,
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* for (let i = 0; i < 50; i++) {
|
|
63
|
+
* scroll.addItem(createRow(i));
|
|
64
|
+
* }
|
|
65
|
+
*
|
|
66
|
+
* scene.container.addChild(scroll);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export class ScrollContainer extends PixiScrollBox {
|
|
70
|
+
private _scrollConfig: ScrollContainerConfig;
|
|
71
|
+
|
|
72
|
+
constructor(config: ScrollContainerConfig) {
|
|
73
|
+
const options: ScrollBoxOptions = {
|
|
74
|
+
width: config.width,
|
|
75
|
+
height: config.height,
|
|
76
|
+
type: DIRECTION_MAP[config.direction ?? 'vertical'],
|
|
77
|
+
radius: config.borderRadius ?? 0,
|
|
78
|
+
elementsMargin: config.elementsMargin ?? 0,
|
|
79
|
+
padding: config.padding ?? 0,
|
|
80
|
+
disableDynamicRendering: config.disableDynamicRendering ?? false,
|
|
81
|
+
disableEasing: config.disableEasing ?? false,
|
|
82
|
+
globalScroll: config.globalScroll ?? true,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
if (config.backgroundColor !== undefined) {
|
|
86
|
+
options.background = config.backgroundColor;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
super(options);
|
|
90
|
+
|
|
91
|
+
this._scrollConfig = config;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Set scrollable content. Replaces any existing content. */
|
|
95
|
+
setContent(content: Container): void {
|
|
96
|
+
// Remove existing items
|
|
97
|
+
const existing = this.items;
|
|
98
|
+
if (existing.length > 0) {
|
|
99
|
+
for (let i = existing.length - 1; i >= 0; i--) {
|
|
100
|
+
this.removeItem(i);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Add all children from the content container
|
|
105
|
+
const children = [...content.children] as Container[];
|
|
106
|
+
if (children.length > 0) {
|
|
107
|
+
this.addItems(children);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Add a single item */
|
|
112
|
+
addItem(...items: Container[]): Container {
|
|
113
|
+
this.addItems(items);
|
|
114
|
+
return items[0];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Scroll to make a specific item/child visible */
|
|
118
|
+
scrollToItem(index: number): void {
|
|
119
|
+
this.scrollTo(index);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Current scroll position */
|
|
123
|
+
get scrollPosition(): { x: number; y: number } {
|
|
124
|
+
return { x: this.scrollX, y: this.scrollY };
|
|
125
|
+
}
|
|
126
|
+
}
|
package/src/ui/Toast.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Container,
|
|
1
|
+
import { Container, Text } from 'pixi.js';
|
|
2
|
+
import { LayoutContainer } from '@pixi/layout/components';
|
|
2
3
|
import { Tween } from '../animation/Tween';
|
|
3
4
|
import { Easing } from '../animation/Easing';
|
|
4
5
|
|
|
@@ -21,6 +22,8 @@ const TOAST_COLORS: Record<ToastType, number> = {
|
|
|
21
22
|
/**
|
|
22
23
|
* Toast notification component for displaying transient messages.
|
|
23
24
|
*
|
|
25
|
+
* Uses `@pixi/layout` LayoutContainer for auto-sized background.
|
|
26
|
+
*
|
|
24
27
|
* @example
|
|
25
28
|
* ```ts
|
|
26
29
|
* const toast = new Toast();
|
|
@@ -29,7 +32,7 @@ const TOAST_COLORS: Record<ToastType, number> = {
|
|
|
29
32
|
* ```
|
|
30
33
|
*/
|
|
31
34
|
export class Toast extends Container {
|
|
32
|
-
private _bg:
|
|
35
|
+
private _bg: LayoutContainer;
|
|
33
36
|
private _text: Text;
|
|
34
37
|
private _config: Required<ToastConfig>;
|
|
35
38
|
private _dismissTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
@@ -38,12 +41,11 @@ export class Toast extends Container {
|
|
|
38
41
|
super();
|
|
39
42
|
|
|
40
43
|
this._config = {
|
|
41
|
-
duration: 3000,
|
|
42
|
-
bottomOffset: 60,
|
|
43
|
-
...config,
|
|
44
|
+
duration: config.duration ?? 3000,
|
|
45
|
+
bottomOffset: config.bottomOffset ?? 60,
|
|
44
46
|
};
|
|
45
47
|
|
|
46
|
-
this._bg = new
|
|
48
|
+
this._bg = new LayoutContainer();
|
|
47
49
|
this.addChild(this._bg);
|
|
48
50
|
|
|
49
51
|
this._text = new Text({
|
|
@@ -69,7 +71,6 @@ export class Toast extends Container {
|
|
|
69
71
|
viewWidth?: number,
|
|
70
72
|
viewHeight?: number,
|
|
71
73
|
): Promise<void> {
|
|
72
|
-
// Clear previous dismiss
|
|
73
74
|
if (this._dismissTimeout) {
|
|
74
75
|
clearTimeout(this._dismissTimeout);
|
|
75
76
|
}
|
|
@@ -81,10 +82,17 @@ export class Toast extends Container {
|
|
|
81
82
|
const height = 44;
|
|
82
83
|
const radius = 8;
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
this._bg.
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
// Style the background
|
|
86
|
+
this._bg.layout = {
|
|
87
|
+
width,
|
|
88
|
+
height,
|
|
89
|
+
borderRadius: radius,
|
|
90
|
+
backgroundColor: TOAST_COLORS[type],
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Center the bg around origin
|
|
94
|
+
this._bg.x = -width / 2;
|
|
95
|
+
this._bg.y = -height / 2;
|
|
88
96
|
|
|
89
97
|
// Position
|
|
90
98
|
if (viewWidth && viewHeight) {
|
|
@@ -96,10 +104,8 @@ export class Toast extends Container {
|
|
|
96
104
|
this.alpha = 0;
|
|
97
105
|
this.y += 20;
|
|
98
106
|
|
|
99
|
-
// Animate in
|
|
100
107
|
await Tween.to(this, { alpha: 1, y: this.y - 20 }, 300, Easing.easeOutCubic);
|
|
101
108
|
|
|
102
|
-
// Auto-dismiss
|
|
103
109
|
if (this._config.duration > 0) {
|
|
104
110
|
this._dismissTimeout = setTimeout(() => {
|
|
105
111
|
this.dismiss();
|
package/src/ui/index.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// ─── @pixi/layout setup (must be imported before creating containers) ────
|
|
2
|
+
import '@pixi/layout';
|
|
3
|
+
|
|
4
|
+
// ─── Engine UI Components ─────────────────────────────────
|
|
1
5
|
export { Button } from './Button';
|
|
2
6
|
export type { ButtonConfig, ButtonState } from './Button';
|
|
3
7
|
export { ProgressBar } from './ProgressBar';
|
|
@@ -14,3 +18,16 @@ export { Modal } from './Modal';
|
|
|
14
18
|
export type { ModalConfig } from './Modal';
|
|
15
19
|
export { Toast } from './Toast';
|
|
16
20
|
export type { ToastConfig, ToastType } from './Toast';
|
|
21
|
+
export { Layout } from './Layout';
|
|
22
|
+
export type { LayoutConfig, LayoutDirection, LayoutAlignment, LayoutAnchor } from './Layout';
|
|
23
|
+
export { ScrollContainer } from './ScrollContainer';
|
|
24
|
+
export type { ScrollContainerConfig, ScrollDirection } from './ScrollContainer';
|
|
25
|
+
|
|
26
|
+
// ─── Re-exports from @pixi/ui for direct use ─────────────
|
|
27
|
+
export { FancyButton, ScrollBox, ButtonContainer } from '@pixi/ui';
|
|
28
|
+
export type { ButtonOptions, ScrollBoxOptions, ProgressBarOptions } from '@pixi/ui';
|
|
29
|
+
|
|
30
|
+
// ─── Re-exports from @pixi/layout for direct use ─────────
|
|
31
|
+
export { LayoutContainer } from '@pixi/layout/components';
|
|
32
|
+
export { Layout as PixiLayout } from '@pixi/layout';
|
|
33
|
+
export type { LayoutStyles, LayoutOptions } from '@pixi/layout';
|
|
@@ -205,6 +205,8 @@ export class ViewportManager extends EventEmitter<ViewportEvents> {
|
|
|
205
205
|
this._destroyed = true;
|
|
206
206
|
this._resizeObserver?.disconnect();
|
|
207
207
|
this._resizeObserver = null;
|
|
208
|
+
// Remove fallback window resize listener if it was used
|
|
209
|
+
window.removeEventListener('resize', this.onWindowResize);
|
|
208
210
|
if (this._resizeTimeout !== null) {
|
|
209
211
|
clearTimeout(this._resizeTimeout);
|
|
210
212
|
}
|