diff --git a/examples/class/edit-control.js b/examples/class/edit-control.js
deleted file mode 100644
index c89a84e..0000000
--- a/examples/class/edit-control.js
+++ /dev/null
@@ -1,252 +0,0 @@
-import React, { Component, createRef } from 'react';
-import { MapContainer, TileLayer, Circle, FeatureGroup } from 'react-leaflet';
-import L from 'leaflet';
-import { EditControl } from '../../src';
-
-// work around broken icons when using webpack, see https://github.com/PaulLeCam/react-leaflet/issues/255
-
-delete L.Icon.Default.prototype._getIconUrl;
-L.Icon.Default.mergeOptions({
- iconRetinaUrl:
- 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0/images/marker-icon.png',
- iconUrl:
- 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0/images/marker-icon.png',
- shadowUrl:
- 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0/images/marker-shadow.png',
-});
-
-//
-
-let polyline;
-
-export default class EditControlExample extends Component {
- featureGroupRef = createRef();
- // see http://leaflet.github.io/Leaflet.draw/docs/leaflet-draw-latest.html#l-draw-event for leaflet-draw events doc
-
- _onEdited = (e) => {
- let numEdited = 0;
- e.layers.eachLayer((layer) => {
- numEdited += 1;
- });
- console.log(`_onEdited: edited ${numEdited} layers`, e);
-
- this._onChange();
- };
-
- _onCreated = (e) => {
- let type = e.layerType;
- let layer = e.layer;
- if (type === 'marker') {
- // Do marker specific actions
- console.log('_onCreated: marker created', e);
- } else {
- console.log('_onCreated: something else created:', type, e);
- }
- // Do whatever else you need to. (save to db; etc)
-
- this._onChange();
- };
-
- _onDeleted = (e) => {
- let numDeleted = 0;
- e.layers.eachLayer((layer) => {
- numDeleted += 1;
- });
- console.log(`onDeleted: removed ${numDeleted} layers`, e);
-
- this._onChange();
- };
-
- _onMounted = (drawControl) => {
- console.log('_onMounted', drawControl);
- };
-
- _onEditStart = (e) => {
- console.log('_onEditStart', e);
- };
-
- _onEditStop = (e) => {
- console.log('_onEditStop', e);
- };
-
- _onDeleteStart = (e) => {
- console.log('_onDeleteStart', e);
- };
-
- _onDeleteStop = (e) => {
- console.log('_onDeleteStop', e);
- };
-
- render() {
- const fgInstance = this.featureGroupRef.current;
- return (
-
-
-
- {fgInstance && fgInstance._leaflet_id && (
-
- )}
-
-
- );
- }
-
- _editableFG = null;
-
- _onFeatureGroupReady = (reactFGref) => {
- // populate the leaflet FeatureGroup with the geoJson layers
-
- let leafletGeoJSON = new L.GeoJSON(getGeoJson());
- let leafletFG = reactFGref;
-
- leafletGeoJSON.eachLayer((layer) => {
- leafletFG.addLayer(layer);
- });
-
- // store the ref for future access to content
-
- this._editableFG = reactFGref;
- };
-
- _onChange = () => {
- // this._editableFG contains the edited geometry, which can be manipulated through the leaflet API
-
- const { onChange } = this.props;
-
- if (!this._editableFG || !onChange) {
- return;
- }
- console.log(this._editableFG);
- const geojsonData = this._editableFG.toGeoJSON();
- onChange(geojsonData);
- };
-}
-
-// data taken from the example in https://github.com/PaulLeCam/react-leaflet/issues/176
-
-function getGeoJson() {
- return {
- type: 'FeatureCollection',
- features: [
- {
- type: 'Feature',
- properties: {},
- geometry: {
- type: 'LineString',
- coordinates: [
- [-122.47979164123535, 37.830124319877235],
- [-122.47721672058105, 37.809377088502615],
- ],
- },
- },
- {
- type: 'Feature',
- properties: {},
- geometry: {
- type: 'Point',
- coordinates: [-122.46923446655273, 37.80293476836673],
- },
- },
- {
- type: 'Feature',
- properties: {},
- geometry: {
- type: 'Point',
- coordinates: [-122.48399734497069, 37.83466623607849],
- },
- },
- {
- type: 'Feature',
- properties: {},
- geometry: {
- type: 'Point',
- coordinates: [-122.47867584228514, 37.81893781173967],
- },
- },
- {
- type: 'Feature',
- properties: {},
- geometry: {
- type: 'Polygon',
- coordinates: [
- [
- [-122.48069286346434, 37.800637436707525],
- [-122.48069286346434, 37.803104310307276],
- [-122.47950196266174, 37.803104310307276],
- [-122.47950196266174, 37.800637436707525],
- [-122.48069286346434, 37.800637436707525],
- ],
- ],
- },
- },
- {
- type: 'Feature',
- properties: {},
- geometry: {
- type: 'Polygon',
- coordinates: [
- [
- [-122.48103886842728, 37.833075326166274],
- [-122.48065531253813, 37.832558431940114],
- [-122.4799284338951, 37.8322660885204],
- [-122.47963070869446, 37.83231693093747],
- [-122.47948586940764, 37.832467339549524],
- [-122.47945636510849, 37.83273426112019],
- [-122.47959315776825, 37.83289737938241],
- [-122.48004108667372, 37.833109220743104],
- [-122.48058557510376, 37.83328293020496],
- [-122.48080283403395, 37.83332529830436],
- [-122.48091548681259, 37.83322785163939],
- [-122.48103886842728, 37.833075326166274],
- ],
- ],
- },
- },
- {
- type: 'Feature',
- properties: {},
- geometry: {
- type: 'Polygon',
- coordinates: [
- [
- [-122.48043537139893, 37.82564992009924],
- [-122.48129367828368, 37.82629397920697],
- [-122.48240947723389, 37.82544653184479],
- [-122.48373985290527, 37.82632787689904],
- [-122.48425483703613, 37.82680244295304],
- [-122.48605728149415, 37.82639567223645],
- [-122.4898338317871, 37.82663295542695],
- [-122.4930953979492, 37.82415839321614],
- [-122.49700069427489, 37.821887146654376],
- [-122.4991464614868, 37.82171764783966],
- [-122.49850273132326, 37.81798857543524],
- [-122.50923156738281, 37.82090404811055],
- [-122.51232147216798, 37.823344820392535],
- [-122.50150680541992, 37.8271414168374],
- [-122.48743057250977, 37.83093781796035],
- [-122.48313903808594, 37.82822612280363],
- [-122.48043537139893, 37.82564992009924],
- ],
- ],
- },
- },
- ],
- };
-}
diff --git a/examples/class/edit-control.tsx b/examples/class/edit-control.tsx
new file mode 100644
index 0000000..b33af1e
--- /dev/null
+++ b/examples/class/edit-control.tsx
@@ -0,0 +1,112 @@
+import React, { Component, createRef } from 'react';
+import { MapContainer, TileLayer, FeatureGroup } from 'react-leaflet';
+import * as L from 'leaflet';
+import { EditControl } from '../../src';
+
+delete (L.Icon.Default.prototype as any)._getIconUrl;
+L.Icon.Default.mergeOptions({
+ iconRetinaUrl:
+ 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0/images/marker-icon.png',
+ iconUrl:
+ 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0/images/marker-icon.png',
+ shadowUrl:
+ 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0/images/marker-shadow.png',
+});
+
+export default class EditControlExample extends Component<{ onChange?: (g: any) => void }> {
+ featureGroupRef = createRef();
+
+ _onEdited = (e: L.DrawEvents.Edited) => {
+ let numEdited = 0;
+ e.layers.eachLayer(() => {
+ numEdited += 1;
+ });
+ // eslint-disable-next-line no-console
+ console.log(`_onEdited: edited ${numEdited} layers`, e);
+ this._onChange();
+ };
+
+ _onCreated = (e: L.DrawEvents.Created) => {
+ const type = e.layerType;
+ // eslint-disable-next-line no-console
+ console.log('_onCreated:', type, e);
+ this._onChange();
+ };
+
+ _onDeleted = (e: L.DrawEvents.Deleted) => {
+ let numDeleted = 0;
+ e.layers.eachLayer(() => {
+ numDeleted += 1;
+ });
+ // eslint-disable-next-line no-console
+ console.log(`onDeleted: removed ${numDeleted} layers`, e);
+ this._onChange();
+ };
+
+ _onMounted = (drawControl: L.Control.Draw) => {
+ // eslint-disable-next-line no-console
+ console.log('_onMounted', drawControl);
+ };
+
+ _onEditStart = (e: L.DrawEvents.EditStart) => {
+ // eslint-disable-next-line no-console
+ console.log('_onEditStart', e);
+ };
+
+ _onEditStop = (e: L.DrawEvents.EditStop) => {
+ // eslint-disable-next-line no-console
+ console.log('_onEditStop', e);
+ };
+
+ _onDeleteStart = (e: L.DrawEvents.DeleteStart) => {
+ // eslint-disable-next-line no-console
+ console.log('_onDeleteStart', e);
+ };
+
+ _onDeleteStop = (e: L.DrawEvents.DeleteStop) => {
+ // eslint-disable-next-line no-console
+ console.log('_onDeleteStop', e);
+ };
+
+ render() {
+ const fgInstance = this.featureGroupRef.current as unknown as L.FeatureGroup | undefined;
+ return (
+
+
+
+ {fgInstance && (fgInstance as any)._leaflet_id && (
+
+ )}
+
+
+ );
+ }
+
+ _editableFG: L.FeatureGroup | null = null;
+
+ _onChange = () => {
+ const { onChange } = this.props;
+ if (!this._editableFG || !onChange) return;
+ const geojsonData = (this._editableFG as any).toGeoJSON();
+ onChange(geojsonData);
+ };
+}
+
+
diff --git a/examples/class/index.js b/examples/class/index.tsx
similarity index 65%
rename from examples/class/index.js
rename to examples/class/index.tsx
index 1a927e4..357cf7a 100644
--- a/examples/class/index.js
+++ b/examples/class/index.tsx
@@ -9,10 +9,11 @@ const example = (
);
-function onChange(geojson) {
+function onChange(geojson: unknown) {
+ // eslint-disable-next-line no-console
console.log('geojson changed', geojson);
}
-createRoot(document.getElementById('app')).render(
- example
-);
+createRoot(document.getElementById('app') as HTMLElement).render(example);
+
+
diff --git a/examples/class/tsconfig.json b/examples/class/tsconfig.json
new file mode 100644
index 0000000..fa677a4
--- /dev/null
+++ b/examples/class/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "module": "ESNext",
+ "moduleResolution": "node",
+ "target": "ES2020",
+ "jsx": "react-jsx",
+ "strict": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "sourceMap": true
+ },
+ "include": ["./**/*"],
+ "exclude": ["dist", "node_modules"]
+}
+
+
diff --git a/examples/class/webpack.config.js b/examples/class/webpack.config.js
index ba285ac..1691fe1 100644
--- a/examples/class/webpack.config.js
+++ b/examples/class/webpack.config.js
@@ -1,19 +1,32 @@
/* eslint-disable */
const webpack = require("webpack");
const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");
+const path = require("path");
module.exports = {
mode: "development",
devtool: "source-map",
entry: {
- app: __dirname + "/index.js",
+ app: __dirname + "/index.tsx",
+ },
+ resolve: {
+ extensions: [".ts", ".tsx", ".js"],
+ alias: {
+ // Use a local tsconfig that doesn't constrain rootDir to src
+ // This avoids TS picking root tsconfig for the example app
+ }
},
module: {
rules: [
{
- test: /\.js$/,
+ test: /\.(ts|tsx)$/,
exclude: /node_modules/,
- loader: "babel-loader",
+ use: {
+ loader: "ts-loader",
+ options: {
+ configFile: path.resolve(__dirname, "tsconfig.json"),
+ },
+ },
},
],
},
diff --git a/package-lock.json b/package-lock.json
index cce343a..bf92be0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "react-leaflet-draw-next",
- "version": "1.0.2",
+ "version": "1.0.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "react-leaflet-draw-next",
- "version": "1.0.2",
+ "version": "1.0.3",
"license": "ISC",
"dependencies": {
"fast-deep-equal": "^3.1.3",
@@ -25,6 +25,8 @@
"@types/leaflet-draw": "^1.0.11",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
+ "@typescript-eslint/parser": "^6.0.0",
"babel-loader": "^8.1.0",
"eslint": "^8.17.0",
"eslint-plugin-react": "^7.21.5",
@@ -35,6 +37,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-leaflet": "^5.0.0",
+ "ts-loader": "^9.0.0",
"typescript": "^5.9.2",
"vite": "^6.3.5",
"webpack": "^5.99.9",
@@ -2586,6 +2589,48 @@
"node": ">=18"
}
},
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
+ "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+ "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
"node_modules/@eslint/eslintrc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
@@ -3311,6 +3356,13 @@
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
"dev": true
},
+ "node_modules/@types/semver": {
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz",
+ "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/serve-index": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz",
@@ -3348,6 +3400,282 @@
"@types/node": "*"
}
},
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz",
+ "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.5.1",
+ "@typescript-eslint/scope-manager": "6.21.0",
+ "@typescript-eslint/type-utils": "6.21.0",
+ "@typescript-eslint/utils": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0",
+ "debug": "^4.3.4",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.4",
+ "natural-compare": "^1.4.0",
+ "semver": "^7.5.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
+ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "6.21.0",
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/typescript-estree": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
+ "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz",
+ "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "6.21.0",
+ "@typescript-eslint/utils": "6.21.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
+ "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
+ "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "minimatch": "9.0.3",
+ "semver": "^7.5.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+ "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz",
+ "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@types/json-schema": "^7.0.12",
+ "@types/semver": "^7.5.0",
+ "@typescript-eslint/scope-manager": "6.21.0",
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/typescript-estree": "6.21.0",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/utils/node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
+ "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "6.21.0",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/@webassemblyjs/ast": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
@@ -5738,6 +6066,13 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/handle-thing": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
@@ -5953,10 +6288,11 @@
}
},
"node_modules/ignore": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
- "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 4"
}
@@ -8632,6 +8968,139 @@
"node": ">=0.6"
}
},
+ "node_modules/ts-api-utils": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
+ "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.2.0"
+ }
+ },
+ "node_modules/ts-loader": {
+ "version": "9.5.2",
+ "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.2.tgz",
+ "integrity": "sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "enhanced-resolve": "^5.0.0",
+ "micromatch": "^4.0.0",
+ "semver": "^7.3.4",
+ "source-map": "^0.7.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "typescript": "*",
+ "webpack": "^5.0.0"
+ }
+ },
+ "node_modules/ts-loader/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/ts-loader/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/ts-loader/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/ts-loader/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ts-loader/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ts-loader/node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ts-loader/node_modules/source-map": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/ts-loader/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/package.json b/package.json
index 25a7bfd..6444b87 100644
--- a/package.json
+++ b/package.json
@@ -7,9 +7,10 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 0",
"build:dist": "npm run build:umd && npm run build:umd:min && npm run build:esm",
- "build:umd": "webpack ./src/index.js --output-filename react-leaflet-draw-next.js",
- "build:umd:min": "webpack ./src/index.js --output-filename react-leaflet-draw-next.min.js",
- "build:esm": "babel src --out-dir dist/esm",
+ "typecheck": "tsc --noEmit",
+ "build:umd": "webpack ./src/index.ts --output-filename react-leaflet-draw-next.js",
+ "build:umd:min": "webpack ./src/index.ts --output-filename react-leaflet-draw-next.min.js",
+ "build:esm": "tsc -p tsconfig.json",
"build": " npm run build:dist",
"prepublish": "npm run build",
"version": "npm run build",
@@ -52,7 +53,7 @@
"url": "https://github.com/itseasy21/react-leaflet-draw-next/issues"
},
"homepage": "https://github.com/itseasy21/react-leaflet-draw-next#readme",
- "types": "src/index.d.ts",
+ "types": "dist/esm/index.d.ts",
"peerDependencies": {
"leaflet": "^1.9.4",
"leaflet-draw": "^1.0.4",
@@ -73,6 +74,8 @@
"@types/leaflet-draw": "^1.0.11",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
+ "@typescript-eslint/parser": "^6.0.0",
"babel-loader": "^8.1.0",
"eslint": "^8.17.0",
"eslint-plugin-react": "^7.21.5",
@@ -83,6 +86,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-leaflet": "^5.0.0",
+ "ts-loader": "^9.0.0",
"typescript": "^5.9.2",
"vite": "^6.3.5",
"webpack": "^5.99.9",
diff --git a/src/EditControl.js b/src/EditControl.js
deleted file mode 100644
index 8f601fc..0000000
--- a/src/EditControl.js
+++ /dev/null
@@ -1,157 +0,0 @@
-import { PropTypes } from 'prop-types';
-import 'leaflet-draw'; // eslint-disable-line
-import isEqual from 'fast-deep-equal';
-import React, { useRef } from 'react';
-import { useMap } from 'react-leaflet';
-
-import leaflet, { Map, Control } from 'leaflet';
-
-const eventHandlers = {
- onEdited: 'draw:edited',
- onDrawStart: 'draw:drawstart',
- onDrawStop: 'draw:drawstop',
- onDrawVertex: 'draw:drawvertex',
- onEditStart: 'draw:editstart',
- onEditMove: 'draw:editmove',
- onEditResize: 'draw:editresize',
- onEditVertex: 'draw:editvertex',
- onEditStop: 'draw:editstop',
- onDeleted: 'draw:deleted',
- onDeleteStart: 'draw:deletestart',
- onDeleteStop: 'draw:deletestop',
-};
-
-function EditControl(props) {
- const map = useMap();
- const drawRef = useRef();
- const propsRef = useRef(props);
-
- function onDrawCreate(e) {
- const { onCreated, featureGroup } = props;
- if (featureGroup) {
- featureGroup.addLayer(e.layer);
- }
- onCreated && onCreated(e);
- }
-
- React.useEffect(() => {
- const { onMounted, featureGroup } = props;
-
- for (const key in eventHandlers) {
- if (Object.prototype.hasOwnProperty.call(eventHandlers, key)) {
- map.on(eventHandlers[key], (evt) => {
- let handlers = Object.keys(eventHandlers).filter(
- (handler) => eventHandlers[handler] === evt.type
- );
- if (handlers.length === 1) {
- let handler = handlers[0];
- props[handler] && props[handler](evt);
- }
- });
- }
- }
- map.on(leaflet.Draw.Event.CREATED, onDrawCreate);
- drawRef.current = createDrawElement(props, featureGroup);
- map.addControl(drawRef.current);
- onMounted && onMounted(drawRef.current);
-
- return () => {
- map.off(leaflet.Draw.Event.CREATED, onDrawCreate);
-
- for (const key in eventHandlers) {
- if (Object.prototype.hasOwnProperty.call(eventHandlers, key) && props[key]) {
- map.off(eventHandlers[key], props[key]);
- }
- }
-
- if (drawRef.current) {
- drawRef.current.remove(map);
- }
- };
- }, [props.onCreated, props.onDeleted, props.onEdited, props.featureGroup]);
-
- React.useEffect(() => {
- if (
- isEqual(props.draw, propsRef.current.draw) &&
- isEqual(props.edit, propsRef.current.edit) &&
- props.position === propsRef.current.position &&
- props.featureGroup === propsRef.current.featureGroup
- ) {
- return undefined;
- }
-
- drawRef.current.remove(map);
- drawRef.current = createDrawElement(props, props.featureGroup);
- drawRef.current.addTo(map);
-
- const { onMounted } = props;
- onMounted && onMounted(drawRef.current);
-
- return () => {
- if (drawRef.current) {
- drawRef.current.remove(map);
- }
- };
- }, [
- props.draw,
- props.edit,
- props.position,
- props.featureGroup,
- props.onCreated,
- props.onDeleted,
- props.onEdited
- ]);
-
- return null;
-}
-
-function createDrawElement(props, featureGroup) {
- const { draw, edit, position } = props;
- const options = {
- edit: {
- ...edit,
- featureGroup: featureGroup,
- },
- };
-
- if (draw) {
- options.draw = { ...draw };
- }
-
- if (position) {
- options.position = position;
- }
-
- return new Control.Draw(options);
-}
-
-EditControl.propTypes = {
- ...Object.keys(eventHandlers).reduce((acc, val) => {
- acc[val] = PropTypes.func;
- return acc;
- }, {}),
- onCreated: PropTypes.func,
- onMounted: PropTypes.func,
- draw: PropTypes.shape({
- polyline: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
- polygon: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
- rectangle: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
- circle: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
- marker: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
- }),
- edit: PropTypes.shape({
- edit: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
- remove: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
- poly: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
- allowIntersection: PropTypes.bool,
- }),
- position: PropTypes.oneOf([
- 'topright',
- 'topleft',
- 'bottomright',
- 'bottomleft',
- ]),
- featureGroup: PropTypes.object, // L.FeatureGroup instance
-};
-
-export default EditControl;
diff --git a/src/EditControl.tsx b/src/EditControl.tsx
new file mode 100644
index 0000000..77959dd
--- /dev/null
+++ b/src/EditControl.tsx
@@ -0,0 +1,138 @@
+import 'leaflet-draw';
+import isEqual from 'fast-deep-equal';
+import React from 'react';
+import { useMap } from 'react-leaflet';
+import * as L from 'leaflet';
+import type { EditControlProps } from './types';
+
+const eventHandlers = {
+ onEdited: L.Draw.Event.EDITED,
+ onDrawStart: L.Draw.Event.DRAWSTART,
+ onDrawStop: L.Draw.Event.DRAWSTOP,
+ onDrawVertex: L.Draw.Event.DRAWVERTEX,
+ onEditStart: L.Draw.Event.EDITSTART,
+ onEditMove: L.Draw.Event.EDITMOVE,
+ onEditResize: L.Draw.Event.EDITRESIZE,
+ onEditVertex: L.Draw.Event.EDITVERTEX,
+ onEditStop: L.Draw.Event.EDITSTOP,
+ onDeleted: L.Draw.Event.DELETED,
+ onDeleteStart: L.Draw.Event.DELETESTART,
+ onDeleteStop: L.Draw.Event.DELETESTOP,
+} as const;
+
+function createDrawElement(
+ props: EditControlProps,
+ featureGroup?: L.FeatureGroup
+): L.Control.Draw {
+ const { draw, edit, position } = props;
+ const options: L.Control.DrawConstructorOptions = {
+ edit: {
+ ...(edit ?? {}),
+ featureGroup: featureGroup as unknown as L.FeatureGroup,
+ },
+ };
+
+ if (draw) {
+ // Cast is safe: keys align with L.Control.DrawOptions
+ options.draw = { ...(draw as L.Control.DrawOptions) };
+ }
+
+ if (position) {
+ options.position = position;
+ }
+
+ return new L.Control.Draw(options);
+}
+
+function EditControl(
+ props: EditControlProps
+) {
+ const map = useMap() as L.Map;
+ const drawRef = React.useRef(null);
+ const propsRef = React.useRef(props);
+
+ const onDrawCreate = React.useCallback(
+ (evt: L.LeafletEvent) => {
+ const e = evt as L.DrawEvents.Created;
+ const { onCreated, featureGroup } = props;
+ if (featureGroup) {
+ featureGroup.addLayer(e.layer);
+ }
+ onCreated && (onCreated as unknown as (e: L.LeafletEvent) => void)(e);
+ },
+ [props]
+ );
+
+ React.useEffect(() => {
+ const { onMounted, featureGroup } = props;
+
+ (Object.keys(eventHandlers) as Array).forEach((key) => {
+ const eventType = eventHandlers[key];
+ map.on(eventType, (evt: L.LeafletEvent) => {
+ const maybeHandler = props[key] as ((e: L.LeafletEvent) => void) | undefined;
+ if (maybeHandler) {
+ maybeHandler(evt);
+ }
+ });
+ });
+
+ map.on(L.Draw.Event.CREATED, onDrawCreate);
+ drawRef.current = createDrawElement(props, featureGroup);
+ map.addControl(drawRef.current);
+ onMounted && onMounted(drawRef.current);
+
+ return () => {
+ map.off(L.Draw.Event.CREATED, onDrawCreate);
+
+ (Object.keys(eventHandlers) as Array).forEach((key) => {
+ const eventType = eventHandlers[key];
+ map.off(eventType);
+ });
+
+ if (drawRef.current) {
+ drawRef.current.remove();
+ }
+ };
+ }, [map, onDrawCreate, props]);
+
+ React.useEffect(() => {
+ if (
+ isEqual(props.draw, propsRef.current.draw) &&
+ isEqual(props.edit, propsRef.current.edit) &&
+ props.position === propsRef.current.position &&
+ props.featureGroup === propsRef.current.featureGroup
+ ) {
+ return undefined;
+ }
+
+ if (drawRef.current) {
+ drawRef.current.remove();
+ }
+ drawRef.current = createDrawElement(props, props.featureGroup);
+ drawRef.current.addTo(map);
+
+ const { onMounted } = props;
+ onMounted && onMounted(drawRef.current);
+
+ return () => {
+ if (drawRef.current) {
+ drawRef.current.remove();
+ }
+ };
+ }, [
+ map,
+ props.draw,
+ props.edit,
+ props.position,
+ props.featureGroup,
+ props.onCreated,
+ props.onDeleted,
+ props.onEdited,
+ ]);
+
+ return null;
+}
+
+export default EditControl;
+
+
diff --git a/src/index.d.ts b/src/index.d.ts
deleted file mode 100644
index d3d2dff..0000000
--- a/src/index.d.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import * as React from 'react';
-import 'leaflet-draw';
-import type {
- DrawOptions,
- Control,
- ControlPosition,
- DrawEvents,
-} from 'leaflet';
-import * as L from 'leaflet';
-
-/**
- * Props interface for the EditControl component
- */
-interface EditControlProps {
- /** Callback fired when features are edited */
- onEdited?: (v: DrawEvents.Edited) => void;
- /** Callback fired when drawing starts */
- onDrawStart?: (v: DrawEvents.DrawStart) => void;
- /** Callback fired when drawing stops */
- onDrawStop?: (v: DrawEvents.DrawStop) => void;
- /** Callback fired when a vertex is drawn */
- onDrawVertex?: (v: DrawEvents.DrawVertex) => void;
- /** Callback fired when editing starts */
- onEditStart?: (v: DrawEvents.EditStart) => void;
- /** Callback fired when features are moved during editing */
- onEditMove?: (v: DrawEvents.EditMove) => void;
- /** Callback fired when features are resized during editing */
- onEditResize?: (v: DrawEvents.EditResize) => void;
- /** Callback fired when a vertex is edited */
- onEditVertex?: (v: DrawEvents.EditVertex) => void;
- /** Callback fired when editing stops */
- onEditStop?: (v: DrawEvents.EditStop) => void;
- /** Callback fired when features are deleted */
- onDeleted?: (v: DrawEvents.Deleted) => void;
- /** Callback fired when deletion starts */
- onDeleteStart?: (v: DrawEvents.DeleteStart) => void;
- /** Callback fired when deletion stops */
- onDeleteStop?: (v: DrawEvents.DeleteStop) => void;
- /** Callback fired when new features are created */
- onCreated?: (v: DrawEvents.Created) => void;
- /** Callback fired when the control is mounted */
- onMounted?: Function;
- /** Edit options for the control */
- edit?: Control.EditOptions;
- /** Draw options for different shape types */
- draw: {
- /** Polyline drawing options */
- polyline?: DrawOptions.PolylineOptions | boolean;
- /** Polygon drawing options */
- polygon?: DrawOptions.PolygonOptions | boolean;
- /** Rectangle drawing options */
- rectangle?: DrawOptions.RectangleOptions | boolean;
- /** Circle drawing options */
- circle?: DrawOptions.CircleOptions | boolean;
- /** Marker drawing options */
- marker?: DrawOptions.MarkerOptions | boolean;
- /** Circle marker drawing options */
- circlemarker?: DrawOptions.CircleOptions | boolean;
- };
- /** Position of the control on the map */
- position: ControlPosition;
- /** Feature group to manage drawn features */
- featureGroup?: L.FeatureGroup;
-}
-
-export class EditControl extends React.Component {}
diff --git a/src/index.js b/src/index.ts
similarity index 52%
rename from src/index.js
rename to src/index.ts
index 3b476c5..be1978a 100644
--- a/src/index.js
+++ b/src/index.ts
@@ -1 +1,4 @@
export { default as EditControl } from './EditControl';
+export type { EditControlProps } from './types';
+
+
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 0000000..026b188
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,46 @@
+import type * as L from 'leaflet';
+
+export type DrawEventMap = {
+ onEdited?: (e: L.DrawEvents.Edited) => void;
+ onDrawStart?: (e: L.DrawEvents.DrawStart) => void;
+ onDrawStop?: (e: L.DrawEvents.DrawStop) => void;
+ onDrawVertex?: (e: L.DrawEvents.DrawVertex) => void;
+ onEditStart?: (e: L.DrawEvents.EditStart) => void;
+ onEditMove?: (e: L.DrawEvents.EditMove) => void;
+ onEditResize?: (e: L.DrawEvents.EditResize) => void;
+ onEditVertex?: (e: L.DrawEvents.EditVertex) => void;
+ onEditStop?: (e: L.DrawEvents.EditStop) => void;
+ onDeleted?: (e: L.DrawEvents.Deleted) => void;
+ onDeleteStart?: (e: L.DrawEvents.DeleteStart) => void;
+ onDeleteStop?: (e: L.DrawEvents.DeleteStop) => void;
+ onCreated?: (e: L.DrawEvents.Created & { layer: TLayer }) => void;
+};
+
+export type DrawOptions = {
+ polyline?: L.DrawOptions.PolylineOptions | boolean;
+ polygon?: L.DrawOptions.PolygonOptions | boolean;
+ rectangle?: L.DrawOptions.RectangleOptions | boolean;
+ circle?: L.DrawOptions.CircleOptions | boolean;
+ marker?: L.DrawOptions.MarkerOptions | boolean;
+ circlemarker?: L.DrawOptions.CircleMarkerOptions | boolean;
+};
+
+export interface EditControlProps<
+ TLayer extends L.Layer = L.Layer,
+ TProperties = unknown
+> extends DrawEventMap {
+ onMounted?: (control: L.Control.Draw) => void;
+ edit?: L.Control.EditOptions;
+ draw?: DrawOptions;
+ position?: L.ControlPosition;
+ featureGroup?: L.FeatureGroup;
+}
+
+export type EditControlEventHandlers = DrawEventMap<
+ TLayer,
+ TProperties
+>;
+
+export type { L };
+
+
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..d042d9f
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,30 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ESNext",
+ "moduleResolution": "node",
+ "jsx": "react-jsx",
+ "strict": true,
+ "noImplicitAny": true,
+ "noImplicitThis": true,
+ "exactOptionalPropertyTypes": true,
+ "noUncheckedIndexedAccess": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "skipLibCheck": true,
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "rootDir": "src",
+ "outDir": "dist/esm",
+ "types": [
+ "leaflet",
+ "leaflet-draw",
+ "react"
+ ]
+ },
+ "include": ["src"],
+ "exclude": ["dist", "node_modules", "examples"]
+}
+
+
diff --git a/webpack.config.js b/webpack.config.js
index 18c54cc..d5eb66e 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -4,6 +4,9 @@ const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
module.exports = {
mode: 'production',
+ resolve: {
+ extensions: ['.ts', '.tsx', '.js']
+ },
output: {
library: 'ReactLeaflet',
libraryTarget: 'umd'
@@ -43,9 +46,14 @@ module.exports = {
],
module: {
rules: [
+ {
+ test: /\.(ts|tsx)$/,
+ use: 'ts-loader',
+ exclude: /node_modules/
+ },
{
test: /\.js$/,
- use: "babel-loader"
+ use: 'babel-loader'
}
]
},