Skip to content

Commit 1acd515

Browse files
authored
Merge pull request #33 from Q42/feature/improve-event-attribute-types
Feature/improve event attribute types
2 parents 97edd74 + aeb757c commit 1acd515

File tree

12 files changed

+226
-25
lines changed

12 files changed

+226
-25
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"publish": "node publish.js",
1111
"docs": "npm run create:client --prefix ../Micrio/server/doc.micr.io",
1212
"asbuild:untouched": "asc src/wasm/exports.ts --target debug --sourceMap \"http://localhost:2000/build/untouched.wasm.map\" --importMemory",
13-
"asbuild:optimized": "asc src/wasm/exports.ts --target release -O3s --converge --runtime stub --disable mutable-globals --disable sign-extension --noExportMemory --noAssert --pedantic --importMemory"
13+
"asbuild:optimized": "asc src/wasm/exports.ts --target release -O3s --converge --runtime stub --disable mutable-globals --disable sign-extension --noExportMemory --noAssert --pedantic --importMemory",
14+
"typecheck": "tsc"
1415
},
1516
"keywords": [
1617
"micrio"

src/svelte/common/Controls.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@
8282
let secondaryPortrait:boolean = $state(false);
8383
8484
/** Event handler for 'splitscreen-start'. Sets up secondary controls if needed. */
85-
function splitStart(e:Event) {
86-
const img = (e as CustomEvent).detail as MicrioImage;
85+
function splitStart(e:Models.MicrioEventMap['splitscreen-start']) {
86+
const img = e.detail;
8787
// Only show separate controls for the secondary image if it's interactive (not passive)
8888
secondaryPortrait = micrio.canvas.viewport.portrait; // Store orientation for styling
8989
if(!img.opts.isPassive) secondaryControls = img;

src/svelte/common/Gallery.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,9 @@
373373
}
374374
375375
/** Handles the end of a pan gesture (or pinch). */
376-
function pEnd(e:Event) : void {
376+
function pEnd(e:Models.MicrioEventMap['panend']) : void {
377377
// If triggered by 'panend' but detail is missing, it means pinch took over, reset panning
378-
const d = (e as CustomEvent).detail;
378+
const d = e.detail;
379379
if(e.type == 'panend' && !d) {
380380
panning = false;
381381
}

src/svelte/common/Subtitles.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
/** Local state variable to store the current media playback time. */
9191
let currentTime:number = $state(0);
9292
/** Event handler to update `currentTime` based on 'timeupdate' events dispatched by Media.svelte. */
93-
const setTime = (e:Event) => currentTime = (e as CustomEvent).detail;
93+
const setTime = (e:Models.MicrioEventMap['timeupdate']) => currentTime = e.detail;
9494
9595
// --- Lifecycle ---
9696

src/svelte/components/Marker.svelte

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,9 +505,12 @@
505505
}
506506
}
507507
508-
/** Handles external position changes (e.g., from Spaces editor). */
508+
/**
509+
* Handles external position changes (e.g., from Spaces editor).
510+
* TODO: what event should this be in the MicrioEventMap? It's the 'changed' event of a div!
511+
*/
509512
function changed(e:Event) {
510-
const m = (e as CustomEvent).detail as typeof marker;
513+
const m = (e as Models.MicrioEvent<typeof marker>).detail;
511514
marker.x = m.x;
512515
marker.y = m.y;
513516
moved(); // Recalculate position

src/ts/element.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import type { Writable } from 'svelte/store';
22
import type { Models } from '../types/models';
33
import type { Camera } from './camera';
4+
5+
/** @ts-ignore */
46
import type Svelte from '../svelte/Main.svelte';
57

68
import { once, deepCopy, fetchJson, jsonCache, fetchInfo, fetchAlbumInfo, idIsV5 } from './utils';
@@ -189,7 +191,7 @@ export class HTMLMicrioElement extends HTMLElement {
189191
* Called when an observed attribute changes. Handles changes to `id`, `muted`, `data-grid`, `data-limited`, and `lang`.
190192
* @internal
191193
*/
192-
attributeChangedCallback(attr:string, oldVal:string, newVal:string) {
194+
attributeChangedCallback(attr:keyof Models.Attributes.MicrioCustomAttributes, oldVal:string, newVal:string) {
193195
switch(attr) {
194196
case 'id': { // Handle ID change (initial load or subsequent open)
195197
if(!this.isConnected || !newVal) return;
@@ -255,6 +257,18 @@ export class HTMLMicrioElement extends HTMLElement {
255257
}
256258
}
257259

260+
// Custom overloads for addEventListener to support fully typed custom Micrio events
261+
addEventListener<K extends keyof Models.MicrioEventMap>(type: K, listener: (this: HTMLMicrioElement, ev: Models.MicrioEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
262+
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLMicrioElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
263+
addEventListener(type: string, listener: (this: HTMLMicrioElement, ev: Event) => any, options?: boolean | AddEventListenerOptions): void;
264+
addEventListener(type: string, listener: EventListener | EventListenerObject, useCapture?: boolean): void { super.addEventListener(type, listener, useCapture); }
265+
266+
// Custom overloads for removeEventListener to support fully typed custom Micrio events
267+
removeEventListener<K extends keyof Models.MicrioEventMap>(type: K, listener: (this: HTMLMicrioElement, ev: Models.MicrioEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
268+
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLMicrioElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
269+
removeEventListener(type: string, listener: (this: HTMLMicrioElement, ev: Event) => any, options?: boolean | EventListenerOptions): void;
270+
removeEventListener(type: string, listener: EventListener | EventListenerObject, useCapture?: boolean): void { super.removeEventListener(type, listener, useCapture); }
271+
258272
/** Destroys the Micrio instance, cleans up resources, and removes event listeners. */
259273
destroy() : void {
260274
this.current.set(undefined); // Clear current image
@@ -348,7 +362,7 @@ export class HTMLMicrioElement extends HTMLElement {
348362
// --- Final Setup & Open ---
349363
this.keepRendering = !!opts.settings.keepRendering; // Set continuous rendering flag
350364
const doOpen = opts.id || opts.gallery || opts.grid; // Check if there's something to open
351-
this.events.dispatch('print', opts); // Dispatch 'print' event
365+
this.events.dispatch('print', opts as Models.ImageInfo.ImageInfo); // Dispatch 'print' event
352366

353367
// Handle lazy loading
354368
if(opts.settings.lazyload !== undefined && 'IntersectionObserver' in window) {

src/ts/events.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ function cancelPrevent(e:AllEvents){
6161
* @internal
6262
* @readonly
6363
*/
64-
export const UpdateEvents:string[] = [
64+
export const UpdateEvents:(keyof Models.MicrioEventMap)[] = [
6565
'move',
6666
'marker-open',
6767
'marker-opened',
@@ -237,7 +237,7 @@ export const UpdateEvents:string[] = [
237237
* @param type The event type string.
238238
* @param detail Optional event detail payload.
239239
*/
240-
dispatch(type:string, detail?:any) : void {
240+
dispatch<K extends keyof Models.MicrioEventDetails>(type:K, detail?:Models.MicrioEventDetails[K]) : void {
241241
this.micrio.dispatchEvent(new CustomEvent(type, detail !== undefined ? { detail } : undefined))
242242
}
243243

src/ts/grid.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ export class Grid {
419419
/**
420420
* Parses an individual image grid string into a GridImage object.
421421
* @param s The grid string for a single image.
422-
* @returns The parsed {@link Models.Grid.GridImage} object.
422+
* @returns The parsed `Models.Grid.GridImage` object.
423423
*/
424424
getImage(s:string) : Models.Grid.GridImage {
425425
const g = s.split('|'), p = g[0].split(','), // Split main parts and size

src/ts/image.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ export class MicrioImage {
674674
// Dispatch pre-data event allowing external modification of all loaded data
675675
this.wasm.micrio.events.dispatch('pre-data', {
676676
[this.id]: d, // Current image data
677-
...Object.fromEntries(micIdsUnique.map((id,i) => [id, micData[i]])) // Preloaded linked data
677+
...Object.fromEntries(micIdsUnique.map((id,i) => [id, micData[i]!])) // Preloaded linked data
678678
});
679679

680680
// If linked images were already initialized but lacked data, set it now

src/ts/state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,8 @@ export namespace State {
283283
this.view.subscribe(view => {
284284
this._view = view; // Update internal reference
285285
const nV = view?.toString(); // Stringify for simple comparison
286-
const detail = {image, view}; // Event detail payload
287286
if(view && nV && pV != nV) { // If view changed
287+
const detail = {image, view}; // Event detail payload
288288
pV = nV;
289289
const nW = view[2]-view[0], nH = view[3]-view[1]; // Calculate new width/height
290290
// Dispatch 'zoom' event if dimensions changed significantly

0 commit comments

Comments
 (0)