diff --git a/src/lib/components/RichTextRenderer.svelte b/src/lib/components/RichTextRenderer.svelte index 64eb8d0..1e96332 100644 --- a/src/lib/components/RichTextRenderer.svelte +++ b/src/lib/components/RichTextRenderer.svelte @@ -2,6 +2,7 @@ import type { BlahRichText } from '$lib/richText'; import { tw } from '$lib/tw'; import RichTextSpan from './RichTextRenderer/RichTextSpan.svelte'; + import PlainTextRenderer from './RichTextRenderer/PlainTextRenderer.svelte'; export let content: BlahRichText; let className = ''; @@ -9,20 +10,14 @@
- {#each content as block} -

- {#each block as span} - {#if typeof span === 'string'} - {#if span === ''} -
- {:else} - {span} - {/if} - {:else} - {@const [text, attributes] = span} - - {/if} - {/each} -

- {/each} +

+ {#each content as span} + {#if typeof span === 'string'} + + {:else} + {@const [text, attributes] = span} + + {/if} + {/each} +

diff --git a/src/lib/components/RichTextRenderer/PlainTextRenderer.svelte b/src/lib/components/RichTextRenderer/PlainTextRenderer.svelte new file mode 100644 index 0000000..1cc4027 --- /dev/null +++ b/src/lib/components/RichTextRenderer/PlainTextRenderer.svelte @@ -0,0 +1,10 @@ + + +{#each text.split('\n') as segment, idx} + {#if idx > 0} +
+ {/if} + {segment} +{/each} diff --git a/src/lib/components/RichTextRenderer/RichTextSpan.svelte b/src/lib/components/RichTextRenderer/RichTextSpan.svelte index 69bb3e5..db64052 100644 --- a/src/lib/components/RichTextRenderer/RichTextSpan.svelte +++ b/src/lib/components/RichTextRenderer/RichTextSpan.svelte @@ -1,5 +1,6 @@ -{#if attribute === '' || !attributes[attribute]} - {text} +{#if attribute === ''} + +{:else if !attributes[attribute]} + {:else if attribute === 'link'} diff --git a/src/lib/richText.ts b/src/lib/richText.ts index ceca1ca..69e9a4a 100644 --- a/src/lib/richText.ts +++ b/src/lib/richText.ts @@ -1,3 +1,4 @@ +import canonicalize from 'canonicalize'; import type { AttributeMap, Delta } from 'typewriter-editor'; import { z } from 'zod'; @@ -18,10 +19,7 @@ export const blahRichTextSpanSchema = z.union([ ]); export type BlahRichTextSpan = z.input; -export const blahRichTextBlockSchema = z.array(blahRichTextSpanSchema); -export type BlahRichTextBlock = z.input; - -export const blahRichTextSchema = z.array(blahRichTextBlockSchema); +export const blahRichTextSchema = z.array(blahRichTextSpanSchema); export type BlahRichText = z.input; function isObjectEmpty(obj: object) { @@ -48,23 +46,34 @@ function deltaAttributesToBlahRichTextSpanAttributes( } export function deltaToBlahRichText(delta: Delta): BlahRichText { - const blocks: BlahRichText = []; + const spans: BlahRichText = []; - let block: BlahRichTextBlock = []; - for (const op of delta.ops) { - const lines = op.insert?.split('\n'); - if (!lines) continue; - const attributes = deltaAttributesToBlahRichTextSpanAttributes(op.attributes); + let lastText = ''; + let lastAttributes: BlahRichTextSpanAttributes | null = null; + let canonicalizedLastAttributes: string = 'null'; - const line = lines.shift(); - block.push(attributes ? [line, attributes] : line); - - for (const line of lines) { - blocks.push(block); - block = []; - block.push(attributes ? [line, attributes] : line); - } + function commitSpan() { + spans.push(lastAttributes === null ? lastText : [lastText, lastAttributes]); } - return blocks; + for (const op of delta.ops) { + // Not sure in what cases op.insert would not be a string, but let's be safe + if (typeof op.insert !== 'string') continue; + + const attributes = deltaAttributesToBlahRichTextSpanAttributes(op.attributes); + const canonicalizedAttributes = canonicalize(attributes) ?? 'null'; + + if (canonicalizedAttributes === canonicalizedLastAttributes) { + lastText += op.insert; + continue; + } + + commitSpan(); + lastText = op.insert; + lastAttributes = attributes; + canonicalizedLastAttributes = canonicalizedAttributes; + } + commitSpan(); + + return spans; }