@payloadcms/richtext-lexical 3.84.0-canary.1 → 3.84.0-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,5 +2,19 @@
2
2
  * Code taken from https://github.com/facebook/lexical/blob/main/packages/lexical-markdown/src/MarkdownTransformers.ts#L357
3
3
  */
4
4
  import type { TextMatchTransformer } from '../../packages/@lexical/markdown/MarkdownTransformers.js';
5
+ import type { SerializedLinkNode } from './nodes/types.js';
6
+ export type CreateLinkMarkdownTransformerArgs = {
7
+ /**
8
+ * A function that receives a serialized internal link node and returns the URL string.
9
+ * Required for internal links (linkType === 'internal') to be exported correctly, since
10
+ * internal links store a doc reference rather than a URL.
11
+ *
12
+ * Without this, internal links will export as `[text]()` with an empty href.
13
+ */
14
+ internalDocToHref?: (args: {
15
+ linkNode: SerializedLinkNode;
16
+ }) => string;
17
+ };
18
+ export declare const createLinkMarkdownTransformer: (args?: CreateLinkMarkdownTransformerArgs) => TextMatchTransformer;
5
19
  export declare const LinkMarkdownTransformer: TextMatchTransformer;
6
20
  //# sourceMappingURL=markdownTransformer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdownTransformer.d.ts","sourceRoot":"","sources":["../../../src/features/link/markdownTransformer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0DAA0D,CAAA;AAKpG,eAAO,MAAM,uBAAuB,EAAE,oBAoCrC,CAAA"}
1
+ {"version":3,"file":"markdownTransformer.d.ts","sourceRoot":"","sources":["../../../src/features/link/markdownTransformer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0DAA0D,CAAA;AACpG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAO1D,MAAM,MAAM,iCAAiC,GAAG;IAC9C;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,kBAAkB,CAAA;KAAE,KAAK,MAAM,CAAA;CACvE,CAAA;AAoBD,eAAO,MAAM,6BAA6B,UACjC,iCAAiC,KACvC,oBAiCD,CAAA;AAEF,eAAO,MAAM,uBAAuB,EAAE,oBAAsD,CAAA"}
@@ -4,9 +4,25 @@
4
4
  //
5
5
  // - code should go first as it prevents any transformations inside
6
6
  import { $createTextNode } from 'lexical';
7
+ import { sanitizeUrl } from '../../lexical/utils/url.js';
7
8
  import { $createLinkNode, $isLinkNode, LinkNode } from './nodes/LinkNode.js';
8
- // - then longer tags match (e.g. ** or __ should go before * or _)
9
- export const LinkMarkdownTransformer = {
9
+ const replaceTransformer = (textNode, match) => {
10
+ const [, linkText, linkUrl] = match;
11
+ const linkNode = $createLinkNode({
12
+ fields: {
13
+ doc: null,
14
+ linkType: 'custom',
15
+ newTab: false,
16
+ url: linkUrl
17
+ }
18
+ });
19
+ const linkTextNode = $createTextNode(linkText);
20
+ linkTextNode.setFormat(textNode.getFormat());
21
+ linkNode.append(linkTextNode);
22
+ textNode.replace(linkNode);
23
+ return linkTextNode;
24
+ };
25
+ export const createLinkMarkdownTransformer = args => ({
10
26
  type: 'text-match',
11
27
  dependencies: [LinkNode],
12
28
  export: (_node, exportChildren) => {
@@ -14,31 +30,28 @@ export const LinkMarkdownTransformer = {
14
30
  return null;
15
31
  }
16
32
  const node = _node;
17
- const {
18
- url
19
- } = node.getFields();
33
+ const fields = node.getFields();
34
+ let url;
35
+ if (fields.linkType === 'internal') {
36
+ if (args?.internalDocToHref) {
37
+ url = sanitizeUrl(args.internalDocToHref({
38
+ linkNode: node.exportJSON()
39
+ }));
40
+ } else {
41
+ // eslint-disable-next-line no-console
42
+ console.warn('Lexical → Markdown converter: found internal link but internalDocToHref is not provided — link will have an empty href');
43
+ url = '';
44
+ }
45
+ } else {
46
+ url = sanitizeUrl(fields.url ?? '');
47
+ }
20
48
  const textContent = exportChildren(node);
21
- const linkContent = `[${textContent}](${url})`;
22
- return linkContent;
49
+ return `[${textContent}](${url})`;
23
50
  },
24
51
  importRegExp: /(?<!!)\[([^[]+)\]\(([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?\)/,
25
52
  regExp: /(?<!!)\[([^[]+)\]\(([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?\)$/,
26
- replace: (textNode, match) => {
27
- const [, linkText, linkUrl] = match;
28
- const linkNode = $createLinkNode({
29
- fields: {
30
- doc: null,
31
- linkType: 'custom',
32
- newTab: false,
33
- url: linkUrl
34
- }
35
- });
36
- const linkTextNode = $createTextNode(linkText);
37
- linkTextNode.setFormat(textNode.getFormat());
38
- linkNode.append(linkTextNode);
39
- textNode.replace(linkNode);
40
- return linkTextNode;
41
- },
53
+ replace: replaceTransformer,
42
54
  trigger: ')'
43
- };
55
+ });
56
+ export const LinkMarkdownTransformer = createLinkMarkdownTransformer();
44
57
  //# sourceMappingURL=markdownTransformer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdownTransformer.js","names":["$createTextNode","$createLinkNode","$isLinkNode","LinkNode","LinkMarkdownTransformer","type","dependencies","export","_node","exportChildren","node","url","getFields","textContent","linkContent","importRegExp","regExp","replace","textNode","match","linkText","linkUrl","linkNode","fields","doc","linkType","newTab","linkTextNode","setFormat","getFormat","append","trigger"],"sources":["../../../src/features/link/markdownTransformer.ts"],"sourcesContent":["/**\n * Code taken from https://github.com/facebook/lexical/blob/main/packages/lexical-markdown/src/MarkdownTransformers.ts#L357\n */\n\n// Order of text transformers matters:\n//\n// - code should go first as it prevents any transformations inside\n\nimport { $createTextNode, $isTextNode } from 'lexical'\n\nimport type { TextMatchTransformer } from '../../packages/@lexical/markdown/MarkdownTransformers.js'\n\nimport { $createLinkNode, $isLinkNode, LinkNode } from './nodes/LinkNode.js'\n\n// - then longer tags match (e.g. ** or __ should go before * or _)\nexport const LinkMarkdownTransformer: TextMatchTransformer = {\n type: 'text-match',\n dependencies: [LinkNode],\n export: (_node, exportChildren) => {\n if (!$isLinkNode(_node)) {\n return null\n }\n const node: LinkNode = _node\n const { url } = node.getFields()\n\n const textContent = exportChildren(node)\n\n const linkContent = `[${textContent}](${url})`\n\n return linkContent\n },\n importRegExp: /(?<!!)\\[([^[]+)\\]\\(([^()\\s]+)(?:\\s\"((?:[^\"]*\\\\\")*[^\"]*)\"\\s*)?\\)/,\n regExp: /(?<!!)\\[([^[]+)\\]\\(([^()\\s]+)(?:\\s\"((?:[^\"]*\\\\\")*[^\"]*)\"\\s*)?\\)$/,\n replace: (textNode, match) => {\n const [, linkText, linkUrl] = match\n const linkNode = $createLinkNode({\n fields: {\n doc: null,\n linkType: 'custom',\n newTab: false,\n url: linkUrl,\n },\n })\n const linkTextNode = $createTextNode(linkText)\n linkTextNode.setFormat(textNode.getFormat())\n linkNode.append(linkTextNode)\n textNode.replace(linkNode)\n\n return linkTextNode\n },\n trigger: ')',\n}\n"],"mappings":"AAAA;;GAAA,CAIA;AACA;AACA;AAEA,SAASA,eAAe,QAAqB;AAI7C,SAASC,eAAe,EAAEC,WAAW,EAAEC,QAAQ,QAAQ;AAEvD;AACA,OAAO,MAAMC,uBAAA,GAAgD;EAC3DC,IAAA,EAAM;EACNC,YAAA,EAAc,CAACH,QAAA,CAAS;EACxBI,MAAA,EAAQA,CAACC,KAAA,EAAOC,cAAA;IACd,IAAI,CAACP,WAAA,CAAYM,KAAA,GAAQ;MACvB,OAAO;IACT;IACA,MAAME,IAAA,GAAiBF,KAAA;IACvB,MAAM;MAAEG;IAAG,CAAE,GAAGD,IAAA,CAAKE,SAAS;IAE9B,MAAMC,WAAA,GAAcJ,cAAA,CAAeC,IAAA;IAEnC,MAAMI,WAAA,GAAc,IAAID,WAAA,KAAgBF,GAAA,GAAM;IAE9C,OAAOG,WAAA;EACT;EACAC,YAAA,EAAc;EACdC,MAAA,EAAQ;EACRC,OAAA,EAASA,CAACC,QAAA,EAAUC,KAAA;IAClB,MAAM,GAAGC,QAAA,EAAUC,OAAA,CAAQ,GAAGF,KAAA;IAC9B,MAAMG,QAAA,GAAWrB,eAAA,CAAgB;MAC/BsB,MAAA,EAAQ;QACNC,GAAA,EAAK;QACLC,QAAA,EAAU;QACVC,MAAA,EAAQ;QACRf,GAAA,EAAKU;MACP;IACF;IACA,MAAMM,YAAA,GAAe3B,eAAA,CAAgBoB,QAAA;IACrCO,YAAA,CAAaC,SAAS,CAACV,QAAA,CAASW,SAAS;IACzCP,QAAA,CAASQ,MAAM,CAACH,YAAA;IAChBT,QAAA,CAASD,OAAO,CAACK,QAAA;IAEjB,OAAOK,YAAA;EACT;EACAI,OAAA,EAAS;AACX","ignoreList":[]}
1
+ {"version":3,"file":"markdownTransformer.js","names":["$createTextNode","sanitizeUrl","$createLinkNode","$isLinkNode","LinkNode","replaceTransformer","textNode","match","linkText","linkUrl","linkNode","fields","doc","linkType","newTab","url","linkTextNode","setFormat","getFormat","append","replace","createLinkMarkdownTransformer","args","type","dependencies","export","_node","exportChildren","node","getFields","internalDocToHref","exportJSON","console","warn","textContent","importRegExp","regExp","trigger","LinkMarkdownTransformer"],"sources":["../../../src/features/link/markdownTransformer.ts"],"sourcesContent":["/**\n * Code taken from https://github.com/facebook/lexical/blob/main/packages/lexical-markdown/src/MarkdownTransformers.ts#L357\n */\n\n// Order of text transformers matters:\n//\n// - code should go first as it prevents any transformations inside\n\nimport { $createTextNode, $isTextNode } from 'lexical'\n\nimport type { TextMatchTransformer } from '../../packages/@lexical/markdown/MarkdownTransformers.js'\nimport type { SerializedLinkNode } from './nodes/types.js'\n\nimport { sanitizeUrl } from '../../lexical/utils/url.js'\nimport { $createLinkNode, $isLinkNode, LinkNode } from './nodes/LinkNode.js'\n\n// - then longer tags match (e.g. ** or __ should go before * or _)\n\nexport type CreateLinkMarkdownTransformerArgs = {\n /**\n * A function that receives a serialized internal link node and returns the URL string.\n * Required for internal links (linkType === 'internal') to be exported correctly, since\n * internal links store a doc reference rather than a URL.\n *\n * Without this, internal links will export as `[text]()` with an empty href.\n */\n internalDocToHref?: (args: { linkNode: SerializedLinkNode }) => string\n}\n\nconst replaceTransformer: TextMatchTransformer['replace'] = (textNode, match) => {\n const [, linkText, linkUrl] = match\n const linkNode = $createLinkNode({\n fields: {\n doc: null,\n linkType: 'custom',\n newTab: false,\n url: linkUrl,\n },\n })\n const linkTextNode = $createTextNode(linkText)\n linkTextNode.setFormat(textNode.getFormat())\n linkNode.append(linkTextNode)\n textNode.replace(linkNode)\n\n return linkTextNode\n}\n\nexport const createLinkMarkdownTransformer = (\n args?: CreateLinkMarkdownTransformerArgs,\n): TextMatchTransformer => ({\n type: 'text-match',\n dependencies: [LinkNode],\n export: (_node, exportChildren) => {\n if (!$isLinkNode(_node)) {\n return null\n }\n const node: LinkNode = _node\n const fields = node.getFields()\n\n let url: string\n\n if (fields.linkType === 'internal') {\n if (args?.internalDocToHref) {\n url = sanitizeUrl(args.internalDocToHref({ linkNode: node.exportJSON() }))\n } else {\n // eslint-disable-next-line no-console\n console.warn(\n 'Lexical → Markdown converter: found internal link but internalDocToHref is not provided — link will have an empty href',\n )\n url = ''\n }\n } else {\n url = sanitizeUrl(fields.url ?? '')\n }\n\n const textContent = exportChildren(node)\n return `[${textContent}](${url})`\n },\n importRegExp: /(?<!!)\\[([^[]+)\\]\\(([^()\\s]+)(?:\\s\"((?:[^\"]*\\\\\")*[^\"]*)\"\\s*)?\\)/,\n regExp: /(?<!!)\\[([^[]+)\\]\\(([^()\\s]+)(?:\\s\"((?:[^\"]*\\\\\")*[^\"]*)\"\\s*)?\\)$/,\n replace: replaceTransformer,\n trigger: ')',\n})\n\nexport const LinkMarkdownTransformer: TextMatchTransformer = createLinkMarkdownTransformer()\n"],"mappings":"AAAA;;GAAA,CAIA;AACA;AACA;AAEA,SAASA,eAAe,QAAqB;AAK7C,SAASC,WAAW,QAAQ;AAC5B,SAASC,eAAe,EAAEC,WAAW,EAAEC,QAAQ,QAAQ;AAevD,MAAMC,kBAAA,GAAsDA,CAACC,QAAA,EAAUC,KAAA;EACrE,MAAM,GAAGC,QAAA,EAAUC,OAAA,CAAQ,GAAGF,KAAA;EAC9B,MAAMG,QAAA,GAAWR,eAAA,CAAgB;IAC/BS,MAAA,EAAQ;MACNC,GAAA,EAAK;MACLC,QAAA,EAAU;MACVC,MAAA,EAAQ;MACRC,GAAA,EAAKN;IACP;EACF;EACA,MAAMO,YAAA,GAAehB,eAAA,CAAgBQ,QAAA;EACrCQ,YAAA,CAAaC,SAAS,CAACX,QAAA,CAASY,SAAS;EACzCR,QAAA,CAASS,MAAM,CAACH,YAAA;EAChBV,QAAA,CAASc,OAAO,CAACV,QAAA;EAEjB,OAAOM,YAAA;AACT;AAEA,OAAO,MAAMK,6BAAA,GACXC,IAAA,KAC0B;EAC1BC,IAAA,EAAM;EACNC,YAAA,EAAc,CAACpB,QAAA,CAAS;EACxBqB,MAAA,EAAQA,CAACC,KAAA,EAAOC,cAAA;IACd,IAAI,CAACxB,WAAA,CAAYuB,KAAA,GAAQ;MACvB,OAAO;IACT;IACA,MAAME,IAAA,GAAiBF,KAAA;IACvB,MAAMf,MAAA,GAASiB,IAAA,CAAKC,SAAS;IAE7B,IAAId,GAAA;IAEJ,IAAIJ,MAAA,CAAOE,QAAQ,KAAK,YAAY;MAClC,IAAIS,IAAA,EAAMQ,iBAAA,EAAmB;QAC3Bf,GAAA,GAAMd,WAAA,CAAYqB,IAAA,CAAKQ,iBAAiB,CAAC;UAAEpB,QAAA,EAAUkB,IAAA,CAAKG,UAAU;QAAG;MACzE,OAAO;QACL;QACAC,OAAA,CAAQC,IAAI,CACV;QAEFlB,GAAA,GAAM;MACR;IACF,OAAO;MACLA,GAAA,GAAMd,WAAA,CAAYU,MAAA,CAAOI,GAAG,IAAI;IAClC;IAEA,MAAMmB,WAAA,GAAcP,cAAA,CAAeC,IAAA;IACnC,OAAO,IAAIM,WAAA,KAAgBnB,GAAA,GAAM;EACnC;EACAoB,YAAA,EAAc;EACdC,MAAA,EAAQ;EACRhB,OAAA,EAASf,kBAAA;EACTgC,OAAA,EAAS;AACX;AAEA,OAAO,MAAMC,uBAAA,GAAgDjB,6BAAA","ignoreList":[]}
@@ -0,0 +1,195 @@
1
+ import { createHeadlessEditor } from '@lexical/headless';
2
+ import { $createParagraphNode, $createTextNode, $getRoot } from 'lexical';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { $convertToMarkdownString } from '../../packages/@lexical/markdown/index.js';
5
+ import { AutoLinkNode } from './nodes/AutoLinkNode.js';
6
+ import { $createLinkNode, LinkNode } from './nodes/LinkNode.js';
7
+ import { LinkMarkdownTransformer, createLinkMarkdownTransformer } from './markdownTransformer.js';
8
+ function createEditor() {
9
+ return createHeadlessEditor({
10
+ nodes: [LinkNode, AutoLinkNode]
11
+ });
12
+ }
13
+ function toMarkdown(setupFn, transformer = LinkMarkdownTransformer) {
14
+ const editor = createEditor();
15
+ editor.update(setupFn, {
16
+ discrete: true
17
+ });
18
+ let markdown = '';
19
+ editor.getEditorState().read(() => {
20
+ markdown = $convertToMarkdownString([transformer]);
21
+ });
22
+ return markdown;
23
+ }
24
+ describe('createLinkMarkdownTransformer', () => {
25
+ describe('custom links', () => {
26
+ it('should export a custom link with its url', () => {
27
+ const markdown = toMarkdown(() => {
28
+ const link = $createLinkNode({
29
+ fields: {
30
+ linkType: 'custom',
31
+ url: 'https://payloadcms.com',
32
+ newTab: false,
33
+ doc: null
34
+ }
35
+ });
36
+ link.append($createTextNode('Payload'));
37
+ $getRoot().append($createParagraphNode().append(link));
38
+ });
39
+ expect(markdown).toBe('[Payload](https://payloadcms.com)');
40
+ });
41
+ it('should export a custom link that opens in a new tab', () => {
42
+ // newTab is a Payload field — markdown has no equivalent, so it is intentionally dropped
43
+ const markdown = toMarkdown(() => {
44
+ const link = $createLinkNode({
45
+ fields: {
46
+ linkType: 'custom',
47
+ url: 'https://payloadcms.com',
48
+ newTab: true,
49
+ doc: null
50
+ }
51
+ });
52
+ link.append($createTextNode('Payload'));
53
+ $getRoot().append($createParagraphNode().append(link));
54
+ });
55
+ expect(markdown).toBe('[Payload](https://payloadcms.com)');
56
+ });
57
+ it('should produce an empty href when url is null or undefined', () => {
58
+ const markdownNull = toMarkdown(() => {
59
+ const link = $createLinkNode({
60
+ fields: {
61
+ linkType: 'custom',
62
+ url: null,
63
+ newTab: false,
64
+ doc: null
65
+ }
66
+ });
67
+ link.append($createTextNode('Broken'));
68
+ $getRoot().append($createParagraphNode().append(link));
69
+ });
70
+ const markdownUndefined = toMarkdown(() => {
71
+ const link = $createLinkNode({
72
+ fields: {
73
+ linkType: 'custom',
74
+ newTab: false,
75
+ doc: null
76
+ }
77
+ });
78
+ link.append($createTextNode('Broken'));
79
+ $getRoot().append($createParagraphNode().append(link));
80
+ });
81
+ expect(markdownNull).toBe('[Broken]()');
82
+ expect(markdownUndefined).toBe('[Broken]()');
83
+ });
84
+ });
85
+ describe('internal links', () => {
86
+ it('should export an empty href when no internalDocToHref is provided', () => {
87
+ const markdown = toMarkdown(() => {
88
+ const link = $createLinkNode({
89
+ fields: {
90
+ linkType: 'internal',
91
+ doc: {
92
+ relationTo: 'pages',
93
+ value: {
94
+ id: '1',
95
+ slug: 'about'
96
+ }
97
+ },
98
+ newTab: false
99
+ }
100
+ });
101
+ link.append($createTextNode('About'));
102
+ $getRoot().append($createParagraphNode().append(link));
103
+ });
104
+ expect(markdown).toBe('[About]()');
105
+ });
106
+ it('should call internalDocToHref and use the returned url', () => {
107
+ const transformer = createLinkMarkdownTransformer({
108
+ internalDocToHref: ({
109
+ linkNode
110
+ }) => {
111
+ const value = linkNode.fields.doc?.value;
112
+ if (value && typeof value === 'object' && 'slug' in value) {
113
+ return `/${value.slug}`;
114
+ }
115
+ return '/';
116
+ }
117
+ });
118
+ const markdown = toMarkdown(() => {
119
+ const link = $createLinkNode({
120
+ fields: {
121
+ linkType: 'internal',
122
+ doc: {
123
+ relationTo: 'pages',
124
+ value: {
125
+ id: '1',
126
+ slug: 'about'
127
+ }
128
+ },
129
+ newTab: false
130
+ }
131
+ });
132
+ link.append($createTextNode('About'));
133
+ $getRoot().append($createParagraphNode().append(link));
134
+ }, transformer);
135
+ expect(markdown).toBe('[About](/about)');
136
+ });
137
+ it('should pass the full serialized link node to internalDocToHref', () => {
138
+ let capturedLinkNode = null;
139
+ const transformer = createLinkMarkdownTransformer({
140
+ internalDocToHref: ({
141
+ linkNode
142
+ }) => {
143
+ capturedLinkNode = linkNode;
144
+ return '/captured';
145
+ }
146
+ });
147
+ toMarkdown(() => {
148
+ const link = $createLinkNode({
149
+ fields: {
150
+ linkType: 'internal',
151
+ doc: {
152
+ relationTo: 'pages',
153
+ value: {
154
+ id: '42',
155
+ title: 'Home'
156
+ }
157
+ },
158
+ newTab: true
159
+ }
160
+ });
161
+ link.append($createTextNode('Home'));
162
+ $getRoot().append($createParagraphNode().append(link));
163
+ }, transformer);
164
+ expect(capturedLinkNode).not.toBeNull();
165
+ expect(capturedLinkNode.fields.linkType).toBe('internal');
166
+ expect(capturedLinkNode.fields.doc?.relationTo).toBe('pages');
167
+ expect(capturedLinkNode.fields.doc?.value).toMatchObject({
168
+ id: '42',
169
+ title: 'Home'
170
+ });
171
+ expect(capturedLinkNode.fields.newTab).toBe(true);
172
+ });
173
+ });
174
+ describe('LinkMarkdownTransformer (static export)', () => {
175
+ it('should behave identically to createLinkMarkdownTransformer() with no args', () => {
176
+ const setup = () => {
177
+ const link = $createLinkNode({
178
+ fields: {
179
+ linkType: 'custom',
180
+ url: 'https://example.com',
181
+ newTab: false,
182
+ doc: null
183
+ }
184
+ });
185
+ link.append($createTextNode('Example'));
186
+ $getRoot().append($createParagraphNode().append(link));
187
+ };
188
+ const fromStatic = toMarkdown(setup, LinkMarkdownTransformer);
189
+ const fromFactory = toMarkdown(setup, createLinkMarkdownTransformer());
190
+ expect(fromStatic).toBe(fromFactory);
191
+ expect(fromStatic).toBe('[Example](https://example.com)');
192
+ });
193
+ });
194
+ });
195
+ //# sourceMappingURL=markdownTransformer.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownTransformer.spec.js","names":["createHeadlessEditor","$createParagraphNode","$createTextNode","$getRoot","describe","expect","it","$convertToMarkdownString","AutoLinkNode","$createLinkNode","LinkNode","LinkMarkdownTransformer","createLinkMarkdownTransformer","createEditor","nodes","toMarkdown","setupFn","transformer","editor","update","discrete","markdown","getEditorState","read","link","fields","linkType","url","newTab","doc","append","toBe","markdownNull","markdownUndefined","relationTo","value","id","slug","internalDocToHref","linkNode","capturedLinkNode","title","not","toBeNull","toMatchObject","setup","fromStatic","fromFactory"],"sources":["../../../src/features/link/markdownTransformer.spec.ts"],"sourcesContent":["import { createHeadlessEditor } from '@lexical/headless'\nimport { $createParagraphNode, $createTextNode, $getRoot } from 'lexical'\nimport { describe, expect, it } from 'vitest'\n\nimport { $convertToMarkdownString } from '../../packages/@lexical/markdown/index.js'\nimport { AutoLinkNode } from './nodes/AutoLinkNode.js'\nimport { $createLinkNode, LinkNode } from './nodes/LinkNode.js'\nimport type { SerializedLinkNode } from './nodes/types.js'\nimport { LinkMarkdownTransformer, createLinkMarkdownTransformer } from './markdownTransformer.js'\n\nfunction createEditor() {\n return createHeadlessEditor({ nodes: [LinkNode, AutoLinkNode] })\n}\n\nfunction toMarkdown(setupFn: () => void, transformer = LinkMarkdownTransformer): string {\n const editor = createEditor()\n editor.update(setupFn, { discrete: true })\n let markdown = ''\n editor.getEditorState().read(() => {\n markdown = $convertToMarkdownString([transformer])\n })\n return markdown\n}\n\ndescribe('createLinkMarkdownTransformer', () => {\n describe('custom links', () => {\n it('should export a custom link with its url', () => {\n const markdown = toMarkdown(() => {\n const link = $createLinkNode({\n fields: { linkType: 'custom', url: 'https://payloadcms.com', newTab: false, doc: null },\n })\n link.append($createTextNode('Payload'))\n $getRoot().append($createParagraphNode().append(link))\n })\n\n expect(markdown).toBe('[Payload](https://payloadcms.com)')\n })\n\n it('should export a custom link that opens in a new tab', () => {\n // newTab is a Payload field — markdown has no equivalent, so it is intentionally dropped\n const markdown = toMarkdown(() => {\n const link = $createLinkNode({\n fields: { linkType: 'custom', url: 'https://payloadcms.com', newTab: true, doc: null },\n })\n link.append($createTextNode('Payload'))\n $getRoot().append($createParagraphNode().append(link))\n })\n\n expect(markdown).toBe('[Payload](https://payloadcms.com)')\n })\n\n it('should produce an empty href when url is null or undefined', () => {\n const markdownNull = toMarkdown(() => {\n const link = $createLinkNode({\n fields: { linkType: 'custom', url: null as unknown as string, newTab: false, doc: null },\n })\n link.append($createTextNode('Broken'))\n $getRoot().append($createParagraphNode().append(link))\n })\n\n const markdownUndefined = toMarkdown(() => {\n const link = $createLinkNode({\n fields: { linkType: 'custom', newTab: false, doc: null },\n })\n link.append($createTextNode('Broken'))\n $getRoot().append($createParagraphNode().append(link))\n })\n\n expect(markdownNull).toBe('[Broken]()')\n expect(markdownUndefined).toBe('[Broken]()')\n })\n })\n\n describe('internal links', () => {\n it('should export an empty href when no internalDocToHref is provided', () => {\n const markdown = toMarkdown(() => {\n const link = $createLinkNode({\n fields: {\n linkType: 'internal',\n doc: { relationTo: 'pages', value: { id: '1', slug: 'about' } },\n newTab: false,\n },\n })\n link.append($createTextNode('About'))\n $getRoot().append($createParagraphNode().append(link))\n })\n\n expect(markdown).toBe('[About]()')\n })\n\n it('should call internalDocToHref and use the returned url', () => {\n const transformer = createLinkMarkdownTransformer({\n internalDocToHref: ({ linkNode }) => {\n const value = linkNode.fields.doc?.value\n if (value && typeof value === 'object' && 'slug' in value) {\n return `/${value.slug}`\n }\n return '/'\n },\n })\n\n const markdown = toMarkdown(() => {\n const link = $createLinkNode({\n fields: {\n linkType: 'internal',\n doc: { relationTo: 'pages', value: { id: '1', slug: 'about' } },\n newTab: false,\n },\n })\n link.append($createTextNode('About'))\n $getRoot().append($createParagraphNode().append(link))\n }, transformer)\n\n expect(markdown).toBe('[About](/about)')\n })\n\n it('should pass the full serialized link node to internalDocToHref', () => {\n let capturedLinkNode: SerializedLinkNode | null = null\n\n const transformer = createLinkMarkdownTransformer({\n internalDocToHref: ({ linkNode }) => {\n capturedLinkNode = linkNode\n return '/captured'\n },\n })\n\n toMarkdown(() => {\n const link = $createLinkNode({\n fields: {\n linkType: 'internal',\n doc: { relationTo: 'pages', value: { id: '42', title: 'Home' } },\n newTab: true,\n },\n })\n link.append($createTextNode('Home'))\n $getRoot().append($createParagraphNode().append(link))\n }, transformer)\n\n expect(capturedLinkNode).not.toBeNull()\n expect(capturedLinkNode!.fields.linkType).toBe('internal')\n expect(capturedLinkNode!.fields.doc?.relationTo).toBe('pages')\n expect(capturedLinkNode!.fields.doc?.value).toMatchObject({ id: '42', title: 'Home' })\n expect(capturedLinkNode!.fields.newTab).toBe(true)\n })\n })\n\n describe('LinkMarkdownTransformer (static export)', () => {\n it('should behave identically to createLinkMarkdownTransformer() with no args', () => {\n const setup = () => {\n const link = $createLinkNode({\n fields: { linkType: 'custom', url: 'https://example.com', newTab: false, doc: null },\n })\n link.append($createTextNode('Example'))\n $getRoot().append($createParagraphNode().append(link))\n }\n\n const fromStatic = toMarkdown(setup, LinkMarkdownTransformer)\n const fromFactory = toMarkdown(setup, createLinkMarkdownTransformer())\n\n expect(fromStatic).toBe(fromFactory)\n expect(fromStatic).toBe('[Example](https://example.com)')\n })\n })\n})\n"],"mappings":"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","ignoreList":[]}
@@ -1,5 +1,6 @@
1
1
  import type { CollectionSlug, Field, FieldAffectingData, SanitizedConfig } from 'payload';
2
2
  import type { ClientProps } from '../client/index.js';
3
+ import type { SerializedLinkNode } from '../nodes/types.js';
3
4
  export type ExclusiveLinkCollectionsProps = {
4
5
  /**
5
6
  * The collections that should be disabled for internal linking. Overrides the `enableRichTextLink` property in the collection config.
@@ -34,6 +35,14 @@ export type LinkFeatureServerProps = {
34
35
  config: SanitizedConfig;
35
36
  defaultFields: FieldAffectingData[];
36
37
  }) => (Field | FieldAffectingData)[]) | Field[];
38
+ /**
39
+ * Resolves an internal link node to a URL string for use in the markdown converter.
40
+ * Internal links store a doc reference rather than a URL, so without this the markdown
41
+ * output will have an empty href: `[link text]()`.
42
+ */
43
+ internalDocToHref?: (args: {
44
+ linkNode: SerializedLinkNode;
45
+ }) => string;
37
46
  /**
38
47
  * Sets a maximum population depth for the internal doc default field of link, regardless of the remaining depth when the field is reached.
39
48
  * This behaves exactly like the maxDepth properties of relationship and upload fields.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/features/link/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAEd,KAAK,EACL,kBAAkB,EAElB,eAAe,EAChB,MAAM,SAAS,CAAA;AAMhB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAarD,MAAM,MAAM,6BAA6B,GACrC;IACE;;;QAGI;IACJ,mBAAmB,CAAC,EAAE,cAAc,EAAE,CAAA;IAGtC,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAC3B,GACD;IAEE,mBAAmB,CAAC,EAAE,KAAK,CAAA;IAE3B;;;QAGI;IACJ,kBAAkB,CAAC,EAAE,cAAc,EAAE,CAAA;CACtC,CAAA;AAEL,MAAM,MAAM,sBAAsB,GAAG;IACnC;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;IACxC;;;OAGG;IACH,MAAM,CAAC,EACH,CAAC,CAAC,IAAI,EAAE;QACN,MAAM,EAAE,eAAe,CAAA;QACvB,aAAa,EAAE,kBAAkB,EAAE,CAAA;KACpC,KAAK,CAAC,KAAK,GAAG,kBAAkB,CAAC,EAAE,CAAC,GACrC,KAAK,EAAE,CAAA;IACX;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,GAAG,6BAA6B,CAAA;AAEjC,eAAO,MAAM,WAAW,2HA0LtB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/features/link/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAEd,KAAK,EACL,kBAAkB,EAElB,eAAe,EAChB,MAAM,SAAS,CAAA;AAMhB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAa3D,MAAM,MAAM,6BAA6B,GACrC;IACE;;;QAGI;IACJ,mBAAmB,CAAC,EAAE,cAAc,EAAE,CAAA;IAGtC,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAC3B,GACD;IAEE,mBAAmB,CAAC,EAAE,KAAK,CAAA;IAE3B;;;QAGI;IACJ,kBAAkB,CAAC,EAAE,cAAc,EAAE,CAAA;CACtC,CAAA;AAEL,MAAM,MAAM,sBAAsB,GAAG;IACnC;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;IACxC;;;OAGG;IACH,MAAM,CAAC,EACH,CAAC,CAAC,IAAI,EAAE;QACN,MAAM,EAAE,eAAe,CAAA;QACvB,aAAa,EAAE,kBAAkB,EAAE,CAAA;KACpC,KAAK,CAAC,KAAK,GAAG,kBAAkB,CAAC,EAAE,CAAC,GACrC,KAAK,EAAE,CAAA;IACX;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,kBAAkB,CAAA;KAAE,KAAK,MAAM,CAAA;IACtE;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,GAAG,6BAA6B,CAAA;AAEjC,eAAO,MAAM,WAAW,2HA4LtB,CAAA"}
@@ -3,7 +3,7 @@ import { sanitizeFields } from 'payload';
3
3
  import { createServerFeature } from '../../../utilities/createServerFeature.js';
4
4
  import { convertLexicalNodesToHTML } from '../../converters/lexicalToHtml_deprecated/converter/index.js';
5
5
  import { createNode } from '../../typeUtilities.js';
6
- import { LinkMarkdownTransformer } from '../markdownTransformer.js';
6
+ import { createLinkMarkdownTransformer } from '../markdownTransformer.js';
7
7
  import { AutoLinkNode } from '../nodes/AutoLinkNode.js';
8
8
  import { LinkNode } from '../nodes/LinkNode.js';
9
9
  import { linkPopulationPromiseHOC } from './graphQLPopulationPromise.js';
@@ -66,7 +66,9 @@ export const LinkFeature = createServerFeature({
66
66
  return schemaMap;
67
67
  },
68
68
  i18n,
69
- markdownTransformers: [LinkMarkdownTransformer],
69
+ markdownTransformers: [createLinkMarkdownTransformer({
70
+ internalDocToHref: props.internalDocToHref
71
+ })],
70
72
  nodes: [props?.disableAutoLinks === true ? null : createNode({
71
73
  converters: {
72
74
  html: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["escapeHTML","sanitizeFields","createServerFeature","convertLexicalNodesToHTML","createNode","LinkMarkdownTransformer","AutoLinkNode","LinkNode","linkPopulationPromiseHOC","i18n","transformExtraFields","linkValidation","LinkFeature","feature","config","_config","isRoot","parentIsLocalized","props","validRelationships","collections","map","c","slug","_transformedFields","fields","enabledCollections","disabledCollections","maxDepth","sanitizedFields","requireFieldLevelRichTextEditor","sanitizedFieldsWithoutText","filter","field","name","linkTypeField","linkURLField","defaultLinkType","defaultValue","undefined","defaultLinkURL","ClientFeature","clientFeatureProps","disableAutoLinks","generateSchemaMap","Array","isArray","length","schemaMap","Map","set","markdownTransformers","nodes","converters","html","converter","currentDepth","depth","draft","node","overrideAccess","parent","req","showHiddenFields","childrenText","lexicalNodes","children","href","url","linkType","doc","value","String","id","newTab","nodeTypes","getType","validations","getSubFields","getSubFieldsData","graphQLPopulationPromises","Boolean","sanitizedServerFeatureProps","key"],"sources":["../../../../src/features/link/server/index.ts"],"sourcesContent":["import type {\n CollectionSlug,\n Config,\n Field,\n FieldAffectingData,\n FieldSchemaMap,\n SanitizedConfig,\n} from 'payload'\n\nimport escapeHTML from 'escape-html'\nimport { sanitizeFields } from 'payload'\n\nimport type { NodeWithHooks } from '../../typesServer.js'\nimport type { ClientProps } from '../client/index.js'\n\nimport { createServerFeature } from '../../../utilities/createServerFeature.js'\nimport { convertLexicalNodesToHTML } from '../../converters/lexicalToHtml_deprecated/converter/index.js'\nimport { createNode } from '../../typeUtilities.js'\nimport { LinkMarkdownTransformer } from '../markdownTransformer.js'\nimport { AutoLinkNode } from '../nodes/AutoLinkNode.js'\nimport { LinkNode } from '../nodes/LinkNode.js'\nimport { linkPopulationPromiseHOC } from './graphQLPopulationPromise.js'\nimport { i18n } from './i18n.js'\nimport { transformExtraFields } from './transformExtraFields.js'\nimport { linkValidation } from './validate.js'\n\nexport type ExclusiveLinkCollectionsProps =\n | {\n /**\n * The collections that should be disabled for internal linking. Overrides the `enableRichTextLink` property in the collection config.\n * When this property is set, `enabledCollections` will not be available.\n **/\n disabledCollections?: CollectionSlug[]\n\n // Ensures that enabledCollections is not available when disabledCollections is set\n enabledCollections?: never\n }\n | {\n // Ensures that disabledCollections is not available when enabledCollections is set\n disabledCollections?: never\n\n /**\n * The collections that should be enabled for internal linking. Overrides the `enableRichTextLink` property in the collection config\n * When this property is set, `disabledCollections` will not be available.\n **/\n enabledCollections?: CollectionSlug[]\n }\n\nexport type LinkFeatureServerProps = {\n /**\n * Disables the automatic creation of links from URLs pasted into the editor, as well\n * as auto link nodes.\n *\n * If set to 'creationOnly', only the creation of new auto link nodes will be disabled.\n * Existing auto link nodes will still be editable.\n *\n * @default false\n */\n disableAutoLinks?: 'creationOnly' | true\n /**\n * A function or array defining additional fields for the link feature. These will be\n * displayed in the link editor drawer.\n */\n fields?:\n | ((args: {\n config: SanitizedConfig\n defaultFields: FieldAffectingData[]\n }) => (Field | FieldAffectingData)[])\n | Field[]\n /**\n * Sets a maximum population depth for the internal doc default field of link, regardless of the remaining depth when the field is reached.\n * This behaves exactly like the maxDepth properties of relationship and upload fields.\n *\n * {@link https://payloadcms.com/docs/getting-started/concepts#field-level-max-depth}\n */\n maxDepth?: number\n} & ExclusiveLinkCollectionsProps\n\nexport const LinkFeature = createServerFeature<\n LinkFeatureServerProps,\n LinkFeatureServerProps,\n ClientProps\n>({\n feature: async ({ config: _config, isRoot, parentIsLocalized, props }) => {\n if (!props) {\n props = {}\n }\n const validRelationships = _config.collections.map((c) => c.slug) || []\n\n const _transformedFields = transformExtraFields(\n props.fields ? props.fields : null,\n _config,\n props.enabledCollections,\n props.disabledCollections,\n props.maxDepth,\n )\n\n const sanitizedFields = await sanitizeFields({\n config: _config as unknown as Config,\n fields: _transformedFields,\n parentIsLocalized,\n requireFieldLevelRichTextEditor: isRoot,\n validRelationships,\n })\n props.fields = sanitizedFields\n\n // the text field is not included in the node data.\n // Thus, for tasks like validation, we do not want to pass it a text field in the schema which will never have data.\n // Otherwise, it will cause a validation error (field is required).\n const sanitizedFieldsWithoutText = sanitizedFields.filter(\n (field) => !('name' in field) || field.name !== 'text',\n )\n\n let linkTypeField: Field | null = null\n let linkURLField: Field | null = null\n\n for (const field of sanitizedFields) {\n if ('name' in field && field.name === 'linkType') {\n linkTypeField = field\n }\n\n if ('name' in field && field.name === 'url') {\n linkURLField = field\n }\n }\n\n const defaultLinkType = linkTypeField\n ? 'defaultValue' in linkTypeField && typeof linkTypeField.defaultValue === 'string'\n ? linkTypeField.defaultValue\n : 'custom'\n : undefined\n\n const defaultLinkURL = linkURLField\n ? 'defaultValue' in linkURLField && typeof linkURLField.defaultValue === 'string'\n ? linkURLField.defaultValue\n : 'https://'\n : undefined\n\n return {\n ClientFeature: '@payloadcms/richtext-lexical/client#LinkFeatureClient',\n clientFeatureProps: {\n defaultLinkType,\n defaultLinkURL,\n disableAutoLinks: props.disableAutoLinks,\n disabledCollections: props.disabledCollections,\n enabledCollections: props.enabledCollections,\n } as ClientProps,\n generateSchemaMap: () => {\n if (!sanitizedFields || !Array.isArray(sanitizedFields) || sanitizedFields.length === 0) {\n return null\n }\n\n const schemaMap: FieldSchemaMap = new Map()\n schemaMap.set('fields', {\n fields: sanitizedFields,\n })\n\n return schemaMap\n },\n i18n,\n markdownTransformers: [LinkMarkdownTransformer],\n nodes: [\n props?.disableAutoLinks === true\n ? null\n : createNode({\n converters: {\n html: {\n converter: async ({\n converters,\n currentDepth,\n depth,\n draft,\n node,\n overrideAccess,\n parent,\n req,\n showHiddenFields,\n }) => {\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n currentDepth,\n depth,\n draft,\n lexicalNodes: node.children,\n overrideAccess,\n parent: {\n ...node,\n parent,\n },\n req,\n showHiddenFields,\n })\n\n let href: string = node.fields.url ?? ''\n if (node.fields.linkType === 'internal') {\n href =\n typeof node.fields.doc?.value !== 'object'\n ? String(node.fields.doc?.value)\n : String(node.fields.doc?.value?.id)\n }\n\n return `<a href=\"${href}\"${node.fields.newTab ? ' rel=\"noopener noreferrer\" target=\"_blank\"' : ''}>${childrenText}</a>`\n },\n nodeTypes: [AutoLinkNode.getType()],\n },\n },\n node: AutoLinkNode,\n // Since AutoLinkNodes are just internal links, they need no hooks or graphQL population promises\n validations: [linkValidation(props, sanitizedFieldsWithoutText)],\n }),\n createNode({\n converters: {\n html: {\n converter: async ({\n converters,\n currentDepth,\n depth,\n draft,\n node,\n overrideAccess,\n parent,\n req,\n showHiddenFields,\n }) => {\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n currentDepth,\n depth,\n draft,\n lexicalNodes: node.children,\n overrideAccess,\n parent: {\n ...node,\n parent,\n },\n req,\n showHiddenFields,\n })\n\n const href: string =\n node.fields.linkType === 'custom'\n ? escapeHTML(node.fields.url)\n : (node.fields.doc?.value as string)\n\n return `<a href=\"${href}\"${node.fields.newTab ? ' rel=\"noopener noreferrer\" target=\"_blank\"' : ''}>${childrenText}</a>`\n },\n nodeTypes: [LinkNode.getType()],\n },\n },\n getSubFields: () => {\n return sanitizedFieldsWithoutText\n },\n getSubFieldsData: ({ node }) => {\n return node?.fields\n },\n graphQLPopulationPromises: [linkPopulationPromiseHOC(props)],\n node: LinkNode,\n validations: [linkValidation(props, sanitizedFieldsWithoutText)],\n }),\n ].filter(Boolean) as Array<NodeWithHooks>,\n sanitizedServerFeatureProps: props,\n }\n },\n key: 'link',\n})\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["escapeHTML","sanitizeFields","createServerFeature","convertLexicalNodesToHTML","createNode","createLinkMarkdownTransformer","AutoLinkNode","LinkNode","linkPopulationPromiseHOC","i18n","transformExtraFields","linkValidation","LinkFeature","feature","config","_config","isRoot","parentIsLocalized","props","validRelationships","collections","map","c","slug","_transformedFields","fields","enabledCollections","disabledCollections","maxDepth","sanitizedFields","requireFieldLevelRichTextEditor","sanitizedFieldsWithoutText","filter","field","name","linkTypeField","linkURLField","defaultLinkType","defaultValue","undefined","defaultLinkURL","ClientFeature","clientFeatureProps","disableAutoLinks","generateSchemaMap","Array","isArray","length","schemaMap","Map","set","markdownTransformers","internalDocToHref","nodes","converters","html","converter","currentDepth","depth","draft","node","overrideAccess","parent","req","showHiddenFields","childrenText","lexicalNodes","children","href","url","linkType","doc","value","String","id","newTab","nodeTypes","getType","validations","getSubFields","getSubFieldsData","graphQLPopulationPromises","Boolean","sanitizedServerFeatureProps","key"],"sources":["../../../../src/features/link/server/index.ts"],"sourcesContent":["import type {\n CollectionSlug,\n Config,\n Field,\n FieldAffectingData,\n FieldSchemaMap,\n SanitizedConfig,\n} from 'payload'\n\nimport escapeHTML from 'escape-html'\nimport { sanitizeFields } from 'payload'\n\nimport type { NodeWithHooks } from '../../typesServer.js'\nimport type { ClientProps } from '../client/index.js'\nimport type { SerializedLinkNode } from '../nodes/types.js'\n\nimport { createServerFeature } from '../../../utilities/createServerFeature.js'\nimport { convertLexicalNodesToHTML } from '../../converters/lexicalToHtml_deprecated/converter/index.js'\nimport { createNode } from '../../typeUtilities.js'\nimport { createLinkMarkdownTransformer } from '../markdownTransformer.js'\nimport { AutoLinkNode } from '../nodes/AutoLinkNode.js'\nimport { LinkNode } from '../nodes/LinkNode.js'\nimport { linkPopulationPromiseHOC } from './graphQLPopulationPromise.js'\nimport { i18n } from './i18n.js'\nimport { transformExtraFields } from './transformExtraFields.js'\nimport { linkValidation } from './validate.js'\n\nexport type ExclusiveLinkCollectionsProps =\n | {\n /**\n * The collections that should be disabled for internal linking. Overrides the `enableRichTextLink` property in the collection config.\n * When this property is set, `enabledCollections` will not be available.\n **/\n disabledCollections?: CollectionSlug[]\n\n // Ensures that enabledCollections is not available when disabledCollections is set\n enabledCollections?: never\n }\n | {\n // Ensures that disabledCollections is not available when enabledCollections is set\n disabledCollections?: never\n\n /**\n * The collections that should be enabled for internal linking. Overrides the `enableRichTextLink` property in the collection config\n * When this property is set, `disabledCollections` will not be available.\n **/\n enabledCollections?: CollectionSlug[]\n }\n\nexport type LinkFeatureServerProps = {\n /**\n * Disables the automatic creation of links from URLs pasted into the editor, as well\n * as auto link nodes.\n *\n * If set to 'creationOnly', only the creation of new auto link nodes will be disabled.\n * Existing auto link nodes will still be editable.\n *\n * @default false\n */\n disableAutoLinks?: 'creationOnly' | true\n /**\n * A function or array defining additional fields for the link feature. These will be\n * displayed in the link editor drawer.\n */\n fields?:\n | ((args: {\n config: SanitizedConfig\n defaultFields: FieldAffectingData[]\n }) => (Field | FieldAffectingData)[])\n | Field[]\n /**\n * Resolves an internal link node to a URL string for use in the markdown converter.\n * Internal links store a doc reference rather than a URL, so without this the markdown\n * output will have an empty href: `[link text]()`.\n */\n internalDocToHref?: (args: { linkNode: SerializedLinkNode }) => string\n /**\n * Sets a maximum population depth for the internal doc default field of link, regardless of the remaining depth when the field is reached.\n * This behaves exactly like the maxDepth properties of relationship and upload fields.\n *\n * {@link https://payloadcms.com/docs/getting-started/concepts#field-level-max-depth}\n */\n maxDepth?: number\n} & ExclusiveLinkCollectionsProps\n\nexport const LinkFeature = createServerFeature<\n LinkFeatureServerProps,\n LinkFeatureServerProps,\n ClientProps\n>({\n feature: async ({ config: _config, isRoot, parentIsLocalized, props }) => {\n if (!props) {\n props = {}\n }\n const validRelationships = _config.collections.map((c) => c.slug) || []\n\n const _transformedFields = transformExtraFields(\n props.fields ? props.fields : null,\n _config,\n props.enabledCollections,\n props.disabledCollections,\n props.maxDepth,\n )\n\n const sanitizedFields = await sanitizeFields({\n config: _config as unknown as Config,\n fields: _transformedFields,\n parentIsLocalized,\n requireFieldLevelRichTextEditor: isRoot,\n validRelationships,\n })\n props.fields = sanitizedFields\n\n // the text field is not included in the node data.\n // Thus, for tasks like validation, we do not want to pass it a text field in the schema which will never have data.\n // Otherwise, it will cause a validation error (field is required).\n const sanitizedFieldsWithoutText = sanitizedFields.filter(\n (field) => !('name' in field) || field.name !== 'text',\n )\n\n let linkTypeField: Field | null = null\n let linkURLField: Field | null = null\n\n for (const field of sanitizedFields) {\n if ('name' in field && field.name === 'linkType') {\n linkTypeField = field\n }\n\n if ('name' in field && field.name === 'url') {\n linkURLField = field\n }\n }\n\n const defaultLinkType = linkTypeField\n ? 'defaultValue' in linkTypeField && typeof linkTypeField.defaultValue === 'string'\n ? linkTypeField.defaultValue\n : 'custom'\n : undefined\n\n const defaultLinkURL = linkURLField\n ? 'defaultValue' in linkURLField && typeof linkURLField.defaultValue === 'string'\n ? linkURLField.defaultValue\n : 'https://'\n : undefined\n\n return {\n ClientFeature: '@payloadcms/richtext-lexical/client#LinkFeatureClient',\n clientFeatureProps: {\n defaultLinkType,\n defaultLinkURL,\n disableAutoLinks: props.disableAutoLinks,\n disabledCollections: props.disabledCollections,\n enabledCollections: props.enabledCollections,\n } as ClientProps,\n generateSchemaMap: () => {\n if (!sanitizedFields || !Array.isArray(sanitizedFields) || sanitizedFields.length === 0) {\n return null\n }\n\n const schemaMap: FieldSchemaMap = new Map()\n schemaMap.set('fields', {\n fields: sanitizedFields,\n })\n\n return schemaMap\n },\n i18n,\n markdownTransformers: [\n createLinkMarkdownTransformer({ internalDocToHref: props.internalDocToHref }),\n ],\n nodes: [\n props?.disableAutoLinks === true\n ? null\n : createNode({\n converters: {\n html: {\n converter: async ({\n converters,\n currentDepth,\n depth,\n draft,\n node,\n overrideAccess,\n parent,\n req,\n showHiddenFields,\n }) => {\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n currentDepth,\n depth,\n draft,\n lexicalNodes: node.children,\n overrideAccess,\n parent: {\n ...node,\n parent,\n },\n req,\n showHiddenFields,\n })\n\n let href: string = node.fields.url ?? ''\n if (node.fields.linkType === 'internal') {\n href =\n typeof node.fields.doc?.value !== 'object'\n ? String(node.fields.doc?.value)\n : String(node.fields.doc?.value?.id)\n }\n\n return `<a href=\"${href}\"${node.fields.newTab ? ' rel=\"noopener noreferrer\" target=\"_blank\"' : ''}>${childrenText}</a>`\n },\n nodeTypes: [AutoLinkNode.getType()],\n },\n },\n node: AutoLinkNode,\n // Since AutoLinkNodes are just internal links, they need no hooks or graphQL population promises\n validations: [linkValidation(props, sanitizedFieldsWithoutText)],\n }),\n createNode({\n converters: {\n html: {\n converter: async ({\n converters,\n currentDepth,\n depth,\n draft,\n node,\n overrideAccess,\n parent,\n req,\n showHiddenFields,\n }) => {\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n currentDepth,\n depth,\n draft,\n lexicalNodes: node.children,\n overrideAccess,\n parent: {\n ...node,\n parent,\n },\n req,\n showHiddenFields,\n })\n\n const href: string =\n node.fields.linkType === 'custom'\n ? escapeHTML(node.fields.url)\n : (node.fields.doc?.value as string)\n\n return `<a href=\"${href}\"${node.fields.newTab ? ' rel=\"noopener noreferrer\" target=\"_blank\"' : ''}>${childrenText}</a>`\n },\n nodeTypes: [LinkNode.getType()],\n },\n },\n getSubFields: () => {\n return sanitizedFieldsWithoutText\n },\n getSubFieldsData: ({ node }) => {\n return node?.fields\n },\n graphQLPopulationPromises: [linkPopulationPromiseHOC(props)],\n node: LinkNode,\n validations: [linkValidation(props, sanitizedFieldsWithoutText)],\n }),\n ].filter(Boolean) as Array<NodeWithHooks>,\n sanitizedServerFeatureProps: props,\n }\n },\n key: 'link',\n})\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/richtext-lexical",
3
- "version": "3.84.0-canary.1",
3
+ "version": "3.84.0-canary.2",
4
4
  "description": "The officially supported Lexical richtext adapter for Payload",
5
5
  "homepage": "https://payloadcms.com",
6
6
  "repository": {
@@ -378,8 +378,8 @@
378
378
  "react-error-boundary": "4.1.2",
379
379
  "ts-essentials": "10.0.3",
380
380
  "uuid": "11.1.0",
381
- "@payloadcms/translations": "3.84.0-canary.1",
382
- "@payloadcms/ui": "3.84.0-canary.1"
381
+ "@payloadcms/translations": "3.84.0-canary.2",
382
+ "@payloadcms/ui": "3.84.0-canary.2"
383
383
  },
384
384
  "devDependencies": {
385
385
  "@babel/cli": "7.27.2",
@@ -398,7 +398,7 @@
398
398
  "esbuild": "0.27.1",
399
399
  "esbuild-sass-plugin": "3.3.1",
400
400
  "swc-plugin-transform-remove-imports": "8.3.0",
401
- "payload": "3.84.0-canary.1",
401
+ "payload": "3.84.0-canary.2",
402
402
  "@payloadcms/eslint-config": "3.28.0"
403
403
  },
404
404
  "peerDependencies": {
@@ -406,8 +406,8 @@
406
406
  "@faceless-ui/scroll-info": "2.0.0",
407
407
  "react": "^19.0.1 || ^19.1.2 || ^19.2.1",
408
408
  "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1",
409
- "@payloadcms/next": "3.84.0-canary.1",
410
- "payload": "3.84.0-canary.1"
409
+ "payload": "3.84.0-canary.2",
410
+ "@payloadcms/next": "3.84.0-canary.2"
411
411
  },
412
412
  "engines": {
413
413
  "node": "^18.20.2 || >=20.9.0"