@xtia/jel 0.7.0 → 0.7.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/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { DomEntity, ElementClassDescriptor, ElementDescriptor, DOMContent, DomHelper, StyleAccessor, JelEntity } from "./internal/types";
2
2
  import { $ } from "./internal/element";
3
3
  export { createEntity } from "./internal/util";
4
- export { createEventSource, interval } from "./internal/emitter";
4
+ export { createEventSource, interval, timeout, SubjectEmitter, toEventEmitter } from "./internal/emitter";
5
5
  export { $ };
6
6
  export declare const $body: import(".").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 } from "./internal/emitter";
3
+ export { createEventSource, interval, timeout, SubjectEmitter, toEventEmitter } from "./internal/emitter";
4
4
  export { $ };
5
5
  export const $body = $(document.body);
@@ -1,14 +1,14 @@
1
- import { DomHelper, Listenable } from "./types";
1
+ import { DomHelper, EmitterLike } from "./types";
2
2
  export declare const $: DomHelper;
3
3
  export declare class ClassAccessor {
4
4
  private classList;
5
5
  private listen;
6
6
  private unlisten;
7
- constructor(classList: DOMTokenList, listen: (className: string, stream: Listenable<boolean>) => void, unlisten: (classNames: string[]) => void);
7
+ constructor(classList: DOMTokenList, listen: (className: string, stream: EmitterLike<boolean>) => void, unlisten: (classNames: string[]) => void);
8
8
  add(...className: string[]): void;
9
9
  remove(...className: string[]): void;
10
10
  toggle(className: string, value?: boolean): boolean;
11
- toggle(className: string, value: Listenable<boolean>): void;
11
+ toggle(className: string, value: EmitterLike<boolean>): void;
12
12
  contains(className: string): boolean;
13
13
  get length(): number;
14
14
  toString(): string;
@@ -1,5 +1,5 @@
1
1
  import { attribsProxy, eventsProxy, styleProxy } from "./proxy";
2
- import { entityDataSymbol, isContent, isJelEntity } from "./util";
2
+ import { entityDataSymbol, isContent, isJelEntity, isReactiveSource } from "./util";
3
3
  const elementWrapCache = new WeakMap();
4
4
  const recursiveAppend = (parent, c) => {
5
5
  if (c === null || c === undefined)
@@ -18,9 +18,9 @@ const recursiveAppend = (parent, c) => {
18
18
  };
19
19
  function createElement(tag, descriptor = {}) {
20
20
  if (isContent(descriptor))
21
- return createElement(tag, {
21
+ descriptor = {
22
22
  content: descriptor,
23
- });
23
+ };
24
24
  const domElement = document.createElement(tag);
25
25
  const ent = getWrappedElement(domElement);
26
26
  const applyClasses = (classes) => {
@@ -68,6 +68,8 @@ function createElement(tag, descriptor = {}) {
68
68
  if (descriptor.on) {
69
69
  Object.entries(descriptor.on).forEach(([eventName, handler]) => ent.events[eventName].apply(handler));
70
70
  }
71
+ if (descriptor.init)
72
+ descriptor.init(ent);
71
73
  return ent;
72
74
  }
73
75
  ;
@@ -132,10 +134,6 @@ function observeMutations() {
132
134
  subtree: true
133
135
  });
134
136
  }
135
- function isReactiveSource(value) {
136
- return typeof value == "object" && value && (("listen" in value && typeof value.listen == "function")
137
- || ("subscribe" in value && typeof value.subscribe == "function"));
138
- }
139
137
  function getWrappedElement(element) {
140
138
  if (!elementWrapCache.has(element)) {
141
139
  const setCSSVariable = (k, v) => {
@@ -173,7 +171,7 @@ function getWrappedElement(element) {
173
171
  elementMutationMap.set(element, {
174
172
  add: () => {
175
173
  Object.values(listeners).forEach(group => {
176
- Object.values(group).forEach(l => { var _a; return l.unsubscribe = (_a = l.subscribe) === null || _a === void 0 ? void 0 : _a.call(l); });
174
+ Object.values(group).forEach(l => l.unsubscribe = l.subscribe());
177
175
  });
178
176
  },
179
177
  remove: () => {
@@ -221,9 +219,11 @@ function getWrappedElement(element) {
221
219
  },
222
220
  get element() { return element; },
223
221
  on(eventId, handler) {
224
- element.addEventListener(eventId, eventData => {
222
+ const fn = (eventData) => {
225
223
  handler.call(domEntity, eventData);
226
- });
224
+ };
225
+ element.addEventListener(eventId, fn);
226
+ return () => element.removeEventListener(eventId, fn);
227
227
  },
228
228
  append(...content) {
229
229
  var _a;
@@ -1,4 +1,4 @@
1
- import { Listenable } from "./types";
1
+ import { EmitterLike } from "./types";
2
2
  type Handler<T> = (value: T) => void;
3
3
  export type ListenFunc<T> = (handler: Handler<T>) => UnsubscribeFunc;
4
4
  export type UnsubscribeFunc = () => void;
@@ -95,7 +95,7 @@ export declare class EventEmitter<T> {
95
95
  * @param notifier
96
96
  * @returns
97
97
  */
98
- takeUntil(notifier: Listenable<any>): EventEmitter<T>;
98
+ takeUntil(notifier: EmitterLike<any>): EventEmitter<T>;
99
99
  /**
100
100
  * Creates a chainable emitter that forwards its parent's emissions while the predicate returns true
101
101
  * Disconnects from the parent and becomes inert when the predicate returns false
@@ -115,9 +115,15 @@ export declare class EventEmitter<T> {
115
115
  * @returns
116
116
  */
117
117
  cached(): EventEmitter<T>;
118
+ /**
119
+ * Creates a chainable emitter that forwards emissions from the parent and any of the provided emitters
120
+ * @param emitters
121
+ */
122
+ or(...emitters: EmitterLike<T>[]): EmitterLike<T>;
123
+ or<U>(...emitters: EmitterLike<U>[]): EmitterLike<T | U>;
118
124
  }
119
125
  /**
120
- * Creates a linked Emitter and emit() pair
126
+ * Creates a linked EventEmitter and emit() pair
121
127
  * @example
122
128
  * ```ts
123
129
  * function createForm(options?: { onsubmit?: (data: FormData) => void }) {
@@ -151,17 +157,39 @@ export declare function createEventSource<T>(initialHandler?: Handler<T>): {
151
157
  emit: (value: T) => void;
152
158
  emitter: EventEmitter<T>;
153
159
  };
154
- export declare function createListenable<T>(onAddFirst?: () => void, onRemoveLast?: () => void): {
160
+ export declare function createListenable<T>(sourceListen?: () => UnsubscribeFunc | undefined): {
155
161
  listen: (fn: (v: T) => void) => UnsubscribeFunc;
156
162
  emit: (value: T) => void;
157
163
  };
158
- export declare function interval(t: number | {
164
+ export declare function interval(ms: number | {
159
165
  asMilliseconds: number;
160
166
  }): EventEmitter<number>;
161
- export declare function timeoutx(t: number | {
162
- asMilliseconds: number;
163
- }): EventEmitter<void>;
164
167
  export declare function timeout(t: number | {
165
168
  asMilliseconds: number;
166
169
  }): EventEmitter<void>;
170
+ export declare class SubjectEmitter<T> extends EventEmitter<T> {
171
+ private emit;
172
+ private _value;
173
+ constructor(initial: T);
174
+ get value(): T;
175
+ next(value: T): void;
176
+ }
177
+ type EventSource<T, E extends string> = {
178
+ on: (eventName: E, handler: (value: T) => void) => UnsubscribeFunc;
179
+ } | {
180
+ on: (eventName: E, handler: (value: T) => void) => void | UnsubscribeFunc;
181
+ off: (eventName: E, handler: (value: T) => void) => void;
182
+ } | {
183
+ addEventListener: (eventName: E, handler: (value: T) => void) => UnsubscribeFunc;
184
+ } | {
185
+ addEventListener: (eventName: E, handler: (value: T) => void) => void | UnsubscribeFunc;
186
+ removeEventListener: (eventName: E, handler: (value: T) => void) => void;
187
+ };
188
+ /**
189
+ * Create an EventEmitter from an event source. Event sources can be RxJS observables, existing EventEmitters, or objects that
190
+ * provide a subscribe()/listen() => UnsubscribeFunc method.
191
+ * @param source
192
+ */
193
+ export declare function toEventEmitter<T>(source: EmitterLike<T>): EventEmitter<T>;
194
+ export declare function toEventEmitter<T, E extends string>(source: EventSource<T, E>, eventName: E): EventEmitter<T>;
167
195
  export {};
@@ -1,16 +1,12 @@
1
+ import { isReactiveSource } from "./util";
1
2
  export class EventEmitter {
2
3
  constructor(onListen) {
3
4
  this.onListen = onListen;
4
5
  }
5
6
  transform(handler) {
6
- let parentUnsubscribe = null;
7
- const parentListen = this.onListen;
8
- const { emit, listen } = createListenable(() => parentUnsubscribe = parentListen(value => {
7
+ const { emit, listen } = createListenable(() => this.onListen(value => {
9
8
  handler(value, emit);
10
- }), () => {
11
- parentUnsubscribe();
12
- parentUnsubscribe = null;
13
- });
9
+ }));
14
10
  return listen;
15
11
  }
16
12
  /**
@@ -171,7 +167,8 @@ export class EventEmitter {
171
167
  clear();
172
168
  emit(v);
173
169
  });
174
- }, clear);
170
+ return clear;
171
+ });
175
172
  return new EventEmitter(listen);
176
173
  }
177
174
  delay(ms) {
@@ -226,11 +223,7 @@ export class EventEmitter {
226
223
  }
227
224
  });
228
225
  }
229
- }, () => {
230
- if (sourceUnsub) {
231
- sourceUnsub();
232
- sourceUnsub = null;
233
- }
226
+ return sourceUnsub;
234
227
  });
235
228
  return new EventEmitter(listen);
236
229
  }
@@ -245,14 +238,8 @@ export class EventEmitter {
245
238
  let notifierUnsub = null;
246
239
  let completed = false;
247
240
  const clear = () => {
248
- if (parentUnsubscribe) {
249
- parentUnsubscribe();
250
- parentUnsubscribe = null;
251
- }
252
- if (notifierUnsub) {
253
- notifierUnsub();
254
- notifierUnsub = null;
255
- }
241
+ parentUnsubscribe === null || parentUnsubscribe === void 0 ? void 0 : parentUnsubscribe();
242
+ notifierUnsub === null || notifierUnsub === void 0 ? void 0 : notifierUnsub();
256
243
  };
257
244
  const { emit, listen } = createListenable(() => {
258
245
  if (completed)
@@ -262,10 +249,9 @@ export class EventEmitter {
262
249
  completed = true;
263
250
  clear();
264
251
  };
265
- notifierUnsub = "subscribe" in notifier
266
- ? notifier.subscribe(handler)
267
- : notifier.listen(handler);
268
- }, clear);
252
+ notifierUnsub = toEventEmitter(notifier).listen(handler);
253
+ return clear;
254
+ });
269
255
  return new EventEmitter(listen);
270
256
  }
271
257
  /**
@@ -274,14 +260,8 @@ export class EventEmitter {
274
260
  * @param predicate Callback to determine whether to keep forwarding
275
261
  */
276
262
  takeWhile(predicate) {
277
- let parentUnsubscribe = null;
263
+ let parentUnsubscribe;
278
264
  let completed = false;
279
- const clear = () => {
280
- if (parentUnsubscribe) {
281
- parentUnsubscribe();
282
- parentUnsubscribe = null;
283
- }
284
- };
285
265
  const { emit, listen } = createListenable(() => {
286
266
  if (completed)
287
267
  return;
@@ -291,10 +271,12 @@ export class EventEmitter {
291
271
  }
292
272
  else {
293
273
  completed = true;
294
- clear();
274
+ parentUnsubscribe();
275
+ parentUnsubscribe = undefined;
295
276
  }
296
277
  });
297
- }, clear);
278
+ return () => parentUnsubscribe === null || parentUnsubscribe === void 0 ? void 0 : parentUnsubscribe();
279
+ });
298
280
  return new EventEmitter(listen);
299
281
  }
300
282
  /**
@@ -316,24 +298,25 @@ export class EventEmitter {
316
298
  */
317
299
  cached() {
318
300
  let cache = null;
319
- let unsub = null;
320
- const { listen, emit } = createListenable(() => {
321
- unsub = this.onListen((value => {
322
- cache = { value };
323
- emit(value);
324
- }));
325
- }, () => {
326
- unsub();
327
- });
301
+ const { listen, emit } = createListenable(() => this.onListen((value => {
302
+ cache = { value };
303
+ emit(value);
304
+ })));
328
305
  return new EventEmitter(handler => {
329
306
  if (cache)
330
307
  handler(cache.value);
331
308
  return listen(handler);
332
309
  });
333
310
  }
311
+ or(...emitters) {
312
+ return new EventEmitter(handler => {
313
+ const unsubs = [this, ...emitters].map(e => toEventEmitter(e).listen(handler));
314
+ return () => unsubs.forEach(unsub => unsub());
315
+ });
316
+ }
334
317
  }
335
318
  /**
336
- * Creates a linked Emitter and emit() pair
319
+ * Creates a linked EventEmitter and emit() pair
337
320
  * @example
338
321
  * ```ts
339
322
  * function createForm(options?: { onsubmit?: (data: FormData) => void }) {
@@ -372,13 +355,14 @@ export function createEventSource(initialHandler) {
372
355
  emitter: new EventEmitter(listen)
373
356
  };
374
357
  }
375
- export function createListenable(onAddFirst, onRemoveLast) {
358
+ export function createListenable(sourceListen) {
376
359
  const handlers = [];
360
+ let onRemoveLast;
377
361
  const addListener = (fn) => {
378
362
  const unique = { fn };
379
363
  handlers.push(unique);
380
- if (onAddFirst && handlers.length == 1)
381
- onAddFirst();
364
+ if (sourceListen && handlers.length == 1)
365
+ onRemoveLast = sourceListen();
382
366
  return () => {
383
367
  const idx = handlers.indexOf(unique);
384
368
  if (idx === -1)
@@ -393,19 +377,17 @@ export function createListenable(onAddFirst, onRemoveLast) {
393
377
  emit: (value) => handlers.forEach(h => h.fn(value)),
394
378
  };
395
379
  }
396
- export function interval(t) {
380
+ export function interval(ms) {
397
381
  let intervalId = null;
398
382
  let idx = 0;
399
383
  const { emit, listen } = createListenable(() => {
400
384
  intervalId = setInterval(() => {
401
385
  emit(idx++);
402
- }, typeof t == "number" ? t : t.asMilliseconds);
403
- }, () => clearInterval(intervalId));
386
+ }, typeof ms == "number" ? ms : ms.asMilliseconds);
387
+ return () => clearInterval(intervalId);
388
+ });
404
389
  return new EventEmitter(listen);
405
390
  }
406
- export function timeoutx(t) {
407
- return interval(t).once().map(() => { });
408
- }
409
391
  export function timeout(t) {
410
392
  const ms = typeof t === "number" ? t : t.asMilliseconds;
411
393
  const targetTime = Date.now() + ms;
@@ -415,8 +397,62 @@ export function timeout(t) {
415
397
  if (reminaingMs < 0)
416
398
  return;
417
399
  timeoutId = setTimeout(emit, reminaingMs);
418
- }, () => {
419
- clearTimeout(timeoutId);
400
+ return () => clearTimeout(timeoutId);
420
401
  });
421
402
  return new EventEmitter(listen);
422
403
  }
404
+ export class SubjectEmitter extends EventEmitter {
405
+ constructor(initial) {
406
+ const { emit, listen } = createListenable();
407
+ super(h => {
408
+ h(this._value);
409
+ return listen(h);
410
+ });
411
+ this.emit = emit;
412
+ this._value = initial;
413
+ }
414
+ get value() {
415
+ return this._value;
416
+ }
417
+ next(value) {
418
+ this._value = value;
419
+ this.emit(value);
420
+ }
421
+ }
422
+ export function toEventEmitter(source, eventName) {
423
+ if (source instanceof EventEmitter)
424
+ return source;
425
+ if (eventName !== undefined) {
426
+ // addEL()
427
+ if ("addEventListener" in source) {
428
+ if ("removeEventListener" in source && typeof source.removeEventListener == "function") {
429
+ return new EventEmitter(h => {
430
+ var _a;
431
+ return (_a = source.addEventListener(eventName, h)) !== null && _a !== void 0 ? _a : (() => source.removeEventListener(eventName, h));
432
+ });
433
+ }
434
+ return new EventEmitter(h => {
435
+ return source.addEventListener(eventName, h);
436
+ });
437
+ }
438
+ // on()
439
+ if ("on" in source) {
440
+ if ("off" in source && typeof source.off == "function") {
441
+ return new EventEmitter(h => {
442
+ var _a;
443
+ return (_a = source.on(eventName, h)) !== null && _a !== void 0 ? _a : (() => source.off(eventName, h));
444
+ });
445
+ }
446
+ return new EventEmitter(h => {
447
+ return source.on(eventName, h);
448
+ });
449
+ }
450
+ }
451
+ if (isReactiveSource(source)) {
452
+ const subscribe = "subscribe" in source
453
+ ? (h) => source.subscribe(h)
454
+ : (h) => source.listen(h);
455
+ return new EventEmitter(subscribe);
456
+ }
457
+ throw new Error("Invalid event source");
458
+ }
package/internal/proxy.js CHANGED
@@ -1,4 +1,4 @@
1
- import { EventEmitter } from "./emitter";
1
+ import { toEventEmitter } from "./emitter";
2
2
  export const styleProxy = {
3
3
  get(style, prop) {
4
4
  return style(prop);
@@ -42,13 +42,6 @@ export const eventsProxy = {
42
42
  if (key == "removeEventListener") {
43
43
  return (name, handler) => element.removeEventListener(name, handler);
44
44
  }
45
- const listen = (handler) => {
46
- const wrappedHandler = (event) => handler(event);
47
- element.addEventListener(key, wrappedHandler);
48
- return () => {
49
- element.removeEventListener(key, wrappedHandler);
50
- };
51
- };
52
- return new EventEmitter(listen);
45
+ return toEventEmitter(element, key);
53
46
  }
54
47
  };
@@ -1,10 +1,11 @@
1
1
  import { type ClassAccessor } from "./element";
2
2
  import { EventEmitter, UnsubscribeFunc } from "./emitter";
3
3
  import { entityDataSymbol } from "./util";
4
- export type ElementClassDescriptor = string | Record<string, boolean | Listenable<boolean> | undefined> | undefined | ElementClassDescriptor[];
4
+ export type ElementClassDescriptor = string | Record<string, boolean | EmitterLike<boolean> | undefined> | undefined | ElementClassDescriptor[];
5
5
  export type DOMContent = number | null | string | Element | JelEntity<object> | Text | DOMContent[];
6
6
  export type DomEntity<T extends HTMLElement> = JelEntity<ElementAPI<T>>;
7
- export type Listenable<T> = {
7
+ export type HTMLTag = keyof HTMLElementTagNameMap;
8
+ export type EmitterLike<T> = {
8
9
  subscribe: (callback: (value: T) => void) => UnsubscribeFunc;
9
10
  } | {
10
11
  listen: (callback: (value: T) => void) => UnsubscribeFunc;
@@ -19,10 +20,10 @@ export type StylesDescriptor = {
19
20
  [K in keyof CSSStyleDeclaration as [
20
21
  K,
21
22
  CSSStyleDeclaration[K]
22
- ] extends [string, string] ? K : never]+?: CSSValue | Listenable<CSSValue>;
23
+ ] extends [string, string] ? K : never]+?: CSSValue | EmitterLike<CSSValue>;
23
24
  };
24
- export type SetStyleFunc = ((property: CSSProperty, value: CSSValue | Listenable<CSSValue>) => void);
25
- export type SetGetStyleFunc = SetStyleFunc & ((property: CSSProperty) => string | Listenable<CSSValue>);
25
+ export type SetStyleFunc = ((property: CSSProperty, value: CSSValue | EmitterLike<CSSValue>) => void);
26
+ export type SetGetStyleFunc = SetStyleFunc & ((property: CSSProperty) => string | EmitterLike<CSSValue>);
26
27
  export type StyleAccessor = ((styles: StylesDescriptor) => void) & StylesDescriptor & SetStyleFunc;
27
28
  type ContentlessTag = "area" | "br" | "hr" | "iframe" | "input" | "textarea" | "img" | "canvas" | "link" | "meta" | "source" | "embed" | "track" | "base";
28
29
  type TagWithHref = "a" | "link" | "base";
@@ -32,18 +33,19 @@ type TagWithWidthHeight = "canvas" | "img" | "embed" | "iframe" | "video";
32
33
  type TagWithType = "input" | "source" | "button";
33
34
  type TagWithName = 'input' | 'textarea' | 'select' | 'form';
34
35
  type ContentlessElement = HTMLElementTagNameMap[ContentlessTag];
35
- export type ElementDescriptor<Tag extends string> = {
36
+ export type ElementDescriptor<Tag extends HTMLTag> = {
36
37
  classes?: ElementClassDescriptor;
37
38
  attribs?: Record<string, string | number | boolean>;
38
39
  on?: {
39
40
  [E in keyof HTMLElementEventMap]+?: (event: HTMLElementEventMap[E]) => void;
40
41
  };
41
42
  style?: StylesDescriptor;
42
- cssVariables?: Record<string, CSSValue | Listenable<CSSValue>>;
43
+ cssVariables?: Record<string, CSSValue | EmitterLike<CSSValue>>;
44
+ init?: (entity: DomEntity<HTMLElementTagNameMap[Tag]>) => void;
43
45
  } & (Tag extends TagWithValue ? {
44
46
  value?: string | number;
45
47
  } : {}) & (Tag extends ContentlessTag ? {} : {
46
- content?: DOMContent | Listenable<DOMContent>;
48
+ content?: DOMContent | EmitterLike<DOMContent>;
47
49
  }) & (Tag extends TagWithSrc ? {
48
50
  src?: string;
49
51
  } : {}) & (Tag extends TagWithHref ? {
@@ -64,18 +66,18 @@ type ElementAPI<T extends HTMLElement> = {
64
66
  };
65
67
  readonly events: EventsAccessor;
66
68
  readonly style: StyleAccessor;
67
- setCSSVariable(variableName: string, value: CSSValue | Listenable<CSSValue>): void;
68
- setCSSVariable(table: Record<string, CSSValue | Listenable<CSSValue>>): void;
69
+ setCSSVariable(variableName: string, value: CSSValue | EmitterLike<CSSValue>): void;
70
+ setCSSVariable(table: Record<string, CSSValue | EmitterLike<CSSValue>>): void;
69
71
  qsa(selector: string): (Element | DomEntity<HTMLElement>)[];
70
72
  remove(): void;
71
73
  getRect(): DOMRect;
72
74
  focus(): void;
73
75
  blur(): void;
74
- on<E extends keyof HTMLElementEventMap>(eventId: E, handler: (this: ElementAPI<T>, data: HTMLElementEventMap[E]) => void): void;
76
+ on<E extends keyof HTMLElementEventMap>(eventId: E, handler: (this: ElementAPI<T>, data: HTMLElementEventMap[E]) => void): UnsubscribeFunc;
75
77
  } & (T extends ContentlessElement ? {} : {
76
78
  append(...content: DOMContent[]): void;
77
79
  innerHTML: string;
78
- content: DOMContent | Listenable<DOMContent>;
80
+ content: DOMContent | EmitterLike<DOMContent>;
79
81
  }) & (T extends HTMLElementTagNameMap[TagWithValue] ? {
80
82
  value: string;
81
83
  select(): void;
@@ -99,26 +101,26 @@ export type DomHelper = ((
99
101
  /**
100
102
  * Creates an element of the specified tag
101
103
  */
102
- <T extends keyof HTMLElementTagNameMap>(tagName: T, descriptor: ElementDescriptor<T>) => DomEntity<HTMLElementTagNameMap[T]>) & (
104
+ <T extends HTMLTag>(tagName: T, descriptor: ElementDescriptor<T>) => DomEntity<HTMLElementTagNameMap[T]>) & (
103
105
  /**
104
106
  * Creates an element of the specified tag
105
107
  */
106
- <T extends keyof HTMLElementTagNameMap>(tagName: T) => DomEntity<HTMLElementTagNameMap[T]>) & (
108
+ <T extends HTMLTag>(tagName: T) => DomEntity<HTMLElementTagNameMap[T]>) & (
107
109
  /**
108
110
  * Creates an element with ID and classes as specified by a selector-like string
109
111
  */
110
- <T extends keyof HTMLElementTagNameMap>(selector: `${T}#${string}`, content?: T extends ContentlessTag ? void : DOMContent) => DomEntity<HTMLElementTagNameMap[T]>) & (
112
+ <T extends HTMLTag>(selector: `${T}#${string}`, content?: T extends ContentlessTag ? void : DOMContent) => DomEntity<HTMLElementTagNameMap[T]>) & (
111
113
  /**
112
114
  * Creates an element with ID and classes as specified by a selector-like string
113
115
  */
114
- <T extends keyof HTMLElementTagNameMap>(selector: `${T}.${string}`, content?: T extends ContentlessTag ? void : DOMContent) => DomEntity<HTMLElementTagNameMap[T]>) & (
116
+ <T extends HTMLTag>(selector: `${T}.${string}`, content?: T extends ContentlessTag ? void : DOMContent) => DomEntity<HTMLElementTagNameMap[T]>) & (
115
117
  /**
116
118
  * Wraps an existing element as a DomEntity
117
119
  */
118
120
  <T extends HTMLElement>(element: T) => DomEntity<T>) & {
119
- [T in keyof HTMLElementTagNameMap]: (descriptor: ElementDescriptor<T>) => DomEntity<HTMLElementTagNameMap[T]>;
121
+ [T in HTMLTag]: (descriptor: ElementDescriptor<T>) => DomEntity<HTMLElementTagNameMap[T]>;
120
122
  } & {
121
- [T in keyof HTMLElementTagNameMap]: T extends ContentlessTag ? () => DomEntity<HTMLElementTagNameMap[T]> : (content?: DOMContent) => DomEntity<HTMLElementTagNameMap[T]>;
123
+ [T in HTMLTag]: T extends ContentlessTag ? () => DomEntity<HTMLElementTagNameMap[T]> : (content?: DOMContent) => DomEntity<HTMLElementTagNameMap[T]>;
122
124
  });
123
125
  type JelEntityData = {
124
126
  dom: DOMContent;
@@ -1,6 +1,6 @@
1
- import { DOMContent, ElementDescriptor, JelEntity } from "./types";
1
+ import { DOMContent, ElementDescriptor, EmitterLike, HTMLTag, JelEntity } from "./types";
2
2
  export declare const entityDataSymbol: unique symbol;
3
- export declare const isContent: (value: DOMContent | ElementDescriptor<string> | undefined) => value is DOMContent;
3
+ export declare const isContent: <T extends HTMLTag>(value: DOMContent | ElementDescriptor<T> | undefined) => value is DOMContent;
4
4
  export declare function isJelEntity(content: DOMContent): content is JelEntity<object>;
5
5
  /**
6
6
  * Wraps an object such that it can be appended as DOM content while retaining its original API
@@ -9,3 +9,4 @@ export declare function isJelEntity(content: DOMContent): content is JelEntity<o
9
9
  */
10
10
  export declare function createEntity<API extends object>(content: DOMContent, api: API extends DOMContent ? never : API): JelEntity<API>;
11
11
  export declare function createEntity(content: DOMContent): JelEntity<void>;
12
+ export declare function isReactiveSource(value: any): value is EmitterLike<any>;
package/internal/util.js CHANGED
@@ -26,3 +26,7 @@ export function createEntity(content, api) {
26
26
  });
27
27
  }
28
28
  ;
29
+ export function isReactiveSource(value) {
30
+ return typeof value == "object" && value && (("listen" in value && typeof value.listen == "function")
31
+ || ("subscribe" in value && typeof value.subscribe == "function"));
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtia/jel",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "repository": {
5
5
  "url": "https://github.com/tiadrop/jel-ts",
6
6
  "type": "github"