diff --git a/packages/slate-editor/src/extensions/variables/VariableMenu.tsx b/packages/slate-editor/src/extensions/variables/VariableMenu.tsx index a39cec1a1..e131e7269 100644 --- a/packages/slate-editor/src/extensions/variables/VariableMenu.tsx +++ b/packages/slate-editor/src/extensions/variables/VariableMenu.tsx @@ -48,10 +48,6 @@ export function VariableMenu({ container, element, onClose, variables }: Props) useEffect(() => { if (!option?.withFallback) { - // Even though the API supports `null` for the fallback, - // we can't use it here because Slate will remove this property - // and the API will add it back upon saving, creating an endless loop - // since the two values will differ. updateVariable(editor, { fallback: '' }); } }, [option?.withFallback]); diff --git a/packages/slate-editor/src/extensions/variables/VariablesExtension.tsx b/packages/slate-editor/src/extensions/variables/VariablesExtension.tsx index b5b59474c..8a52e3697 100644 --- a/packages/slate-editor/src/extensions/variables/VariablesExtension.tsx +++ b/packages/slate-editor/src/extensions/variables/VariablesExtension.tsx @@ -8,6 +8,7 @@ import { MentionsExtension } from '#extensions/mentions'; import { parseSerializedElement } from './lib'; import { convertLegacyPlaceholderNodesToVariables, + removeFallbackPropertyIfEmpty, removeUnknownVariableNodeAttributes, removeUnknownVariables, } from './normalization'; @@ -25,6 +26,7 @@ export function VariablesExtension({ variables }: VariablesExtensionParameters): convertLegacyPlaceholderNodesToVariables, removeUnknownVariables(variablesNames), removeUnknownVariableNodeAttributes, + removeFallbackPropertyIfEmpty, ], parseSerializedElement, renderElement: ({ attributes, children, element }: RenderElementProps) => { diff --git a/packages/slate-editor/src/extensions/variables/lib/createVariableNode.ts b/packages/slate-editor/src/extensions/variables/lib/createVariableNode.ts index 40d2712d4..8cff550f3 100644 --- a/packages/slate-editor/src/extensions/variables/lib/createVariableNode.ts +++ b/packages/slate-editor/src/extensions/variables/lib/createVariableNode.ts @@ -4,7 +4,6 @@ export function createVariableNode(key: VariableNode['key']): VariableNode { return { children: [{ text: '' }], key, - fallback: null, type: VARIABLE_NODE_TYPE, }; } diff --git a/packages/slate-editor/src/extensions/variables/normalization/index.ts b/packages/slate-editor/src/extensions/variables/normalization/index.ts index b321e1b1f..e1b8d9c05 100644 --- a/packages/slate-editor/src/extensions/variables/normalization/index.ts +++ b/packages/slate-editor/src/extensions/variables/normalization/index.ts @@ -1,3 +1,4 @@ export { convertLegacyPlaceholderNodesToVariables } from './convertLegacyPlaceholderNodesToVariables'; +export { removeFallbackPropertyIfEmpty } from './removeFallbackPropertyIfEmpty'; export { removeUnknownVariableNodeAttributes } from './removeUnknownVariableNodeAttributes'; export { removeUnknownVariables } from './removeUnknownVariables'; diff --git a/packages/slate-editor/src/extensions/variables/normalization/normalization.test.tsx b/packages/slate-editor/src/extensions/variables/normalization/normalization.test.tsx index b60e1aa8b..e8d174309 100644 --- a/packages/slate-editor/src/extensions/variables/normalization/normalization.test.tsx +++ b/packages/slate-editor/src/extensions/variables/normalization/normalization.test.tsx @@ -9,12 +9,14 @@ import { convertLegacyPlaceholderNodesToVariables, removeUnknownVariables, removeUnknownVariableNodeAttributes, + removeFallbackPropertyIfEmpty, } from './'; const normalizations = [ convertLegacyPlaceholderNodesToVariables, removeUnknownVariables(['contact.firstname', 'contact.lastname']), removeUnknownVariableNodeAttributes, + removeFallbackPropertyIfEmpty, ]; function normalizeNode(editor: Editor, entry: NodeEntry) { @@ -154,4 +156,40 @@ describe('VariablesExtension', () => { expect(editor.children).toEqual(expected.children); }); }); + + describe('removeFallbackPropertyIfEmpty', () => { + it("should remove fallback property, if it's an empty string", () => { + const editor = ( + + + Hello, + + %contact.firstname% + + ! + + + ) as unknown as Editor; + + const expected = ( + + + Hello, + + %contact.firstname% + + ! + + + ) as unknown as Editor; + + editor.normalizeNode = function (entry) { + normalizeNode(editor, entry); + }; + + Editor.normalize(editor, { force: true }); + + expect(editor.children).toEqual(expected.children); + }); + }); }); diff --git a/packages/slate-editor/src/extensions/variables/normalization/removeFallbackPropertyIfEmpty.ts b/packages/slate-editor/src/extensions/variables/normalization/removeFallbackPropertyIfEmpty.ts new file mode 100644 index 000000000..159065f53 --- /dev/null +++ b/packages/slate-editor/src/extensions/variables/normalization/removeFallbackPropertyIfEmpty.ts @@ -0,0 +1,18 @@ +import { type VariableNode, isVariableNode } from '@prezly/slate-types'; +import { Transforms, type Editor, type NodeEntry } from 'slate'; + +export function removeFallbackPropertyIfEmpty( + editor: Editor, + [node, path]: NodeEntry, +): boolean { + if (!isVariableNode(node)) { + return false; + } + + if (node.fallback === '') { + Transforms.setNodes(editor, { fallback: undefined }, { at: path }); + return true; + } + + return false; +} diff --git a/packages/slate-types/src/nodes/VariableNode.ts b/packages/slate-types/src/nodes/VariableNode.ts index 1024e7a5b..05a579521 100644 --- a/packages/slate-types/src/nodes/VariableNode.ts +++ b/packages/slate-types/src/nodes/VariableNode.ts @@ -5,7 +5,7 @@ export const VARIABLE_NODE_TYPE = 'variable'; export interface VariableNode extends ElementNode { type: typeof VARIABLE_NODE_TYPE; - fallback?: string | null; + fallback?: string; key: string; }