From a5605d947484835bb39f83dba5368a919072a068 Mon Sep 17 00:00:00 2001 From: Francois Date: Fri, 9 Oct 2026 09:54:06 +0200 Subject: [PATCH] fix: ignore a value set again by the host Vue sets the value property of a custom element on every render of its parent. With the store kept per element, the host's initial value was applied again when the editor was closed, erasing the user's changes. Only a new string value replaces the content now, 0.1.x ignored every value after the first one. The compatibility page sets the value again on every toggle, like Vue. --- docs/docs/changelog.mdx | 1 + visual-editor/server/compat.html | 8 +++++++- visual-editor/src/VisualEditor.tsx | 13 ++++++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/docs/changelog.mdx b/docs/docs/changelog.mdx index 793ac51..2c8f709 100644 --- a/docs/docs/changelog.mdx +++ b/docs/docs/changelog.mdx @@ -8,6 +8,7 @@ sidebar_position: 10 - Fix: the `change` event carries the JSON of the page in `detail` again (removed in 0.2.0), and is emitted for every change made in the editor, including the preview arrows. It is not emitted when the host sets `value` - Fix: one store per element, the content is kept when the editor is hidden and shown again, and `value` can be read right after the element is inserted +- Fix: setting `value` again with the same string (Vue does it on every render of the host) no longer resets the content, only a new value replaces it - Fix: the text alignment radios are no longer submitted with the surrounding form (#4) - Fix: preview messages are only accepted from the preview iframe and from the editor window - Fix: English and French translations diff --git a/visual-editor/server/compat.html b/visual-editor/server/compat.html index 6f6da68..a716ad6 100644 --- a/visual-editor/server/compat.html +++ b/visual-editor/server/compat.html @@ -50,7 +50,12 @@ host.changes.push(v.detail) host.value = v.detail }) - el.addEventListener('close', () => (el.hidden = true)) + // Like Vue, every render of the host sets the initial value again + const render = () => (el.value = window.initialValue ?? '[]') + el.addEventListener('close', () => { + el.hidden = true + render() + }) const form = document.querySelector('form') form.addEventListener('submit', (e) => { @@ -59,6 +64,7 @@ }) document.querySelector('#toggle').addEventListener('click', () => { el.hidden = !el.hidden + render() }) form.appendChild(el) host.ready = true diff --git a/visual-editor/src/VisualEditor.tsx b/visual-editor/src/VisualEditor.tsx index 7add5fd..de83d63 100644 --- a/visual-editor/src/VisualEditor.tsx +++ b/visual-editor/src/VisualEditor.tsx @@ -86,6 +86,8 @@ export class VisualEditor { private _store: Store | null = null // Last JSON value known by the element (emitted or received) private _lastValue = '' + // Last string value set by the host + private _hostValue: string | null = null // True while the value comes from the host (no change event) private _silent = false @@ -107,6 +109,14 @@ export class VisualEditor { | EditorComponentData[] | ((v: EditorComponentData[]) => EditorComponentData[]) ) { + if (typeof v === 'string') { + // Hosts like Vue set the same value again on every render, only a + // new value replaces the content (0.1.x ignored every later value) + if (v === this._hostValue) { + return + } + this._hostValue = v + } if (!this._store) { if (!v) { this.removeAttribute('value') @@ -175,7 +185,8 @@ export class VisualEditor { if (this._store) { return this._store } - const data = this.parseValue(this.getAttribute('value')?.toString()) + this._hostValue = this.getAttribute('value') + const data = this.parseValue(this._hostValue ?? undefined) const store = createStore( data, components,