From df29ad109257c0c9020df8797b778e4592533a6e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 18 Nov 2021 20:32:42 +0000 Subject: [PATCH] Be more explicit about the boolean nature of component settings in the manifest and add back in a render key to fix toggling contenteditable attribute on dom elements --- .../client/src/components/Component.svelte | 76 +++++++++++-------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index a4ee290028..b248ee1277 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -72,13 +72,18 @@ $: inSelectedPath = $builderStore.selectedComponentPath?.includes(id) $: inDragPath = inSelectedPath && $builderStore.editMode + // Derive definition properties which can all be optional, so need to be + // coerced to booleans + $: editable = !!definition?.editable + $: hasChildren = !!definition?.hasChildren + $: showEmptyState = !!definition?.showEmptyState + // Interactive components can be selected, dragged and highlighted inside // the builder preview $: interactive = $builderStore.inBuilder && ($builderStore.previewType === "layout" || insideScreenslot) && !isBlock - $: editable = definition?.editable $: editing = editable && selected && $builderStore.editMode $: draggable = !inDragPath && interactive && !isLayout && !isScreen $: droppable = interactive && !isLayout && !isScreen @@ -86,8 +91,8 @@ // Empty components are those which accept children but do not have any. // Empty states can be shown for these components, but can be disabled // in the component manifest. - $: empty = interactive && !children.length && definition?.hasChildren - $: emptyState = empty && definition?.showEmptyState !== false + $: empty = interactive && !children.length && hasChildren + $: emptyState = empty && showEmptyState // Raw settings are all settings excluding internal props and children $: rawSettings = getRawSettings(instance) @@ -103,6 +108,9 @@ // Build up the final settings object to be passed to the component $: cacheSettings(enrichedSettings, nestedSettings, conditionalSettings) + // Render key is used to determine when components need to fully remount + $: renderKey = getRenderKey(id, editing) + // Update component context $: componentStore.set({ id, @@ -268,35 +276,43 @@ }) } } + + // Generates a key used to determine when components need to fully remount. + // Currently only toggling editing requires remounting. + const getRenderKey = (id, editing) => { + return hashString(`${id}-${editing}`) + } -{#if constructor && cachedSettings && (visible || inSelectedPath)} - - -
- - {#if children.length} - {#each children as child (child._id)} - - {/each} - {:else if emptyState} - - {:else if isBlock} - - {/if} - -
-{/if} +{#key renderKey} + {#if constructor && cachedSettings && (visible || inSelectedPath)} + + +
+ + {#if children.length} + {#each children as child (child._id)} + + {/each} + {:else if emptyState} + + {:else if isBlock} + + {/if} + +
+ {/if} +{/key}