From 677dc1f1118c325074c0e7ce154d6ce846d68fdc Mon Sep 17 00:00:00 2001 From: andrewgryan Date: Wed, 29 May 2024 21:29:32 +0100 Subject: [PATCH 1/2] experiment with typing CustomEvent --- src/example.js | 25 +++++++++++++++++++++++++ src/index.d.ts | 9 +++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/example.js create mode 100644 src/index.d.ts diff --git a/src/example.js b/src/example.js new file mode 100644 index 0000000..014c480 --- /dev/null +++ b/src/example.js @@ -0,0 +1,25 @@ +// @ts-check +/// +import { circle } from "leaflet"; +const addTo = "addTo"; + +class Bar extends HTMLElement { + constructor() { + super(); + this.addEventListener(addTo, (ev) => { + ev.detail.layer; + }); + } + + documentConnected() { + /** @type AddToEvent */ + const event = new CustomEvent(addTo, { + detail: { + layer: circle([1, 1], { radius: 5 }), + }, + }); + this.dispatchEvent(event); + } +} + +export default Bar; diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 0000000..1597393 --- /dev/null +++ b/src/index.d.ts @@ -0,0 +1,9 @@ +import type { Layer } from "leaflet"; + +declare global { + type AddToEvent = CustomEvent<{ layer: Layer }>; + + interface HTMLElementEventMap { + addTo: AddToEvent; + } +} From 7cb2cfa542e4f8cde582aafda969fdf6500fc046 Mon Sep 17 00:00:00 2001 From: andrewgryan Date: Wed, 29 May 2024 22:28:56 +0100 Subject: [PATCH 2/2] more typescript experimentation --- jsconfig.json | 6 ++++++ src/index.d.ts | 11 ++++++++++- src/l-icon.js | 16 +++++++++++----- src/l-marker.js | 15 +++++++++++---- src/l-popup.js | 5 +++-- 5 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 jsconfig.json diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..e747a0d --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "target": "es2020", + "types": ["vitest/importMeta"] + } +} diff --git a/src/index.d.ts b/src/index.d.ts index 1597393..a6f1d75 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,9 +1,18 @@ -import type { Layer } from "leaflet"; +import type { Icon, Layer } from "leaflet"; +import type { LIcon } from "l-icon"; declare global { type AddToEvent = CustomEvent<{ layer: Layer }>; + type BindPopupEvent = CustomEvent<{ content: string }>; + type SetIconEvent = CustomEvent<{ icon: Icon }>; interface HTMLElementEventMap { addTo: AddToEvent; + bindPopup: BindPopupEvent; + setIcon: SetIconEvent; + } + + interface HTMLElementTagNameMap { + "l-icon": LIcon; } } diff --git a/src/l-icon.js b/src/l-icon.js index 1499597..dcef705 100644 --- a/src/l-icon.js +++ b/src/l-icon.js @@ -1,7 +1,8 @@ +// @ts-check +/// // @vitest-environment happy-dom import * as L from "leaflet"; -import { kebabToCamel } from "./util.js"; - +import { kebabToCamel } from "./util.js"; class LIcon extends HTMLElement { constructor() { @@ -10,6 +11,7 @@ class LIcon extends HTMLElement { } connectedCallback() { + /** @type {import("leaflet").IconOptions} */ const options = {}; // Strings @@ -42,11 +44,13 @@ class LIcon extends HTMLElement { }); if (this.hasAttribute("cross-origin")) { - options.crossOrigin = this.getAttribute("cross-origin") === "true"; + let k = "crossOrigin"; + options[k] = this.getAttribute("cross-origin") === "true"; } this.icon = L.icon(options); - const event = new CustomEvent("icon:add", { + /** @type SetIconEvent */ + const event = new CustomEvent("setIcon", { cancelable: true, bubbles: true, detail: { @@ -75,8 +79,10 @@ if (import.meta.vitest) { it("emits icon:add event", async () => { const el = document.createElement("l-icon"); + /** @type {keyof HTMLElementEventMap} */ + const eventName = "setIcon"; let promise = new Promise((resolve) => { - el.addEventListener("icon:add", (ev) => { + el.addEventListener(eventName, (ev) => { resolve(ev.detail.icon); }); }); diff --git a/src/l-marker.js b/src/l-marker.js index 09947a4..fceaa5c 100644 --- a/src/l-marker.js +++ b/src/l-marker.js @@ -1,6 +1,8 @@ +// @ts-check +/// // @vitest-environment happy-dom import * as L from "leaflet"; -import { mapAddTo, popupAdd } from "./events.js"; +import { mapAddTo } from "./events.js"; import LLayer from "./l-layer.js"; class LMarker extends LLayer { @@ -9,7 +11,7 @@ class LMarker extends LLayer { constructor() { super(); this.layer = null; - this.addEventListener("icon:add", (ev) => { + this.addEventListener("setIcon", (ev) => { ev.stopPropagation(); this.layer.setIcon(ev.detail.icon); }); @@ -24,9 +26,9 @@ class LMarker extends LLayer { this.layer.setIcon(icon); } - this.setAttribute("leaflet-id", L.stamp(this.layer)); + this.setAttribute("leaflet-id", L.stamp(this.layer).toString()); - this.addEventListener(popupAdd, (ev) => { + this.addEventListener("bindPopup", (ev) => { const { content } = ev.detail; this.layer.bindPopup(content); }); @@ -41,6 +43,11 @@ class LMarker extends LLayer { this.dispatchEvent(event); } + /** + * @param {string} name + * @param {string} _oldValue + * @param {string} newValue + */ attributeChangedCallback(name, _oldValue, newValue) { if (this.layer !== null) { if (name === "lat-lng") { diff --git a/src/l-popup.js b/src/l-popup.js index bdd5ed1..e3d83ae 100644 --- a/src/l-popup.js +++ b/src/l-popup.js @@ -1,5 +1,5 @@ // @ts-check -import { popupAdd } from "./events.js"; +/// class LPopup extends HTMLElement { constructor() { @@ -8,7 +8,8 @@ class LPopup extends HTMLElement { connectedCallback() { const content = this.getAttribute("content"); - const event = new CustomEvent(popupAdd, { + /** @type {BindPopupEvent} */ + const event = new CustomEvent("bindPopup", { cancelable: true, bubbles: true, detail: {