typed-dom
Advanced tools
Comparing version 0.0.279 to 0.0.280
22
dom.ts
@@ -137,2 +137,14 @@ import { Symbol, document } from 'spica/global'; | ||
el.setAttribute(name, value); | ||
if (name.startsWith('on')) { | ||
const type = name.slice(2).toLowerCase(); | ||
switch (type) { | ||
case 'mutate': | ||
case 'connect': | ||
case 'disconnect': | ||
const prop = `on${type}`; | ||
prop in el | ||
? el[prop] ??= (ev: NodeEvent<E>) => ev.returnValue | ||
: el[prop] ??= ''; | ||
} | ||
} | ||
continue; | ||
@@ -144,4 +156,4 @@ case 'function': | ||
if (!name.startsWith('on')) throw new Error(`TypedDOM: Attribute names for event listeners must start with "on" but got "${name}".`); | ||
const eventname = name.slice(2).toLowerCase(); | ||
el.addEventListener(eventname, value, { | ||
const type = name.slice(2).toLowerCase(); | ||
el.addEventListener(type, value, { | ||
passive: [ | ||
@@ -154,9 +166,9 @@ 'wheel', | ||
'touchcancel', | ||
].includes(eventname), | ||
].includes(type), | ||
}); | ||
switch (eventname) { | ||
switch (type) { | ||
case 'mutate': | ||
case 'connect': | ||
case 'disconnect': | ||
const prop = `on${eventname}`; | ||
const prop = `on${type}`; | ||
prop in el | ||
@@ -163,0 +175,0 @@ ? el[prop] ??= (ev: NodeEvent<E>) => ev.returnValue |
@@ -6,4 +6,4 @@ import 'spica/global'; | ||
export { NS, Attrs, Children, Factory, shadow, frag, html, svg, text, element, define, append, prepend, defrag } from './src/util/dom'; | ||
export { listen, delegate, bind, once, wait, currentTarget } from './src/util/listener'; | ||
export { listen, delegate, bind, once, currentTarget } from './src/util/listener'; | ||
export { querySelector, querySelectorAll } from './src/util/query'; | ||
export { identity } from './src/util/identity'; |
@@ -1,2 +0,2 @@ | ||
import { bind, delegate, listen, once, wait, currentTarget } from './listener'; | ||
import { bind, delegate, listen, once, currentTarget } from './listener'; | ||
import { Shadow, HTML } from '../builder'; | ||
@@ -82,4 +82,9 @@ | ||
assert(cnt === 0 && ++cnt); | ||
once(el, 'click', () => void assert(cnt === 1 && ++cnt) || done()); | ||
once(el, 'click', () => void assert(cnt === 2 && ++cnt) || done()); | ||
}); | ||
once(el, 'click').then(ev => { | ||
assert(ev instanceof Event); | ||
assert(ev[currentTarget] === ev.currentTarget); | ||
assert(cnt === 1 && ++cnt); | ||
}); | ||
document.createDocumentFragment().appendChild(el); | ||
@@ -97,32 +102,12 @@ el.click(); | ||
assert(cnt === 0 && ++cnt); | ||
once(dom.element, 'click', () => void assert(cnt === 1 && ++cnt) || done()); | ||
once(dom.element, 'click', () => void assert(cnt === 2 && ++cnt) || done()); | ||
}); | ||
document.createDocumentFragment().appendChild(dom.element); | ||
dom.children[0].element.click(); | ||
dom.children[0].element.click(); | ||
}); | ||
}); | ||
describe('wait', () => { | ||
it('bind', done => { | ||
const el = HTML.a().element; | ||
wait(el, 'click').then(ev => { | ||
once(dom.element, 'a', 'click').then(ev => { | ||
assert(ev instanceof Event); | ||
assert(ev[currentTarget] === ev.currentTarget); | ||
done(); | ||
assert(cnt === 1 && ++cnt); | ||
}); | ||
document.createDocumentFragment().appendChild(el); | ||
el.click(); | ||
}); | ||
it('delegate', done => { | ||
const dom = Shadow.section([HTML.a()]); | ||
wait(dom.element, 'a', 'click').then(ev => { | ||
assert(ev instanceof Event); | ||
assert(ev[currentTarget] === ev.currentTarget); | ||
done(); | ||
}); | ||
document.createDocumentFragment().appendChild(dom.element); | ||
dom.children[0].element.click(); | ||
dom.children[0].element.click(); | ||
}); | ||
@@ -129,0 +114,0 @@ |
131
listener.ts
@@ -13,49 +13,95 @@ import { AtomicPromise } from 'spica/promise'; | ||
export function listen<T extends keyof WindowEventMap>(target: Window, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof WindowEventMap>(target: Window, selector: string, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, selector: string, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof HTMLElementEventMap>(target: HTMLElement, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof MathMLElementEventMap>(target: MathMLElement, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof MathMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof ElementEventMap>(target: Element, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | HTMLElement, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | SVGElement, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>(target: Window | Document | ShadowRoot | Element, a: T | string, b: ((ev: Event) => void) | T, c: boolean | AddEventListenerOptions | ((ev: Event) => void) = false, d: AddEventListenerOptions = {}): () => undefined { | ||
return typeof b === 'string' | ||
? delegate(target as Document, a, b as keyof ElementEventMap, c as () => void, d) | ||
: bind(target as Element, a as keyof ElementEventMap, b, c as boolean); | ||
export function listen<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>( | ||
target: Window | Document | ShadowRoot | Element, | ||
selector: T | string, | ||
type: T | ((ev: Event) => void), | ||
listener?: boolean | AddEventListenerOptions | ((ev: Event) => void), | ||
option?: boolean | AddEventListenerOptions, | ||
): () => undefined { | ||
return typeof type === 'string' | ||
? delegate(target as Document, selector, type as keyof ElementEventMap, listener as () => void, option) | ||
: bind(target as Element, selector as keyof ElementEventMap, type, listener as boolean); | ||
} | ||
export function once<T extends keyof WindowEventMap>(target: Window, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<WindowEventMap[T]>; | ||
export function once<T extends keyof WindowEventMap>(target: Window, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof WindowEventMap>(target: Window, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<WindowEventMap[T]>; | ||
export function once<T extends keyof WindowEventMap>(target: Window, selector: string, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<DocumentEventMap[T]>; | ||
export function once<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<DocumentEventMap[T]>; | ||
export function once<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, selector: string, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof HTMLElementEventMap>(target: HTMLElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<HTMLElementEventMap[T]>; | ||
export function once<T extends keyof HTMLElementEventMap>(target: HTMLElement, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<HTMLElementEventMap[T]>; | ||
export function once<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<SVGElementEventMap[T]>; | ||
export function once<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<SVGElementEventMap[T]>; | ||
export function once<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof MathMLElementEventMap>(target: MathMLElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<MathMLElementEventMap[T]>; | ||
export function once<T extends keyof MathMLElementEventMap>(target: MathMLElement, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof MathMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<MathMLElementEventMap[T]>; | ||
export function once<T extends keyof MathMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof ElementEventMap>(target: Element, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<ElementEventMap[T]>; | ||
export function once<T extends keyof ElementEventMap>(target: Element, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | HTMLElement, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | SVGElement, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: AddEventListenerOptions): AtomicPromise<ElementEventMap[T]>; | ||
export function once<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>(target: Window | Document | ShadowRoot | Element, a: T | string, b: ((ev: Event) => void) | T, c: boolean | AddEventListenerOptions | ((ev: Event) => void) = false, d: AddEventListenerOptions = {}): () => undefined { | ||
return typeof b === 'string' | ||
? delegate(target as Document, a, b as keyof ElementEventMap, c as () => void, { ...typeof d === 'boolean' ? { capture: d } : d, once: true }) | ||
: bind(target as Element, a as keyof ElementEventMap, b, { ...typeof c === 'boolean' ? { capture: c } : c, once: true }); | ||
} | ||
export function wait<T extends keyof WindowEventMap>(target: Window, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<WindowEventMap[T]>; | ||
export function wait<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<DocumentEventMap[T]>; | ||
export function wait<T extends keyof HTMLElementEventMap>(target: HTMLElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<HTMLElementEventMap[T]>; | ||
export function wait<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<SVGElementEventMap[T]>; | ||
export function wait<T extends keyof ElementEventMap>(target: Element, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<ElementEventMap[T]>; | ||
export function wait<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | HTMLElement, selector: string, type: T, option?: AddEventListenerOptions): AtomicPromise<HTMLElementEventMap[T]>; | ||
export function wait<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | SVGElement, selector: string, type: T, option?: AddEventListenerOptions): AtomicPromise<SVGElementEventMap[T]>; | ||
export function wait<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: AddEventListenerOptions): AtomicPromise<ElementEventMap[T]>; | ||
export function wait<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>(target: Window | Document | ShadowRoot | Element, a: T | string, b: T | boolean | AddEventListenerOptions = false, c: AddEventListenerOptions = {}): AtomicPromise<Event> { | ||
export function once<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>( | ||
target: Window | Document | ShadowRoot | Element, | ||
selector: T | string, | ||
type?: T | boolean | AddEventListenerOptions | ((ev: Event) => void), | ||
listener?: boolean | AddEventListenerOptions | ((ev: Event) => void), | ||
option?: boolean | AddEventListenerOptions, | ||
): (() => undefined) | AtomicPromise<Event> { | ||
switch (typeof type) { | ||
case 'string': | ||
switch (typeof listener) { | ||
case 'function': | ||
return delegate(target as Document, selector, type as keyof ElementEventMap, listener as () => void, { ...typeof option === 'boolean' ? { capture: option } : option, once: true }); | ||
case 'object': | ||
option = { ...listener, once: true }; | ||
break; | ||
default: | ||
option = { once: true }; | ||
} | ||
return new AtomicPromise(resolve => | ||
void delegate(target as Element, selector, type as keyof ElementEventMap, resolve, option)); | ||
case 'function': | ||
return bind(target as Element, selector as keyof ElementEventMap, type, { ...typeof listener === 'boolean' ? { capture: listener } : listener, once: true }); | ||
case 'object': | ||
option = { ...type, once: true }; | ||
break; | ||
default: | ||
option = { once: true }; | ||
} | ||
return new AtomicPromise(resolve => | ||
typeof b === 'string' | ||
? once(target as Document, a, b as keyof ElementEventMap, resolve, c) | ||
: once(target as Element, a as keyof ElementEventMap, resolve, b)); | ||
void bind(target as Element, selector as keyof ElementEventMap, resolve, option)); | ||
} | ||
export function delegate<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | HTMLElement, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | SVGElement, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option: AddEventListenerOptions = {}): () => undefined { | ||
return bind(target as Element, type, ev => { | ||
export function delegate<T extends keyof WindowEventMap>(target: Window, selector: string, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, selector: string, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof MathMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>( | ||
target: Window | Document | ShadowRoot | Element, | ||
selector: string, | ||
type: T, | ||
listener: (ev: Event) => void, | ||
option?: boolean | AddEventListenerOptions, | ||
): () => undefined { | ||
return bind(target as Element, type as keyof ElementEventMap, ev => { | ||
assert(ev.target instanceof Element); | ||
@@ -66,4 +112,4 @@ assert(ev.composedPath()[0] instanceof Element); | ||
: (ev.target as Element)?.closest(selector); | ||
cx && once(cx, type, e => { e === ev && listener(ev); }, option); | ||
}, { ...option, capture: true }); | ||
cx && once(cx, type as keyof ElementEventMap, e => { e === ev && listener(ev); }, option); | ||
}, { ...typeof option === 'boolean' ? { capture: true } : option, capture: true }); | ||
} | ||
@@ -75,4 +121,19 @@ | ||
export function bind<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function bind<T extends keyof MathMLElementEventMap>(target: MathMLElement, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function bind<T extends keyof ElementEventMap>(target: Element, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function bind<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>(target: Window | Document | ShadowRoot | Element, type: T, listener: (ev: Event) => void, option: boolean | AddEventListenerOptions = false): () => undefined { | ||
export function bind<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>( | ||
target: Window | Document | ShadowRoot | Element, | ||
type: T, | ||
listener: (ev: Event) => void, | ||
option?: boolean | AddEventListenerOptions, | ||
): () => undefined { | ||
switch (type) { | ||
case 'mutate': | ||
case 'connect': | ||
case 'disconnect': | ||
const prop = `on${type}`; | ||
prop in target | ||
? target[prop] ??= (ev: Event) => ev.returnValue | ||
: target[prop] ??= ''; | ||
} | ||
target.addEventListener(type, handler, option); | ||
@@ -79,0 +140,0 @@ return singleton(() => void target.removeEventListener(type, handler, option)); |
{ | ||
"name": "typed-dom", | ||
"version": "0.0.279", | ||
"version": "0.0.280", | ||
"description": "A value-level and type-level DOM builder.", | ||
@@ -65,3 +65,3 @@ "private": false, | ||
"power-assert": "^1.6.1", | ||
"spica": "0.0.541", | ||
"spica": "0.0.542", | ||
"tsify": "^5.0.4", | ||
@@ -68,0 +68,0 @@ "typescript": "4.6.4", |
@@ -180,2 +180,18 @@ # typed-dom | ||
## Events | ||
These events are enabled only when an event listener is set using the Typed-DOM APIs. | ||
### mutate | ||
It will be dispatched when the children property value is changed. | ||
### connect | ||
It will be dispatched when added to another proxy connected to the context object. | ||
### disconnect | ||
It will be dispatched when removed from the parent proxy connected to the context object. | ||
## Usage | ||
@@ -331,13 +347,18 @@ | ||
super(async function* (this: Component) { | ||
for (const child of this.children) { | ||
child.children = child.children.toUpperCase(); | ||
let count = 0; | ||
this.children = `${count}`; | ||
while (true) { | ||
if (!this.element.isConnected) { | ||
await new Promise(resolve => | ||
this.element.addEventListener('connect', resolve)); | ||
} | ||
this.children = `${++count}`; | ||
yield; | ||
await new Promise(resolve => setTimeout(resolve, 100)); | ||
} | ||
}, { trigger: 'element', capacity: 0 }); | ||
}, { trigger: 'element' }); | ||
} | ||
private readonly dom = Shadow.section({ | ||
private readonly dom = Shadow.section({ onconnect: '' }, { | ||
style: HTML.style(':scope { color: red; }'), | ||
content: HTML.ul([ | ||
HTML.li('item'), | ||
]), | ||
content: HTML.p(''), | ||
}); | ||
@@ -358,3 +379,2 @@ public readonly tag = this.dom.tag; | ||
Create a helper function of APIs for i18n. | ||
Typed-DOM provides `mutate`, `connect`, and `disconnect` events. | ||
@@ -361,0 +381,0 @@ ```ts |
@@ -337,8 +337,7 @@ import { Event } from 'spica/global'; | ||
listeners: El[] | undefined = this[privates.listeners].values, | ||
isConnected = listeners.length !== 0 && this.isConnected, | ||
): void { | ||
if (listeners.length === 0) return; | ||
if (listeners !== this[privates.listeners].values && !isConnected) return; | ||
if (listeners !== this[privates.listeners].values && !this.isConnected) return; | ||
for (const listener of listeners) { | ||
listener.element[proxy].dispatchConnectionEvent(void 0, isConnected); | ||
listener.element[proxy].dispatchConnectionEvent(); | ||
getListeners(listener)?.connect && listener.element.dispatchEvent(new Event('connect', { bubbles: false, cancelable: true })); | ||
@@ -349,8 +348,7 @@ } | ||
listeners: El[] | undefined = this[privates.listeners].values, | ||
isConnected = listeners.length !== 0 && this.isConnected, | ||
): void { | ||
if (listeners.length === 0) return; | ||
if (listeners !== this[privates.listeners].values && !isConnected) return; | ||
if (listeners !== this[privates.listeners].values && !this.isConnected) return; | ||
for (const listener of listeners) { | ||
listener.element[proxy].dispatchDisconnectionEvent(void 0, isConnected); | ||
listener.element[proxy].dispatchDisconnectionEvent(); | ||
getListeners(listener)?.disconnect && listener.element.dispatchEvent(new Event('disconnect', { bubbles: false, cancelable: true })); | ||
@@ -357,0 +355,0 @@ } |
@@ -137,2 +137,14 @@ import { Symbol, document } from 'spica/global'; | ||
el.setAttribute(name, value); | ||
if (name.startsWith('on')) { | ||
const type = name.slice(2).toLowerCase(); | ||
switch (type) { | ||
case 'mutate': | ||
case 'connect': | ||
case 'disconnect': | ||
const prop = `on${type}`; | ||
prop in el | ||
? el[prop] ??= (ev: NodeEvent<E>) => ev.returnValue | ||
: el[prop] ??= ''; | ||
} | ||
} | ||
continue; | ||
@@ -144,4 +156,4 @@ case 'function': | ||
if (!name.startsWith('on')) throw new Error(`TypedDOM: Attribute names for event listeners must start with "on" but got "${name}".`); | ||
const eventname = name.slice(2).toLowerCase(); | ||
el.addEventListener(eventname, value, { | ||
const type = name.slice(2).toLowerCase(); | ||
el.addEventListener(type, value, { | ||
passive: [ | ||
@@ -154,9 +166,9 @@ 'wheel', | ||
'touchcancel', | ||
].includes(eventname), | ||
].includes(type), | ||
}); | ||
switch (eventname) { | ||
switch (type) { | ||
case 'mutate': | ||
case 'connect': | ||
case 'disconnect': | ||
const prop = `on${eventname}`; | ||
const prop = `on${type}`; | ||
prop in el | ||
@@ -163,0 +175,0 @@ ? el[prop] ??= (ev: NodeEvent<E>) => ev.returnValue |
@@ -1,2 +0,2 @@ | ||
import { bind, delegate, listen, once, wait, currentTarget } from './listener'; | ||
import { bind, delegate, listen, once, currentTarget } from './listener'; | ||
import { Shadow, HTML } from '../builder'; | ||
@@ -82,4 +82,9 @@ | ||
assert(cnt === 0 && ++cnt); | ||
once(el, 'click', () => void assert(cnt === 1 && ++cnt) || done()); | ||
once(el, 'click', () => void assert(cnt === 2 && ++cnt) || done()); | ||
}); | ||
once(el, 'click').then(ev => { | ||
assert(ev instanceof Event); | ||
assert(ev[currentTarget] === ev.currentTarget); | ||
assert(cnt === 1 && ++cnt); | ||
}); | ||
document.createDocumentFragment().appendChild(el); | ||
@@ -97,32 +102,12 @@ el.click(); | ||
assert(cnt === 0 && ++cnt); | ||
once(dom.element, 'click', () => void assert(cnt === 1 && ++cnt) || done()); | ||
once(dom.element, 'click', () => void assert(cnt === 2 && ++cnt) || done()); | ||
}); | ||
document.createDocumentFragment().appendChild(dom.element); | ||
dom.children[0].element.click(); | ||
dom.children[0].element.click(); | ||
}); | ||
}); | ||
describe('wait', () => { | ||
it('bind', done => { | ||
const el = HTML.a().element; | ||
wait(el, 'click').then(ev => { | ||
once(dom.element, 'a', 'click').then(ev => { | ||
assert(ev instanceof Event); | ||
assert(ev[currentTarget] === ev.currentTarget); | ||
done(); | ||
assert(cnt === 1 && ++cnt); | ||
}); | ||
document.createDocumentFragment().appendChild(el); | ||
el.click(); | ||
}); | ||
it('delegate', done => { | ||
const dom = Shadow.section([HTML.a()]); | ||
wait(dom.element, 'a', 'click').then(ev => { | ||
assert(ev instanceof Event); | ||
assert(ev[currentTarget] === ev.currentTarget); | ||
done(); | ||
}); | ||
document.createDocumentFragment().appendChild(dom.element); | ||
dom.children[0].element.click(); | ||
dom.children[0].element.click(); | ||
}); | ||
@@ -129,0 +114,0 @@ |
@@ -13,49 +13,95 @@ import { AtomicPromise } from 'spica/promise'; | ||
export function listen<T extends keyof WindowEventMap>(target: Window, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof WindowEventMap>(target: Window, selector: string, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, selector: string, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof HTMLElementEventMap>(target: HTMLElement, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof MathMLElementEventMap>(target: MathMLElement, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof MathMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof ElementEventMap>(target: Element, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | HTMLElement, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | SVGElement, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>(target: Window | Document | ShadowRoot | Element, a: T | string, b: ((ev: Event) => void) | T, c: boolean | AddEventListenerOptions | ((ev: Event) => void) = false, d: AddEventListenerOptions = {}): () => undefined { | ||
return typeof b === 'string' | ||
? delegate(target as Document, a, b as keyof ElementEventMap, c as () => void, d) | ||
: bind(target as Element, a as keyof ElementEventMap, b, c as boolean); | ||
export function listen<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function listen<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>( | ||
target: Window | Document | ShadowRoot | Element, | ||
selector: T | string, | ||
type: T | ((ev: Event) => void), | ||
listener?: boolean | AddEventListenerOptions | ((ev: Event) => void), | ||
option?: boolean | AddEventListenerOptions, | ||
): () => undefined { | ||
return typeof type === 'string' | ||
? delegate(target as Document, selector, type as keyof ElementEventMap, listener as () => void, option) | ||
: bind(target as Element, selector as keyof ElementEventMap, type, listener as boolean); | ||
} | ||
export function once<T extends keyof WindowEventMap>(target: Window, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<WindowEventMap[T]>; | ||
export function once<T extends keyof WindowEventMap>(target: Window, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof WindowEventMap>(target: Window, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<WindowEventMap[T]>; | ||
export function once<T extends keyof WindowEventMap>(target: Window, selector: string, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<DocumentEventMap[T]>; | ||
export function once<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<DocumentEventMap[T]>; | ||
export function once<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, selector: string, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof HTMLElementEventMap>(target: HTMLElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<HTMLElementEventMap[T]>; | ||
export function once<T extends keyof HTMLElementEventMap>(target: HTMLElement, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<HTMLElementEventMap[T]>; | ||
export function once<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<SVGElementEventMap[T]>; | ||
export function once<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<SVGElementEventMap[T]>; | ||
export function once<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof MathMLElementEventMap>(target: MathMLElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<MathMLElementEventMap[T]>; | ||
export function once<T extends keyof MathMLElementEventMap>(target: MathMLElement, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof MathMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<MathMLElementEventMap[T]>; | ||
export function once<T extends keyof MathMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof ElementEventMap>(target: Element, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<ElementEventMap[T]>; | ||
export function once<T extends keyof ElementEventMap>(target: Element, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | HTMLElement, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | SVGElement, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: AddEventListenerOptions): AtomicPromise<ElementEventMap[T]>; | ||
export function once<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function once<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>(target: Window | Document | ShadowRoot | Element, a: T | string, b: ((ev: Event) => void) | T, c: boolean | AddEventListenerOptions | ((ev: Event) => void) = false, d: AddEventListenerOptions = {}): () => undefined { | ||
return typeof b === 'string' | ||
? delegate(target as Document, a, b as keyof ElementEventMap, c as () => void, { ...typeof d === 'boolean' ? { capture: d } : d, once: true }) | ||
: bind(target as Element, a as keyof ElementEventMap, b, { ...typeof c === 'boolean' ? { capture: c } : c, once: true }); | ||
} | ||
export function wait<T extends keyof WindowEventMap>(target: Window, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<WindowEventMap[T]>; | ||
export function wait<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<DocumentEventMap[T]>; | ||
export function wait<T extends keyof HTMLElementEventMap>(target: HTMLElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<HTMLElementEventMap[T]>; | ||
export function wait<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<SVGElementEventMap[T]>; | ||
export function wait<T extends keyof ElementEventMap>(target: Element, type: T, option?: boolean | AddEventListenerOptions): AtomicPromise<ElementEventMap[T]>; | ||
export function wait<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | HTMLElement, selector: string, type: T, option?: AddEventListenerOptions): AtomicPromise<HTMLElementEventMap[T]>; | ||
export function wait<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | SVGElement, selector: string, type: T, option?: AddEventListenerOptions): AtomicPromise<SVGElementEventMap[T]>; | ||
export function wait<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, option?: AddEventListenerOptions): AtomicPromise<ElementEventMap[T]>; | ||
export function wait<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>(target: Window | Document | ShadowRoot | Element, a: T | string, b: T | boolean | AddEventListenerOptions = false, c: AddEventListenerOptions = {}): AtomicPromise<Event> { | ||
export function once<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>( | ||
target: Window | Document | ShadowRoot | Element, | ||
selector: T | string, | ||
type?: T | boolean | AddEventListenerOptions | ((ev: Event) => void), | ||
listener?: boolean | AddEventListenerOptions | ((ev: Event) => void), | ||
option?: boolean | AddEventListenerOptions, | ||
): (() => undefined) | AtomicPromise<Event> { | ||
switch (typeof type) { | ||
case 'string': | ||
switch (typeof listener) { | ||
case 'function': | ||
return delegate(target as Document, selector, type as keyof ElementEventMap, listener as () => void, { ...typeof option === 'boolean' ? { capture: option } : option, once: true }); | ||
case 'object': | ||
option = { ...listener, once: true }; | ||
break; | ||
default: | ||
option = { once: true }; | ||
} | ||
return new AtomicPromise(resolve => | ||
void delegate(target as Element, selector, type as keyof ElementEventMap, resolve, option)); | ||
case 'function': | ||
return bind(target as Element, selector as keyof ElementEventMap, type, { ...typeof listener === 'boolean' ? { capture: listener } : listener, once: true }); | ||
case 'object': | ||
option = { ...type, once: true }; | ||
break; | ||
default: | ||
option = { once: true }; | ||
} | ||
return new AtomicPromise(resolve => | ||
typeof b === 'string' | ||
? once(target as Document, a, b as keyof ElementEventMap, resolve, c) | ||
: once(target as Element, a as keyof ElementEventMap, resolve, b)); | ||
void bind(target as Element, selector as keyof ElementEventMap, resolve, option)); | ||
} | ||
export function delegate<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | HTMLElement, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | SVGElement, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option: AddEventListenerOptions = {}): () => undefined { | ||
return bind(target as Element, type, ev => { | ||
export function delegate<T extends keyof WindowEventMap>(target: Window, selector: string, type: T, listener: (ev: WindowEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof DocumentEventMap>(target: Document | ShadowRoot, selector: string, type: T, listener: (ev: DocumentEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof HTMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: HTMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof SVGElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof MathMLElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof ElementEventMap>(target: Document | ShadowRoot | Element, selector: string, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function delegate<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>( | ||
target: Window | Document | ShadowRoot | Element, | ||
selector: string, | ||
type: T, | ||
listener: (ev: Event) => void, | ||
option?: boolean | AddEventListenerOptions, | ||
): () => undefined { | ||
return bind(target as Element, type as keyof ElementEventMap, ev => { | ||
assert(ev.target instanceof Element); | ||
@@ -66,4 +112,4 @@ assert(ev.composedPath()[0] instanceof Element); | ||
: (ev.target as Element)?.closest(selector); | ||
cx && once(cx, type, e => { e === ev && listener(ev); }, option); | ||
}, { ...option, capture: true }); | ||
cx && once(cx, type as keyof ElementEventMap, e => { e === ev && listener(ev); }, option); | ||
}, { ...typeof option === 'boolean' ? { capture: true } : option, capture: true }); | ||
} | ||
@@ -75,4 +121,19 @@ | ||
export function bind<T extends keyof SVGElementEventMap>(target: SVGElement, type: T, listener: (ev: SVGElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function bind<T extends keyof MathMLElementEventMap>(target: MathMLElement, type: T, listener: (ev: MathMLElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function bind<T extends keyof ElementEventMap>(target: Element, type: T, listener: (ev: ElementEventMap[T]) => void, option?: boolean | AddEventListenerOptions): () => undefined; | ||
export function bind<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>(target: Window | Document | ShadowRoot | Element, type: T, listener: (ev: Event) => void, option: boolean | AddEventListenerOptions = false): () => undefined { | ||
export function bind<T extends keyof WindowEventMap | keyof DocumentEventMap | keyof ElementEventMap>( | ||
target: Window | Document | ShadowRoot | Element, | ||
type: T, | ||
listener: (ev: Event) => void, | ||
option?: boolean | AddEventListenerOptions, | ||
): () => undefined { | ||
switch (type) { | ||
case 'mutate': | ||
case 'connect': | ||
case 'disconnect': | ||
const prop = `on${type}`; | ||
prop in target | ||
? target[prop] ??= (ev: Event) => ev.returnValue | ||
: target[prop] ??= ''; | ||
} | ||
target.addEventListener(type, handler, option); | ||
@@ -79,0 +140,0 @@ return singleton(() => void target.removeEventListener(type, handler, option)); |
import { Shadow, HTML, SVG, El, Attrs, shadow, html } from '../..'; | ||
import { Coroutine } from 'spica/coroutine'; | ||
import { Sequence } from 'spica/sequence'; | ||
import { wait } from 'spica/timer'; | ||
@@ -403,2 +404,5 @@ declare global { | ||
]); | ||
assert.deepStrictEqual( | ||
dom.children.map(v => v.element), | ||
[...dom.element.children]); | ||
dom.children = [ | ||
@@ -424,2 +428,5 @@ dom.children[1], | ||
]); | ||
assert.deepStrictEqual( | ||
dom.children.map(v => v.element), | ||
[...dom.element.children]); | ||
}); | ||
@@ -460,2 +467,5 @@ | ||
]); | ||
assert.deepStrictEqual( | ||
[...Object.values(dom.children)].map(v => v.element), | ||
[...dom.element.children]); | ||
dom.children = { | ||
@@ -481,2 +491,15 @@ a: dom.children.a, | ||
[...dom.element.children]); | ||
doc.children = []; | ||
assert.deepStrictEqual( | ||
Object.entries(dom.children).map(([k, v]) => [k, v.children]), | ||
[ | ||
['a', 'aAa'], | ||
['b', 'cCc'], | ||
['c', 'bBb'], | ||
['d', 'fFf'], | ||
['e', 'gGg'], | ||
]); | ||
assert.deepStrictEqual( | ||
[...Object.values(dom.children)].map(v => v.element), | ||
[...dom.element.children]); | ||
}); | ||
@@ -565,3 +588,3 @@ | ||
it('component coroutine', function () { | ||
it('component coroutine', async function () { | ||
class Component extends Coroutine implements El { | ||
@@ -571,15 +594,18 @@ constructor() { | ||
assert(this.element); | ||
assert(this.children); | ||
for (const child of this.children) { | ||
child.children = child.children.toUpperCase(); | ||
let count = 0; | ||
this.children = `${count}`; | ||
while (true) { | ||
if (!this.element.isConnected) { | ||
await new Promise(resolve => | ||
this.element.addEventListener('connect', resolve, { once: true })); | ||
} | ||
this.children = `${++count}`; | ||
yield; | ||
await new Promise(resolve => setTimeout(resolve, 100)); | ||
} | ||
}, { trigger: 'element', capacity: 0 }); | ||
assert(this.children[0].children === 'ITEM'); | ||
}, { trigger: 'element' }); | ||
} | ||
private readonly dom = Shadow.section({ | ||
private readonly dom = Shadow.section({ onconnect: '' }, { | ||
style: HTML.style(':scope { color: red; }'), | ||
content: HTML.ul([ | ||
HTML.li('item'), | ||
]), | ||
content: HTML.p(''), | ||
}); | ||
@@ -597,8 +623,15 @@ public readonly tag = this.dom.tag; | ||
const dom = new Component(); | ||
assert(dom.children[0].children === 'ITEM'); | ||
dom.children = [ | ||
HTML.li('item'), | ||
]; | ||
assert(dom.children[0].children === 'item'); | ||
assert(HTML.div([dom])); | ||
assert(dom.children === '0'); | ||
doc.children = [dom]; | ||
await 0; | ||
assert(dom.children === '1'); | ||
await wait(110); | ||
assert(dom.children === '2'); | ||
doc.children = []; | ||
await wait(110); | ||
assert(dom.children === '2'); | ||
doc.children = [dom]; | ||
await 0; | ||
assert(dom.children === '3'); | ||
doc.children = []; | ||
}); | ||
@@ -605,0 +638,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { API, Shadow, HTML, SVG, NS, shadow, frag, html, svg, text, element, define, append, prepend, defrag, listen, once, wait, bind, delegate, currentTarget, querySelector, querySelectorAll, identity } from '../..'; | ||
import { API, Shadow, HTML, SVG, NS, shadow, frag, html, svg, text, element, define, append, prepend, defrag, listen, once, bind, delegate, currentTarget, querySelector, querySelectorAll, identity } from '../..'; | ||
@@ -78,6 +78,2 @@ describe('Interface: Package', function () { | ||
it('wait', function () { | ||
assert(typeof wait === 'function'); | ||
}); | ||
it('bind', function () { | ||
@@ -84,0 +80,0 @@ assert(typeof bind === 'function'); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
696593
16303
439