@xtia/jel 0.7.2 → 0.8.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.
package/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { DomEntity, ElementClassDescriptor, ElementDescriptor, DOMContent, DomHelper, StyleAccessor, JelEntity } from "./internal/types";
2
2
  import { $ } from "./internal/element";
3
+ import { DomEntity } from "./internal/types";
3
4
  export { createEntity } from "./internal/util";
4
- export { createEventSource, interval, timeout, SubjectEmitter, toEventEmitter } from "./internal/emitter";
5
+ export { createEventSource, interval, timeout, SubjectEmitter, toEventEmitter, type EventEmitter, combineEmitters } from "./internal/emitter";
5
6
  export { $ };
6
- export declare const $body: import(".").DomEntity<HTMLElement>;
7
+ export declare const $body: DomEntity<HTMLElement>;
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { $ } from "./internal/element";
2
2
  export { createEntity } from "./internal/util";
3
- export { createEventSource, interval, timeout, SubjectEmitter, toEventEmitter } from "./internal/emitter";
3
+ export { createEventSource, interval, timeout, SubjectEmitter, toEventEmitter, combineEmitters } from "./internal/emitter";
4
4
  export { $ };
5
- export const $body = $(document.body);
5
+ export const $body = "document" in globalThis ? $(document.body) : undefined;
@@ -121,6 +121,9 @@ export declare class EventEmitter<T> {
121
121
  */
122
122
  or(...emitters: EmitterLike<T>[]): EventEmitter<T>;
123
123
  or<U>(...emitters: EmitterLike<U>[]): EventEmitter<T | U>;
124
+ memo(): Memo<T | undefined>;
125
+ memo(initial: T): Memo<T>;
126
+ memo<U>(initial: U): Memo<T | U>;
124
127
  }
125
128
  /**
126
129
  * Creates a linked EventEmitter and emit() pair
@@ -157,16 +160,19 @@ export declare function createEventSource<T>(initialHandler?: Handler<T>): {
157
160
  emit: (value: T) => void;
158
161
  emitter: EventEmitter<T>;
159
162
  };
160
- export declare function createListenable<T>(sourceListen?: () => UnsubscribeFunc | undefined): {
161
- listen: (fn: (v: T) => void) => UnsubscribeFunc;
162
- emit: (value: T) => void;
163
- };
164
163
  export declare function interval(ms: number | {
165
164
  asMilliseconds: number;
166
165
  }): EventEmitter<number>;
167
166
  export declare function timeout(t: number | {
168
167
  asMilliseconds: number;
169
168
  }): EventEmitter<void>;
169
+ declare class Memo<T> {
170
+ private _value;
171
+ private unsubscribeFunc;
172
+ get value(): T;
173
+ constructor(source: EmitterLike<T>, initial: T);
174
+ dispose(): void;
175
+ }
170
176
  export declare class SubjectEmitter<T> extends EventEmitter<T> {
171
177
  private emit;
172
178
  private _value;
@@ -192,4 +198,13 @@ type EventSource<T, E extends string> = {
192
198
  */
193
199
  export declare function toEventEmitter<T>(source: EmitterLike<T>): EventEmitter<T>;
194
200
  export declare function toEventEmitter<T, E extends string>(source: EventSource<T, E>, eventName: E): EventEmitter<T>;
201
+ type Dictionary<T> = Record<string | symbol, T>;
202
+ type ExtractEmitterValue<T> = T extends EmitterLike<infer U> ? U : never;
203
+ type CombinedRecord<T extends Dictionary<EmitterLike<any>>> = {
204
+ readonly [K in keyof T]: ExtractEmitterValue<T[K]>;
205
+ };
206
+ export declare function combineEmitters<U extends Dictionary<EmitterLike<any>>>(emitters: U): EventEmitter<CombinedRecord<U>>;
207
+ export declare function combineEmitters<U extends EmitterLike<any>[]>(emitters: [...U]): EventEmitter<{
208
+ [K in keyof U]: ExtractEmitterValue<U[K]>;
209
+ }>;
195
210
  export {};
@@ -314,6 +314,9 @@ export class EventEmitter {
314
314
  return () => unsubs.forEach(unsub => unsub());
315
315
  });
316
316
  }
317
+ memo(initial) {
318
+ return new Memo(this, initial);
319
+ }
317
320
  }
318
321
  /**
319
322
  * Creates a linked EventEmitter and emit() pair
@@ -355,7 +358,7 @@ export function createEventSource(initialHandler) {
355
358
  emitter: new EventEmitter(listen)
356
359
  };
357
360
  }
358
- export function createListenable(sourceListen) {
361
+ function createListenable(sourceListen) {
359
362
  const handlers = [];
360
363
  let onRemoveLast;
361
364
  const addListener = (fn) => {
@@ -401,6 +404,22 @@ export function timeout(t) {
401
404
  });
402
405
  return new EventEmitter(listen);
403
406
  }
407
+ class Memo {
408
+ get value() {
409
+ return this._value;
410
+ }
411
+ constructor(source, initial) {
412
+ this._value = initial;
413
+ const emitter = toEventEmitter(source);
414
+ this.unsubscribeFunc = emitter.listen(v => this._value = v);
415
+ }
416
+ dispose() {
417
+ this.unsubscribeFunc();
418
+ this.unsubscribeFunc = () => {
419
+ throw new Error("Memo object already disposed");
420
+ };
421
+ }
422
+ }
404
423
  export class SubjectEmitter extends EventEmitter {
405
424
  constructor(initial) {
406
425
  const { emit, listen } = createListenable();
@@ -456,3 +475,39 @@ export function toEventEmitter(source, eventName) {
456
475
  }
457
476
  throw new Error("Invalid event source");
458
477
  }
478
+ function combineArray(emitters) {
479
+ let values = Array.from({ length: emitters.length });
480
+ const { emit, listen } = createListenable(() => {
481
+ const unsubFuncs = emitters.map((emitter, idx) => {
482
+ return emitter.listen(v => {
483
+ values[idx] = { value: v };
484
+ if (values.every(v => v !== undefined))
485
+ emit(values.map(vc => vc.value));
486
+ });
487
+ });
488
+ return () => unsubFuncs.forEach(f => f());
489
+ });
490
+ return new EventEmitter(listen);
491
+ }
492
+ function combineRecord(emitters) {
493
+ const keys = Object.keys(emitters);
494
+ let values = {};
495
+ const { emit, listen } = createListenable(() => {
496
+ const unsubFuncs = keys.map(key => {
497
+ return emitters[key].listen(v => {
498
+ values[key] = { value: v };
499
+ if (keys.every(k => values[k] !== undefined)) {
500
+ const record = Object.fromEntries(Object.entries(values).map(([k, vc]) => [k, vc.value]));
501
+ emit(record);
502
+ }
503
+ });
504
+ });
505
+ return () => unsubFuncs.forEach(f => f());
506
+ });
507
+ return new EventEmitter(listen);
508
+ }
509
+ export function combineEmitters(emitters) {
510
+ if (Array.isArray(emitters))
511
+ return combineArray(emitters.map(toEventEmitter));
512
+ return combineRecord(Object.fromEntries(Object.entries(emitters).map(([k, e]) => [k, toEventEmitter(e)])));
513
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtia/jel",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "repository": {
5
5
  "url": "https://github.com/tiadrop/jel-ts",
6
6
  "type": "github"