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

This commit is contained in:
Andrew Kingston 2021-11-18 20:32:42 +00:00
parent a1b2f9d57d
commit a9a50545c9
1 changed files with 46 additions and 30 deletions

View File

@ -72,13 +72,18 @@
$: inSelectedPath = $builderStore.selectedComponentPath?.includes(id) $: inSelectedPath = $builderStore.selectedComponentPath?.includes(id)
$: inDragPath = inSelectedPath && $builderStore.editMode $: 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 // Interactive components can be selected, dragged and highlighted inside
// the builder preview // the builder preview
$: interactive = $: interactive =
$builderStore.inBuilder && $builderStore.inBuilder &&
($builderStore.previewType === "layout" || insideScreenslot) && ($builderStore.previewType === "layout" || insideScreenslot) &&
!isBlock !isBlock
$: editable = definition?.editable
$: editing = editable && selected && $builderStore.editMode $: editing = editable && selected && $builderStore.editMode
$: draggable = !inDragPath && interactive && !isLayout && !isScreen $: draggable = !inDragPath && interactive && !isLayout && !isScreen
$: droppable = interactive && !isLayout && !isScreen $: droppable = interactive && !isLayout && !isScreen
@ -86,8 +91,8 @@
// Empty components are those which accept children but do not have any. // Empty components are those which accept children but do not have any.
// Empty states can be shown for these components, but can be disabled // Empty states can be shown for these components, but can be disabled
// in the component manifest. // in the component manifest.
$: empty = interactive && !children.length && definition?.hasChildren $: empty = interactive && !children.length && hasChildren
$: emptyState = empty && definition?.showEmptyState !== false $: emptyState = empty && showEmptyState
// Raw settings are all settings excluding internal props and children // Raw settings are all settings excluding internal props and children
$: rawSettings = getRawSettings(instance) $: rawSettings = getRawSettings(instance)
@ -103,6 +108,9 @@
// Build up the final settings object to be passed to the component // Build up the final settings object to be passed to the component
$: cacheSettings(enrichedSettings, nestedSettings, conditionalSettings) $: cacheSettings(enrichedSettings, nestedSettings, conditionalSettings)
// Render key is used to determine when components need to fully remount
$: renderKey = getRenderKey(id, editing)
// Update component context // Update component context
$: componentStore.set({ $: componentStore.set({
id, 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}`)
}
</script> </script>
{#if constructor && cachedSettings && (visible || inSelectedPath)} {#key renderKey}
<!-- The ID is used as a class because getElementsByClassName is O(1) --> {#if constructor && cachedSettings && (visible || inSelectedPath)}
<!-- and the performance matters for the selection indicators --> <!-- The ID is used as a class because getElementsByClassName is O(1) -->
<div <!-- and the performance matters for the selection indicators -->
class={`component ${id}`} <div
class:draggable class={`component ${id}`}
class:droppable class:draggable
class:empty class:droppable
class:interactive class:empty
class:editing class:interactive
class:block={isBlock} class:editing
data-id={id} class:block={isBlock}
data-name={name} data-id={id}
> data-name={name}
<svelte:component this={constructor} {...cachedSettings}> >
{#if children.length} <svelte:component this={constructor} {...cachedSettings}>
{#each children as child (child._id)} {#if children.length}
<svelte:self instance={child} /> {#each children as child (child._id)}
{/each} <svelte:self instance={child} />
{:else if emptyState} {/each}
<Placeholder /> {:else if emptyState}
{:else if isBlock} <Placeholder />
<slot /> {:else if isBlock}
{/if} <slot />
</svelte:component> {/if}
</div> </svelte:component>
{/if} </div>
{/if}
{/key}
<style> <style>
.component { .component {