@psytask/core 1.1.0 → 1.1.1
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/index.d.ts +44 -73
- package/dist/index.js +13 -32
- package/dist/index.min.js +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,5 @@
|
|
|
1
1
|
type LooseObject = Record<string, unknown>;
|
|
2
2
|
type Merge<T, U> = T extends unknown ? Omit<T, keyof U> & U : never;
|
|
3
|
-
type Split<T extends string, S extends string> = T extends unknown
|
|
4
|
-
? T extends `${infer L}${S}${infer R}`
|
|
5
|
-
? [L, ...Split<R, S>]
|
|
6
|
-
: [T]
|
|
7
|
-
: never;
|
|
8
|
-
|
|
9
|
-
declare global {
|
|
10
|
-
interface ObjectConstructor {
|
|
11
|
-
keys<T>(o: T): (keyof T & string)[];
|
|
12
|
-
}
|
|
13
|
-
interface String {
|
|
14
|
-
split<T extends string, S extends string>(
|
|
15
|
-
this: T,
|
|
16
|
-
separator: S,
|
|
17
|
-
): Split<T, S>;
|
|
18
|
-
}
|
|
19
|
-
interface Array<T> {
|
|
20
|
-
map<R>(fn: <E extends T>(e: E, i: number, arr: this) => R): R[];
|
|
21
|
-
}
|
|
22
|
-
interface Performance {
|
|
23
|
-
getEntriesByType(type: 'resource'): PerformanceResourceTiming[];
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
3
|
|
|
27
4
|
declare const symbol: typeof Symbol.dispose;
|
|
28
5
|
type EventMap<T extends LooseObject> = T & {
|
|
@@ -46,41 +23,56 @@ declare class EventEmitter<T extends LooseObject & {
|
|
|
46
23
|
emit<K extends keyof EventMap<T>>(type: K, ...[evt]: EventMap<T>[K] extends undefined ? [evt?: EventMap<T>[K]] : [evt: EventMap<T>[K]]): this;
|
|
47
24
|
}
|
|
48
25
|
|
|
26
|
+
/** Timestamps of elapsed frames */
|
|
49
27
|
type TimerRecords = number[];
|
|
50
28
|
type Timer = {
|
|
51
|
-
|
|
29
|
+
/**
|
|
30
|
+
* If called in {@link window.requestAnimationFrame rAF} callback or microtasks
|
|
31
|
+
* generated by rAF callback, the start time (the first element of
|
|
32
|
+
* {@link TimerRecords timer records}) will be the current frame time,
|
|
33
|
+
* otherwise the next frame time.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
*
|
|
37
|
+
* Do not repeat
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* timer.start();
|
|
41
|
+
* timer.start(); // error
|
|
42
|
+
*
|
|
43
|
+
* await timer.start();
|
|
44
|
+
* timer.start(); // right
|
|
45
|
+
*
|
|
46
|
+
* timer.start();
|
|
47
|
+
* timer.stop();
|
|
48
|
+
* timer.start(); // right
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
start(onFrame?: (time: number) => void): Promise<TimerRecords>;
|
|
52
52
|
stop(): void;
|
|
53
53
|
};
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
55
|
+
* Create {@link requestAnimationFrame rAF} timer
|
|
56
56
|
*
|
|
57
|
-
*
|
|
58
|
-
* rAF(scene_1.show) -> render -> vsync -> rAF[scene_1.start_time] -> ... ->
|
|
59
|
-
* rAF(scene_2.show) -> ...
|
|
60
|
-
* ```
|
|
61
|
-
*
|
|
62
|
-
* ## Closing condition
|
|
63
|
-
*
|
|
64
|
-
* | symbol/expression | description |
|
|
65
|
-
* | :---------------------: | ------------------- |
|
|
66
|
-
* | t | current frame time |
|
|
67
|
-
* | t_0 | start frame time |
|
|
68
|
-
* | D | duration |
|
|
69
|
-
* | \delta | next frame duration |
|
|
70
|
-
* | e = t - t_0 - D | duration error |
|
|
71
|
-
* | \|e\| <= \|e + \delta\| | closing condition |
|
|
57
|
+
* @example Basic usage
|
|
72
58
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* if e + \delta >= 0 then -e <= e + \delta -> e >= -\delta / 2
|
|
80
|
-
* if e + \delta < 0 then -e <= -e - \delta -> false
|
|
59
|
+
* ```ts
|
|
60
|
+
* const frame_ms = 16.67;
|
|
61
|
+
* const duration = 100;
|
|
62
|
+
* const timer = createTimer(
|
|
63
|
+
* (time, records) => time - records[0] >= duration - frame_ms / 2,
|
|
64
|
+
* );
|
|
81
65
|
* ```
|
|
82
66
|
*/
|
|
83
|
-
declare const createTimer: (
|
|
67
|
+
declare const createTimer: (
|
|
68
|
+
/**
|
|
69
|
+
* Return true to stop timer
|
|
70
|
+
*
|
|
71
|
+
* @param time Current frame time
|
|
72
|
+
* @param records History frame times, the first frame means the first frame
|
|
73
|
+
* that triggers VSync
|
|
74
|
+
*/
|
|
75
|
+
shouldStop: (time: number, records: TimerRecords) => boolean) => Timer;
|
|
84
76
|
type NodeLike = string | Node;
|
|
85
77
|
type BuiltinData = {
|
|
86
78
|
frame_times: TimerRecords;
|
|
@@ -205,33 +197,12 @@ declare class Scene<T extends MaybeGenericComponent> extends EventEmitter<SceneE
|
|
|
205
197
|
*
|
|
206
198
|
* @example
|
|
207
199
|
*
|
|
208
|
-
*
|
|
200
|
+
* Basic usage
|
|
209
201
|
*
|
|
210
202
|
* ```ts
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* using scene = new Scene(
|
|
214
|
-
* (props: { text: string }) => {
|
|
215
|
-
* const node = document.createElement('div');
|
|
216
|
-
* effect(() => {
|
|
217
|
-
* node.textContent = props.text; // auto update when props.text changes
|
|
218
|
-
* });
|
|
219
|
-
* return node;
|
|
220
|
-
* },
|
|
221
|
-
* {
|
|
222
|
-
* root: document.createElement('div'),
|
|
223
|
-
* defaultProps: { text: 'default' },
|
|
224
|
-
* adapter: createComponentAdapter(reactive),
|
|
225
|
-
* timer: () => createTimer((records) => records.length > 100), // show 100 frames
|
|
226
|
-
* },
|
|
227
|
-
* );
|
|
228
|
-
* document.body.appendChild(scene.root);
|
|
229
|
-
*
|
|
230
|
-
* await scene.show({ text: 'new' }); // show `new`
|
|
231
|
-
* await scene.show(); // show `default`
|
|
203
|
+
* await scene.show({ text: 'new' }); // show with new props
|
|
204
|
+
* await scene.show(); // show with default props
|
|
232
205
|
* ```
|
|
233
|
-
*
|
|
234
|
-
* @function
|
|
235
206
|
*/
|
|
236
207
|
show: T extends Component<infer P, infer D> ? SceneShow<P, D> : T;
|
|
237
208
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @psytask/core v1.1.
|
|
1
|
+
/** @psytask/core v1.1.1 cubxx MIT */
|
|
2
2
|
const symbol = Symbol.dispose ?? /* @__PURE__ */ Symbol.for("Symbol.dispose");
|
|
3
3
|
class EventEmitter {
|
|
4
4
|
listeners = {};
|
|
@@ -54,17 +54,21 @@ new Proxy(
|
|
|
54
54
|
);
|
|
55
55
|
const array_normalize = (e) => Array.isArray(e) ? e : [e];
|
|
56
56
|
|
|
57
|
+
let currentFrameTime;
|
|
58
|
+
const setCurrentFrameTime = (time) => (currentFrameTime = time, setTimeout(() => currentFrameTime = 0), // reset after render pipeline
|
|
59
|
+
rAF(setCurrentFrameTime));
|
|
57
60
|
const createTimer = (shouldStop) => {
|
|
61
|
+
currentFrameTime ?? setCurrentFrameTime(0);
|
|
58
62
|
const timer = {
|
|
59
63
|
start: (cb) => new Promise((resolve) => {
|
|
60
|
-
timer.stop = () => (cancelAnimationFrame(handle), resolve(records));
|
|
61
64
|
const records = [];
|
|
65
|
+
const record = (time) => (records.push(time), cb?.(time));
|
|
66
|
+
currentFrameTime && record(currentFrameTime);
|
|
62
67
|
const frame = (time) => {
|
|
63
|
-
records.
|
|
64
|
-
cb?.(records);
|
|
65
|
-
shouldStop(records) ? timer.stop() : handle = rAF(frame);
|
|
68
|
+
shouldStop(time, records) ? timer.stop() : (handle = rAF(frame), record(time));
|
|
66
69
|
};
|
|
67
70
|
let handle = rAF(frame);
|
|
71
|
+
timer.stop = () => (cancelAnimationFrame(handle), resolve(records));
|
|
68
72
|
}),
|
|
69
73
|
stop() {
|
|
70
74
|
}
|
|
@@ -120,33 +124,12 @@ class Scene extends EventEmitter {
|
|
|
120
124
|
*
|
|
121
125
|
* @example
|
|
122
126
|
*
|
|
123
|
-
*
|
|
127
|
+
* Basic usage
|
|
124
128
|
*
|
|
125
129
|
* ```ts
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* using scene = new Scene(
|
|
129
|
-
* (props: { text: string }) => {
|
|
130
|
-
* const node = document.createElement('div');
|
|
131
|
-
* effect(() => {
|
|
132
|
-
* node.textContent = props.text; // auto update when props.text changes
|
|
133
|
-
* });
|
|
134
|
-
* return node;
|
|
135
|
-
* },
|
|
136
|
-
* {
|
|
137
|
-
* root: document.createElement('div'),
|
|
138
|
-
* defaultProps: { text: 'default' },
|
|
139
|
-
* adapter: createComponentAdapter(reactive),
|
|
140
|
-
* timer: () => createTimer((records) => records.length > 100), // show 100 frames
|
|
141
|
-
* },
|
|
142
|
-
* );
|
|
143
|
-
* document.body.appendChild(scene.root);
|
|
144
|
-
*
|
|
145
|
-
* await scene.show({ text: 'new' }); // show `new`
|
|
146
|
-
* await scene.show(); // show `default`
|
|
130
|
+
* await scene.show({ text: 'new' }); // show with new props
|
|
131
|
+
* await scene.show(); // show with default props
|
|
147
132
|
* ```
|
|
148
|
-
*
|
|
149
|
-
* @function
|
|
150
133
|
*/
|
|
151
134
|
//@ts-expect-error impl generic component
|
|
152
135
|
show = this.#show;
|
|
@@ -163,9 +146,7 @@ class Scene extends EventEmitter {
|
|
|
163
146
|
this.emit("show");
|
|
164
147
|
root.style.scale = "1";
|
|
165
148
|
root.focus();
|
|
166
|
-
const records = await this.#timer.start(
|
|
167
|
-
(records2) => this.emit("frame", records2[records2.length - 1])
|
|
168
|
-
);
|
|
149
|
+
const records = await this.#timer.start((time) => this.emit("frame", time));
|
|
169
150
|
root.style.scale = "0";
|
|
170
151
|
return {
|
|
171
152
|
...this.emit("close").data?.(),
|
package/dist/index.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const f=Symbol.dispose??Symbol.for("Symbol.dispose");class m{listeners={};[f](){this.emit("dispose")}on(t,s){return(this.listeners[t]??=new Set).add(s),this}off(t,s){const e=this.listeners[t];return e&&(e.delete(s),e.size===0&&delete this.listeners[t]),this}once(t,s){const e=r=>{try{s(r)}finally{this.off(t,e)}};return this.on(t,e),this}emit(t,...[s]){const e=this.listeners[t];if(e)for(const r of[...e])r(s);return this}}const y=o=>{throw Error(o)},h=requestAnimationFrame,w=Object,b=(o,t)=>w.assign(o,t),S=document;new Proxy({},{get:(o,t)=>s=>b(S.createElement(t),s)});const g=o=>Array.isArray(o)?o:[o];let d;const p=o=>(d=o,setTimeout(()=>d=0),h(p)),A=o=>{d??p(0);const t={start:s=>new Promise(e=>{const r=[],n=c=>(r.push(c),s?.(c));d&&n(d);const i=c=>{o(c,r)?t.stop():(a=h(i),n(c))};let a=h(i);t.stop=()=>(cancelAnimationFrame(a),e(r))}),stop(){}};return t},E=o=>o,F=o=>({wrap:t=>(s=>t(o(s))),render:(t,s,e)=>{const r=o(s);e&&l.push(e);const n=t(r);e&&l.pop();let i;const a=g(typeof n!="string"&&"node"in n?(i=n.data,n.node):n);return{props:r,nodes:a,data:i}}}),l=[],P=()=>l[l.length-1]??y("Not found current scene");class O extends m{constructor(t,s){super(),this.options=s;const{root:e,adapter:r,defaultProps:n,timer:i}=s;(this.root=e).tabIndex=-1,e.style.scale="0";const{props:a,nodes:c,data:u}=r.render(t,{...n},this.on("dispose",()=>e.remove()));this.#t=i(),this.#s=a,this.data=u,e.append(...c)}root;#t;#s;data;show=this.#e;async close(){await 0,this.#t.stop()}async#e(t){const{root:s,defaultProps:e}=this.options,r={...e,...t};for(const i of Object.keys({...this.#s,...r}))this.#s[i]=r[i];this.emit("show"),s.style.scale="1",s.focus();const n=await this.#t.start(i=>this.emit("frame",i));return s.style.scale="0",{...this.emit("close").data?.(),frame_times:n}}}export{m as EventEmitter,O as Scene,F as createComponentAdapter,A as createTimer,E as generic,P as getCurrentScene};
|