canvasengine 2.0.0-beta.60 → 2.0.0-beta.61
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/dist/components/Canvas.d.ts.map +1 -1
- package/dist/components/Graphic.d.ts.map +1 -1
- package/dist/components/Text.d.ts +2 -3
- package/dist/components/Text.d.ts.map +1 -1
- package/dist/directives/Scheduler.d.ts +1 -0
- package/dist/directives/Scheduler.d.ts.map +1 -1
- package/dist/engine/bootstrap.d.ts +8 -4
- package/dist/engine/bootstrap.d.ts.map +1 -1
- package/dist/engine/reactive.d.ts +1 -0
- package/dist/engine/reactive.d.ts.map +1 -1
- package/dist/engine/signal.d.ts +3 -1
- package/dist/engine/signal.d.ts.map +1 -1
- package/dist/index.global.js +6 -3
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +6134 -1194
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/components/Canvas.ts +24 -9
- package/src/components/DisplayObject.ts +3 -0
- package/src/components/Graphic.ts +16 -11
- package/src/components/Text.ts +151 -14
- package/src/directives/Scheduler.ts +9 -1
- package/src/engine/bootstrap.ts +57 -13
- package/src/engine/reactive.ts +1 -1
- package/src/engine/signal.ts +136 -30
package/src/engine/signal.ts
CHANGED
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Observable,
|
|
3
|
+
Subject,
|
|
3
4
|
Subscription
|
|
4
5
|
} from "rxjs";
|
|
5
6
|
import { isSignal } from "@signe/reactive";
|
|
6
7
|
import type { Element } from "./reactive";
|
|
7
|
-
import { isElementFrozen, waitForDependencies } from "./reactive";
|
|
8
|
+
import { destroyElement, isElementFrozen, waitForDependencies } from "./reactive";
|
|
8
9
|
import { isPromise } from "./utils";
|
|
9
10
|
import { Tick } from "../directives/Scheduler";
|
|
10
11
|
import { Container } from "../components";
|
|
11
12
|
|
|
12
|
-
type
|
|
13
|
+
type MountCallback = (element: Element) => any;
|
|
14
|
+
type MountFunction = (fn: MountCallback) => void;
|
|
13
15
|
|
|
14
16
|
// Define ComponentFunction type
|
|
15
17
|
export type ComponentFunction<P = {}> = (props: P) => Element | Promise<Element>;
|
|
18
|
+
type HotFlowResult = { elements: Element[] };
|
|
19
|
+
type HotComponentRecord = {
|
|
20
|
+
component: ComponentFunction<any>;
|
|
21
|
+
updates: Subject<void>;
|
|
22
|
+
wrapper?: ComponentFunction<any>;
|
|
23
|
+
};
|
|
16
24
|
|
|
17
25
|
export let currentSubscriptionsTracker: ((subscription: Subscription) => void) | null = null;
|
|
18
26
|
export let mountTracker: MountFunction | null = null;
|
|
19
27
|
|
|
28
|
+
const getHotComponentRegistry = (): Map<string, HotComponentRecord> => {
|
|
29
|
+
const hotGlobal = globalThis as any;
|
|
30
|
+
if (!hotGlobal.__CANVAS_ENGINE_HOT_COMPONENTS__) {
|
|
31
|
+
hotGlobal.__CANVAS_ENGINE_HOT_COMPONENTS__ = new Map<string, HotComponentRecord>();
|
|
32
|
+
}
|
|
33
|
+
return hotGlobal.__CANVAS_ENGINE_HOT_COMPONENTS__;
|
|
34
|
+
};
|
|
35
|
+
|
|
20
36
|
/**
|
|
21
37
|
* Registers a mount function to be called when the component is mounted.
|
|
22
38
|
* To unmount the component, the function must return a function that will be called by the engine.
|
|
@@ -57,7 +73,7 @@ export function tick(fn: (tickValue: Tick, element: Element) => void) {
|
|
|
57
73
|
const { context } = el.props
|
|
58
74
|
let subscription: Subscription | undefined
|
|
59
75
|
if (context.tick) {
|
|
60
|
-
subscription = context.tick.observable.subscribe(({ value }) => {
|
|
76
|
+
subscription = context.tick.observable.subscribe(({ value }: { value: Tick }) => {
|
|
61
77
|
// Block tick if element is frozen
|
|
62
78
|
if (isElementFrozen(el)) {
|
|
63
79
|
return;
|
|
@@ -104,17 +120,6 @@ function _h<C extends ComponentFunction<any>>(
|
|
|
104
120
|
props: Parameters<C>[0] = {} as Parameters<C>[0],
|
|
105
121
|
children: any[]
|
|
106
122
|
): ReturnType<C> {
|
|
107
|
-
const allSubscriptions = new Set<Subscription>();
|
|
108
|
-
const allMounts = new Set<MountFunction>();
|
|
109
|
-
|
|
110
|
-
currentSubscriptionsTracker = (subscription) => {
|
|
111
|
-
allSubscriptions.add(subscription);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
mountTracker = (fn: any) => {
|
|
115
|
-
allMounts.add(fn);
|
|
116
|
-
};
|
|
117
|
-
|
|
118
123
|
if (children[0] instanceof Array) {
|
|
119
124
|
children = children[0]
|
|
120
125
|
}
|
|
@@ -136,38 +141,139 @@ function _h<C extends ComponentFunction<any>>(
|
|
|
136
141
|
component = componentFunction as any
|
|
137
142
|
}
|
|
138
143
|
else {
|
|
139
|
-
component = componentFunction
|
|
144
|
+
component = createTrackedComponent(componentFunction, { ...props, children }) as Element;
|
|
140
145
|
}
|
|
141
146
|
|
|
142
147
|
if (!component) {
|
|
143
148
|
component = {} as any
|
|
144
149
|
}
|
|
145
150
|
|
|
146
|
-
component.effectSubscriptions = Array.from(allSubscriptions);
|
|
147
|
-
component.effectMounts = [
|
|
148
|
-
...Array.from(allMounts),
|
|
149
|
-
...((component as any).effectMounts ?? [])
|
|
150
|
-
];
|
|
151
|
-
|
|
152
151
|
// Copy dependencies prop to the returned element so it can be used for delayed mounting
|
|
153
152
|
if (props?.dependencies) {
|
|
154
153
|
component.props = component.props || {};
|
|
155
154
|
component.props.dependencies = props.dependencies;
|
|
156
155
|
}
|
|
157
156
|
|
|
158
|
-
|
|
157
|
+
return component as ReturnType<C>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function createTrackedComponent<C extends ComponentFunction<any>>(
|
|
161
|
+
componentFunction: C,
|
|
162
|
+
props: Parameters<C>[0]
|
|
163
|
+
): ReturnType<C> {
|
|
164
|
+
const allSubscriptions = new Set<Subscription>();
|
|
165
|
+
const allMounts = new Set<MountCallback>();
|
|
166
|
+
|
|
167
|
+
currentSubscriptionsTracker = (subscription) => {
|
|
168
|
+
allSubscriptions.add(subscription);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
mountTracker = (fn: any) => {
|
|
172
|
+
allMounts.add(fn);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
let component: ReturnType<C> = undefined as any;
|
|
176
|
+
try {
|
|
177
|
+
component = componentFunction(props) as ReturnType<C>;
|
|
178
|
+
} finally {
|
|
179
|
+
currentSubscriptionsTracker = null;
|
|
180
|
+
mountTracker = null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const applyTrackedEffects = (element: Element) => {
|
|
184
|
+
if (!element) return;
|
|
185
|
+
element.effectSubscriptions = [
|
|
186
|
+
...Array.from(allSubscriptions),
|
|
187
|
+
...((element as any).effectSubscriptions ?? [])
|
|
188
|
+
];
|
|
189
|
+
element.effectMounts = [
|
|
190
|
+
...Array.from(allMounts),
|
|
191
|
+
...((element as any).effectMounts ?? [])
|
|
192
|
+
];
|
|
193
|
+
};
|
|
194
|
+
|
|
159
195
|
if (component instanceof Promise) {
|
|
160
|
-
component.then((
|
|
161
|
-
|
|
162
|
-
|
|
196
|
+
component.then((element) => {
|
|
197
|
+
applyTrackedEffects(element);
|
|
198
|
+
if (element?.props?.isRoot) {
|
|
199
|
+
allMounts.forEach((fn) => fn(element));
|
|
163
200
|
}
|
|
164
|
-
})
|
|
201
|
+
});
|
|
202
|
+
} else if (component instanceof Observable) {
|
|
203
|
+
(component as any).effectSubscriptions = [
|
|
204
|
+
...Array.from(allSubscriptions),
|
|
205
|
+
...((component as any).effectSubscriptions ?? [])
|
|
206
|
+
];
|
|
207
|
+
(component as any).effectMounts = [
|
|
208
|
+
...Array.from(allMounts),
|
|
209
|
+
...((component as any).effectMounts ?? [])
|
|
210
|
+
];
|
|
211
|
+
} else {
|
|
212
|
+
applyTrackedEffects(component as Element);
|
|
165
213
|
}
|
|
166
214
|
|
|
167
|
-
|
|
168
|
-
|
|
215
|
+
return component;
|
|
216
|
+
}
|
|
169
217
|
|
|
170
|
-
|
|
218
|
+
export function createHotComponent<P>(
|
|
219
|
+
id: string,
|
|
220
|
+
component: ComponentFunction<P>
|
|
221
|
+
): ComponentFunction<P> {
|
|
222
|
+
const registry = getHotComponentRegistry();
|
|
223
|
+
let record = registry.get(id);
|
|
224
|
+
|
|
225
|
+
if (!record) {
|
|
226
|
+
record = {
|
|
227
|
+
component,
|
|
228
|
+
updates: new Subject<void>(),
|
|
229
|
+
};
|
|
230
|
+
registry.set(id, record);
|
|
231
|
+
} else {
|
|
232
|
+
record.component = component;
|
|
233
|
+
record.updates.next();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (!record.wrapper) {
|
|
237
|
+
record.wrapper = ((props: P) => {
|
|
238
|
+
return new Observable<HotFlowResult>((subscriber) => {
|
|
239
|
+
let disposed = false;
|
|
240
|
+
let currentElement: Element | null = null;
|
|
241
|
+
|
|
242
|
+
const emit = () => {
|
|
243
|
+
const rendered = createTrackedComponent(record!.component, props);
|
|
244
|
+
const next = (element: Element | null | undefined) => {
|
|
245
|
+
if (!disposed) {
|
|
246
|
+
subscriber.next({ elements: element ? [element] : [] });
|
|
247
|
+
if (currentElement && currentElement !== element) {
|
|
248
|
+
destroyElement(currentElement);
|
|
249
|
+
}
|
|
250
|
+
currentElement = element ?? null;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
if (rendered instanceof Promise) {
|
|
255
|
+
rendered.then(next).catch((error) => subscriber.error(error));
|
|
256
|
+
} else {
|
|
257
|
+
next(rendered as Element);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
emit();
|
|
262
|
+
const subscription = record!.updates.subscribe(emit);
|
|
263
|
+
|
|
264
|
+
return () => {
|
|
265
|
+
disposed = true;
|
|
266
|
+
if (currentElement) {
|
|
267
|
+
destroyElement(currentElement);
|
|
268
|
+
currentElement = null;
|
|
269
|
+
}
|
|
270
|
+
subscription.unsubscribe();
|
|
271
|
+
};
|
|
272
|
+
}) as any;
|
|
273
|
+
}) as ComponentFunction<any>;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return record.wrapper as ComponentFunction<P>;
|
|
171
277
|
}
|
|
172
278
|
|
|
173
279
|
/**
|
|
@@ -206,7 +312,7 @@ export function h<C extends ComponentFunction<any>>(
|
|
|
206
312
|
if (props?.dependencies) {
|
|
207
313
|
const hasPromise = props.dependencies.some(isPromise);
|
|
208
314
|
if (!hasPromise) {
|
|
209
|
-
const allReady = props.dependencies.every(dep => {
|
|
315
|
+
const allReady = props.dependencies.every((dep: any) => {
|
|
210
316
|
if (isSignal(dep)) return dep() !== undefined;
|
|
211
317
|
return dep !== undefined;
|
|
212
318
|
});
|