Skip to content

Commit de310c4

Browse files
committed
add markdown field
1 parent b6bc069 commit de310c4

6 files changed

Lines changed: 104 additions & 0 deletions

File tree

lib/Yancy/Editor/src/edit-form.svelte

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
JSONSchema7TypeName,
55
} from "json-schema";
66
import type { HTMLFormAttributes } from "svelte/elements";
7+
import MarkdownField from "./markdown-field.svelte";
78
89
function isNumberType(schema: JSONSchema): boolean {
910
const typeName =
@@ -99,6 +100,9 @@
99100
value={value[col.field]}
100101
disabled={col.schema.readOnly}
101102
/>
103+
{:else if col.schema.type == "string" && col.schema.format == "markdown"}
104+
<MarkdownField id="field-{col.field}" bind:value={value[col.field]}
105+
></MarkdownField>
102106
{:else if col.schema.type == "string" && col.schema.format == "date"}
103107
<input
104108
type="date"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<script lang="ts">
2+
import { marked } from "marked";
3+
let { id, value = $bindable("") }: { id: string; value: string } = $props();
4+
let showHtml: boolean = $state(false);
5+
</script>
6+
7+
<div>
8+
<div>
9+
<button
10+
onclick={() => {
11+
showHtml = !showHtml;
12+
}}>Preview</button
13+
>
14+
</div>
15+
<div>
16+
<textarea
17+
bind:value
18+
{id}
19+
class={showHtml ? "hidden" : ""}
20+
placeholder="Markdown content"
21+
></textarea>
22+
<div data-testid="markdown-preview" class={!showHtml ? "hidden" : ""}>
23+
{@html marked(value)}
24+
</div>
25+
</div>
26+
</div>
27+
28+
<style>
29+
.hidden {
30+
display: none;
31+
}
32+
</style>

package-lock.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@sveltejs/vite-plugin-svelte": "^6.2.4",
1818
"@testing-library/jest-dom": "^6.9.1",
1919
"@testing-library/svelte": "^5.3.1",
20+
"@testing-library/user-event": "^14.6.1",
2021
"@tsconfig/svelte": "^5.0.5",
2122
"@types/json-schema": "^7.0.15",
2223
"@types/node": "^24.10.0",

t/editor/edit-form.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ describe("EditForm", () => {
3737
},
3838
},
3939

40+
{
41+
title: "shows correct input for markdown string",
42+
schema: { type: "string", format: "markdown" },
43+
value: "stringValue",
44+
check: async (testCase: TestCase): Promise<void> => {
45+
const field = screen.getByLabelText("fieldName");
46+
expect(field).toBeVisible();
47+
expect(field).toBeInstanceOf(HTMLTextAreaElement);
48+
expect(field).toHaveValue(testCase.value);
49+
},
50+
},
51+
4052
{
4153
title: "shows correct input for string enum",
4254
schema: { type: "string", enum: ["enumOne", "enumTwo"] },

t/editor/markdown-field.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { render, screen } from "@testing-library/svelte";
2+
import userEvent from "@testing-library/user-event";
3+
import { expect, test, describe } from "vitest";
4+
5+
import MarkdownField from "../../lib/Yancy/Editor/src/markdown-field.svelte";
6+
7+
describe("MarkdownField", () => {
8+
test("shows markdown field", async () => {
9+
render(MarkdownField, { id: "mdfield", value: "# heading\n" });
10+
const field = screen.getByPlaceholderText("Markdown content");
11+
expect(field).toBeInstanceOf(HTMLTextAreaElement);
12+
expect(field).toHaveValue("# heading\n");
13+
14+
const button = screen.getByText("Preview");
15+
expect(button).toBeVisible();
16+
});
17+
test("preview button shows rendered markdown", async () => {
18+
render(MarkdownField, { id: "mdfield", value: "# heading\n\nbody" });
19+
screen.getByText("Preview").click();
20+
const preview = screen.getByTestId("markdown-preview");
21+
expect(preview).toBeVisible();
22+
expect(preview).toContainHTML("<h1>heading</h1>");
23+
});
24+
test("value is updated", async () => {
25+
const user = userEvent.setup();
26+
let value = "# heading\n\nbody";
27+
render(MarkdownField, {
28+
id: "mdfield",
29+
get value() {
30+
return value;
31+
},
32+
set value(nextValue) {
33+
value = nextValue;
34+
},
35+
});
36+
const field = screen.getByPlaceholderText("Markdown content");
37+
await user.type(field, "\n\n## second heading\n");
38+
expect(value).toMatch(/## second heading/);
39+
});
40+
});

0 commit comments

Comments
 (0)