From 926bdfa79983e3f3f2d79e730fca0f6a119f77b7 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Thu, 22 May 2025 09:53:18 +0200 Subject: [PATCH] implement easymde --- package-lock.json | 136 +++++++++++++++++++++++-- package.json | 3 + rollup.config.js | 5 + src/Components/Input/TextAreaInput.tsx | 82 +++++++++++++-- src/css.tsx | 3 + 5 files changed, 214 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 86f3a0b1..07b64b96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,11 @@ "license": "GPL-3.0-only", "dependencies": { "@heroicons/react": "^2.0.17", + "@rollup/plugin-commonjs": "^28.0.3", "@tanstack/react-query": "^5.17.8", "axios": "^1.6.5", "date-fns": "^3.3.1", + "easymde": "^2.20.0", "leaflet": "^1.9.4", "leaflet.locatecontrol": "^0.79.0", "radash": "^12.1.0", @@ -24,6 +26,7 @@ "react-markdown": "^9.0.1", "react-photo-album": "^3.0.2", "react-router-dom": "^6.16.0", + "react-simplemde-editor": "^5.2.0", "react-toastify": "^9.1.3", "remark-breaks": "^4.0.0", "yet-another-react-lightbox": "^3.21.7" @@ -1200,7 +1203,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -1324,6 +1326,32 @@ } } }, + "node_modules/@rollup/plugin-commonjs": { + "version": "28.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.3.tgz", + "integrity": "sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==", + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0 || 14 >= 14.17" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-node-resolve": { "version": "16.0.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.0.tgz", @@ -1380,7 +1408,6 @@ "version": "5.1.4", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -2380,6 +2407,15 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/codemirror": { + "version": "5.60.15", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.15.tgz", + "integrity": "sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==", + "license": "MIT", + "dependencies": { + "@types/tern": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -2454,6 +2490,12 @@ "@types/leaflet": "*" } }, + "node_modules/@types/marked": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.3.2.tgz", + "integrity": "sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==", + "license": "MIT" + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -2534,6 +2576,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/tern": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -3859,6 +3910,21 @@ "node": ">=6" } }, + "node_modules/codemirror": { + "version": "5.65.19", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.19.tgz", + "integrity": "sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==", + "license": "MIT" + }, + "node_modules/codemirror-spell-checker": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz", + "integrity": "sha512-2Tl6n0v+GJRsC9K3MLCdLaMOmvWL0uukajNJseorZJsslaxZyZMgENocPU8R0DyoTAiKsyqiemSOZo7kjGV0LQ==", + "license": "MIT", + "dependencies": { + "typo-js": "*" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3935,6 +4001,12 @@ "node": ">=4.0.0" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4627,6 +4699,19 @@ "dev": true, "license": "MIT" }, + "node_modules/easymde": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/easymde/-/easymde-2.20.0.tgz", + "integrity": "sha512-V1Z5f92TfR42Na852OWnIZMbM7zotWQYTddNaLYZFVKj7APBbyZ3FYJ27gBw2grMW3R6Qdv9J8n5Ij7XRSIgXQ==", + "license": "MIT", + "dependencies": { + "@types/codemirror": "^5.60.10", + "@types/marked": "^4.0.7", + "codemirror": "^5.65.15", + "codemirror-spell-checker": "1.1.2", + "marked": "^4.1.0" + } + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -5614,7 +5699,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, "license": "MIT" }, "node_modules/esutils": { @@ -5807,7 +5891,6 @@ "version": "6.4.3", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", - "dev": true, "license": "MIT", "peerDependencies": { "picomatch": "^3 || ^4" @@ -7073,6 +7156,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -8075,7 +8167,6 @@ "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -8140,6 +8231,18 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -9470,7 +9573,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -10531,6 +10633,20 @@ "react-dom": ">=16.8" } }, + "node_modules/react-simplemde-editor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-simplemde-editor/-/react-simplemde-editor-5.2.0.tgz", + "integrity": "sha512-GkTg1MlQHVK2Rks++7sjuQr/GVS/xm6y+HchZ4GPBWrhcgLieh4CjK04GTKbsfYorSRYKa0n37rtNSJmOzEDkQ==", + "license": "MIT", + "dependencies": { + "@types/codemirror": "~5.60.5" + }, + "peerDependencies": { + "easymde": ">= 2.0.0 < 3.0.0", + "react": ">=16.8.2", + "react-dom": ">=16.8.2" + } + }, "node_modules/react-toastify": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", @@ -10771,7 +10887,7 @@ "version": "4.40.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.7" @@ -12209,6 +12325,12 @@ "node": ">=14.17" } }, + "node_modules/typo-js": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.5.tgz", + "integrity": "sha512-F45vFWdGX8xahIk/sOp79z2NJs8ETMYsmMChm9D5Hlx3+9j7VnCyQyvij5MOCrNY3NNe8noSyokRjQRfq+Bc7A==", + "license": "BSD-3-Clause" + }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", diff --git a/package.json b/package.json index b8309549..dadbef4b 100644 --- a/package.json +++ b/package.json @@ -92,9 +92,11 @@ }, "dependencies": { "@heroicons/react": "^2.0.17", + "@rollup/plugin-commonjs": "^28.0.3", "@tanstack/react-query": "^5.17.8", "axios": "^1.6.5", "date-fns": "^3.3.1", + "easymde": "^2.20.0", "leaflet": "^1.9.4", "leaflet.locatecontrol": "^0.79.0", "radash": "^12.1.0", @@ -106,6 +108,7 @@ "react-markdown": "^9.0.1", "react-photo-album": "^3.0.2", "react-router-dom": "^6.16.0", + "react-simplemde-editor": "^5.2.0", "react-toastify": "^9.1.3", "remark-breaks": "^4.0.0", "yet-another-react-lightbox": "^3.21.7" diff --git a/rollup.config.js b/rollup.config.js index ed8799f3..1f9188c1 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -7,6 +7,7 @@ import typescript from '@rollup/plugin-typescript' import { dts } from 'rollup-plugin-dts' import postcss from 'rollup-plugin-postcss' import svg from 'rollup-plugin-svg' +import commonjs from '@rollup/plugin-commonjs' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) @@ -38,6 +39,10 @@ export default [ postcss({ plugins: [], }), + commonjs({ + include: /node_modules/, + requireReturnsDefault: 'auto', // this solves missing default export + }), typescript({ tsconfig: './tsconfig.json', noEmitOnError: true, diff --git a/src/Components/Input/TextAreaInput.tsx b/src/Components/Input/TextAreaInput.tsx index 2ab53264..ed664f3b 100644 --- a/src/Components/Input/TextAreaInput.tsx +++ b/src/Components/Input/TextAreaInput.tsx @@ -1,5 +1,7 @@ import { useEffect, useRef, useState } from 'react' +import SimpleMDE from 'react-simplemde-editor' + interface TextAreaProps { labelTitle?: string labelStyle?: string @@ -26,21 +28,22 @@ export function TextAreaInput({ required = true, updateFormValue, }: TextAreaProps) { - const ref = useRef(null) + const ref = useRef(null) const [inputValue, setInputValue] = useState(defaultValue) useEffect(() => { setInputValue(defaultValue) }, [defaultValue]) - const handleChange = (e: React.ChangeEvent) => { - const newValue = e.target.value + const handleChange = (value: string) => { + const newValue = value setInputValue(newValue) if (updateFormValue) { updateFormValue(newValue) } } + console.log('required not enforced', required) return (
{labelTitle ? ( @@ -50,15 +53,78 @@ export function TextAreaInput({ ) : null} - + /* + options={ + autoDownloadFontAwesome?: boolean; + autofocus?: boolean; + autosave?: AutoSaveOptions; + autoRefresh?: boolean | { delay: number; }; + blockStyles?: BlockStyleOptions; + element?: HTMLElement; + forceSync?: boolean; + hideIcons?: ReadonlyArray; + indentWithTabs?: boolean; + initialValue?: string; + insertTexts?: InsertTextOptions; + lineNumbers?: boolean; + lineWrapping?: boolean; + minHeight?: string; + maxHeight?: string; + parsingConfig?: ParsingOptions; + placeholder?: string; + previewClass?: string | ReadonlyArray; + previewImagesInEditor?: boolean; + imagesPreviewHandler?: (src: string) => string, + previewRender?: (markdownPlaintext: string, previewElement: HTMLElement) => string | null; + promptURLs?: boolean; + renderingConfig?: RenderingOptions; + shortcuts?: Shortcuts; + showIcons?: ReadonlyArray; + spellChecker?: boolean | ((options: SpellCheckerOptions) => void); + inputStyle?: 'textarea' | 'contenteditable'; + nativeSpellcheck?: boolean; + sideBySideFullscreen?: boolean; + status?: boolean | ReadonlyArray; + styleSelectedText?: boolean; + tabSize?: number; + toolbar?: boolean | ReadonlyArray<'|' | ToolbarButton | ToolbarIcon | ToolbarDropdownIcon>; + toolbarTips?: boolean; + toolbarButtonClassPrefix?: string; + onToggleFullScreen?: (goingIntoFullScreen: boolean) => void; + theme?: string; + scrollbarStyle?: string; + unorderedListStyle?: '*' | '-' | '+'; + + uploadImage?: boolean; + imageMaxSize?: number; + imageAccept?: string; + imageUploadFunction?: (file: File, onSuccess: (url: string) => void, onError: (error: string) => void) => void; + imageUploadEndpoint?: string; + imagePathAbsolute?: boolean; + imageCSRFToken?: string; + imageCSRFName?: string; + imageCSRFHeader?: boolean; + imageTexts?: ImageTextsOptions; + imageInputName?: string + errorMessages?: ImageErrorTextsOptions; + errorCallback?: (errorMessage: string) => void; + + promptTexts?: PromptTexts; + syncSideBySidePreviewScroll?: boolean; + + overlayMode?: OverlayModeOptions; + + direction?: 'ltr' | 'rtl'; + } + */ + className={`tw:textarea tw:textarea-bordered tw:w-full tw:leading-5 ${inputStyle ?? ''}`} + />
) } diff --git a/src/css.tsx b/src/css.tsx index 5856b54a..57b30b69 100644 --- a/src/css.tsx +++ b/src/css.tsx @@ -13,3 +13,6 @@ import '#assets/css/misc.css' import '#assets/css/marker-icons.css' import '#assets/css/leaflet.css' import '#assets/css/color-picker.css' + +// MD Editor +import 'easymde/dist/easymde.min.css'