|
| 1 | +import { isServer } from 'lit'; |
| 2 | + |
1 | 3 | export const asPercent = (part: number, whole: number) => (part / whole) * 100; |
2 | 4 |
|
3 | 5 | export const clamp = (number: number, min: number, max: number) => |
@@ -282,6 +284,33 @@ export function addWeakEventListener( |
282 | 284 | element.addEventListener(event, wrapped, options); |
283 | 285 | } |
284 | 286 |
|
| 287 | +type EventTypeOf<T extends keyof HTMLElementEventMap | keyof WindowEventMap> = |
| 288 | + (HTMLElementEventMap & WindowEventMap)[T]; |
| 289 | + |
| 290 | +/** |
| 291 | + * Safely adds an event listener to an HTMLElement, automatically handling |
| 292 | + * server-side rendering environments by doing nothing if `isServer` is true. |
| 293 | + * This function also correctly binds the `handler`'s `this` context to the `target` element |
| 294 | + * and ensures proper event type inference. |
| 295 | + */ |
| 296 | +export function addSafeEventListener< |
| 297 | + E extends keyof HTMLElementEventMap | keyof WindowEventMap, |
| 298 | +>( |
| 299 | + target: HTMLElement, |
| 300 | + eventName: E, |
| 301 | + handler: (event: EventTypeOf<E>) => unknown, |
| 302 | + options?: boolean | AddEventListenerOptions |
| 303 | +): void { |
| 304 | + if (isServer) { |
| 305 | + return; |
| 306 | + } |
| 307 | + |
| 308 | + const boundHandler = (event: Event) => |
| 309 | + handler.call(target, event as EventTypeOf<E>); |
| 310 | + |
| 311 | + target.addEventListener(eventName, boundHandler, options); |
| 312 | +} |
| 313 | + |
285 | 314 | /** |
286 | 315 | * Returns whether a given collection is empty. |
287 | 316 | */ |
|
0 commit comments