Skip to content

Commit

Permalink
feat(ui): support inline markdown in AnnotatedText - WF-169
Browse files Browse the repository at this point in the history
Use `BaseMarkdown` in `CoreAnnotatedText` to support inline markdown
syntax. I also reworked a bit `BaseMarkdown` to have an inline mode.
  • Loading branch information
madeindjs committed Jan 24, 2025
1 parent ef7030d commit 8b86174
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 19 deletions.
47 changes: 47 additions & 0 deletions src/ui/src/components/core/base/BaseMarkdown.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { beforeEach, describe, expect, it, Mock, vi } from "vitest";
import { flushPromises, shallowMount } from "@vue/test-utils";
import VueDOMPurifyHTML from "vue-dompurify-html";
import BaseMarkdown from "./BaseMarkdown.vue";
import { parse, parseInline } from "marked";

vi.mock("marked", () => ({
parse: vi.fn().mockImplementation((v) => `<div>${v}</div>`),
parseInline: vi.fn().mockImplementation((v) => `<span>${v}</span>`),
}));

describe("BaseMarkdown", () => {
const rawText = "# hello\nI'm **MD** ";

beforeEach(() => {
(parse as unknown as Mock).mockClear();
(parseInline as unknown as Mock).mockClear();
});

it("should render markdown as block", async () => {
const wrapper = shallowMount(BaseMarkdown, {
props: { rawText },
global: { plugins: [VueDOMPurifyHTML] },
});
await flushPromises();
expect(wrapper.element).toMatchSnapshot();
expect(parse).toHaveBeenCalledOnce();

wrapper.setProps({ rawText: "updated" });
await flushPromises();
expect(parse).toHaveBeenCalledTimes(2);
});

it("should render markdown as inline", async () => {
const wrapper = shallowMount(BaseMarkdown, {
props: { rawText, inline: true },
global: { plugins: [VueDOMPurifyHTML] },
});
await flushPromises();
expect(wrapper.element).toMatchSnapshot();
expect(parseInline).toHaveBeenCalledOnce();

wrapper.setProps({ rawText: "updated" });
await flushPromises();
expect(parseInline).toHaveBeenCalledTimes(2);
});
});
40 changes: 25 additions & 15 deletions src/ui/src/components/core/base/BaseMarkdown.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
<template>
<div
v-if="isMarkedLoaded"
v-dompurify-html="marked.parse(props.rawText).trim()"
class="BaseMarkdown markdown"
></div>
<template v-if="html !== undefined">
<span
v-if="inline"
v-dompurify-html="html"
class="BaseMarkdown markdown"
></span>
<div v-else v-dompurify-html="html" class="BaseMarkdown markdown"></div>
</template>
</template>

<script setup lang="ts">
import { onBeforeMount, ref } from "vue";
import { ref, toRefs, watch } from "vue";
let marked: typeof import("marked");
const isMarkedLoaded = ref(false);
const props = defineProps({
rawText: { type: String, required: true },
inline: { type: Boolean },
});
const props = defineProps<{
rawText: string;
}>();
const html = ref<string | undefined>(undefined);
onBeforeMount(async () => {
marked = await import("marked");
isMarkedLoaded.value = true;
});
const { rawText, inline } = toRefs(props);
async function buildHtml() {
const marked = await import("marked");
const result = inline.value
? marked.parseInline(rawText.value, { async: false })
: marked.parse(rawText.value, { async: false });
html.value = await result;
}
watch([rawText, inline], buildHtml, { immediate: true });
</script>

<style scoped>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`BaseMarkdown > should render markdown as block 1`] = `
<div
data-v-app=""
>
<div
class="BaseMarkdown markdown"
data-v-03a7c885=""
>
<div>
# hello
I'm **MD**
</div>
</div>
</div>
`;

exports[`BaseMarkdown > should render markdown as inline 1`] = `
<div
data-v-app=""
>
<span
class="BaseMarkdown markdown"
data-v-03a7c885=""
>
<span>
# hello
I'm **MD**
</span>
</span>
</div>
`;
14 changes: 10 additions & 4 deletions src/ui/src/components/core/content/CoreAnnotatedText.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
<div v-if="shouldDisplay" class="CoreAnnotatedText">
<BaseEmptiness v-if="isEmpty" :component-id="componentId" />
<span v-for="(content, i) in safeText" :key="String(content) + i">
<template v-if="typeof content === 'string'">{{
content
}}</template>
<BaseMarkdown
v-if="typeof content === 'string'"
:raw-text="content"
inline
/>
<span
v-if="Array.isArray(content)"
class="annotation"
:style="{ background: content[2] || generateColor(content[1]) }"
>
{{ content[0] }}
<BaseMarkdown :raw-text="content[0]" inline />
<span v-if="content[1]" class="annotation-subject">
{{ content[1] }}
</span>
Expand Down Expand Up @@ -97,6 +99,7 @@ import injectionKeys from "@/injectionKeys";
import { computed, ComputedRef, inject } from "vue";
import chroma, { Color } from "chroma-js";
import BaseEmptiness from "../base/BaseEmptiness.vue";
import BaseMarkdown from "../base/BaseMarkdown.vue";
const fields = inject(injectionKeys.evaluatedFields);
Expand Down Expand Up @@ -267,4 +270,7 @@ function stringifyData(arr: string[]) {
opacity: 0.9;
}
}
:deep(.BaseMarkdown) {
font-size: inherit;
}
</style>

0 comments on commit 8b86174

Please sign in to comment.