pixifact 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +14 -0
  2. package/dist/compiler/builtinScenes.d.ts +0 -5
  3. package/dist/compiler/builtinScenes.js +0 -26
  4. package/dist/compiler/commands/index.js +8 -5
  5. package/dist/compiler/compileScenes.d.ts +4 -1
  6. package/dist/compiler/compileScenes.js +40 -11
  7. package/dist/compiler/index.d.ts +0 -5
  8. package/dist/compiler/index.js +0 -5
  9. package/dist/compiler/pixiNodeSchema.d.ts +4 -3
  10. package/dist/compiler/pixiNodeSchema.js +60 -6
  11. package/dist/compiler/sceneValidation.d.ts +3 -1
  12. package/dist/compiler/sceneValidation.js +105 -6
  13. package/dist/compiler/spec.d.ts +19 -8
  14. package/dist/compiler/spec.js +3 -1
  15. package/dist/compiler/templateParser.js +19 -0
  16. package/dist/compiler/templateSerializer.js +7 -1
  17. package/dist/compiler/typescriptCompiler.js +118 -51
  18. package/dist/compiler-node/builtinSceneInterfaces.d.ts +6 -0
  19. package/dist/compiler-node/builtinSceneInterfaces.js +27 -0
  20. package/dist/compiler-node/index.d.ts +2 -0
  21. package/dist/compiler-node/index.js +2 -0
  22. package/dist/{compiler → compiler-node}/scriptInterfaceExtractor.d.ts +1 -1
  23. package/dist/{compiler → compiler-node}/scriptInterfaceExtractor.js +157 -25
  24. package/dist/compiler-node/vite.d.ts +2 -1
  25. package/dist/compiler-node/vite.js +29 -2
  26. package/dist/platform/wechat/adapter.d.ts +316 -0
  27. package/dist/platform/wechat/adapter.js +26 -0
  28. package/dist/platform/wechat/application.d.ts +32 -0
  29. package/dist/platform/wechat/application.js +79 -0
  30. package/dist/platform/wechat/fetch.d.ts +1 -0
  31. package/dist/platform/wechat/fetch.js +145 -0
  32. package/dist/platform/wechat/index.d.ts +4 -0
  33. package/dist/platform/wechat/index.js +3 -0
  34. package/dist/platform/wechat/input.d.ts +12 -0
  35. package/dist/platform/wechat/input.js +93 -0
  36. package/dist/platform/wechat/lifecycle.d.ts +14 -0
  37. package/dist/platform/wechat/lifecycle.js +42 -0
  38. package/dist/platform/wechat/runtime.d.ts +49 -0
  39. package/dist/platform/wechat/runtime.js +189 -0
  40. package/dist/platform/wechat/subpackage.d.ts +1 -0
  41. package/dist/platform/wechat/subpackage.js +27 -0
  42. package/dist/platform/wechat/types.d.ts +105 -0
  43. package/dist/platform/wechat/types.js +3 -0
  44. package/dist/project/index.d.ts +23 -0
  45. package/dist/project/index.js +69 -0
  46. package/dist/runtime/BitmapLabel.d.ts +9 -0
  47. package/dist/runtime/BitmapLabel.js +7 -0
  48. package/dist/runtime/Label.d.ts +9 -0
  49. package/dist/runtime/Label.js +7 -0
  50. package/dist/runtime/ScrollContainer.d.ts +2 -0
  51. package/dist/runtime/ScrollContainer.js +12 -2
  52. package/dist/runtime/TextBoxControl.d.ts +48 -0
  53. package/dist/runtime/TextBoxControl.js +162 -0
  54. package/dist/runtime/index.d.ts +2 -0
  55. package/dist/runtime/index.js +2 -0
  56. package/dist/runtime/runtimeBehavior.d.ts +3 -0
  57. package/dist/runtime/runtimeBehavior.js +11 -0
  58. package/dist/{compiler → scene}/decorators.d.ts +2 -1
  59. package/dist/{compiler → scene}/decorators.js +12 -7
  60. package/dist/scene/index.d.ts +6 -0
  61. package/dist/scene/index.js +6 -0
  62. package/dist/scene/sceneAssetRuntime.d.ts +11 -0
  63. package/dist/scene/sceneAssetRuntime.js +43 -0
  64. package/dist/scene/sceneBindingRuntime.d.ts +10 -0
  65. package/dist/scene/sceneBindingRuntime.js +124 -0
  66. package/dist/{compiler → scene}/sceneRuntime.d.ts +7 -0
  67. package/dist/scene/sceneRuntime.js +85 -0
  68. package/package.json +11 -1
  69. package/dist/compiler/sceneRuntime.js +0 -22
  70. /package/dist/{compiler → scene}/eventRuntime.d.ts +0 -0
  71. /package/dist/{compiler → scene}/eventRuntime.js +0 -0
  72. /package/dist/{compiler → scene}/slotRuntime.d.ts +0 -0
  73. /package/dist/{compiler → scene}/slotRuntime.js +0 -0
@@ -0,0 +1,105 @@
1
+ export interface WechatCanvas {
2
+ width: number;
3
+ height: number;
4
+ isConnected?: boolean;
5
+ style?: Record<string, string>;
6
+ getContext(contextId: string, options?: Record<string, unknown>): unknown;
7
+ getBoundingClientRect?(): {
8
+ bottom: number;
9
+ height: number;
10
+ left: number;
11
+ right: number;
12
+ top: number;
13
+ width: number;
14
+ x: number;
15
+ y: number;
16
+ };
17
+ requestAnimationFrame?(callback: FrameRequestCallback): number;
18
+ cancelAnimationFrame?(requestId: number): void;
19
+ addEventListener?(type: string, listener: EventListenerOrEventListenerObject, options?: unknown): void;
20
+ removeEventListener?(type: string, listener: EventListenerOrEventListenerObject, options?: unknown): void;
21
+ dispatchEvent?(event: Event): boolean;
22
+ }
23
+ export interface WechatImage {
24
+ width: number;
25
+ height: number;
26
+ complete?: boolean;
27
+ crossOrigin?: string | null;
28
+ src: string;
29
+ onload: (() => void) | null;
30
+ onerror: ((error: unknown) => void) | null;
31
+ }
32
+ export interface WechatTouch {
33
+ clientX?: number;
34
+ clientY?: number;
35
+ force?: number;
36
+ identifier?: number;
37
+ pageX?: number;
38
+ pageY?: number;
39
+ x?: number;
40
+ y?: number;
41
+ }
42
+ export interface WechatTouchEvent {
43
+ changedTouches?: WechatTouch[];
44
+ touches?: WechatTouch[];
45
+ }
46
+ export interface WechatMiniGameApi {
47
+ createCanvas(): WechatCanvas;
48
+ createImage(): WechatImage;
49
+ createOffscreenCanvas?(options: {
50
+ type: '2d' | 'webgl';
51
+ width: number;
52
+ height: number;
53
+ }): WechatCanvas;
54
+ getDeviceInfo?(): Record<string, unknown>;
55
+ getFileSystemManager(): {
56
+ readFile(options: {
57
+ filePath: string;
58
+ fail(error: {
59
+ errMsg: string;
60
+ }): void;
61
+ success(result: {
62
+ data: ArrayBuffer | string;
63
+ }): void;
64
+ }): void;
65
+ };
66
+ getSystemInfoSync?(): Record<string, unknown>;
67
+ getWindowInfo?(): Record<string, unknown>;
68
+ loadSubpackage(options: {
69
+ name: string;
70
+ fail(error: {
71
+ errMsg: string;
72
+ }): void;
73
+ success(): void;
74
+ }): {
75
+ onProgressUpdate(callback: (progress: {
76
+ progress: number;
77
+ }) => void): void;
78
+ };
79
+ request(options: {
80
+ url: string;
81
+ method: 'GET';
82
+ responseType: 'arraybuffer';
83
+ fail(error: {
84
+ errMsg: string;
85
+ }): void;
86
+ success(result: {
87
+ data: ArrayBuffer | string | Record<string, unknown>;
88
+ header: Record<string, string>;
89
+ statusCode: number;
90
+ }): void;
91
+ }): void;
92
+ onHide(callback: () => void): void;
93
+ offHide?(callback: () => void): void;
94
+ onShow(callback: () => void): void;
95
+ offShow?(callback: () => void): void;
96
+ onTouchStart(callback: (event: WechatTouchEvent) => void): void;
97
+ offTouchStart?(callback: (event: WechatTouchEvent) => void): void;
98
+ onTouchMove(callback: (event: WechatTouchEvent) => void): void;
99
+ offTouchMove?(callback: (event: WechatTouchEvent) => void): void;
100
+ onTouchEnd(callback: (event: WechatTouchEvent) => void): void;
101
+ offTouchEnd?(callback: (event: WechatTouchEvent) => void): void;
102
+ onTouchCancel(callback: (event: WechatTouchEvent) => void): void;
103
+ offTouchCancel?(callback: (event: WechatTouchEvent) => void): void;
104
+ }
105
+ export declare function wechatApi(): WechatMiniGameApi;
@@ -0,0 +1,3 @@
1
+ export function wechatApi() {
2
+ return globalThis.wx;
3
+ }
@@ -10,12 +10,33 @@ export interface PixifactProjectResolution {
10
10
  width: number;
11
11
  height: number;
12
12
  }
13
+ export interface PixifactProjectResourcePack {
14
+ root: string;
15
+ }
16
+ export type PixifactWechatResourcePack = {
17
+ delivery: 'subpackage';
18
+ root: string;
19
+ } | {
20
+ delivery: 'remote';
21
+ baseUrl: string;
22
+ };
23
+ export interface PixifactWechatTargetConfig {
24
+ entry: string;
25
+ configDir: string;
26
+ outDir: string;
27
+ resourcePacks: Record<string, PixifactWechatResourcePack>;
28
+ }
29
+ export interface PixifactProjectTargets {
30
+ wechat?: PixifactWechatTargetConfig;
31
+ }
13
32
  export interface PixifactProjectConfig {
14
33
  version: 1;
15
34
  name: string;
16
35
  resolution: PixifactProjectResolution;
17
36
  viewport: PixifactProjectViewport;
18
37
  scenes: Record<string, string>;
38
+ resourcePacks?: Record<string, PixifactProjectResourcePack>;
39
+ targets?: PixifactProjectTargets;
19
40
  run?: PixifactProjectRunConfig;
20
41
  }
21
42
  export type PixifactProjectViewport = PixifactViewportConfig;
@@ -24,6 +45,8 @@ export interface PixifactProjectSummary {
24
45
  resolution: PixifactProjectResolution;
25
46
  viewport: PixifactProjectViewport;
26
47
  scenes: Record<string, string>;
48
+ resourcePacks?: Record<string, PixifactProjectResourcePack>;
49
+ targets?: PixifactProjectTargets;
27
50
  run?: PixifactProjectRunConfig;
28
51
  }
29
52
  export declare const defaultPixifactProjectResolution: PixifactProjectResolution;
@@ -49,6 +49,13 @@ function normalizeRunCwd(value) {
49
49
  }
50
50
  return normalizeProjectPath(input, 'run.cwd');
51
51
  }
52
+ function normalizeProjectChildPath(value, name) {
53
+ const input = normalizeProjectPath(value, name);
54
+ if (input === '.') {
55
+ throw new Error(`${name} must not be projectRoot.`);
56
+ }
57
+ return input;
58
+ }
52
59
  function parseScenes(value) {
53
60
  const scenes = assertRecord(value, 'scenes');
54
61
  return Object.fromEntries(Object.entries(scenes).map(([key, scenePath]) => [
@@ -97,17 +104,77 @@ function parseRun(value) {
97
104
  ...(run.url === undefined ? {} : { url: assertString(run.url, 'run.url') }),
98
105
  };
99
106
  }
107
+ function parseResourcePacks(value) {
108
+ if (value === undefined) {
109
+ return undefined;
110
+ }
111
+ const packs = assertRecord(value, 'resourcePacks');
112
+ return Object.fromEntries(Object.entries(packs).map(([name, packValue]) => {
113
+ const pack = assertRecord(packValue, `resourcePacks.${name}`);
114
+ return [assertString(name, 'resource pack name'), {
115
+ root: normalizeProjectChildPath(pack.root, `resourcePacks.${name}.root`),
116
+ }];
117
+ }));
118
+ }
119
+ function parseWechatResourcePacks(value) {
120
+ const packs = assertRecord(value, 'targets.wechat.resourcePacks');
121
+ return Object.fromEntries(Object.entries(packs).map(([name, packValue]) => {
122
+ const pack = assertRecord(packValue, `targets.wechat.resourcePacks.${name}`);
123
+ const delivery = assertString(pack.delivery, `targets.wechat.resourcePacks.${name}.delivery`);
124
+ if (delivery === 'subpackage') {
125
+ return [name, {
126
+ delivery,
127
+ root: normalizeProjectChildPath(pack.root, `targets.wechat.resourcePacks.${name}.root`),
128
+ }];
129
+ }
130
+ if (delivery === 'remote') {
131
+ return [name, {
132
+ delivery,
133
+ baseUrl: assertString(pack.baseUrl, `targets.wechat.resourcePacks.${name}.baseUrl`).replace(/\/+$/, ''),
134
+ }];
135
+ }
136
+ throw new Error(`targets.wechat.resourcePacks.${name}.delivery must be subpackage or remote.`);
137
+ }));
138
+ }
139
+ function parseTargets(value) {
140
+ if (value === undefined) {
141
+ return undefined;
142
+ }
143
+ const targets = assertRecord(value, 'targets');
144
+ if (targets.wechat === undefined) {
145
+ return {};
146
+ }
147
+ const wechat = assertRecord(targets.wechat, 'targets.wechat');
148
+ const outDir = normalizeProjectChildPath(wechat.outDir, 'targets.wechat.outDir');
149
+ return {
150
+ wechat: {
151
+ entry: normalizeProjectPath(wechat.entry, 'targets.wechat.entry'),
152
+ configDir: normalizeProjectPath(wechat.configDir, 'targets.wechat.configDir'),
153
+ outDir,
154
+ resourcePacks: parseWechatResourcePacks(wechat.resourcePacks),
155
+ },
156
+ };
157
+ }
100
158
  export function parsePixifactProjectConfig(value) {
101
159
  const config = assertRecord(value, 'pixifact.project.json');
102
160
  if (config.version !== 1) {
103
161
  throw new Error('pixifact.project.json version must be 1.');
104
162
  }
163
+ const resourcePacks = parseResourcePacks(config.resourcePacks);
164
+ const targets = parseTargets(config.targets);
165
+ for (const name of Object.keys(targets?.wechat?.resourcePacks ?? {})) {
166
+ if (!resourcePacks?.[name]) {
167
+ throw new Error(`targets.wechat.resourcePacks.${name} must reference resourcePacks.${name}.`);
168
+ }
169
+ }
105
170
  return {
106
171
  version: 1,
107
172
  name: assertString(config.name, 'name'),
108
173
  resolution: parseResolution(config.resolution),
109
174
  viewport: parseViewport(config.viewport),
110
175
  scenes: parseScenes(config.scenes),
176
+ ...(resourcePacks === undefined ? {} : { resourcePacks }),
177
+ ...(targets === undefined ? {} : { targets }),
111
178
  run: parseRun(config.run),
112
179
  };
113
180
  }
@@ -117,6 +184,8 @@ export function summarizePixifactProjectConfig(config) {
117
184
  resolution: config.resolution,
118
185
  viewport: config.viewport,
119
186
  scenes: config.scenes,
187
+ ...(config.resourcePacks === undefined ? {} : { resourcePacks: config.resourcePacks }),
188
+ ...(config.targets === undefined ? {} : { targets: config.targets }),
120
189
  ...(config.run === undefined ? {} : { run: config.run }),
121
190
  };
122
191
  }
@@ -0,0 +1,9 @@
1
+ import { BitmapText } from 'pixi.js';
2
+ import { TextBoxControl, type TextBoxAlign, type TextBoxFontWeight, type TextBoxOptions, type TextBoxOverflow } from './TextBoxControl.js';
3
+ export type BitmapLabelAlign = TextBoxAlign;
4
+ export type BitmapLabelOverflow = TextBoxOverflow;
5
+ export type BitmapLabelFontWeight = TextBoxFontWeight;
6
+ export type BitmapLabelOptions = TextBoxOptions;
7
+ export declare class BitmapLabel extends TextBoxControl<BitmapText> {
8
+ constructor(options?: BitmapLabelOptions);
9
+ }
@@ -0,0 +1,7 @@
1
+ import { BitmapText } from 'pixi.js';
2
+ import { TextBoxControl, } from './TextBoxControl.js';
3
+ export class BitmapLabel extends TextBoxControl {
4
+ constructor(options = {}) {
5
+ super(options, (textOptions) => new BitmapText(textOptions));
6
+ }
7
+ }
@@ -0,0 +1,9 @@
1
+ import { Text } from 'pixi.js';
2
+ import { TextBoxControl, type TextBoxAlign, type TextBoxFontWeight, type TextBoxOptions, type TextBoxOverflow } from './TextBoxControl.js';
3
+ export type LabelAlign = TextBoxAlign;
4
+ export type LabelOverflow = TextBoxOverflow;
5
+ export type LabelFontWeight = TextBoxFontWeight;
6
+ export type LabelOptions = TextBoxOptions;
7
+ export declare class Label extends TextBoxControl<Text> {
8
+ constructor(options?: LabelOptions);
9
+ }
@@ -0,0 +1,7 @@
1
+ import { Text } from 'pixi.js';
2
+ import { TextBoxControl, } from './TextBoxControl.js';
3
+ export class Label extends TextBoxControl {
4
+ constructor(options = {}) {
5
+ super(options, (textOptions) => new Text(textOptions));
6
+ }
7
+ }
@@ -1,6 +1,7 @@
1
1
  import { Container, type ContainerChild, type DestroyOptions } from 'pixi.js';
2
2
  import { Control } from './Control.js';
3
3
  import type { GroupOptions } from './Group.js';
4
+ import { runtimeBehavior } from './runtimeBehavior.js';
4
5
  export type ScrollDirection = 'vertical' | 'horizontal' | 'both';
5
6
  export type ScrollContainerOptions = GroupOptions & {
6
7
  direction?: ScrollDirection;
@@ -11,6 +12,7 @@ export declare class ScrollContainer extends Control {
11
12
  #private;
12
13
  readonly contentLayer: Container<ContainerChild>;
13
14
  constructor(options?: ScrollContainerOptions);
15
+ [runtimeBehavior](): void;
14
16
  get direction(): ScrollDirection;
15
17
  set direction(value: ScrollDirection);
16
18
  get scrollX(): number;
@@ -1,5 +1,6 @@
1
1
  import { Container, Graphics, Ticker, } from 'pixi.js';
2
2
  import { Control } from './Control.js';
3
+ import { runtimeBehavior } from './runtimeBehavior.js';
3
4
  const elasticResistance = 0.5;
4
5
  const inertiaFriction = 0.92;
5
6
  const springStrength = 0.18;
@@ -26,19 +27,21 @@ export class ScrollContainer extends Control {
26
27
  this.#direction = direction ?? this.#direction;
27
28
  this.#targetScrollX = scrollX ?? this.#targetScrollX;
28
29
  this.#targetScrollY = scrollY ?? this.#targetScrollY;
29
- this.eventMode = 'static';
30
30
  this.contentLayer.mask = this.#mask;
31
31
  this.contentLayer.on('childAdded', this.#handleContentChildAdded, this);
32
32
  this.contentLayer.on('childRemoved', this.#handleContentChildRemoved, this);
33
33
  super.addChild(this.contentLayer);
34
34
  super.addChild(this.#mask);
35
+ this.layout();
36
+ }
37
+ [runtimeBehavior]() {
38
+ this.eventMode = 'static';
35
39
  this.on('wheel', this.#handleWheel, this);
36
40
  this.on('pointerdown', this.#handlePointerDown, this);
37
41
  this.on('globalpointermove', this.#handleGlobalPointerMove, this);
38
42
  this.on('pointerup', this.#handlePointerUp, this);
39
43
  this.on('pointerupoutside', this.#handlePointerUp, this);
40
44
  this.on('pointercancel', this.#handlePointerUp, this);
41
- this.layout();
42
45
  }
43
46
  get direction() {
44
47
  return this.#direction;
@@ -116,6 +119,13 @@ export class ScrollContainer extends Control {
116
119
  destroy(options) {
117
120
  this.#destroying = true;
118
121
  this.#stopMomentum();
122
+ this.#drag = undefined;
123
+ this.off('wheel', this.#handleWheel, this);
124
+ this.off('pointerdown', this.#handlePointerDown, this);
125
+ this.off('globalpointermove', this.#handleGlobalPointerMove, this);
126
+ this.off('pointerup', this.#handlePointerUp, this);
127
+ this.off('pointerupoutside', this.#handlePointerUp, this);
128
+ this.off('pointercancel', this.#handlePointerUp, this);
119
129
  this.contentLayer.off('childAdded', this.#handleContentChildAdded, this);
120
130
  this.contentLayer.off('childRemoved', this.#handleContentChildRemoved, this);
121
131
  for (const child of this.#watchedContent) {
@@ -0,0 +1,48 @@
1
+ import { BitmapText, Text, type TextOptions } from 'pixi.js';
2
+ import { Control } from './Control.js';
3
+ import type { GroupOptions } from './Group.js';
4
+ export type TextBoxAlign = 'start' | 'center' | 'end';
5
+ export type TextBoxOverflow = 'visible' | 'clip';
6
+ export type TextBoxFontWeight = 400 | 500 | 600 | 700 | '400' | '500' | '600' | '700' | 'bold';
7
+ export type TextBoxOptions = GroupOptions & {
8
+ text?: string;
9
+ fontFamily?: string;
10
+ fontSize?: number;
11
+ fontWeight?: TextBoxFontWeight;
12
+ fill?: number;
13
+ lineHeight?: number;
14
+ letterSpacing?: number;
15
+ wordWrap?: boolean;
16
+ alignX?: TextBoxAlign;
17
+ alignY?: TextBoxAlign;
18
+ overflow?: TextBoxOverflow;
19
+ };
20
+ type TextBoxRenderer = Text | BitmapText;
21
+ export declare class TextBoxControl<T extends TextBoxRenderer> extends Control {
22
+ #private;
23
+ constructor(options: TextBoxOptions, createTextNode: (options: TextOptions) => T);
24
+ get text(): string;
25
+ set text(value: string);
26
+ get fontFamily(): string;
27
+ set fontFamily(value: string);
28
+ get fontSize(): number;
29
+ set fontSize(value: number);
30
+ get fontWeight(): TextBoxFontWeight;
31
+ set fontWeight(value: TextBoxFontWeight);
32
+ get fill(): number;
33
+ set fill(value: number);
34
+ get lineHeight(): number;
35
+ set lineHeight(value: number);
36
+ get letterSpacing(): number;
37
+ set letterSpacing(value: number);
38
+ get wordWrap(): boolean;
39
+ set wordWrap(value: boolean);
40
+ get alignX(): TextBoxAlign;
41
+ set alignX(value: TextBoxAlign);
42
+ get alignY(): TextBoxAlign;
43
+ set alignY(value: TextBoxAlign);
44
+ get overflow(): TextBoxOverflow;
45
+ set overflow(value: TextBoxOverflow);
46
+ layout(): void;
47
+ }
48
+ export {};
@@ -0,0 +1,162 @@
1
+ import { Graphics, } from 'pixi.js';
2
+ import { Control } from './Control.js';
3
+ export class TextBoxControl extends Control {
4
+ #textNode;
5
+ #clipMask = new Graphics();
6
+ #fontFamily = 'Arial';
7
+ #fontSize = 16;
8
+ #fontWeight = 400;
9
+ #fill = 0x111827;
10
+ #lineHeight = 0;
11
+ #letterSpacing = 0;
12
+ #wordWrap = false;
13
+ #alignX = 'start';
14
+ #alignY = 'start';
15
+ #overflow = 'visible';
16
+ constructor(options, createTextNode) {
17
+ const { text = 'Text', width = 120, height = 28, fontFamily = 'Arial', fontSize = 16, fontWeight = 400, fill = 0x111827, lineHeight = 0, letterSpacing = 0, wordWrap = false, alignX = 'start', alignY = 'start', overflow = 'visible', ...groupOptions } = options;
18
+ super({ ...groupOptions, width, height });
19
+ this.#fontFamily = fontFamily;
20
+ this.#fontSize = fontSize;
21
+ this.#fontWeight = fontWeight;
22
+ this.#fill = fill;
23
+ this.#lineHeight = lineHeight;
24
+ this.#letterSpacing = letterSpacing;
25
+ this.#wordWrap = wordWrap;
26
+ this.#alignX = alignX;
27
+ this.#alignY = alignY;
28
+ this.#overflow = overflow;
29
+ this.#textNode = createTextNode({
30
+ text,
31
+ style: {
32
+ fontFamily,
33
+ fontSize,
34
+ fontWeight: String(fontWeight),
35
+ fill,
36
+ lineHeight,
37
+ letterSpacing,
38
+ wordWrap,
39
+ wordWrapWidth: width,
40
+ align: horizontalTextAlign(alignX),
41
+ },
42
+ });
43
+ super.addChild(this.#textNode, this.#clipMask);
44
+ this.layout();
45
+ }
46
+ get text() {
47
+ return this.#textNode.text;
48
+ }
49
+ set text(value) {
50
+ this.#textNode.text = value;
51
+ this.layout();
52
+ }
53
+ get fontFamily() {
54
+ return this.#fontFamily;
55
+ }
56
+ set fontFamily(value) {
57
+ this.#fontFamily = value;
58
+ this.#textNode.style.fontFamily = value;
59
+ this.layout();
60
+ }
61
+ get fontSize() {
62
+ return this.#fontSize;
63
+ }
64
+ set fontSize(value) {
65
+ this.#fontSize = value;
66
+ this.#textNode.style.fontSize = value;
67
+ this.layout();
68
+ }
69
+ get fontWeight() {
70
+ return this.#fontWeight;
71
+ }
72
+ set fontWeight(value) {
73
+ this.#fontWeight = value;
74
+ this.#textNode.style.fontWeight = String(value);
75
+ this.layout();
76
+ }
77
+ get fill() {
78
+ return this.#fill;
79
+ }
80
+ set fill(value) {
81
+ this.#fill = value;
82
+ this.#textNode.style.fill = value;
83
+ this.layout();
84
+ }
85
+ get lineHeight() {
86
+ return this.#lineHeight;
87
+ }
88
+ set lineHeight(value) {
89
+ this.#lineHeight = value;
90
+ this.#textNode.style.lineHeight = value;
91
+ this.layout();
92
+ }
93
+ get letterSpacing() {
94
+ return this.#letterSpacing;
95
+ }
96
+ set letterSpacing(value) {
97
+ this.#letterSpacing = value;
98
+ this.#textNode.style.letterSpacing = value;
99
+ this.layout();
100
+ }
101
+ get wordWrap() {
102
+ return this.#wordWrap;
103
+ }
104
+ set wordWrap(value) {
105
+ this.#wordWrap = value;
106
+ this.#textNode.style.wordWrap = value;
107
+ this.layout();
108
+ }
109
+ get alignX() {
110
+ return this.#alignX;
111
+ }
112
+ set alignX(value) {
113
+ this.#alignX = value;
114
+ this.#textNode.style.align = horizontalTextAlign(value);
115
+ this.layout();
116
+ }
117
+ get alignY() {
118
+ return this.#alignY;
119
+ }
120
+ set alignY(value) {
121
+ this.#alignY = value;
122
+ this.layout();
123
+ }
124
+ get overflow() {
125
+ return this.#overflow;
126
+ }
127
+ set overflow(value) {
128
+ this.#overflow = value;
129
+ this.layout();
130
+ }
131
+ layout() {
132
+ super.layout();
133
+ if (!this.#textNode) {
134
+ return;
135
+ }
136
+ this.#textNode.style.wordWrapWidth = this.width;
137
+ this.#textNode.anchor.set(alignmentFactor(this.#alignX), alignmentFactor(this.#alignY));
138
+ this.#textNode.position.set(this.width * alignmentFactor(this.#alignX), this.height * alignmentFactor(this.#alignY));
139
+ this.#clipMask.clear().rect(0, 0, this.width, this.height).fill(0xffffff);
140
+ const clip = this.#overflow === 'clip';
141
+ this.#clipMask.visible = clip;
142
+ this.#textNode.mask = clip ? this.#clipMask : null;
143
+ }
144
+ }
145
+ function horizontalTextAlign(align) {
146
+ if (align === 'center') {
147
+ return 'center';
148
+ }
149
+ if (align === 'end') {
150
+ return 'right';
151
+ }
152
+ return 'left';
153
+ }
154
+ function alignmentFactor(align) {
155
+ if (align === 'center') {
156
+ return 0.5;
157
+ }
158
+ if (align === 'end') {
159
+ return 1;
160
+ }
161
+ return 0;
162
+ }
@@ -1,5 +1,7 @@
1
1
  export * from './Group.js';
2
2
  export * from './Control.js';
3
+ export * from './Label.js';
4
+ export * from './BitmapLabel.js';
3
5
  export * from './Rect.js';
4
6
  export * from './Image.js';
5
7
  export * from './NineImage.js';
@@ -1,5 +1,7 @@
1
1
  export * from './Group.js';
2
2
  export * from './Control.js';
3
+ export * from './Label.js';
4
+ export * from './BitmapLabel.js';
3
5
  export * from './Rect.js';
4
6
  export * from './Image.js';
5
7
  export * from './NineImage.js';
@@ -0,0 +1,3 @@
1
+ import type { Container } from 'pixi.js';
2
+ export declare const runtimeBehavior: unique symbol;
3
+ export declare function activateRuntimeTree(root: Container): void;
@@ -0,0 +1,11 @@
1
+ export const runtimeBehavior = Symbol('pixifact.runtimeBehavior');
2
+ const activatedContainers = new WeakSet();
3
+ export function activateRuntimeTree(root) {
4
+ if (runtimeBehavior in root && !activatedContainers.has(root)) {
5
+ activatedContainers.add(root);
6
+ root[runtimeBehavior]();
7
+ }
8
+ for (const child of root.children) {
9
+ activateRuntimeTree(child);
10
+ }
11
+ }
@@ -1,6 +1,7 @@
1
- import type { SceneClassDecorator, SceneEventDecoratorOptions, SceneMemberDecorator, ScenePartDecoratorOptions, ScenePropDecoratorOptions, SceneSlotDecoratorOptions } from './spec.js';
1
+ import type { SceneClassDecorator, SceneEventDecoratorOptions, SceneMemberDecorator, ScenePartDecoratorOptions, ScenePropDecoratorOptions, SceneSlotDecoratorOptions, SceneVariants } from '../compiler/spec.js';
2
2
  export declare function scene(): SceneClassDecorator;
3
3
  export declare function prop(options: ScenePropDecoratorOptions): SceneMemberDecorator;
4
+ export declare function defineVariants<const TVariants extends SceneVariants>(variants: TVariants): TVariants;
4
5
  export declare function event(_options?: SceneEventDecoratorOptions): SceneMemberDecorator;
5
6
  export declare function slot(options?: SceneSlotDecoratorOptions): SceneMemberDecorator;
6
7
  export declare function part(options?: ScenePartDecoratorOptions): SceneMemberDecorator;
@@ -1,15 +1,21 @@
1
+ import { activateRuntimeTree } from '../runtime/runtimeBehavior.js';
1
2
  import { mountSceneClass } from './sceneRuntime.js';
3
+ import { initializeSceneProps } from './sceneBindingRuntime.js';
2
4
  const metadataByConstructor = new WeakMap();
3
5
  export function scene() {
4
6
  return ((constructor) => {
5
7
  const SceneClass = class extends constructor {
6
8
  constructor(...args) {
7
- super(...args);
9
+ super();
8
10
  if (new.target !== SceneClass) {
9
11
  return;
10
12
  }
11
- const result = mountSceneClass(this, SceneClass);
12
13
  const metadata = sceneMetadata(constructor);
14
+ const initialProps = args[0] && typeof args[0] === 'object'
15
+ ? args[0]
16
+ : {};
17
+ initializeSceneProps(this, metadata.props, initialProps);
18
+ const result = mountSceneClass(this, SceneClass);
13
19
  for (const [property, id] of metadata.parts) {
14
20
  Object.defineProperty(this, property, {
15
21
  configurable: true,
@@ -26,11 +32,7 @@ export function scene() {
26
32
  writable: false,
27
33
  });
28
34
  }
29
- for (const [property, propOptions] of metadata.props) {
30
- if (propOptions.default !== undefined) {
31
- this[property] = propOptions.default;
32
- }
33
- }
35
+ activateRuntimeTree(this);
34
36
  const ready = this.onMounted;
35
37
  if (ready) {
36
38
  ready.call(this);
@@ -46,6 +48,9 @@ export function prop(options) {
46
48
  sceneMetadata(target.constructor).props.set(memberName(propertyKey), options);
47
49
  });
48
50
  }
51
+ export function defineVariants(variants) {
52
+ return variants;
53
+ }
49
54
  export function event(_options = {}) {
50
55
  return noopMemberDecorator;
51
56
  }
@@ -0,0 +1,6 @@
1
+ export * from './decorators.js';
2
+ export * from './eventRuntime.js';
3
+ export * from './sceneAssetRuntime.js';
4
+ export * from './sceneBindingRuntime.js';
5
+ export * from './sceneRuntime.js';
6
+ export * from './slotRuntime.js';
@@ -0,0 +1,6 @@
1
+ export * from './decorators.js';
2
+ export * from './eventRuntime.js';
3
+ export * from './sceneAssetRuntime.js';
4
+ export * from './sceneBindingRuntime.js';
5
+ export * from './sceneRuntime.js';
6
+ export * from './slotRuntime.js';