@block_factory/lib 0.0.2 → 0.0.3

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.
@@ -0,0 +1,31 @@
1
+ import { Player, RawMessage, world } from "@minecraft/server";
2
+ import { uiManager } from "@minecraft/server-ui";
3
+
4
+ export declare type IFormValue = string | boolean | number | undefined;
5
+
6
+ export abstract class IForm {
7
+ private static readonly occupiedPlayers: Set<string> = new Set();
8
+ public static returnText: RawMessage | string = "Back";
9
+
10
+ public static isOccupied(player: Player): boolean {
11
+ return IForm.occupiedPlayers.has(player.id);
12
+ }
13
+
14
+ public static closeForms(player: Player): void {
15
+ uiManager.closeAllForms(player);
16
+ }
17
+
18
+ public static closeOccupiedForms(): void {
19
+ for (const playerId of IForm.occupiedPlayers) {
20
+ const player = world.getEntity(playerId) as Player | undefined;
21
+ if (player) uiManager.closeAllForms(player);
22
+ }
23
+ }
24
+
25
+ protected setOccupied(player: Player, occupied: boolean): void {
26
+ if (occupied) IForm.occupiedPlayers.add(player.id);
27
+ else IForm.occupiedPlayers.delete(player.id);
28
+ }
29
+
30
+ protected abstract build(player: Player): void;
31
+ }
@@ -1,4 +1,4 @@
1
- import { Form } from "@block_factory/lib/util/Form";
1
+ import { IForm } from "./Form";
2
2
  import { Player, RawMessage } from "@minecraft/server";
3
3
  import { ActionFormData, FormCancelationReason } from "@minecraft/server-ui";
4
4
 
@@ -18,7 +18,7 @@ export declare interface IActionFormResponse {
18
18
  readonly id?: string | number;
19
19
  }
20
20
 
21
- export declare abstract class IActionFormData extends Form {
21
+ export declare abstract class IActionFormData extends IForm {
22
22
  protected form: ActionFormData;
23
23
 
24
24
  protected abstract build(player: Player): void;
@@ -1,4 +1,4 @@
1
- import { Form } from "@block_factory/lib/util/Form";
1
+ import { IForm } from "./Form";
2
2
  import { Player, RawMessage } from "@minecraft/server";
3
3
  import { ActionFormData, ActionFormResponse, FormCancelationReason } from "@minecraft/server-ui";
4
4
 
@@ -47,24 +47,13 @@ type ButtonMeta = {
47
47
  * Normalized response object returned by IActionFormData.
48
48
  */
49
49
  export interface IActionFormResponse {
50
- /**
51
- * Reason the form was canceled, if applicable.
52
- */
50
+ /**Reason the form was canceled, if applicable.*/
53
51
  readonly cancelationReason?: FormCancelationReason;
54
-
55
- /**
56
- * Whether the form was canceled by the player.
57
- */
52
+ /** Whether the form was canceled by the player.*/
58
53
  readonly canceled: boolean;
59
-
60
- /**
61
- * Raw button index selected by the player.
62
- */
54
+ /**Raw button index selected by the player.*/
63
55
  readonly selection?: number;
64
-
65
- /**
66
- * Logical button id associated with the selection.
67
- */
56
+ /**Logical button id associated with the selection.*/
68
57
  readonly id?: string | number;
69
58
  }
70
59
 
@@ -77,7 +66,7 @@ export interface IActionFormResponse {
77
66
  * - Sub-form chaining with automatic Back navigation
78
67
  * - Normalized response objects
79
68
  */
80
- export abstract class IActionFormData extends Form {
69
+ export abstract class IActionFormData extends IForm {
81
70
  protected form: ActionFormData = new ActionFormData();
82
71
 
83
72
  private _buttons = new Map<number, ButtonMeta>();
@@ -86,7 +75,7 @@ export abstract class IActionFormData extends Form {
86
75
 
87
76
  protected abstract build(player: Player): void;
88
77
 
89
- protected abstract onSubmit( player: Player, response: IActionFormResponse): void;
78
+ protected abstract onSubmit(player: Player, response: IActionFormResponse): void;
90
79
 
91
80
  protected onCancel?(player: Player, response: IActionFormResponse): void;
92
81
 
@@ -96,13 +85,13 @@ export abstract class IActionFormData extends Form {
96
85
  return this;
97
86
  }
98
87
 
99
- public body(bodyText: RawMessage | string): this { this.form.body(bodyText); return this;}
88
+ public body(bodyText: RawMessage | string): this { this.form.body(bodyText); return this; }
100
89
 
101
- public divider(): this { this.form.divider(); return this;}
90
+ public divider(): this { this.form.divider(); return this; }
102
91
 
103
- public header(text: RawMessage | string): this { this.form.header(text); return this;}
92
+ public header(text: RawMessage | string): this { this.form.header(text); return this; }
104
93
 
105
- public label(text: RawMessage | string): this { this.form.label(text); return this;}
94
+ public label(text: RawMessage | string): this { this.form.label(text); return this; }
106
95
 
107
96
  public button(text: RawMessage | string, options: IButtonOptions = {}): this {
108
97
  if (options.iconPath) this.form.button(text, options.iconPath);
@@ -122,7 +111,7 @@ export abstract class IActionFormData extends Form {
122
111
  }
123
112
 
124
113
  public async show(player: Player): Promise<IActionFormResponse> {
125
- if (Form.isOccupied(player)) {
114
+ if (IForm.isOccupied(player)) {
126
115
  throw new Error(`Player ${player.id} is already occupied by form: ${this._id}`);
127
116
  }
128
117
 
@@ -135,11 +124,11 @@ export abstract class IActionFormData extends Form {
135
124
  }
136
125
  }
137
126
 
138
- protected async _showChained(player: Player,returnStack: ActionFormCtor[]): Promise<IActionFormResponse> {
127
+ protected async _showChained(player: Player, returnStack: ActionFormCtor[]): Promise<IActionFormResponse> {
139
128
  return await this._showInternal(player, returnStack);
140
129
  }
141
130
 
142
- private _wrapResponse(response: ActionFormResponse,id?: string | number): IActionFormResponse {
131
+ private _wrapResponse(response: ActionFormResponse, id?: string | number): IActionFormResponse {
143
132
  return {
144
133
  canceled: response.canceled,
145
134
  cancelationReason: response.cancelationReason,
@@ -158,7 +147,7 @@ export abstract class IActionFormData extends Form {
158
147
  this.build(player);
159
148
 
160
149
  if (returnStack.length > 0) {
161
- this.form.button(Form.returnText);
150
+ this.form.button(IForm.returnText);
162
151
  this._buttons.set(this._nextButtonIndex, {
163
152
  id: RETURN_ID,
164
153
  subForm: returnStack[returnStack.length - 1],
@@ -0,0 +1,30 @@
1
+ import { IForm } from "./Form";
2
+ import { Player, RawMessage } from "@minecraft/server";
3
+ import { MessageFormData, MessageFormResponse } from "@minecraft/server-ui";
4
+
5
+ export declare abstract class IMessageFormData extends IForm {
6
+ protected form: MessageFormData;
7
+
8
+ private _id: string;
9
+
10
+ protected abstract build(player: Player): void;
11
+
12
+ protected abstract onSubmit(
13
+ player: Player,
14
+ response: MessageFormResponse
15
+ ): void;
16
+
17
+ protected onCancel?(player: Player, response: MessageFormResponse): void;
18
+
19
+ title(titleText: RawMessage | string): this;
20
+
21
+ body(bodyText: RawMessage | string): this;
22
+
23
+ button0(text: RawMessage | string, id?: string | number): this;
24
+
25
+ button1(text: RawMessage | string, id?: string | number): this;
26
+
27
+ show(player: Player): Promise<MessageFormResponse>;
28
+
29
+ private _showInternal(player: Player): Promise<MessageFormResponse>;
30
+ }
@@ -0,0 +1,87 @@
1
+ import { IForm } from "./Form";
2
+ import { Player, RawMessage } from "@minecraft/server";
3
+ import {
4
+ MessageFormData,
5
+ MessageFormResponse,
6
+ } from "@minecraft/server-ui";
7
+
8
+ /**
9
+ * Abstract base class for MessageFormData.
10
+ *
11
+ * Provides:
12
+ * - occupied player handling
13
+ */
14
+
15
+ export type IMessageFormResponse = MessageFormResponse; // re-export wrapper for consistency
16
+
17
+ export abstract class IMessageFormData extends IForm {
18
+ protected form: MessageFormData = new MessageFormData();
19
+
20
+ private _id: string = "untitled";
21
+
22
+ protected abstract build(player: Player): void;
23
+
24
+ protected abstract onSubmit(
25
+ player: Player,
26
+ response: IMessageFormResponse
27
+ ): void;
28
+
29
+ protected onCancel?(player: Player, response: IMessageFormResponse): void;
30
+
31
+ public title(titleText: RawMessage | string): this {
32
+ this.form.title(titleText);
33
+ this._id =
34
+ typeof titleText === "string"
35
+ ? titleText
36
+ : JSON.stringify(titleText);
37
+ return this;
38
+ }
39
+
40
+ public body(bodyText: RawMessage | string): this {
41
+ this.form.body(bodyText);
42
+ return this;
43
+ }
44
+ public button0(text: RawMessage | string,id: string | number = 0): this {
45
+ this.form.button1(text);
46
+ return this;
47
+ }
48
+
49
+ public button1(text: RawMessage | string,id: string | number = 1): this {
50
+ this.form.button2(text);
51
+ return this;
52
+ }
53
+
54
+ public async show(player: Player): Promise<IMessageFormResponse> {
55
+ if (IForm.isOccupied(player)) {
56
+ throw new Error(
57
+ `Player ${player.id} is already occupied by form: ${this._id}`
58
+ );
59
+ }
60
+
61
+ this.setOccupied(player, true);
62
+
63
+ try {
64
+ return await this._showInternal(player);
65
+ } finally {
66
+ this.setOccupied(player, false);
67
+ }
68
+ }
69
+
70
+ private async _showInternal(
71
+ player: Player
72
+ ): Promise<IMessageFormResponse> {
73
+ this.form = new MessageFormData();
74
+
75
+ this.build(player);
76
+
77
+ const res = await this.form.show(player);
78
+
79
+ if (res.canceled || res.selection === undefined) {
80
+ this.onCancel?.(player, res);
81
+ return res;
82
+ }
83
+
84
+ this.onSubmit(player, res);
85
+ return res;
86
+ }
87
+ }
@@ -0,0 +1,57 @@
1
+ import { IForm, IFormValue } from "./Form";
2
+ import { Player, RawMessage } from "@minecraft/server";
3
+ import { ModalFormData, FormCancelationReason } from "@minecraft/server-ui";
4
+
5
+ export declare interface IModalFormResponse {
6
+ readonly cancelationReason?: FormCancelationReason;
7
+ readonly canceled: boolean;
8
+ readonly formValues?: IFormValue[];
9
+ readonly widget?: Map<string, IFormValue>;
10
+ }
11
+
12
+ export declare interface ITextFieldOptions {
13
+ id: string;
14
+ placeholder: string | RawMessage;
15
+ defaultValue?: string;
16
+ }
17
+
18
+ export declare interface IDropdownOptions {
19
+ id: string;
20
+ choices: string[];
21
+ defaultValueIndex?: number;
22
+ }
23
+
24
+ export declare interface ISliderOptions {
25
+ id: string;
26
+ min: number;
27
+ max: number;
28
+ step: number;
29
+ defaultValue?: number;
30
+ }
31
+
32
+ export declare interface IToggleOptions {
33
+ id: string;
34
+ defaultValue?: boolean;
35
+ }
36
+
37
+ export declare abstract class IModalFormData extends IForm {
38
+ protected form: ModalFormData;
39
+
40
+ protected abstract build(player: Player): void;
41
+
42
+ protected abstract onSubmit(player: Player, response: IModalFormResponse): void;
43
+
44
+ protected onCancel?(player: Player, response: IModalFormResponse): void;
45
+
46
+ title(titleText: RawMessage | string): this;
47
+ divider(): this;
48
+ header(text: RawMessage | string): this;
49
+ label(text: RawMessage | string): this;
50
+
51
+ textField(label: string | RawMessage, options: ITextFieldOptions): this;
52
+ dropdown(label: string | RawMessage, options: IDropdownOptions): this;
53
+ slider(label: string | RawMessage, options: ISliderOptions): this;
54
+ toggle(label: string | RawMessage, options: IToggleOptions): this;
55
+
56
+ show(player: Player): Promise<IModalFormResponse>;
57
+ }
@@ -0,0 +1,183 @@
1
+ import { IForm } from "./Form";
2
+ import { Player, RawMessage } from "@minecraft/server";
3
+ import {
4
+ ModalFormData,
5
+ ModalFormResponse,
6
+ FormCancelationReason,
7
+ ModalFormDataDropdownOptions,
8
+ ModalFormDataSliderOptions,
9
+ ModalFormDataTextFieldOptions,
10
+ ModalFormDataToggleOptions,
11
+ } from "@minecraft/server-ui";
12
+
13
+ export type FormValue = string | boolean | number | undefined;
14
+
15
+ /** Normalized response for Modal forms */
16
+ export interface IModalFormResponse {
17
+ /**Reason the form was canceled, if applicable.*/
18
+ readonly cancelationReason?: FormCancelationReason;
19
+ /** Whether the form was canceled by the player.*/
20
+ readonly canceled: boolean;
21
+ /** Raw values array from the form */
22
+ readonly formValues?: FormValue[];
23
+ /** Mapped values by widget id */
24
+ readonly widget?: Map<string, FormValue>;
25
+ }
26
+
27
+ /** Options for each widget type */
28
+ export interface ITextFieldOptions {
29
+ id: string;
30
+ placeholder: string | RawMessage;
31
+ defaultValue?: string;
32
+ }
33
+ export interface IDropdownOptions {
34
+ id: string;
35
+ choices: string[];
36
+ defaultValueIndex?: number;
37
+ }
38
+ export interface ISliderOptions {
39
+ id: string;
40
+ min: number;
41
+ max: number;
42
+ step: number;
43
+ defaultValue?: number;
44
+ }
45
+ export interface IToggleOptions {
46
+ id: string;
47
+ defaultValue?: boolean;
48
+ }
49
+
50
+ type WidgetMeta =
51
+ | { type: "textField"; id: string }
52
+ | { type: "dropdown"; id: string }
53
+ | { type: "slider"; id: string }
54
+ | { type: "toggle"; id: string };
55
+
56
+ /**
57
+ * Abstract base class for ModalFormData-based menus.
58
+ *
59
+ * Provides:
60
+ * - Occupied player handling
61
+ * - Widget id mapping into a Map<string, FormValue>
62
+ * - Normalized response object
63
+ */
64
+ export abstract class IModalFormData extends IForm {
65
+ protected form: ModalFormData = new ModalFormData();
66
+
67
+ private _id: string = "untitled";
68
+ private _widgetMeta: WidgetMeta[] = [];
69
+
70
+ protected abstract build(player: Player): void;
71
+
72
+ protected abstract onSubmit(player: Player, response: IModalFormResponse): void;
73
+
74
+ protected onCancel?(player: Player, response: IModalFormResponse): void;
75
+
76
+ public title(titleText: RawMessage | string): this {
77
+ this.form.title(titleText);
78
+ this._id = typeof titleText === "string" ? titleText : JSON.stringify(titleText);
79
+ return this;
80
+ }
81
+
82
+ public divider(): this {
83
+ this.form.divider();
84
+ return this;
85
+ }
86
+
87
+ public header(text: RawMessage | string): this {
88
+ this.form.header(text);
89
+ return this;
90
+ }
91
+
92
+ public label(text: RawMessage | string): this {
93
+ this.form.label(text);
94
+ return this;
95
+ }
96
+
97
+ public textField(label: string | RawMessage, options: ITextFieldOptions): this {
98
+ const opts: ModalFormDataTextFieldOptions = { defaultValue: options.defaultValue };
99
+ this.form.textField(label, options.placeholder, opts);
100
+ this._widgetMeta.push({ type: "textField", id: options.id });
101
+ return this;
102
+ }
103
+
104
+ public dropdown(label: string | RawMessage, options: IDropdownOptions): this {
105
+ const opts: ModalFormDataDropdownOptions = { defaultValueIndex: options.defaultValueIndex };
106
+ this.form.dropdown(label, options.choices, opts);
107
+ this._widgetMeta.push({ type: "dropdown", id: options.id });
108
+ return this;
109
+ }
110
+
111
+ public slider(label: string | RawMessage, options: ISliderOptions): this {
112
+ const opts: ModalFormDataSliderOptions = {
113
+ defaultValue: options.defaultValue,
114
+ valueStep: options.step,
115
+ };
116
+ this.form.slider(label, options.min, options.max, opts);
117
+ this._widgetMeta.push({ type: "slider", id: options.id });
118
+ return this;
119
+ }
120
+
121
+ public toggle(label: string | RawMessage, options: IToggleOptions): this {
122
+ const opts: ModalFormDataToggleOptions = { defaultValue: options.defaultValue };
123
+ this.form.toggle(label, opts);
124
+ this._widgetMeta.push({ type: "toggle", id: options.id });
125
+ return this;
126
+ }
127
+
128
+ public async show(player: Player): Promise<IModalFormResponse> {
129
+ if (IForm.isOccupied(player)) {
130
+ throw new Error(`Player ${player.id} is already occupied by form: ${this._id}`);
131
+ }
132
+
133
+ this.setOccupied(player, true);
134
+
135
+ try {
136
+ return await this._showInternal(player);
137
+ } finally {
138
+ this.setOccupied(player, false);
139
+ }
140
+ }
141
+
142
+ private _wrapResponse(res: ModalFormResponse, values?: Map<string, FormValue>): IModalFormResponse {
143
+ return {
144
+ canceled: res.canceled,
145
+ cancelationReason: res.cancelationReason,
146
+ formValues: res.formValues as FormValue[] | undefined,
147
+ widget: values,
148
+ };
149
+ }
150
+
151
+ private _mapValues(formValues: FormValue[] | undefined): Map<string, FormValue> | undefined {
152
+ if (!formValues) return undefined;
153
+
154
+ const out = new Map<string, FormValue>();
155
+ for (let i = 0; i < formValues.length; i++) {
156
+ const meta = this._widgetMeta[i];
157
+ if (!meta) continue;
158
+ out.set(meta.id, formValues[i]);
159
+ }
160
+ return out;
161
+ }
162
+
163
+ private async _showInternal(player: Player): Promise<IModalFormResponse> {
164
+ this.form = new ModalFormData();
165
+ this._widgetMeta = [];
166
+
167
+ this.build(player);
168
+
169
+ const res = await this.form.show(player);
170
+
171
+ if (res.canceled) {
172
+ const wrapped = this._wrapResponse(res);
173
+ this.onCancel?.(player, wrapped);
174
+ return wrapped;
175
+ }
176
+
177
+ const values = this._mapValues(res.formValues as FormValue[] | undefined);
178
+ const wrapped = this._wrapResponse(res, values);
179
+
180
+ this.onSubmit(player, wrapped);
181
+ return wrapped;
182
+ }
183
+ }
@@ -0,0 +1,26 @@
1
+ import { IActionFormData } from "./FormAction";
2
+ import { IModalFormData } from "./FormModal";
3
+ import { IMessageFormData } from "./FormMessage";
4
+
5
+ export type AnyShowableForm =
6
+ | IActionFormData
7
+ | IModalFormData
8
+ | IMessageFormData;
9
+
10
+ export type AnyShowableCtor = new () => AnyShowableForm;
11
+
12
+ export interface IFormRegistration {
13
+ itemId: string;
14
+ formCtor: AnyShowableCtor;
15
+ }
16
+
17
+ /**
18
+ * Decorator factory used to bind a form class to an itemId.
19
+ *
20
+ * Usage:
21
+ * @RegisterForm("minecraft:stick")
22
+ * export class MyForm extends IMessageFormData {}
23
+ */
24
+ export declare function RegisterForm(
25
+ itemId: string
26
+ ): <T extends AnyShowableCtor>(formCtor: T) => void;
@@ -0,0 +1,43 @@
1
+ import { ItemUseAfterEvent, Player, world } from "@minecraft/server";
2
+ import { IActionFormData } from "./FormAction";
3
+ import { IModalFormData } from "./FormModal";
4
+ import { IMessageFormData } from "./FormMessage";
5
+
6
+ type AnyShowableForm = IActionFormData | IModalFormData | IMessageFormData;
7
+ type AnyShowableCtor = new () => AnyShowableForm;
8
+
9
+ export interface IFormRegistration {
10
+ itemId: string;
11
+ formCtor: AnyShowableCtor;
12
+ }
13
+
14
+ const registeredForms: IFormRegistration[] = [];
15
+
16
+ export function RegisterForm(itemId: string) {
17
+ return function <T extends AnyShowableCtor>(formCtor: T): void {
18
+ const i = registeredForms.findIndex(r => r.itemId === itemId);
19
+ if (i !== -1) registeredForms[i] = { itemId, formCtor };
20
+ else registeredForms.push({ itemId, formCtor });
21
+ };
22
+ }
23
+
24
+ function getFormForItem(itemId: string): AnyShowableCtor | undefined {
25
+ return registeredForms.find(r => r.itemId === itemId)?.formCtor;
26
+ }
27
+
28
+ world.afterEvents.itemUse.subscribe((event: ItemUseAfterEvent) => {
29
+ const player = event.source;
30
+ if (!(player instanceof Player)) return;
31
+
32
+ const item = event.itemStack;
33
+ if (!item) return;
34
+
35
+ const formCtor = getFormForItem(item.typeId);
36
+ if (!formCtor) return;
37
+
38
+ const form = new formCtor();
39
+
40
+ form.show(player).catch((e) => {
41
+ player.sendMessage(`§cForm error: ${String(e)}`);
42
+ });
43
+ });
package/util/Signal.d.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  export type Callback<T = void> = (data: T) => void;
2
+
2
3
  export declare class Signal<T = void> {
3
- private listeners;
4
+ private readonly listeners;
5
+
6
+ readonly count: number;
7
+
4
8
  connect(callback: Callback<T>): void;
5
- disconnect(callback?: Callback<T>): boolean;
6
- once(callback: Callback<T>): void;
9
+ disconnect(callback: Callback<T>): boolean;
10
+ clear(): void;
11
+ isConnected(callback: Callback<T>): boolean;
7
12
  emit(data: T): void;
8
13
  }
9
- //# sourceMappingURL=Signal.d.ts.map
package/util/Signal.ts CHANGED
@@ -1,72 +1,30 @@
1
- export type Callback<T = void> = (data: T) => void;
2
-
3
- /**
4
- * Signal class for event handling.
5
- * Allows connecting, disconnecting, and emitting events to listeners.
6
- *
7
- * @template T - Type of data passed to listeners.
8
- *
9
- * @example
10
- * ```typescript
11
- * import { Signal } from "./_lib/signal";
12
- *
13
- * interface ExampleEvent {
14
- * n: number;
15
- * s: string;
16
- * b: boolean;
17
- * }
18
- *
19
- * class TestObject {
20
- * example = new Signal<ExampleEvent>();
21
- * }
22
- *
23
- * const tstObject = new TestObject();
24
- * tstObject.example.connect(({n, s, b}) => console.warn(`n: ${n}, s: ${s}, b: ${b}`));
25
- *
26
- * for (let i = 0; i < 4; i++) {
27
- * let n: number = 1;
28
- * let s: string = "example";
29
- * let b: boolean = true;
30
- * tstObject.example.emit({n, s, b});
31
- * if (i === 3) { // Disconnect after 4th emit
32
- * tstObject.example.disconnect();
33
- * tstObject.example.emit({n, s, b});
34
- * }
35
- * }
36
- * ```
37
- */
1
+ export type Callback<T> = (data: T) => void;
38
2
 
39
3
  export class Signal<T = void> {
40
- private listeners: Set<Callback<T>> = new Set();
4
+ private readonly listeners = new Set<Callback<T>>();
5
+
6
+ public get count(): number {
7
+ return this.listeners.size;
8
+ }
41
9
 
42
- /** Connect a listener */
43
10
  public connect(callback: Callback<T>): void {
44
11
  this.listeners.add(callback);
45
12
  }
46
13
 
47
- /** Disconnect a listener */
48
- public disconnect(callback?: Callback<T>): boolean {
49
- if (callback) {
50
- this.listeners.delete(callback);
51
- return true;
52
- } else {
53
- this.listeners.clear();
54
- return false;
55
- }
14
+ public disconnect(callback: Callback<T>): boolean {
15
+ return this.listeners.delete(callback);
16
+ }
17
+
18
+ public clear(): void {
19
+ this.listeners.clear();
56
20
  }
57
21
 
58
- /** Connect a listener that runs only once */
59
- public once(callback: Callback<T>) {
60
- const wrapper: Callback<T> = (data) => {
61
- this.disconnect(wrapper);
62
- callback(data);
63
- };
64
- this.connect(wrapper);
22
+ public isConnected(callback: Callback<T>): boolean {
23
+ return this.listeners.has(callback);
65
24
  }
66
25
 
67
- /** Emit signal to all listeners */
68
- public emit(data: T) {
69
- for (const cb of [...this.listeners]) {
26
+ public emit(data: T): void {
27
+ for (const cb of Array.from(this.listeners)) {
70
28
  cb(data);
71
29
  }
72
30
  }
@@ -0,0 +1,4 @@
1
+ export declare namespace System {
2
+ const ProxyConstructor: (_instance: any, source: any) => any;
3
+ }
4
+ //# sourceMappingURL=System.d.ts.map