2
0
mirror of https://github.com/Ionaru/easy-markdown-editor synced 2025-08-02 23:02:45 -06:00

Modernize code

This commit is contained in:
Jeroen akkerman 2025-05-01 17:44:31 +02:00
parent 31d9ae828e
commit 58cb51e2d7
8 changed files with 533 additions and 84 deletions

447
package-lock.json generated
View File

@ -22,6 +22,7 @@
"@eslint/js": "^9.25.1", "@eslint/js": "^9.25.1",
"@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.2",
"@types/node": "^22.15.3", "@types/node": "^22.15.3",
"@vitest/coverage-v8": "^3.1.2", "@vitest/coverage-v8": "^3.1.2",
"@vitest/ui": "^3.1.2", "@vitest/ui": "^3.1.2",
@ -35,6 +36,8 @@
"prettier": "^3.5.3", "prettier": "^3.5.3",
"rollup": "^4.40.1", "rollup": "^4.40.1",
"rollup-plugin-cleaner": "^1.0.0", "rollup-plugin-cleaner": "^1.0.0",
"rollup-plugin-scss": "^4.0.1",
"sass": "^1.87.0",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.31.1", "typescript-eslint": "^8.31.1",
@ -1333,6 +1336,316 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/@parcel/watcher": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"detect-libc": "^1.0.3",
"is-glob": "^4.0.3",
"micromatch": "^4.0.5",
"node-addon-api": "^7.0.0"
},
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"@parcel/watcher-android-arm64": "2.5.1",
"@parcel/watcher-darwin-arm64": "2.5.1",
"@parcel/watcher-darwin-x64": "2.5.1",
"@parcel/watcher-freebsd-x64": "2.5.1",
"@parcel/watcher-linux-arm-glibc": "2.5.1",
"@parcel/watcher-linux-arm-musl": "2.5.1",
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
"@parcel/watcher-linux-arm64-musl": "2.5.1",
"@parcel/watcher-linux-x64-glibc": "2.5.1",
"@parcel/watcher-linux-x64-musl": "2.5.1",
"@parcel/watcher-win32-arm64": "2.5.1",
"@parcel/watcher-win32-ia32": "2.5.1",
"@parcel/watcher-win32-x64": "2.5.1"
}
},
"node_modules/@parcel/watcher-android-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
"integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
"integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
"integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-freebsd-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
"integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
"integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
"integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
"integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
"integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
"integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-ia32": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
"integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
"integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@pkgjs/parseargs": { "node_modules/@pkgjs/parseargs": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@ -1399,6 +1712,33 @@
} }
} }
}, },
"node_modules/@rollup/plugin-typescript": {
"version": "12.1.2",
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.1.2.tgz",
"integrity": "sha512-cdtSp154H5sv637uMr1a8OTWB0L1SWDSm1rDGiyfcGcvQ6cuTs4MDk2BVEBGysUWago4OJN4EQZqOTl/QY3Jgg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rollup/pluginutils": "^5.1.0",
"resolve": "^1.22.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^2.14.0||^3.0.0||^4.0.0",
"tslib": "*",
"typescript": ">=3.7.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
},
"tslib": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils": { "node_modules/@rollup/pluginutils": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
@ -2893,6 +3233,22 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
},
"engines": {
"node": ">= 14.16.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/ci-info": { "node_modules/ci-info": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz",
@ -3356,6 +3712,20 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"bin": {
"detect-libc": "bin/detect-libc.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/dunder-proto": { "node_modules/dunder-proto": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@ -4916,6 +5286,13 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/immutable": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.1.tgz",
"integrity": "sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==",
"dev": true,
"license": "MIT"
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@ -6036,6 +6413,14 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
"dev": true,
"license": "MIT",
"optional": true
},
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.19", "version": "2.0.19",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
@ -6577,6 +6962,20 @@
"safe-buffer": "^5.1.0" "safe-buffer": "^5.1.0"
} }
}, },
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14.18.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/refa": { "node_modules/refa": {
"version": "0.12.1", "version": "0.12.1",
"resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz",
@ -6799,6 +7198,33 @@
"rimraf": "bin.js" "rimraf": "bin.js"
} }
}, },
"node_modules/rollup-plugin-scss": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/rollup-plugin-scss/-/rollup-plugin-scss-4.0.1.tgz",
"integrity": "sha512-3W3+3OzR+shkDl3hJ1XTAuGkP4AfiLgIjie2GtcoZ9pHfRiNqeDbtCu1EUnkjZ98EPIM6nnMIXkKlc7Sx5bRvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"rollup-pluginutils": "^2.3.3"
}
},
"node_modules/rollup-pluginutils": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"estree-walker": "^0.6.1"
}
},
"node_modules/rollup-pluginutils/node_modules/estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
"dev": true,
"license": "MIT"
},
"node_modules/rrweb-cssom": { "node_modules/rrweb-cssom": {
"version": "0.8.0", "version": "0.8.0",
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
@ -6905,6 +7331,27 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/sass": {
"version": "1.87.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.87.0.tgz",
"integrity": "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^4.0.0",
"immutable": "^5.0.2",
"source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
},
"optionalDependencies": {
"@parcel/watcher": "^2.4.1"
}
},
"node_modules/saxes": { "node_modules/saxes": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",

View File

@ -16,8 +16,7 @@
"author": "Jeroen Akkerman", "author": "Jeroen Akkerman",
"repository": "github:Ionaru/easy-markdown-editor", "repository": "github:Ionaru/easy-markdown-editor",
"scripts": { "scripts": {
"clean": "npx rimraf dist", "clean": "npx -y rimraf dist",
"prebuild": "npm run clean",
"build": "rollup -c", "build": "rollup -c",
"build:watch": "rollup -c -w", "build:watch": "rollup -c -w",
"build:types": "tsc --emitDeclarationOnly --declaration --outDir dist/types", "build:types": "tsc --emitDeclarationOnly --declaration --outDir dist/types",
@ -43,6 +42,7 @@
"@eslint/js": "^9.25.1", "@eslint/js": "^9.25.1",
"@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.2",
"@types/node": "^22.15.3", "@types/node": "^22.15.3",
"@vitest/coverage-v8": "^3.1.2", "@vitest/coverage-v8": "^3.1.2",
"@vitest/ui": "^3.1.2", "@vitest/ui": "^3.1.2",
@ -56,6 +56,8 @@
"prettier": "^3.5.3", "prettier": "^3.5.3",
"rollup": "^4.40.1", "rollup": "^4.40.1",
"rollup-plugin-cleaner": "^1.0.0", "rollup-plugin-cleaner": "^1.0.0",
"rollup-plugin-scss": "^4.0.1",
"sass": "^1.87.0",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.31.1", "typescript-eslint": "^8.31.1",

View File

@ -17,15 +17,14 @@ import { InputOptions, Options } from "./options";
import "./styles.scss"; import "./styles.scss";
export class EasyMDE { export class EasyMDE {
private readonly element: HTMLTextAreaElement; readonly #element: HTMLTextAreaElement;
#container?: HTMLDivElement; #container?: HTMLDivElement;
#codemirror?: EditorView; #codemirror?: EditorView;
// private rendered = false;
readonly #options: Options; readonly #options: Options;
private readonly plugins: IEasyMDEPlugin[] = []; readonly #plugins: IEasyMDEPlugin[] = [];
public constructor(options: InputOptions) { constructor(options: InputOptions) {
this.#options = { this.#options = {
...options, ...options,
blockStyles: { blockStyles: {
@ -35,33 +34,31 @@ export class EasyMDE {
code: "`", code: "`",
}, },
}; };
this.element = EasyMDE.verifyAndReturnElement(options.element); this.#element = EasyMDE.#verifyAndReturnElement(options.element);
marked.parse("# EasyMDE", { async: false }); marked.parse("# EasyMDE", { async: false });
// eslint-disable-next-line sonarjs/no-async-constructor // eslint-disable-next-line sonarjs/no-async-constructor
void this.construct(); void this.construct();
} }
public get container(): HTMLDivElement { get container(): HTMLDivElement {
if (!this.#container) { if (!this.#container) {
throw new NotConstructedError(); throw new NotConstructedError();
} }
return this.#container; return this.#container;
} }
public get codemirror(): EditorView { get codemirror(): EditorView {
if (!this.#codemirror) { if (!this.#codemirror) {
throw new NotConstructedError(); throw new NotConstructedError();
} }
return this.#codemirror; return this.#codemirror;
} }
public get options(): Readonly<Options> { get options(): Readonly<Options> {
return Object.freeze(this.#options); return Object.freeze(this.#options);
} }
private static verifyAndReturnElement( static #verifyAndReturnElement(element?: HTMLElement): HTMLTextAreaElement {
element?: HTMLElement,
): HTMLTextAreaElement {
if (!(element instanceof HTMLTextAreaElement)) { if (!(element instanceof HTMLTextAreaElement)) {
throw new TypeError( throw new TypeError(
'EasyMDE: Parameter "element" must be a TextArea.', 'EasyMDE: Parameter "element" must be a TextArea.',
@ -71,11 +68,11 @@ export class EasyMDE {
return element; return element;
} }
public get isRendered(): boolean { get isRendered(): boolean {
return Boolean(this.container && this.codemirror); return Boolean(this.container && this.codemirror);
} }
public async construct(): Promise<void> { async construct(): Promise<void> {
if (this.#container && this.#codemirror) { if (this.#container && this.#codemirror) {
throw new AlreadyConstructedError(); throw new AlreadyConstructedError();
} }
@ -126,10 +123,10 @@ export class EasyMDE {
}, },
]); ]);
this.element.hidden = true; this.#element.hidden = true;
this.#codemirror = new EditorView({ this.#codemirror = new EditorView({
state: EditorState.create({ state: EditorState.create({
doc: this.element.value, doc: this.#element.value,
extensions: [ extensions: [
syntaxHighlighting(highlightStyle), syntaxHighlighting(highlightStyle),
syntaxHighlighting(defaultHighlightStyle), syntaxHighlighting(defaultHighlightStyle),
@ -140,35 +137,35 @@ export class EasyMDE {
drawSelection(), drawSelection(),
], ],
selection: { selection: {
anchor: this.element.value.length, anchor: this.#element.value.length,
}, },
}), }),
// parent: this.element.parentElement || document.body, // parent: this.element.parentElement || document.body,
}); });
const easyMDEContainer = this.createContainer(); const easyMDEContainer = this.#createContainer();
if (this.options.toolbar !== false) { if (this.options.toolbar !== false) {
easyMDEContainer.append(await this.createToolbar()); easyMDEContainer.append(await this.#createToolbar());
} }
easyMDEContainer.append(this.codemirror.dom); easyMDEContainer.append(this.codemirror.dom);
if (this.options.statusbar !== false) { if (this.options.statusbar !== false) {
easyMDEContainer.append(await this.createStatusBar()); easyMDEContainer.append(await this.#createStatusBar());
} }
this.element.insertAdjacentElement("afterend", easyMDEContainer); this.#element.insertAdjacentElement("afterend", easyMDEContainer);
this.codemirror.focus(); this.codemirror.focus();
this.#container = easyMDEContainer; this.#container = easyMDEContainer;
} }
public destruct(): void { destruct(): void {
this.element.value = this.codemirror.state.doc.toString(); this.#element.value = this.codemirror.state.doc.toString();
for (const plugin of this.plugins) { for (const plugin of this.#plugins) {
void plugin.destroy(); void plugin.destroy();
} }
@ -178,15 +175,15 @@ export class EasyMDE {
this.#container = undefined; this.#container = undefined;
this.#codemirror = undefined; this.#codemirror = undefined;
this.element.hidden = false; this.#element.hidden = false;
} }
public addPlugin(plugin: IEasyMDEPlugin): IEasyMDEPlugin { addPlugin(plugin: IEasyMDEPlugin): IEasyMDEPlugin {
this.plugins.push(plugin); this.#plugins.push(plugin);
return plugin; return plugin;
} }
private async createToolbar(): Promise<HTMLDivElement> { async #createToolbar(): Promise<HTMLDivElement> {
const [{ Toolbar }, { defaultToolbar }] = await Promise.all([ const [{ Toolbar }, { defaultToolbar }] = await Promise.all([
importToolbar(), importToolbar(),
importDefaultToolbar(), importDefaultToolbar(),
@ -197,13 +194,13 @@ export class EasyMDE {
return toolbar.element; return toolbar.element;
} }
private async createStatusBar(): Promise<HTMLDivElement> { async #createStatusBar(): Promise<HTMLDivElement> {
const { StatusBar } = await import("./status-bar/status-bar"); const { StatusBar } = await import("./status-bar/status-bar");
const statusBar = new StatusBar(this); const statusBar = new StatusBar(this);
return statusBar.element; return statusBar.element;
} }
private createContainer(): HTMLDivElement { #createContainer(): HTMLDivElement {
const container = document.createElement("div"); const container = document.createElement("div");
container.classList.add("easymde-container"); container.classList.add("easymde-container");
return container; return container;

View File

@ -1,5 +1,5 @@
export class AlreadyConstructedError extends Error { export class AlreadyConstructedError extends Error {
public constructor() { constructor() {
super("EasyMDE is already initialized."); super("EasyMDE is already initialized.");
this.name = "AlreadyConstructedError"; this.name = "AlreadyConstructedError";
} }

View File

@ -1,5 +1,5 @@
export class NotConstructedError extends Error { export class NotConstructedError extends Error {
public constructor() { constructor() {
super( super(
'EasyMDE is not initialized, run the "construct()" method to do so.', 'EasyMDE is not initialized, run the "construct()" method to do so.',
); );

View File

@ -5,34 +5,34 @@ import { EasyMDE } from "../easymde";
import { countWords } from "../utils/count-words"; import { countWords } from "../utils/count-words";
export class StatusBar { export class StatusBar {
public element: HTMLDivElement; element: HTMLDivElement;
private characterCount = 0; #characterCount = 0;
private wordCount = 0; #wordCount = 0;
private lineCount = 1; #lineCount = 1;
private cursorLine = 1; #cursorLine = 1;
private cursorColumn = 1; #cursorColumn = 1;
private selectionStart = 0; #selectionStart = 0;
private selectionEnd = 0; #selectionEnd = 0;
public constructor(private editor: EasyMDE) { constructor(private editor: EasyMDE) {
this.element = document.createElement("div"); this.element = document.createElement("div");
this.element.className = "easymde-statusbar"; this.element.className = "easymde-statusbar";
// Initial values // Initial values
this.characterCount = this.editor.codemirror.state.doc.length; this.#characterCount = this.editor.codemirror.state.doc.length;
this.wordCount = countWords(this.editor.codemirror.state.doc); this.#wordCount = countWords(this.editor.codemirror.state.doc);
this.lineCount = this.editor.codemirror.state.doc.lines; this.#lineCount = this.editor.codemirror.state.doc.lines;
const line = this.editor.codemirror.state.doc.lineAt( const line = this.editor.codemirror.state.doc.lineAt(
this.editor.codemirror.state.selection.main.to, this.editor.codemirror.state.selection.main.to,
); );
this.cursorLine = line.number; this.#cursorLine = line.number;
this.cursorColumn = this.#cursorColumn =
this.editor.codemirror.state.selection.main.to - line.from + 1; this.editor.codemirror.state.selection.main.to - line.from + 1;
this.selectionStart = this.editor.codemirror.state.selection.main.from; this.#selectionStart = this.editor.codemirror.state.selection.main.from;
this.selectionEnd = this.editor.codemirror.state.selection.main.to; this.#selectionEnd = this.editor.codemirror.state.selection.main.to;
this.editor.codemirror.dispatch({ this.editor.codemirror.dispatch({
effects: StateEffect.appendConfig.of( effects: StateEffect.appendConfig.of(
@ -41,11 +41,12 @@ export class StatusBar {
const document = update.state.doc; const document = update.state.doc;
const selection = update.state.selection.main; const selection = update.state.selection.main;
this.characterCount = document.length; this.#characterCount = document.length;
this.wordCount = countWords(document); this.#wordCount = countWords(document);
this.lineCount = document.lines; this.#lineCount = document.lines;
const direction = this.getSelectionDirection(selection); const direction =
this.#getSelectionDirection(selection);
const toLine = document.lineAt(selection.to); const toLine = document.lineAt(selection.to);
const fromLine = document.lineAt(selection.from); const fromLine = document.lineAt(selection.from);
@ -54,25 +55,25 @@ export class StatusBar {
if (direction === "left") { if (direction === "left") {
// Cursor is at the start of the selection. // Cursor is at the start of the selection.
cursorLine = fromLine; cursorLine = fromLine;
this.cursorColumn = this.#cursorColumn =
selection.from - cursorLine.from; selection.from - cursorLine.from;
} else { } else {
// Cursor is at the end of the selection, or there is no selection. // Cursor is at the end of the selection, or there is no selection.
cursorLine = toLine; cursorLine = toLine;
this.cursorColumn = selection.to - cursorLine.from; this.#cursorColumn = selection.to - cursorLine.from;
if (this.cursorColumn > toLine.length) { if (this.#cursorColumn > toLine.length) {
// Column is incorrect, can happen when Ctrl+A is used. We need to manually adjust it. // Column is incorrect, can happen when Ctrl+A is used. We need to manually adjust it.
this.cursorColumn = toLine.length; this.#cursorColumn = toLine.length;
} }
} }
this.cursorLine = cursorLine.number; this.#cursorLine = cursorLine.number;
this.selectionStart = selection.from; this.#selectionStart = selection.from;
this.selectionEnd = selection.to; this.#selectionEnd = selection.to;
// We start counting columns at 1. // We start counting columns at 1.
this.cursorColumn++; this.#cursorColumn++;
this.render(); this.render();
}, },
@ -83,22 +84,22 @@ export class StatusBar {
this.render(); this.render();
} }
public render() { render() {
this.element.innerHTML = ` this.element.innerHTML = `
<span class="status-bar-element">Lines: ${this.lineCount}</span> <span class="status-bar-element">Lines: ${this.#lineCount}</span>
<span class="status-bar-element">Words: ${this.wordCount}</span> <span class="status-bar-element">Words: ${this.#wordCount}</span>
<span class="status-bar-element">Characters: ${this.characterCount}</span> <span class="status-bar-element">Characters: ${this.#characterCount}</span>
<span class="status-bar-element">Pos: ${this.cursorLine}:${this.cursorColumn}</span> <span class="status-bar-element">Pos: ${this.#cursorLine}:${this.#cursorColumn}</span>
`; `;
} }
private getSelectionDirection( #getSelectionDirection(
selection: SelectionRange, selection: SelectionRange,
): "right" | "left" | undefined { ): "right" | "left" | undefined {
return selection.from === this.selectionStart return selection.from === this.#selectionStart
? "right" ? "right"
: // eslint-disable-next-line sonarjs/no-nested-conditional : // eslint-disable-next-line sonarjs/no-nested-conditional
selection.to === this.selectionEnd selection.to === this.#selectionEnd
? "left" ? "left"
: undefined; : undefined;
} }

View File

@ -1,10 +1,12 @@
@use "sass:color";
$light-border-color: #d1d1d1; $light-border-color: #d1d1d1;
:root { :root {
--easymde-border-color: #{$light-border-color}; --easymde-border-color: #{$light-border-color};
--easymde-enabled-color: #{lighten($light-border-color, 5%)}; --easymde-enabled-color: #{color.adjust($light-border-color, $lightness: 5%)};
--easymde-hover-color: #{$light-border-color}; --easymde-hover-color: #{$light-border-color};
--easymde-active-color: #{darken($light-border-color, 5%)}; --easymde-active-color: #{color.adjust($light-border-color, $lightness: -5%)};
} }
// @media (prefers-color-scheme: dark) { // @media (prefers-color-scheme: dark) {

View File

@ -6,11 +6,11 @@ import { EasyMDE, IEasyMDEPlugin } from "../easymde";
import { IToolbarButtonOptions } from "./default-toolbar"; import { IToolbarButtonOptions } from "./default-toolbar";
export class Toolbar implements IEasyMDEPlugin { export class Toolbar implements IEasyMDEPlugin {
private static readonly activeClass = "enabled"; static readonly #activeClass = "enabled";
public element: HTMLDivElement; element: HTMLDivElement;
public constructor( constructor(
private editor: EasyMDE, private editor: EasyMDE,
toolbarLayout: IToolbarButtonOptions[][], toolbarLayout: IToolbarButtonOptions[][],
) { ) {
@ -22,7 +22,7 @@ export class Toolbar implements IEasyMDEPlugin {
for (const toolBarButtonOptions of toolBarButtonSection) { for (const toolBarButtonOptions of toolBarButtonSection) {
toolBarSection.push( toolBarSection.push(
this.createToolBarButton(toolBarButtonOptions), this.#createToolBarButton(toolBarButtonOptions),
); );
} }
@ -31,7 +31,7 @@ export class Toolbar implements IEasyMDEPlugin {
toolbarLayout.indexOf(toolBarButtonSection) !== toolbarLayout.indexOf(toolBarButtonSection) !==
toolbarLayout.length - 1 toolbarLayout.length - 1
) { ) {
toolBarSection.push(this.createToolBarSeparator()); toolBarSection.push(this.#createToolBarSeparator());
} }
for (const toolBarEntry of toolBarSection) { for (const toolBarEntry of toolBarSection) {
@ -52,13 +52,13 @@ export class Toolbar implements IEasyMDEPlugin {
} }
// eslint-disable-next-line @typescript-eslint/require-await // eslint-disable-next-line @typescript-eslint/require-await
public async build(toolbarLayout: IToolbarButtonOptions[][]) { async build(toolbarLayout: IToolbarButtonOptions[][]) {
for (const toolBarButtonSection of toolbarLayout) { for (const toolBarButtonSection of toolbarLayout) {
const toolBarSection: (HTMLButtonElement | HTMLSpanElement)[] = []; const toolBarSection: (HTMLButtonElement | HTMLSpanElement)[] = [];
for (const toolBarButtonOptions of toolBarButtonSection) { for (const toolBarButtonOptions of toolBarButtonSection) {
toolBarSection.push( toolBarSection.push(
this.createToolBarButton(toolBarButtonOptions), this.#createToolBarButton(toolBarButtonOptions),
); );
} }
@ -67,7 +67,7 @@ export class Toolbar implements IEasyMDEPlugin {
toolbarLayout.indexOf(toolBarButtonSection) !== toolbarLayout.indexOf(toolBarButtonSection) !==
toolbarLayout.length - 1 toolbarLayout.length - 1
) { ) {
toolBarSection.push(this.createToolBarSeparator()); toolBarSection.push(this.#createToolBarSeparator());
} }
for (const toolBarEntry of toolBarSection) { for (const toolBarEntry of toolBarSection) {
@ -76,18 +76,18 @@ export class Toolbar implements IEasyMDEPlugin {
} }
} }
// eslint-disable-next-line @typescript-eslint/require-await // eslint-disable-next-line @typescript-eslint/require-await
public async destroy() { async destroy() {
this.element.remove(); this.element.remove();
} }
private createToolBarSeparator() { #createToolBarSeparator() {
const separatorElement = document.createElement("span"); const separatorElement = document.createElement("span");
separatorElement.className = "separator"; separatorElement.className = "separator";
separatorElement.innerHTML = "|"; separatorElement.innerHTML = "|";
return separatorElement; return separatorElement;
} }
private createToolBarButton( #createToolBarButton(
toolBarButtonOptions: IToolbarButtonOptions, toolBarButtonOptions: IToolbarButtonOptions,
): HTMLButtonElement { ): HTMLButtonElement {
const buttonElement: HTMLButtonElement = const buttonElement: HTMLButtonElement =
@ -114,7 +114,7 @@ export class Toolbar implements IEasyMDEPlugin {
if (typeof toolBarButtonOptions.active === "boolean") { if (typeof toolBarButtonOptions.active === "boolean") {
buttonElement.classList.toggle( buttonElement.classList.toggle(
Toolbar.activeClass, Toolbar.#activeClass,
toolBarButtonOptions.active, toolBarButtonOptions.active,
); );
} else if (typeof toolBarButtonOptions.active === "function") { } else if (typeof toolBarButtonOptions.active === "function") {
@ -132,7 +132,7 @@ export class Toolbar implements IEasyMDEPlugin {
update, update,
); );
buttonElement.classList.toggle( buttonElement.classList.toggle(
Toolbar.activeClass, Toolbar.#activeClass,
result, result,
); );
} }