From 57bc5b98283cf9edb205a858796f929979dcca61 Mon Sep 17 00:00:00 2001
From: Emma Hamilton
Date: Thu, 29 Aug 2024 12:19:16 +1000
Subject: [PATCH] Support ordered lists that don't start at 1 in
`fields.markdoc` and `fields.mdx`
---
.changeset/honest-seahorses-whisper.md | 5 ++
.../fields/markdoc/editor/inputrules/rules.ts | 6 +-
.../fields/markdoc/editor/markdoc/parse.ts | 8 ++-
.../markdoc/editor/markdoc/serialize.ts | 6 +-
.../form/fields/markdoc/editor/mdx/parse.ts | 6 +-
.../fields/markdoc/editor/mdx/serialize.ts | 1 +
.../src/form/fields/markdoc/editor/schema.tsx | 23 ++++++-
.../markdoc/editor/tests/lists.test.tsx | 68 ++++++++++++++++---
.../markdoc/editor/tests/markdoc.test.tsx | 17 ++++-
.../fields/markdoc/editor/tests/mdx.test.tsx | 17 ++++-
.../tests/pasting/from-other-editors.test.tsx | 32 ++++++---
.../editor/tests/pasting/markdown.test.tsx | 8 ++-
12 files changed, 167 insertions(+), 30 deletions(-)
create mode 100644 .changeset/honest-seahorses-whisper.md
diff --git a/.changeset/honest-seahorses-whisper.md b/.changeset/honest-seahorses-whisper.md
new file mode 100644
index 000000000..26907e370
--- /dev/null
+++ b/.changeset/honest-seahorses-whisper.md
@@ -0,0 +1,5 @@
+---
+'@keystatic/core': patch
+---
+
+Support ordered lists that don't start at 1 in `fields.markdoc` and `fields.mdx`
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/inputrules/rules.ts b/packages/keystatic/src/form/fields/markdoc/editor/inputrules/rules.ts
index ba7d13f68..53669f647 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/inputrules/rules.ts
+++ b/packages/keystatic/src/form/fields/markdoc/editor/inputrules/rules.ts
@@ -28,8 +28,10 @@ export function inputRulesForSchema({ nodes, marks, config }: EditorSchema) {
}
if (nodes.ordered_list) {
rules.push({
- pattern: /^\s*\d+(?:\.|\))\s$/,
- handler: wrappingInputRuleHandler(nodes.ordered_list),
+ pattern: /^\s*(\d+)(?:\.|\))\s$/,
+ handler: wrappingInputRuleHandler(nodes.ordered_list, match => ({
+ start: parseInt(match[1], 10),
+ })),
});
}
if (nodes.unordered_list) {
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/markdoc/parse.ts b/packages/keystatic/src/form/fields/markdoc/editor/markdoc/parse.ts
index e0bcd2cba..6e6f67b25 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/markdoc/parse.ts
+++ b/packages/keystatic/src/form/fields/markdoc/editor/markdoc/parse.ts
@@ -297,7 +297,13 @@ function markdocNodeToProseMirrorNode(
? schema.nodes.ordered_list
: schema.nodes.unordered_list;
if (!listType) return notAllowed(node, parentType);
- return createAndFill(node, listType, {});
+ return createAndFill(
+ node,
+ listType,
+ node.attributes.ordered && node.attributes.start !== undefined
+ ? { start: node.attributes.start }
+ : {}
+ );
}
if (node.type === 'table') {
if (!schema.nodes.table) return notAllowed(node, parentType);
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/markdoc/serialize.ts b/packages/keystatic/src/form/fields/markdoc/editor/markdoc/serialize.ts
index bec3f9d19..3831248fd 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/markdoc/serialize.ts
+++ b/packages/keystatic/src/form/fields/markdoc/editor/markdoc/serialize.ts
@@ -244,7 +244,11 @@ export function proseMirrorToMarkdoc(
return new Ast.Node('item', {}, listItemContent);
}
if (node.type === schema.nodes.ordered_list) {
- return new Ast.Node('list', { ordered: true }, blocks(node.content));
+ return new Ast.Node(
+ 'list',
+ { ordered: true, start: node.attrs.start },
+ blocks(node.content)
+ );
}
if (node.type === schema.nodes.unordered_list) {
return new Ast.Node('list', { ordered: false }, blocks(node.content));
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/mdx/parse.ts b/packages/keystatic/src/form/fields/markdoc/editor/mdx/parse.ts
index ebf38f1b6..13456fc96 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/mdx/parse.ts
+++ b/packages/keystatic/src/form/fields/markdoc/editor/mdx/parse.ts
@@ -318,7 +318,11 @@ function markdocNodeToProseMirrorNode(
? schema.nodes.ordered_list
: schema.nodes.unordered_list;
if (!listType) return notAllowed(node, parentType);
- return createAndFill(node, listType, {});
+ return createAndFill(
+ node,
+ listType,
+ node.ordered && node.start != null ? { start: node.start } : {}
+ );
}
if (node.type === 'table') {
if (!schema.nodes.table) return notAllowed(node, parentType);
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/mdx/serialize.ts b/packages/keystatic/src/form/fields/markdoc/editor/mdx/serialize.ts
index 988aff370..b596fdcec 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/mdx/serialize.ts
+++ b/packages/keystatic/src/form/fields/markdoc/editor/mdx/serialize.ts
@@ -249,6 +249,7 @@ function proseMirrorToMDX(
type: 'list',
ordered: true,
spread: false,
+ start: node.attrs.start,
children: mapContent(node, node => convertListItem(blocks(node.content))),
};
}
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/schema.tsx b/packages/keystatic/src/form/fields/markdoc/editor/schema.tsx
index 7c69f981e..cf5fc8c08 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/schema.tsx
+++ b/packages/keystatic/src/form/fields/markdoc/editor/schema.tsx
@@ -221,9 +221,26 @@ const nodeSpecs = {
ordered_list: {
content: 'list_item+',
group: 'block',
- parseDOM: [{ tag: 'ol' }],
- toDOM() {
- return olDOM;
+ attrs: {
+ start: { default: 1 },
+ },
+ parseDOM: [
+ {
+ tag: 'ol',
+ getAttrs: node => {
+ if (typeof node === 'string') {
+ return false;
+ }
+ if (!(node instanceof HTMLOListElement) || node.start < 0) {
+ return { start: 1 };
+ }
+ return { start: node.start };
+ },
+ },
+ ],
+ toDOM(node) {
+ if (node.attrs.start === 1) return olDOM;
+ return ['ol', { start: node.attrs.start }, 0];
},
insertMenu: {
label: 'Ordered list',
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/tests/lists.test.tsx b/packages/keystatic/src/form/fields/markdoc/editor/tests/lists.test.tsx
index a5e1a5e19..9491f7064 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/tests/lists.test.tsx
+++ b/packages/keystatic/src/form/fields/markdoc/editor/tests/lists.test.tsx
@@ -19,7 +19,37 @@ test('ordered list shortcut', async () => {
await user.keyboard(' ');
expect(state()).toMatchInlineSnapshot(`
-
+
+
+
+
+
+
+
+
+ `);
+});
+
+test('ordered list shortcut with different start', async () => {
+ const { state, user } = renderEditor(
+
+
+
+ 5.
+
+
+
+
+ );
+
+ await user.keyboard(' ');
+ expect(state()).toMatchInlineSnapshot(`
+
+
@@ -190,7 +220,9 @@ test('toggle list on empty line', async () => {
expect(state()).toMatchInlineSnapshot(`
-
+
@@ -219,7 +251,9 @@ test('toggle list on line with text', async () => {
expect(state()).toMatchInlineSnapshot(`
-
+
@@ -252,7 +286,9 @@ test('toggle list on line with text with marks', async () => {
expect(state()).toMatchInlineSnapshot(`
-
+
@@ -382,7 +418,9 @@ test('toggle ordered_list inside of multi-item ordered_list', async () => {
expect(state()).toMatchInlineSnapshot(`
-
+
@@ -397,7 +435,9 @@ test('toggle ordered_list inside of multi-item ordered_list', async () => {
-
+
@@ -572,7 +612,9 @@ test('backspace at start of list only unwraps the first item', async () => {
some text
-
+
@@ -788,7 +830,9 @@ test('changing the type of a nested list', async () => {
some text
-
+
@@ -846,14 +890,18 @@ test('changing the type of a nested list to something which it is nested inside'
top text
-
+
middle text
-
+
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/tests/markdoc.test.tsx b/packages/keystatic/src/form/fields/markdoc/editor/tests/markdoc.test.tsx
index a794f3c61..519b7c389 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/tests/markdoc.test.tsx
+++ b/packages/keystatic/src/form/fields/markdoc/editor/tests/markdoc.test.tsx
@@ -297,7 +297,9 @@ test('link in list', () => {
const editor = fromMarkdoc(markdoc);
expect(editor).toMatchInlineSnapshot(`
-
+
@@ -690,3 +692,16 @@ test('undefined in conditional value', () => {
"
`);
});
+
+test('ordered list with start', () => {
+ const markdoc = `5. a
+1. b
+1. c`;
+ const editor = fromMarkdoc(markdoc);
+ expect(toMarkdoc(editor)).toMatchInlineSnapshot(`
+ "5. a
+ 1. b
+ 1. c
+ "
+ `);
+});
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/tests/mdx.test.tsx b/packages/keystatic/src/form/fields/markdoc/editor/tests/mdx.test.tsx
index 24e1c5140..541b01ca3 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/tests/mdx.test.tsx
+++ b/packages/keystatic/src/form/fields/markdoc/editor/tests/mdx.test.tsx
@@ -303,7 +303,9 @@ test('link in list', () => {
const editor = fromMDX(mdx);
expect(editor).toMatchInlineSnapshot(`
-
+
@@ -1032,3 +1034,16 @@ test('loose list', () => {
"
`);
});
+
+test('ordered list with start', () => {
+ const mdx = `5. a
+1. b
+1. c`;
+ const editor = fromMDX(mdx);
+ expect(toMDX(editor)).toMatchInlineSnapshot(`
+ "5. a
+ 6. b
+ 7. c
+ "
+ `);
+});
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/tests/pasting/from-other-editors.test.tsx b/packages/keystatic/src/form/fields/markdoc/editor/tests/pasting/from-other-editors.test.tsx
index 04e11fe7c..0a65d8a32 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/tests/pasting/from-other-editors.test.tsx
+++ b/packages/keystatic/src/form/fields/markdoc/editor/tests/pasting/from-other-editors.test.tsx
@@ -187,7 +187,9 @@ test('confluence', async () => {
-
+
@@ -201,7 +203,9 @@ test('confluence', async () => {
item
-
+
@@ -435,7 +439,9 @@ there is a break before this
-
+
@@ -449,7 +455,9 @@ there is a break before this
item
-
+
@@ -604,7 +612,9 @@ test('dropbox paper', async () => {
-
+
@@ -618,7 +628,9 @@ test('dropbox paper', async () => {
item
-
+
@@ -803,7 +815,9 @@ test('google docs', async () => {
-
+
@@ -817,7 +831,9 @@ test('google docs', async () => {
item
-
+
diff --git a/packages/keystatic/src/form/fields/markdoc/editor/tests/pasting/markdown.test.tsx b/packages/keystatic/src/form/fields/markdoc/editor/tests/pasting/markdown.test.tsx
index da4d26ba6..e55156019 100644
--- a/packages/keystatic/src/form/fields/markdoc/editor/tests/pasting/markdown.test.tsx
+++ b/packages/keystatic/src/form/fields/markdoc/editor/tests/pasting/markdown.test.tsx
@@ -242,7 +242,9 @@ there is a break before this
-
+
@@ -256,7 +258,9 @@ there is a break before this
item
-
+