@psytask/core 1.1.4 → 1.2.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 CHANGED
@@ -100,9 +100,9 @@ type Component<P extends LooseObject = any, D extends LooseObject = LooseObject
100
100
  data: () => D;
101
101
  };
102
102
  };
103
- type SceneShow<P extends LooseObject = LooseObject, D extends LooseObject = LooseObject & ForbiddenData> = (patchProps?: Partial<P>) => Promise<Merge<D, BuiltinData>>;
104
- /** Same with {@link SceneShow} */
105
- type GenericComponent<P extends LooseObject = LooseObject, D extends LooseObject = LooseObject & ForbiddenData> = SceneShow<P, D>;
103
+ type GenericComponent<P extends LooseObject = LooseObject, D extends LooseObject = LooseObject & ForbiddenData> = (patchProps?: Partial<P>,
104
+ /** NOTE: only for type hint */
105
+ __rawProps?: P) => Promise<Merge<D, BuiltinData>>;
106
106
  /**
107
107
  * Provide type infer for generic component, do nothing in runtime.
108
108
  *
@@ -124,12 +124,40 @@ declare const generic: {
124
124
  };
125
125
  /** @ignore */
126
126
  type MaybeGenericComponent<P extends LooseObject = any, D extends LooseObject & ForbiddenData = {}> = Component<P, D> | GenericComponent<P, D>;
127
+ /**
128
+ * @example
129
+ *
130
+ * Must be called on the top scope of component
131
+ *
132
+ * ```ts
133
+ * const Component = (props: {}) => {
134
+ * const ctx = getCurrentScene();
135
+ * return '';
136
+ * };
137
+ * ```
138
+ *
139
+ * DO NOT call on other place
140
+ *
141
+ * ```ts
142
+ * const Component = (props: {}) => {
143
+ * const fn = () => {
144
+ * const ctx = getCurrentScene(); // WRONG!
145
+ * };
146
+ * return '';
147
+ * };
148
+ * ```
149
+ */
150
+ declare const getCurrentScene: () => Scene<MaybeGenericComponent<any, {}>>;
151
+ declare const ReactiveFn: unique symbol;
152
+ type ComponentFlags = {
153
+ [ReactiveFn]?: <T extends LooseObject>(obj: T) => T;
154
+ };
127
155
  type ComponentAdapter = {
128
- /** Wrap a component with reactive props */
129
- wrap: <T extends Component>(component: T) => T;
130
- /** Render a component with default props and provided scene */
131
- render: <T extends Component>(component: T, defaultProps: Parameters<T>[0],
132
- /** If not provided, it will use current scene */
156
+ /** Mark a component with reactive function */
157
+ mark: <T extends Component>(component: T & ComponentFlags) => T;
158
+ /** Call a component with default props and provided scene */
159
+ render: <T extends Component>(component: T & ComponentFlags, defaultProps: Parameters<T>[0],
160
+ /** If not provided, use current scene */
133
161
  ctx?: Scene<Component>) => {
134
162
  props: Parameters<T>[0];
135
163
  } & (ReturnType<T> extends infer R ? R extends {
@@ -143,6 +171,24 @@ type ComponentAdapter = {
143
171
  data: undefined;
144
172
  } : never);
145
173
  };
174
+ /**
175
+ * Adapte third-part reactive systems
176
+ *
177
+ * @example
178
+ *
179
+ * With Vue
180
+ *
181
+ * ```ts
182
+ * import { shallowReactive, effect } from '@vue/reactivity';
183
+ * const adapter = createComponentAdapter(shallowReactive);
184
+ * const VueComponent = (props: { text: string }) => {
185
+ * const node = document.createElement('div');
186
+ * effect(() => (node.textContent = props.text));
187
+ * return node;
188
+ * };
189
+ * const Component = adapter.mark(VueComponent);
190
+ * ```
191
+ */
146
192
  declare const createComponentAdapter: (reactive: <T extends LooseObject>(obj: T) => T) => ComponentAdapter;
147
193
  /**
148
194
  * Lifecycle hooks.
@@ -158,36 +204,12 @@ type SceneEventMap = {
158
204
  frame: number;
159
205
  close: undefined;
160
206
  };
161
- /**
162
- * @example
163
- *
164
- * Must be called on the top scope of component
165
- *
166
- * ```ts
167
- * const Component = (props: {}) => {
168
- * const ctx = getCurrentScene();
169
- * return '';
170
- * };
171
- * ```
172
- *
173
- * DO NOT call on other place
174
- *
175
- * ```ts
176
- * const Component = (props: {}) => {
177
- * const fn = () => {
178
- * const ctx = getCurrentScene(); // WRONG!
179
- * };
180
- * return '';
181
- * };
182
- * ```
183
- */
184
- declare const getCurrentScene: () => Scene<MaybeGenericComponent<any, {}>>;
185
207
  /** Scene options */
186
208
  type SceneOptions<T extends MaybeGenericComponent> = {
187
209
  /** Root element */
188
210
  root: HTMLDivElement;
189
211
  /** Default props */
190
- defaultProps: Parameters<T>[0];
212
+ defaultProps: T extends Component<infer P, infer _> ? P : Parameters<T>[1] & {};
191
213
  /** Control show timing */
192
214
  timer: () => Timer;
193
215
  /** Component adapter */
@@ -197,7 +219,7 @@ declare class Scene<T extends MaybeGenericComponent> extends EventEmitter<SceneE
197
219
  #private;
198
220
  readonly options: SceneOptions<T>;
199
221
  readonly root: HTMLDivElement;
200
- readonly data: T extends MaybeGenericComponent<infer P, infer D> ? () => D : undefined;
222
+ readonly data: T extends MaybeGenericComponent<infer _, infer D> ? () => D : undefined;
201
223
  /**
202
224
  * Show DOM and update props one-time
203
225
  *
@@ -210,13 +232,16 @@ declare class Scene<T extends MaybeGenericComponent> extends EventEmitter<SceneE
210
232
  * await scene.show(); // show with default props
211
233
  * ```
212
234
  */
213
- show: T extends Component<infer P, infer D> ? SceneShow<P, D> : T;
235
+ show: T extends Component<infer P, infer D> ? (patchProps?: Partial<P>) => Promise<Merge<D, BuiltinData>> : T;
214
236
  /**
215
237
  * @param component - {@link Component}
216
238
  * @param options - {@link SceneOptions}
217
239
  */
218
240
  constructor(component: T, options: SceneOptions<T>);
219
- /** Add close task as Microtask if is caled in the frame else next rAF. */
241
+ /**
242
+ * If called in frame, close in current frame (as microtask), else in next
243
+ * frame
244
+ */
220
245
  close(): void;
221
246
  }
222
247
 
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /** @psytask/core v1.1.4 cubxx MIT */
1
+ /** @psytask/core v1.2.1 cubxx MIT */
2
2
  const symbol = Symbol.dispose ?? /* @__PURE__ */ Symbol.for("Symbol.dispose");
3
3
  class EventEmitter {
4
4
  listeners = {};
@@ -56,11 +56,19 @@ const createTimer = (shouldStop) => {
56
56
  const timer = {
57
57
  start: (cb) => new Promise((resolve) => {
58
58
  const records = [];
59
- currentFrameTime && (records.push(currentFrameTime), cb?.(currentFrameTime));
59
+ if (currentFrameTime) {
60
+ records.push(currentFrameTime);
61
+ cb?.(currentFrameTime);
62
+ }
60
63
  const frame = (time) => {
61
64
  const is_stoped = shouldStop(time, records);
62
65
  records.push(time);
63
- is_stoped ? timer.stop() : (cb?.(time), handle = rAF(frame));
66
+ if (is_stoped) {
67
+ timer.stop();
68
+ } else {
69
+ handle = rAF(frame);
70
+ cb?.(time);
71
+ }
64
72
  };
65
73
  let handle = rAF(frame);
66
74
  timer.stop = () => {
@@ -78,23 +86,28 @@ const generic = (f) => (
78
86
  //@ts-expect-error impl generic component
79
87
  f
80
88
  );
89
+ const sceneStack = [];
90
+ const getCurrentScene = () => sceneStack[sceneStack.length - 1] ?? ERR("Not found current scene");
91
+ const ReactiveFn = /* @__PURE__ */ Symbol();
81
92
  const createComponentAdapter = (reactive) => ({
82
- wrap: (component) => ((props) => component(reactive(props))),
83
- render: (component, defaultProps, ctx) => {
84
- const props = reactive(defaultProps);
93
+ mark(component) {
94
+ component[ReactiveFn] = reactive;
95
+ return component;
96
+ },
97
+ render(component, defaultProps, ctx) {
98
+ const rprops = (component[ReactiveFn] ?? reactive)(defaultProps);
85
99
  ctx && sceneStack.push(ctx);
86
- const instanceOrNode = component(props);
100
+ const instanceOrNode = component(rprops);
87
101
  ctx && sceneStack.pop();
88
102
  let data;
89
103
  const nodes = array_normalize(
90
104
  typeof instanceOrNode !== "string" && "node" in instanceOrNode ? (data = instanceOrNode.data, instanceOrNode.node) : instanceOrNode
91
105
  );
92
- return { props, nodes, data };
106
+ return { props: rprops, nodes, data };
93
107
  }
94
108
  });
95
- const sceneStack = [];
96
- const getCurrentScene = () => sceneStack[sceneStack.length - 1] ?? ERR("Not found current scene");
97
109
  class Scene extends EventEmitter {
110
+ // use GenericComponent as Scene.show type
98
111
  /**
99
112
  * @param component - {@link Component}
100
113
  * @param options - {@link SceneOptions}
@@ -106,12 +119,14 @@ class Scene extends EventEmitter {
106
119
  (this.root = root).tabIndex = -1;
107
120
  root.style.scale = "0";
108
121
  const { props, nodes, data } = adapter.render(
122
+ //@ts-expect-error impl generic component
109
123
  component,
110
124
  { ...defaultProps },
111
125
  this.on("dispose", () => root.remove())
112
126
  );
113
127
  this.#timer = timer();
114
- this.#props = props, this.data = data;
128
+ this.#props = props;
129
+ this.data = data;
115
130
  root.append(...nodes);
116
131
  }
117
132
  root;
@@ -130,12 +145,15 @@ class Scene extends EventEmitter {
130
145
  * await scene.show(); // show with default props
131
146
  * ```
132
147
  */
133
- //@ts-expect-error impl generic component
148
+ //@ts-expect-error impl generic show
134
149
  show = this.#show;
135
- /** Add close task as Microtask if is caled in the frame else next rAF. */
150
+ /**
151
+ * If called in frame, close in current frame (as microtask), else in next
152
+ * frame
153
+ */
136
154
  close() {
137
- const t = this.#timer;
138
- (currentFrameTime ? queueMicrotask : rAF)(() => t.stop());
155
+ const ref = this.#timer;
156
+ (currentFrameTime ? queueMicrotask : rAF)(() => ref.stop());
139
157
  }
140
158
  async #show(patchProps) {
141
159
  const { root, defaultProps } = this.options;
package/dist/index.min.js CHANGED
@@ -1 +1 @@
1
- const f=Symbol.dispose??Symbol.for("Symbol.dispose");class l{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||delete this.listeners[t]),this}once(t,s){const e=r=>(this.off(t,e),s(r));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)},d=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 c;const m=o=>(c=o,setTimeout(()=>c=0),d(m)),A=o=>{c??m(0);const t={start:s=>new Promise(e=>{const r=[];c&&(r.push(c),s?.(c));const n=a=>{const p=o(a,r);r.push(a),p?t.stop():(s?.(a),i=d(n))};let i=d(n);t.stop=()=>{r.pop(),cancelAnimationFrame(i),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&&h.push(e);const n=t(r);e&&h.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}}}),h=[],P=()=>h[h.length-1]??y("Not found current scene");class k extends l{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:p,data:u}=r.render(t,{...n},this.on("dispose",()=>e.remove()));this.#t=i(),this.#s=a,this.data=u,e.append(...p)}root;#t;#s;data;show=this.#e;close(){const t=this.#t;(c?queueMicrotask:d)(()=>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,duration:c-n[0]}}}export{l as EventEmitter,k as Scene,F as createComponentAdapter,A as createTimer,E as generic,P as getCurrentScene};
1
+ const y=Symbol.dispose??Symbol.for("Symbol.dispose");class p{listeners={};[y](){this.emit("dispose")}on(t,e){return(this.listeners[t]??=new Set).add(e),this}off(t,e){const s=this.listeners[t];return s&&(s.delete(e),s.size||delete this.listeners[t]),this}once(t,e){const s=r=>(this.off(t,s),e(r));return this.on(t,s),this}emit(t,...[e]){const s=this.listeners[t];if(s)for(const r of[...s])r(e);return this}}const w=o=>{throw Error(o)},d=requestAnimationFrame,b=Object,S=(o,t)=>b.assign(o,t),g=document;new Proxy({},{get:(o,t)=>e=>S(g.createElement(t),e)});const A=o=>Array.isArray(o)?o:[o];let c;const m=o=>(c=o,setTimeout(()=>c=0),d(m)),F=o=>{c??m(0);const t={start:e=>new Promise(s=>{const r=[];c&&(r.push(c),e?.(c));const n=a=>{const h=o(a,r);r.push(a),h?t.stop():(i=d(n),e?.(a))};let i=d(n);t.stop=()=>{r.pop(),cancelAnimationFrame(i),s(r)}}),stop(){}};return t},k=o=>o,l=[],E=()=>l[l.length-1]??w("Not found current scene"),u=Symbol(),P=o=>({mark(t){return t[u]=o,t},render(t,e,s){const r=(t[u]??o)(e);s&&l.push(s);const n=t(r);s&&l.pop();let i;const a=A(typeof n!="string"&&"node"in n?(i=n.data,n.node):n);return{props:r,nodes:a,data:i}}});class O extends p{constructor(t,e){super(),this.options=e;const{root:s,adapter:r,defaultProps:n,timer:i}=e;(this.root=s).tabIndex=-1,s.style.scale="0";const{props:a,nodes:h,data:f}=r.render(t,{...n},this.on("dispose",()=>s.remove()));this.#t=i(),this.#s=a,this.data=f,s.append(...h)}root;#t;#s;data;show=this.#e;close(){const t=this.#t;(c?queueMicrotask:d)(()=>t.stop())}async#e(t){const{root:e,defaultProps:s}=this.options,r={...s,...t};for(const i of Object.keys({...this.#s,...r}))this.#s[i]=r[i];this.emit("show"),e.style.scale="1",e.focus();const n=await this.#t.start(i=>this.emit("frame",i));return e.style.scale="0",{...this.emit("close").data?.(),frame_times:n,duration:c-n[0]}}}export{p as EventEmitter,O as Scene,P as createComponentAdapter,F as createTimer,k as generic,E as getCurrentScene};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@psytask/core",
3
- "version": "1.1.4",
3
+ "version": "1.2.1",
4
4
  "type": "module",
5
5
  "author": "cubxx",
6
6
  "license": "MIT",