diff --git a/composer.lock b/composer.lock index 4fe3e09..079793c 100644 --- a/composer.lock +++ b/composer.lock @@ -2842,7 +2842,7 @@ }, { "name": "livewire/flux", - "version": "v2.5.1", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/livewire/flux.git", @@ -2902,7 +2902,7 @@ ], "support": { "issues": "https://github.com/livewire/flux/issues", - "source": "https://github.com/livewire/flux/tree/v2.5.1" + "source": "https://github.com/livewire/flux/tree/v2.5.0" }, "time": "2025-09-29T21:36:00+00:00" }, diff --git a/package-lock.json b/package-lock.json index 8f8edb6..9732fe8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,22 +5,9 @@ "packages": { "": { "dependencies": { - "@codemirror/commands": "^6.9.0", - "@codemirror/lang-css": "^6.3.1", - "@codemirror/lang-html": "^6.4.11", - "@codemirror/lang-javascript": "^6.2.4", - "@codemirror/lang-json": "^6.0.2", - "@codemirror/lang-liquid": "^6.3.0", - "@codemirror/language": "^6.11.3", - "@codemirror/search": "^6.5.11", - "@codemirror/state": "^6.5.2", - "@codemirror/theme-one-dark": "^6.1.3", - "@codemirror/view": "^6.38.5", - "@fsegurai/codemirror-theme-github-light": "^6.2.2", "@tailwindcss/vite": "^4.1.11", "autoprefixer": "^10.4.20", "axios": "^1.8.2", - "codemirror": "^6.0.2", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0", "puppeteer": "24.17.0", @@ -56,170 +43,6 @@ "node": ">=6.9.0" } }, - "node_modules/@codemirror/autocomplete": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.19.0.tgz", - "integrity": "sha512-61Hfv3cF07XvUxNeC3E7jhG8XNi1Yom1G0lRC936oLnlF+jrbrv8rc/J98XlYzcsAoTVupfsf5fLej1aI8kyIg==", - "license": "MIT", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.17.0", - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/commands": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.9.0.tgz", - "integrity": "sha512-454TVgjhO6cMufsyyGN70rGIfJxJEjcqjBG2x2Y03Y/+Fm99d3O/Kv1QDYWuG6hvxsgmjXmBuATikIIYvERX+w==", - "license": "MIT", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.4.0", - "@codemirror/view": "^6.27.0", - "@lezer/common": "^1.1.0" - } - }, - "node_modules/@codemirror/lang-css": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz", - "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", - "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@lezer/common": "^1.0.2", - "@lezer/css": "^1.1.7" - } - }, - "node_modules/@codemirror/lang-html": { - "version": "6.4.11", - "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", - "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", - "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/lang-css": "^6.0.0", - "@codemirror/lang-javascript": "^6.0.0", - "@codemirror/language": "^6.4.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.17.0", - "@lezer/common": "^1.0.0", - "@lezer/css": "^1.1.0", - "@lezer/html": "^1.3.12" - } - }, - "node_modules/@codemirror/lang-javascript": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz", - "integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==", - "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/language": "^6.6.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.17.0", - "@lezer/common": "^1.0.0", - "@lezer/javascript": "^1.0.0" - } - }, - "node_modules/@codemirror/lang-json": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz", - "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==", - "license": "MIT", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@lezer/json": "^1.0.0" - } - }, - "node_modules/@codemirror/lang-liquid": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@codemirror/lang-liquid/-/lang-liquid-6.3.0.tgz", - "integrity": "sha512-fY1YsUExcieXRTsCiwX/bQ9+PbCTA/Fumv7C7mTUZHoFkibfESnaXwpr2aKH6zZVwysEunsHHkaIpM/pl3xETQ==", - "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/lang-html": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.3.1" - } - }, - "node_modules/@codemirror/language": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz", - "integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==", - "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.23.0", - "@lezer/common": "^1.1.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" - } - }, - "node_modules/@codemirror/lint": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.0.tgz", - "integrity": "sha512-wZxW+9XDytH3SKvS8cQzMyQCaaazH8XL1EMHleHe00wVzsv7NBQKVW2yzEHrRhmM7ZOhVdItPbvlRBvMp9ej7A==", - "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.35.0", - "crelt": "^1.0.5" - } - }, - "node_modules/@codemirror/search": { - "version": "6.5.11", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz", - "integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==", - "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "node_modules/@codemirror/state": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", - "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", - "license": "MIT", - "dependencies": { - "@marijn/find-cluster-break": "^1.0.0" - } - }, - "node_modules/@codemirror/theme-one-dark": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz", - "integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==", - "license": "MIT", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/highlight": "^1.0.0" - } - }, - "node_modules/@codemirror/view": { - "version": "6.38.5", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.5.tgz", - "integrity": "sha512-SFVsNAgsAoou+BjRewMqN+m9jaztB9wCWN9RSRgePqUbq8UVlvJfku5zB2KVhLPgH/h0RLk38tvd4tGeAhygnw==", - "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.5.0", - "crelt": "^1.0.6", - "style-mod": "^4.1.0", - "w3c-keyname": "^2.2.4" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.10", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", @@ -636,18 +459,6 @@ "node": ">=18" } }, - "node_modules/@fsegurai/codemirror-theme-github-light": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@fsegurai/codemirror-theme-github-light/-/codemirror-theme-github-light-6.2.2.tgz", - "integrity": "sha512-YQr5MbhMlhRlAQcSCSbet4NDDkMvd5sbUyk9JmM0vfZhQbatvw4c56gNG/54JKGM0kWY5zRWzgLtFuz6D7yEsw==", - "license": "MIT", - "peerDependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/highlight": "^1.0.0" - } - }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -705,80 +516,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@lezer/common": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", - "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", - "license": "MIT" - }, - "node_modules/@lezer/css": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz", - "integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.3.0" - } - }, - "node_modules/@lezer/highlight": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", - "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@lezer/html": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.12.tgz", - "integrity": "sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "node_modules/@lezer/javascript": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", - "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.1.3", - "@lezer/lr": "^1.3.0" - } - }, - "node_modules/@lezer/json": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", - "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "node_modules/@lezer/lr": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", - "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@marijn/find-cluster-break": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", - "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", - "license": "MIT" - }, "node_modules/@puppeteer/browsers": { "version": "2.10.7", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.7.tgz", @@ -1748,21 +1485,6 @@ "node": ">=12" } }, - "node_modules/codemirror": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", - "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==", - "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1843,12 +1565,6 @@ } } }, - "node_modules/crelt": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", - "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", - "license": "MIT" - }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", @@ -3305,12 +3021,6 @@ "node": ">=8" } }, - "node_modules/style-mod": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", - "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", - "license": "MIT" - }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -3565,12 +3275,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/w3c-keyname": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", - "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "license": "MIT" - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 4190067..37b6dcf 100644 --- a/package.json +++ b/package.json @@ -6,22 +6,9 @@ "dev": "vite" }, "dependencies": { - "@codemirror/commands": "^6.9.0", - "@codemirror/lang-css": "^6.3.1", - "@codemirror/lang-html": "^6.4.11", - "@codemirror/lang-javascript": "^6.2.4", - "@codemirror/lang-json": "^6.0.2", - "@codemirror/lang-liquid": "^6.3.0", - "@codemirror/language": "^6.11.3", - "@codemirror/search": "^6.5.11", - "@codemirror/state": "^6.5.2", - "@codemirror/theme-one-dark": "^6.1.3", - "@codemirror/view": "^6.38.5", - "@fsegurai/codemirror-theme-github-light": "^6.2.2", "@tailwindcss/vite": "^4.1.11", "autoprefixer": "^10.4.20", "axios": "^1.8.2", - "codemirror": "^6.0.2", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0", "puppeteer": "24.17.0", diff --git a/resources/js/app.js b/resources/js/app.js index db3ebf3..e69de29 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1,3 +0,0 @@ -import { codeEditorFormComponent } from './codemirror-alpine.js'; - -window.codeEditorFormComponent = codeEditorFormComponent; diff --git a/resources/js/codemirror-alpine.js b/resources/js/codemirror-alpine.js deleted file mode 100644 index 9ce12f1..0000000 --- a/resources/js/codemirror-alpine.js +++ /dev/null @@ -1,198 +0,0 @@ -import { createCodeMirror, getSystemTheme, watchThemeChange } from './codemirror-core.js'; -import { EditorView } from '@codemirror/view'; - -/** - * Alpine.js component for CodeMirror that integrates with textarea and Livewire - * Inspired by Filament's approach with proper state entanglement - * @param {Object} config - Configuration object - * @returns {Object} Alpine.js component object - */ -export function codeEditorFormComponent(config) { - return { - editor: null, - textarea: null, - isLoading: false, - unwatchTheme: null, - - // Configuration - isDisabled: config.isDisabled || false, - language: config.language || 'html', - state: config.state || '', - textareaId: config.textareaId || null, - - /** - * Initialize the component - */ - async init() { - this.isLoading = true; - - try { - // Wait for textarea if provided - if (this.textareaId) { - await this.waitForTextarea(); - } - - await this.$nextTick(); - this.createEditor(); - this.setupEventListeners(); - } finally { - this.isLoading = false; - } - }, - - /** - * Wait for textarea to be available in the DOM - */ - async waitForTextarea() { - let attempts = 0; - const maxAttempts = 50; // 5 seconds max wait - - while (attempts < maxAttempts) { - this.textarea = document.getElementById(this.textareaId); - if (this.textarea) { - return; - } - - // Wait 100ms before trying again - await new Promise(resolve => setTimeout(resolve, 100)); - attempts++; - } - - console.error(`Textarea with ID "${this.textareaId}" not found after ${maxAttempts} attempts`); - }, - - /** - * Update both Livewire state and textarea with new value - */ - updateState(value) { - this.state = value; - if (this.textarea) { - this.textarea.value = value; - this.textarea.dispatchEvent(new Event('input', { bubbles: true })); - } - }, - - /** - * Create the CodeMirror editor instance - */ - createEditor() { - // Clean up any existing editor first - if (this.editor) { - this.editor.destroy(); - } - - const effectiveTheme = this.getEffectiveTheme(); - const initialValue = this.textarea ? this.textarea.value : this.state; - - this.editor = createCodeMirror(this.$refs.editor, { - value: initialValue || '', - language: this.language, - theme: effectiveTheme, - readOnly: this.isDisabled, - onChange: (value) => this.updateState(value), - onUpdate: (value) => this.updateState(value), - onBlur: () => { - if (this.editor) { - this.updateState(this.editor.state.doc.toString()); - } - } - }); - }, - - /** - * Get effective theme - */ - getEffectiveTheme() { - return getSystemTheme(); - }, - - /** - * Update editor content with new value - */ - updateEditorContent(value) { - if (this.editor && value !== this.editor.state.doc.toString()) { - this.editor.dispatch({ - changes: { - from: 0, - to: this.editor.state.doc.length, - insert: value - } - }); - } - }, - - /** - * Setup event listeners for theme changes and state synchronization - */ - setupEventListeners() { - // Watch for state changes from Livewire - this.$watch('state', (newValue) => { - this.updateEditorContent(newValue); - }); - - // Watch for disabled state changes - this.$watch('isDisabled', (newValue) => { - if (this.editor) { - this.editor.dispatch({ - effects: EditorView.editable.reconfigure(!newValue) - }); - } - }); - - // Watch for textarea changes (from Livewire updates) - if (this.textarea) { - this.textarea.addEventListener('input', (event) => { - this.updateEditorContent(event.target.value); - this.state = event.target.value; - }); - - // Listen for Livewire updates that might change the textarea value - const observer = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if (mutation.type === 'attributes' && mutation.attributeName === 'value') { - this.updateEditorContent(this.textarea.value); - this.state = this.textarea.value; - } - }); - }); - - observer.observe(this.textarea, { - attributes: true, - attributeFilter: ['value'] - }); - } - - // Listen for theme changes - this.unwatchTheme = watchThemeChange(() => { - this.recreateEditor(); - }); - }, - - /** - * Recreate the editor (useful for theme changes) - */ - async recreateEditor() { - if (this.editor) { - this.editor.destroy(); - this.editor = null; - await this.$nextTick(); - this.createEditor(); - } - }, - - - /** - * Clean up resources when component is destroyed - */ - destroy() { - if (this.editor) { - this.editor.destroy(); - this.editor = null; - } - if (this.unwatchTheme) { - this.unwatchTheme(); - } - } - }; -} - diff --git a/resources/js/codemirror-core.js b/resources/js/codemirror-core.js deleted file mode 100644 index c77bf3d..0000000 --- a/resources/js/codemirror-core.js +++ /dev/null @@ -1,255 +0,0 @@ -import { EditorView, lineNumbers, keymap } from '@codemirror/view'; -import { ViewPlugin } from '@codemirror/view'; -import { indentWithTab } from '@codemirror/commands'; -import { foldGutter, foldKeymap } from '@codemirror/language'; -import { history, historyKeymap } from '@codemirror/commands'; -import { html } from '@codemirror/lang-html'; -import { javascript } from '@codemirror/lang-javascript'; -import { json } from '@codemirror/lang-json'; -import { css } from '@codemirror/lang-css'; -import { liquid } from '@codemirror/lang-liquid'; -import { oneDark } from '@codemirror/theme-one-dark'; -import { githubLight } from '@fsegurai/codemirror-theme-github-light'; - -// Language support mapping -const LANGUAGE_MAP = { - 'javascript': javascript, - 'js': javascript, - 'json': json, - 'css': css, - 'liquid': liquid, - 'html': html, -}; - -// Theme support mapping -const THEME_MAP = { - 'light': githubLight, - 'dark': oneDark, -}; - -/** - * Get language support based on language parameter - * @param {string} language - Language name or comma-separated list - * @returns {Array|Extension} Language extension(s) - */ -function getLanguageSupport(language) { - // Handle comma-separated languages - if (language.includes(',')) { - const languages = language.split(',').map(lang => lang.trim().toLowerCase()); - const languageExtensions = []; - - languages.forEach(lang => { - const languageFn = LANGUAGE_MAP[lang]; - if (languageFn) { - languageExtensions.push(languageFn()); - } - }); - - return languageExtensions; - } - - // Handle single language - const languageFn = LANGUAGE_MAP[language.toLowerCase()] || LANGUAGE_MAP.html; - return languageFn(); -} - -/** - * Get theme support - * @param {string} theme - Theme name - * @returns {Array} Theme extensions - */ -function getThemeSupport(theme) { - const themeFn = THEME_MAP[theme] || THEME_MAP.light; - return [themeFn]; -} - -/** - * Create a resize plugin that handles container resizing - * @returns {ViewPlugin} Resize plugin - */ -function createResizePlugin() { - return ViewPlugin.fromClass(class { - constructor(view) { - this.view = view; - this.resizeObserver = null; - this.setupResizeObserver(); - } - - setupResizeObserver() { - const container = this.view.dom.parentElement; - if (container) { - this.resizeObserver = new ResizeObserver(() => { - // Use requestAnimationFrame to ensure proper timing - requestAnimationFrame(() => { - this.view.requestMeasure(); - }); - }); - this.resizeObserver.observe(container); - } - } - - destroy() { - if (this.resizeObserver) { - this.resizeObserver.disconnect(); - } - } - }); -} - -/** - * Get Flux-like theme styling based on theme - * @param {string} theme - Theme name ('light', 'dark', or 'auto') - * @returns {Object} Theme-specific styling - */ -function getFluxThemeStyling(theme) { - const isDark = theme === 'dark' || (theme === 'auto' && getSystemTheme() === 'dark'); - - if (isDark) { - return { - backgroundColor: 'oklab(0.999994 0.0000455678 0.0000200868 / 0.1)', - gutterBackgroundColor: 'oklch(26.9% 0 0)', - borderColor: '#374151', - focusBorderColor: 'rgb(224 91 68)', - }; - } else { - return { - backgroundColor: '#fff', // zinc-50 - gutterBackgroundColor: '#fafafa', // zinc-50 - borderColor: '#e5e7eb', // gray-200 - focusBorderColor: 'rgb(224 91 68)', // red-500 - }; - } -} - -/** - * Create CodeMirror editor instance - * @param {HTMLElement} element - DOM element to mount editor - * @param {Object} options - Editor options - * @returns {EditorView} CodeMirror editor instance - */ -export function createCodeMirror(element, options = {}) { - const { - value = '', - language = 'html', - theme = 'light', - readOnly = false, - onChange = () => {}, - onUpdate = () => {}, - onBlur = () => {} - } = options; - - // Get language and theme support - const languageSupport = getLanguageSupport(language); - const themeSupport = getThemeSupport(theme); - const fluxStyling = getFluxThemeStyling(theme); - - // Create editor - const editor = new EditorView({ - doc: value, - extensions: [ - lineNumbers(), - foldGutter(), - history(), - EditorView.lineWrapping, - createResizePlugin(), - ...(Array.isArray(languageSupport) ? languageSupport : [languageSupport]), - ...themeSupport, - keymap.of([indentWithTab, ...foldKeymap, ...historyKeymap]), - EditorView.theme({ - '&': { - fontSize: '14px', - border: `1px solid ${fluxStyling.borderColor}`, - borderRadius: '0.375rem', - height: '100%', - maxHeight: '100%', - overflow: 'hidden', - backgroundColor: fluxStyling.backgroundColor + ' !important', - resize: 'vertical', - minHeight: '200px', - }, - '.cm-gutters': { - borderTopLeftRadius: '0.375rem', - backgroundColor: fluxStyling.gutterBackgroundColor + ' !important', - }, - '.cm-gutter': { - backgroundColor: fluxStyling.gutterBackgroundColor + ' !important', - }, - '&.cm-focused': { - outline: 'none', - borderColor: fluxStyling.focusBorderColor, - }, - '.cm-content': { - padding: '12px', - }, - '.cm-scroller': { - fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace', - height: '100%', - overflow: 'auto', - }, - '.cm-editor': { - height: '100%', - }, - '.cm-editor .cm-scroller': { - height: '100%', - overflow: 'auto', - }, - '.cm-foldGutter': { - width: '12px', - }, - '.cm-foldGutter .cm-gutterElement': { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - cursor: 'pointer', - fontSize: '12px', - color: '#6b7280', - }, - '.cm-foldGutter .cm-gutterElement:hover': { - color: '#374151', - }, - '.cm-foldGutter .cm-gutterElement.cm-folded': { - color: '#3b82f6', - } - }), - EditorView.updateListener.of((update) => { - if (update.docChanged) { - const newValue = update.state.doc.toString(); - onChange(newValue); - onUpdate(newValue); - } - }), - EditorView.domEventHandlers({ - blur: onBlur - }), - EditorView.editable.of(!readOnly), - ], - parent: element - }); - - return editor; -} - -/** - * Auto-detect system theme preference - * @returns {string} 'dark' or 'light' - */ -export function getSystemTheme() { - if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { - return 'dark'; - } - return 'light'; -} - -/** - * Watch for system theme changes - * @param {Function} callback - Callback function when theme changes - * @returns {Function} Unwatch function - */ -export function watchThemeChange(callback) { - if (window.matchMedia) { - const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); - mediaQuery.addEventListener('change', callback); - return () => mediaQuery.removeEventListener('change', callback); - } - return () => {}; -} diff --git a/resources/views/livewire/codemirror.blade.php b/resources/views/livewire/codemirror.blade.php deleted file mode 100644 index fad3e53..0000000 --- a/resources/views/livewire/codemirror.blade.php +++ /dev/null @@ -1,64 +0,0 @@ -language = $language; - $this->theme = $theme; - $this->readonly = $readonly; - $this->placeholder = $placeholder; - $this->height = $height; - $this->id = $id; - } - - - public function toJSON() - { - return json_encode([ - 'model' => $this->model, - 'language' => $this->language, - 'theme' => $this->theme, - 'readonly' => $this->readonly, - 'placeholder' => $this->placeholder, - 'height' => $this->height, - 'id' => $this->id, - ]); - } -} ?> - - -
- -
-
- - - - - Loading editor... -
-
- - -
-
diff --git a/resources/views/livewire/plugins/recipe.blade.php b/resources/views/livewire/plugins/recipe.blade.php index 832124f..86efec6 100644 --- a/resources/views/livewire/plugins/recipe.blade.php +++ b/resources/views/livewire/plugins/recipe.blade.php @@ -839,15 +839,6 @@ HTML; @endif - @elseif($field['field_type'] === 'multi_string') - @else Field type "{{ $field['field_type'] }}" not yet supported @endif @@ -1031,48 +1022,14 @@ HTML;
-
- Data Payload - @isset($this->data_payload_updated_at) - {{ $this->data_payload_updated_at?->diffForHumans() ?? 'Never' }} - @endisset -
+ Data Payload + @isset($this->data_payload_updated_at) + {{ $this->data_payload_updated_at?->diffForHumans() ?? 'Never' }} + @endisset - - @php - $textareaId = 'payload-' . uniqid(); - @endphp - - - +
@@ -1084,43 +1041,15 @@ HTML; {{ $plugin->render_markup_view }} to update.
- - @php - $textareaId = 'code-view-' . uniqid(); - @endphp - - - - - +
@else
@@ -1142,41 +1071,15 @@ HTML; @if(!$plugin->render_markup_view)
- - @php - $textareaId = 'code-' . uniqid(); - @endphp - {{ $markup_language === 'liquid' ? 'Liquid Code' : 'Blade Code' }} - - +
diff --git a/tests/Feature/PluginRequiredConfigurationTest.php b/tests/Feature/PluginRequiredConfigurationTest.php index 51e1b76..83be449 100644 --- a/tests/Feature/PluginRequiredConfigurationTest.php +++ b/tests/Feature/PluginRequiredConfigurationTest.php @@ -268,79 +268,3 @@ test('hasMissingRequiredConfigurationFields returns false when required xhrSelec expect($plugin->hasMissingRequiredConfigurationFields())->toBeFalse(); }); - -test('hasMissingRequiredConfigurationFields returns true when required multi_string field is missing', function (): void { - $user = User::factory()->create(); - - $configurationTemplate = [ - 'custom_fields' => [ - [ - 'keyname' => 'tags', - 'field_type' => 'multi_string', - 'name' => 'Tags', - 'description' => 'Enter tags separated by commas', - // Not marked as optional, so it's required - ], - ], - ]; - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'configuration_template' => $configurationTemplate, - 'configuration' => [], // Empty configuration - ]); - - expect($plugin->hasMissingRequiredConfigurationFields())->toBeTrue(); -}); - -test('hasMissingRequiredConfigurationFields returns false when required multi_string field is set', function (): void { - $user = User::factory()->create(); - - $configurationTemplate = [ - 'custom_fields' => [ - [ - 'keyname' => 'tags', - 'field_type' => 'multi_string', - 'name' => 'Tags', - 'description' => 'Enter tags separated by commas', - // Not marked as optional, so it's required - ], - ], - ]; - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'configuration_template' => $configurationTemplate, - 'configuration' => [ - 'tags' => 'tag1, tag2, tag3', // Required field is set with comma-separated values - ], - ]); - - expect($plugin->hasMissingRequiredConfigurationFields())->toBeFalse(); -}); - -test('hasMissingRequiredConfigurationFields returns true when required multi_string field is empty string', function (): void { - $user = User::factory()->create(); - - $configurationTemplate = [ - 'custom_fields' => [ - [ - 'keyname' => 'tags', - 'field_type' => 'multi_string', - 'name' => 'Tags', - 'description' => 'Enter tags separated by commas', - // Not marked as optional, so it's required - ], - ], - ]; - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'configuration_template' => $configurationTemplate, - 'configuration' => [ - 'tags' => '', // Empty string - ], - ]); - - expect($plugin->hasMissingRequiredConfigurationFields())->toBeTrue(); -}); diff --git a/vite.config.js b/vite.config.js index adf57b3..937aae1 100644 --- a/vite.config.js +++ b/vite.config.js @@ -15,18 +15,4 @@ export default defineConfig({ server: { cors: true, }, - build: { - rollupOptions: { - output: { - manualChunks: (id) => { - // Create a separate chunk for CodeMirror - if (id.includes('codemirror') || - id.includes('@codemirror/') || - id.includes('@fsegurai/codemirror-theme-github-light')) { - return 'codemirror'; - } - } - } - } - }, -}); +}); \ No newline at end of file