Skip to content

Commit 6a4754d

Browse files
committed
feat(components): events handler directive
1 parent 4fb2e54 commit 6a4754d

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import {GecutDirective} from '@gecut/lit-helper/directives/directive.js';
2+
import {nothing} from 'lit';
3+
import {directive} from 'lit/directive.js';
4+
5+
import type {ElementPart, PartInfo} from 'lit/directive.js';
6+
7+
export type EventsObject<T = HTMLElementEventMap> = Partial<{
8+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
9+
[P in keyof T]: (evt: T[P]) => any | [(evt: T[P]) => any, boolean | EventListenerOptions];
10+
}>;
11+
12+
export class EventsFromObjectDirective extends GecutDirective {
13+
constructor(partInfo: PartInfo) {
14+
super(partInfo, 'gecut-efo');
15+
}
16+
17+
protected element?: HTMLElement;
18+
protected events: EventsObject = {};
19+
20+
override update(part: ElementPart, [events]: Parameters<this['render']>) {
21+
super.update(part, [events]);
22+
23+
this.element = part.element as HTMLElement;
24+
25+
if (events) {
26+
this.events = events;
27+
}
28+
29+
const removeOrAddEventListener = (funcName: 'removeEventListener' | 'addEventListener') => {
30+
for (const [name, callbackOrCallbackAndOptions] of Object.entries(this.events)) {
31+
if (Array.isArray(callbackOrCallbackAndOptions)) {
32+
this.element?.[funcName](
33+
name,
34+
this.debouncedEventHandler(name, callbackOrCallbackAndOptions[0]),
35+
callbackOrCallbackAndOptions[1],
36+
);
37+
}
38+
else {
39+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
40+
this.element?.[funcName](name, this.debouncedEventHandler<any>(name, callbackOrCallbackAndOptions));
41+
}
42+
}
43+
};
44+
45+
removeOrAddEventListener('removeEventListener');
46+
removeOrAddEventListener('addEventListener');
47+
48+
return nothing;
49+
}
50+
51+
render(events: EventsObject = {}): unknown {
52+
this.log.methodArgs?.('render', events);
53+
54+
return nothing;
55+
}
56+
57+
private debouncedEventHandler<T extends Event = Event>(name: string, func: (event: T) => unknown): EventListener {
58+
return (event: Event) => {
59+
this.log.methodArgs?.(name, {
60+
tag: this.element?.tagName.toLowerCase(),
61+
element: this.element,
62+
});
63+
64+
func(event as T);
65+
};
66+
}
67+
}
68+
69+
export const gecutEFO = directive(EventsFromObjectDirective);

0 commit comments

Comments
 (0)