@valkyrianlabs/payload-markdown 1.3.1 → 1.3.3

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.
Files changed (34) hide show
  1. package/README.md +4 -4
  2. package/package.json +10 -9
  3. package/dist/blocks/MarkdownBlock/types.d.js +0 -3
  4. package/dist/blocks/MarkdownBlock/types.d.js.map +0 -1
  5. package/dist/components/MarkdownRenderer/index.module.css +0 -45
  6. package/dist/components/MarkdownRenderer/index.module.scss +0 -43
  7. package/dist/components/MarkdownRenderer/types.d.js +0 -5
  8. package/dist/components/MarkdownRenderer/types.d.js.map +0 -1
  9. package/dist/core/plugins/remarkLayoutSentinels.d.ts +0 -3
  10. package/dist/core/plugins/remarkLayoutSentinels.js +0 -184
  11. package/dist/core/plugins/remarkLayoutSentinels.js.map +0 -1
  12. package/dist/core/plugins/remarkNormalizeLayoutSyntax.d.ts +0 -3
  13. package/dist/core/types.d.js +0 -7
  14. package/dist/core/types.d.js.map +0 -1
  15. package/dist/core/types.d.ts +0 -238
  16. package/dist/core/types.js +0 -5
  17. package/dist/core/types.js.map +0 -1
  18. package/dist/editor/MarkdownCodeMirror.d.ts +0 -8
  19. package/dist/editor/MarkdownCodeMirror.js +0 -74
  20. package/dist/editor/MarkdownCodeMirror.js.map +0 -1
  21. package/dist/field/BlocksParams/config.d.ts +0 -7
  22. package/dist/field/BlocksParams/config.js +0 -149
  23. package/dist/field/BlocksParams/config.js.map +0 -1
  24. package/dist/field/CodeBlock/config.d.ts +0 -7
  25. package/dist/field/CodeBlock/config.js +0 -321
  26. package/dist/field/CodeBlock/config.js.map +0 -1
  27. package/dist/field/CodeBlockParams/config.d.ts +0 -7
  28. package/dist/field/CodeBlockParams/config.js +0 -321
  29. package/dist/field/CodeBlockParams/config.js.map +0 -1
  30. package/dist/field/TailwindField/config.d.ts +0 -9
  31. package/dist/field/TailwindField/config.js +0 -13
  32. package/dist/field/TailwindField/config.js.map +0 -1
  33. package/dist/types.d.js +0 -3
  34. package/dist/types.d.js.map +0 -1
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  ![@valkyrianlabs/payload-markdown](https://docs-media.valkyrianlabs.com/payload-markdown_v1.3_release_banner.png)
2
2
 
3
- <a href="https://github.com/valkyrianlabs/payload-markdown/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/valkyrianlabs/payload-markdown/deploy.yml"></a>
3
+ [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/valkyrianlabs/payload-markdown/deploy.yml)](https://github.com/valkyrianlabs/payload-markdown/actions)
4
4
  &nbsp;
5
- <a href="https://www.npmjs.com/package/@valkyrianlabs/payload-markdown"><img alt="npm" src="https://img.shields.io/npm/v/@valkyrianlabs/payload-markdown" /></a>
5
+ [![npm](https://img.shields.io/npm/v/@valkyrianlabs/payload-markdown)](https://www.npmjs.com/package/@valkyrianlabs/payload-markdown)
6
6
  &nbsp;
7
- <a href="https://www.npmjs.com/package/@valkyrianlabs/payload-markdown"><img alt="npm" src="https://img.shields.io/npm/dw/@valkyrianlabs/payload-markdown" /></a>
7
+ [![npm](https://img.shields.io/npm/dw/@valkyrianlabs/payload-markdown)](https://www.npmjs.com/package/@valkyrianlabs/payload-markdown)
8
8
  &nbsp;
9
- <a href="https://github.com/valkyrianlabs/payload-markdown?tab=MIT-1-ov-file"><img alt="license" src="https://img.shields.io/npm/l/@valkyrianlabs/payload-markdown" /></a>
9
+ [![license](https://img.shields.io/npm/l/@valkyrianlabs/payload-markdown)](https://github.com/valkyrianlabs/payload-markdown?tab=MIT-1-ov-file)
10
10
 
11
11
  # Payload Markdown
12
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valkyrianlabs/payload-markdown",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Structured Markdown editing and rendering for Payload CMS with CodeMirror, Shiki, directives, themes, and server-first output.",
5
5
  "repository": {
6
6
  "url": "https://github.com/valkyrianlabs/payload-markdown"
@@ -65,7 +65,7 @@
65
65
  "@playwright/test": "1.58.2",
66
66
  "@swc-node/register": "1.10.9",
67
67
  "@swc/cli": "0.6.0",
68
- "@tailwindcss/postcss": "^4.2.4",
68
+ "@tailwindcss/postcss": "^4.3.0",
69
69
  "@tailwindcss/typography": "^0.5.19",
70
70
  "@types/hast": "^3.0.4",
71
71
  "@types/mdast": "^4.0.4",
@@ -73,16 +73,17 @@
73
73
  "@types/react": "19.2.14",
74
74
  "@types/react-dom": "19.2.3",
75
75
  "@types/unist": "^3.0.3",
76
+ "@valkyrianlabs/payload-markdown-docs": "latest",
76
77
  "copyfiles": "2.4.1",
77
78
  "cross-env": "^7.0.3",
78
79
  "eslint": "^9.39.4",
79
80
  "eslint-config-next": "16.2.1",
80
- "graphql": "^16.13.2",
81
+ "graphql": "^16.14.0",
81
82
  "mongodb-memory-server": "10.1.4",
82
- "next": "^16.2.4",
83
+ "next": "^16.2.6",
83
84
  "open": "^10.2.0",
84
85
  "payload": "latest",
85
- "postcss": "^8.5.12",
86
+ "postcss": "^8.5.14",
86
87
  "prettier": "^3.8.3",
87
88
  "qs-esm": "7.0.2",
88
89
  "react": "19.2.4",
@@ -90,7 +91,7 @@
90
91
  "rimraf": "3.0.2",
91
92
  "sharp": "0.34.2",
92
93
  "sort-package-json": "^2.15.1",
93
- "tailwindcss": "^4.2.4",
94
+ "tailwindcss": "^4.3.0",
94
95
  "typescript": "5.7.3",
95
96
  "vite-tsconfig-paths": "6.0.5",
96
97
  "vitest": "4.0.18"
@@ -139,7 +140,7 @@
139
140
  },
140
141
  "registry": "https://registry.npmjs.org/",
141
142
  "dependencies": {
142
- "@codemirror/autocomplete": "^6.20.1",
143
+ "@codemirror/autocomplete": "^6.20.2",
143
144
  "@codemirror/commands": "^6.10.3",
144
145
  "@codemirror/lang-angular": "^0.1.4",
145
146
  "@codemirror/lang-cpp": "^6.0.3",
@@ -159,9 +160,9 @@
159
160
  "@codemirror/lang-xml": "^6.1.0",
160
161
  "@codemirror/lang-yaml": "^6.1.3",
161
162
  "@codemirror/language": "^6.12.3",
162
- "@codemirror/lint": "^6.9.5",
163
+ "@codemirror/lint": "^6.9.6",
163
164
  "@codemirror/state": "^6.6.0",
164
- "@codemirror/view": "^6.41.1",
165
+ "@codemirror/view": "^6.42.1",
165
166
  "@lezer/highlight": "^1.2.3",
166
167
  "hast-util-from-html": "^2.0.3",
167
168
  "hast-util-sanitize": "^5.0.2",
@@ -1,3 +0,0 @@
1
- export { };
2
-
3
- //# sourceMappingURL=types.d.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/blocks/MarkdownBlock/types.d.ts"],"sourcesContent":["export interface MarkdownBlockProps {\n blockName?: null | string\n blockType: '@valkyrianlabs/markdown-block'\n content: string\n id?: null | string\n}\n"],"names":[],"mappings":"AAAA,WAKC"}
@@ -1,45 +0,0 @@
1
- .md-code-pre {
2
- background: #18191c;
3
- padding: 0;
4
- overflow-x: auto;
5
- position: relative;
6
- border: 1px solid rgba(255, 255, 255, 0.06);
7
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
8
- }
9
-
10
- .md-code-block {
11
- display: block;
12
- padding: 0;
13
- margin: 0;
14
- }
15
-
16
- .md-line {
17
- display: block;
18
- position: relative;
19
- white-space: pre;
20
- }
21
-
22
- .md-line-number {
23
- position: absolute;
24
- left: 0;
25
- top: 0;
26
- text-align: right;
27
- color: #7c8596;
28
- opacity: 0.8;
29
- user-select: none;
30
- pointer-events: none;
31
- font-variant-numeric: tabular-nums;
32
- font-feature-settings: "tnum";
33
- line-height: inherit;
34
- }
35
-
36
- .md-empty-line {
37
- display: inline-block;
38
- min-height: 1em;
39
- line-height: inherit;
40
- visibility: hidden;
41
- user-select: none;
42
- pointer-events: none;
43
- }
44
-
45
- /*# sourceMappingURL=index.module.css.map */
@@ -1,43 +0,0 @@
1
- .md-code-pre {
2
- background: #18191c;
3
- padding: 0;
4
- overflow-x: auto;
5
- position: relative;
6
- border: 1px solid rgba(255, 255, 255, 0.06);
7
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
8
- }
9
-
10
- .md-code-block {
11
- display: block;
12
- padding: 0;
13
- margin: 0;
14
- }
15
-
16
- .md-line {
17
- display: block;
18
- position: relative;
19
- white-space: pre;
20
- }
21
-
22
- .md-line-number {
23
- position: absolute;
24
- left: 0;
25
- top: 0;
26
- text-align: right;
27
- color: #7c8596;
28
- opacity: 0.8;
29
- user-select: none;
30
- pointer-events: none;
31
- font-variant-numeric: tabular-nums;
32
- font-feature-settings: "tnum";
33
- line-height: inherit;
34
- }
35
-
36
- .md-empty-line {
37
- display: inline-block;
38
- min-height: 1em;
39
- line-height: inherit;
40
- visibility: hidden;
41
- user-select: none;
42
- pointer-events: none;
43
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Props for the main markdown renderer component.
3
- */ export { };
4
-
5
- //# sourceMappingURL=types.d.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/components/MarkdownRenderer/types.d.ts"],"sourcesContent":["import type React, { JSX, ReactNode } from 'react'\n\n/**\n * Options that control how fenced code blocks are rendered inside markdown content.\n *\n * By default, code blocks use the plugin's enhanced rendering mode:\n * - `highlightLines` defaults to `false`\n * - `lineNumbers` defaults to `true`\n * - `prettyCodeBlocks` defaults to `true`\n * - `theme` defaults to `'github-dark'`\n *\n * These options are passed through the markdown rendering pipeline and primarily\n * affect Shiki-rendered code fences.\n */\nexport type RenderMarkdownOptions = {\n /**\n * Whether to preserve Shiki-provided per-line background highlighting.\n *\n * Defaults to `false`.\n *\n * When disabled, background styles are stripped from highlighted lines and token\n * spans so code blocks integrate more cleanly with the surrounding site design.\n */\n highlightLines?: boolean\n\n /**\n * Whether to show line numbers for fenced code blocks.\n *\n * Defaults to `true`.\n */\n lineNumbers?: boolean\n\n /**\n * Whether to apply the plugin's enhanced code block formatting.\n *\n * Defaults to `true`.\n *\n * When enabled, the renderer normalizes Shiki output for better integration with\n * markdown prose styling. This includes adjustments such as background removal,\n * spacing cleanup, line layout normalization, and other structural fixes needed\n * for features like line numbers and consistent empty-line rendering.\n *\n * Set this to `false` if you want to preserve raw Shiki block styling as much as\n * possible.\n */\n prettyCodeBlocks?: boolean\n\n /**\n * The Shiki theme to use for syntax highlighting.\n *\n * Defaults to `'github-dark'`.\n *\n * Note that this plugin is optimized around themes that still look good when block\n * backgrounds are removed or reduced. Some light themes may require additional\n * customization to maintain good contrast and readability.\n */\n theme?: string\n}\n\n/**\n * The result of compiling markdown into sanitized HTML.\n */\nexport type RenderMarkdownResult = {\n /**\n * The rendered HTML output.\n */\n html: string\n\n /**\n * Non-fatal warnings produced during rendering.\n */\n warnings: string[]\n}\n\n/**\n * Shared base props for markdown renderer components.\n */\nexport type BaseMarkdownRendererProps = {\n /**\n * The HTML tag used for the rendered markdown container.\n *\n * Defaults to `'article'`.\n */\n as?: keyof JSX.IntrinsicElements\n\n /**\n * Additional classes applied to the rendered markdown element itself.\n */\n className?: string\n\n /**\n * Content rendered when the markdown input is empty or missing.\n */\n emptyFallback?: React.ReactNode\n\n /**\n * Content rendered when markdown compilation fails and a fallback is desired.\n */\n errorFallback?: React.ReactNode\n\n /**\n * The markdown source string to render.\n */\n markdown?: null | string\n\n /**\n * Options that control fenced code block rendering.\n */\n options?: RenderMarkdownOptions\n\n /**\n * Additional classes applied to the outer wrapper element.\n */\n wrapperClassName?: string\n}\n\n/**\n * Preset visual styles for rendered markdown content.\n */\nexport type MarkdownVariant = 'blog' | 'compact' | 'docs' | 'unstyled'\n\n/**\n * Preset typography sizes for rendered markdown content.\n */\nexport type MarkdownSize = 'lg' | 'md' | 'sm'\n\n/**\n * Props for the main markdown renderer component.\n */\nexport type MarkdownRendererProps = {\n /**\n * Whether to center the rendered markdown container within its wrapper.\n *\n * Defaults to `true`.\n */\n centered?: boolean\n\n /**\n * Additional classes applied to the rendered markdown element itself.\n */\n className?: string\n\n /**\n * Whether to apply horizontal gutter padding to the outer wrapper.\n *\n * Defaults to `false`.\n */\n enableGutter?: boolean\n\n /**\n * Whether fenced code blocks should extend beyond the normal content width\n * on larger screens.\n *\n * Defaults to `false`.\n */\n fullBleedCode?: boolean\n\n /**\n * Optional content rendered above the markdown body.\n */\n lead?: ReactNode\n\n /**\n * Whether heading colors should be slightly muted.\n *\n * Defaults to `false`.\n */\n mutedHeadings?: boolean\n\n /**\n * Typography size preset for the rendered markdown.\n *\n * Defaults to `'lg'`.\n */\n size?: MarkdownSize\n\n /**\n * Visual style preset for the rendered markdown.\n *\n * Defaults to `'blog'`.\n */\n variant?: MarkdownVariant\n\n /**\n * Additional classes applied to the outer wrapper element.\n */\n wrapperClassName?: string\n} & Omit<BaseMarkdownRendererProps, 'className' | 'wrapperClassName'>\n"],"names":[],"mappings":"AA8HA;;CAEC,GACD,WA0DqE"}
@@ -1,3 +0,0 @@
1
- import type { Root } from 'mdast';
2
- import type { Plugin } from 'unified';
3
- export declare const remarkLayoutSentinels: Plugin<[], Root>;
@@ -1,184 +0,0 @@
1
- function isParagraph(node) {
2
- return node.type === 'paragraph';
3
- }
4
- function isHeading(node) {
5
- return node.type === 'heading';
6
- }
7
- function isText(node) {
8
- return node.type === 'text';
9
- }
10
- function getParagraphText(node) {
11
- if (!node.children.every(isText)) return null;
12
- return node.children.map((child)=>child.value).join('').trim();
13
- }
14
- function getSentinel(node) {
15
- if (!isParagraph(node)) return null;
16
- const text = getParagraphText(node);
17
- if (!text) return null;
18
- if (text === '%%VL_OPEN:section%%') return {
19
- name: 'section',
20
- type: 'open'
21
- };
22
- if (text === '%%VL_OPEN:2col%%') return {
23
- name: '2col',
24
- type: 'open'
25
- };
26
- if (text === '%%VL_OPEN:3col%%') return {
27
- name: '3col',
28
- type: 'open'
29
- };
30
- if (text === '%%VL_CLOSE%%') return {
31
- type: 'close'
32
- };
33
- if (text === '%%VL_CLOSE_GRID%%') return {
34
- type: 'closeGrid'
35
- };
36
- if (text === '%%VL_CLOSE_SECTION%%') return {
37
- type: 'closeSection'
38
- };
39
- return null;
40
- }
41
- function makeDirective(name, parentHeadingDepth, cellHeadingDepth) {
42
- return {
43
- name,
44
- type: 'containerDirective',
45
- attributes: {},
46
- children: [],
47
- data: {
48
- vlCellHeadingDepth: cellHeadingDepth,
49
- vlParentHeadingDepth: parentHeadingDepth
50
- }
51
- };
52
- }
53
- function getChildren(node) {
54
- return node.children;
55
- }
56
- function top(arr) {
57
- return arr[arr.length - 1];
58
- }
59
- function isGridName(name) {
60
- return name === '2col' || name === '3col';
61
- }
62
- function findNearestSectionIndex(stack) {
63
- for(let i = stack.length - 1; i >= 0; --i)if (stack[i]?.name === 'section') return i;
64
- return -1;
65
- }
66
- function findNearestGridIndex(stack) {
67
- for(let i = stack.length - 1; i >= 0; --i)if (isGridName(stack[i]?.name)) return i;
68
- return -1;
69
- }
70
- function closeTop(stack) {
71
- if (stack.length > 1) stack.pop();
72
- }
73
- function closeActiveGrid(stack) {
74
- const gridIndex = findNearestGridIndex(stack);
75
- if (gridIndex < 0) return false;
76
- while(stack.length - 1 >= gridIndex)stack.pop();
77
- return true;
78
- }
79
- function closeActiveGridInsideSection(stack) {
80
- const gridIndex = findNearestGridIndex(stack);
81
- const sectionIndex = findNearestSectionIndex(stack);
82
- if (gridIndex < 0 || sectionIndex < 0) return false;
83
- if (gridIndex < sectionIndex) return false;
84
- while(stack.length - 1 >= gridIndex)stack.pop();
85
- return true;
86
- }
87
- function closeThroughSection(stack) {
88
- const sectionIndex = findNearestSectionIndex(stack);
89
- if (sectionIndex < 0) return false;
90
- while(stack.length - 1 >= sectionIndex)stack.pop();
91
- return true;
92
- }
93
- export const remarkLayoutSentinels = ()=>{
94
- return (tree, file)=>{
95
- const input = [
96
- ...tree.children
97
- ];
98
- const rebuiltRoot = {
99
- ...tree,
100
- children: []
101
- };
102
- const stack = [
103
- {
104
- name: 'root',
105
- node: rebuiltRoot
106
- }
107
- ];
108
- const warnings = [];
109
- let currentHeadingDepth;
110
- const append = (node)=>getChildren(top(stack).node).push(node);
111
- for (const node of input){
112
- const sentinel = getSentinel(node);
113
- if (sentinel) {
114
- if (sentinel.type === 'open') {
115
- if (sentinel.name === 'section') {
116
- const next = makeDirective('section');
117
- append(next);
118
- stack.push({
119
- name: 'section',
120
- node: next
121
- });
122
- continue;
123
- }
124
- // Opening a new grid while already inside a grid inside a section
125
- // rolls over to a sibling grid automatically.
126
- closeActiveGridInsideSection(stack);
127
- const parentDepth = currentHeadingDepth ?? 1;
128
- const cellDepth = parentDepth + 1;
129
- const next = makeDirective(sentinel.name, parentDepth, cellDepth);
130
- append(next);
131
- stack.push({
132
- name: sentinel.name,
133
- cellHeadingDepth: cellDepth,
134
- node: next,
135
- parentHeadingDepth: parentDepth
136
- });
137
- continue;
138
- }
139
- if (sentinel.type === 'close') {
140
- if (stack.length === 1) {
141
- warnings.push('Encountered ::: with no open layout block.');
142
- continue;
143
- }
144
- closeTop(stack);
145
- continue;
146
- }
147
- if (sentinel.type === 'closeGrid') {
148
- if (!closeActiveGrid(stack)) {
149
- warnings.push('Encountered :::endcol with no open grid.');
150
- continue;
151
- }
152
- continue;
153
- }
154
- if (sentinel.type === 'closeSection') {
155
- if (!closeThroughSection(stack)) warnings.push('Encountered :::end or :::endsection with no open section.');
156
- continue;
157
- }
158
- }
159
- if (isHeading(node)) {
160
- const currentFrame = top(stack);
161
- if (isGridName(currentFrame.name)) {
162
- const parentDepth = currentFrame.parentHeadingDepth;
163
- // Same-level heading as the parent section remains inside the grid.
164
- // Only a true ascent above the parent depth auto-closes the grid.
165
- if (typeof parentDepth === 'number' && node.depth < parentDepth) {
166
- closeTop(stack);
167
- }
168
- }
169
- currentHeadingDepth = node.depth;
170
- append(node);
171
- continue;
172
- }
173
- append(node);
174
- }
175
- while(stack.length > 1){
176
- warnings.push(`Auto-closing unclosed layout block: ${top(stack).name}`);
177
- stack.pop();
178
- }
179
- tree.children = rebuiltRoot.children;
180
- for (const warning of warnings)file.message(warning);
181
- };
182
- };
183
-
184
- //# sourceMappingURL=remarkLayoutSentinels.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/core/plugins/remarkLayoutSentinels.ts"],"sourcesContent":["import type { Content, Heading, Paragraph, Root, Text } from 'mdast'\nimport type { ContainerDirective } from 'mdast-util-directive'\nimport type { Plugin } from 'unified'\n\ntype LayoutName = '2col' | '3col' | 'section'\ntype LayoutNode = ContainerDirective | Root\n\ntype LayoutFrame = {\n cellHeadingDepth?: number\n name: 'root' | LayoutName\n node: LayoutNode\n parentHeadingDepth?: number\n}\n\ntype Sentinel =\n | { name: LayoutName; type: 'open' }\n | { type: 'close' }\n | { type: 'closeGrid' }\n | { type: 'closeSection' }\n\nfunction isParagraph(node: Content): node is Paragraph {\n return node.type === 'paragraph'\n}\n\nfunction isHeading(node: Content): node is Heading {\n return node.type === 'heading'\n}\n\nfunction isText(node: Paragraph['children'][number]): node is Text {\n return node.type === 'text'\n}\n\nfunction getParagraphText(node: Paragraph): null | string {\n if (!node.children.every(isText)) return null\n return node.children\n .map((child) => child.value)\n .join('')\n .trim()\n}\n\nfunction getSentinel(node: Content): null | Sentinel {\n if (!isParagraph(node)) return null\n\n const text = getParagraphText(node)\n if (!text) return null\n\n if (text === '%%VL_OPEN:section%%') return { name: 'section', type: 'open' }\n if (text === '%%VL_OPEN:2col%%') return { name: '2col', type: 'open' }\n if (text === '%%VL_OPEN:3col%%') return { name: '3col', type: 'open' }\n if (text === '%%VL_CLOSE%%') return { type: 'close' }\n if (text === '%%VL_CLOSE_GRID%%') return { type: 'closeGrid' }\n if (text === '%%VL_CLOSE_SECTION%%') return { type: 'closeSection' }\n\n return null\n}\n\nfunction makeDirective(\n name: LayoutName,\n parentHeadingDepth?: number,\n cellHeadingDepth?: number,\n): ContainerDirective {\n return {\n name,\n type: 'containerDirective',\n attributes: {},\n children: [],\n data: {\n vlCellHeadingDepth: cellHeadingDepth,\n vlParentHeadingDepth: parentHeadingDepth,\n },\n }\n}\n\nfunction getChildren(node: LayoutNode): Content[] {\n return node.children as Content[]\n}\n\nfunction top<T>(arr: T[]): T {\n return arr[arr.length - 1]\n}\n\nfunction isGridName(name: LayoutFrame['name']): name is '2col' | '3col' {\n return name === '2col' || name === '3col'\n}\n\nfunction findNearestSectionIndex(stack: LayoutFrame[]): number {\n for (let i = stack.length - 1; i >= 0; --i) if (stack[i]?.name === 'section') return i\n\n return -1\n}\n\nfunction findNearestGridIndex(stack: LayoutFrame[]): number {\n for (let i = stack.length - 1; i >= 0; --i) if (isGridName(stack[i]?.name)) return i\n\n return -1\n}\n\nfunction closeTop(stack: LayoutFrame[]) {\n if (stack.length > 1) stack.pop()\n}\n\nfunction closeActiveGrid(stack: LayoutFrame[]): boolean {\n const gridIndex = findNearestGridIndex(stack)\n if (gridIndex < 0) return false\n\n while (stack.length - 1 >= gridIndex) stack.pop()\n\n return true\n}\n\nfunction closeActiveGridInsideSection(stack: LayoutFrame[]): boolean {\n const gridIndex = findNearestGridIndex(stack)\n const sectionIndex = findNearestSectionIndex(stack)\n\n if (gridIndex < 0 || sectionIndex < 0) return false\n if (gridIndex < sectionIndex) return false\n\n while (stack.length - 1 >= gridIndex) stack.pop()\n\n return true\n}\n\nfunction closeThroughSection(stack: LayoutFrame[]): boolean {\n const sectionIndex = findNearestSectionIndex(stack)\n if (sectionIndex < 0) return false\n\n while (stack.length - 1 >= sectionIndex) stack.pop()\n\n return true\n}\n\nexport const remarkLayoutSentinels: Plugin<[], Root> = () => {\n return (tree: Root, file) => {\n const input = [...tree.children]\n const rebuiltRoot: Root = { ...tree, children: [] }\n const stack: LayoutFrame[] = [{ name: 'root', node: rebuiltRoot }]\n const warnings: string[] = []\n\n let currentHeadingDepth: number | undefined\n\n const append = (node: Content) => getChildren(top(stack).node).push(node)\n\n for (const node of input) {\n const sentinel = getSentinel(node)\n\n if (sentinel) {\n if (sentinel.type === 'open') {\n if (sentinel.name === 'section') {\n const next = makeDirective('section')\n append(next)\n stack.push({ name: 'section', node: next })\n continue\n }\n\n // Opening a new grid while already inside a grid inside a section\n // rolls over to a sibling grid automatically.\n closeActiveGridInsideSection(stack)\n\n const parentDepth = currentHeadingDepth ?? 1\n const cellDepth = parentDepth + 1\n const next = makeDirective(sentinel.name, parentDepth, cellDepth)\n\n append(next)\n stack.push({\n name: sentinel.name,\n cellHeadingDepth: cellDepth,\n node: next,\n parentHeadingDepth: parentDepth,\n })\n continue\n }\n\n if (sentinel.type === 'close') {\n if (stack.length === 1) {\n warnings.push('Encountered ::: with no open layout block.')\n continue\n }\n\n closeTop(stack)\n continue\n }\n\n if (sentinel.type === 'closeGrid') {\n if (!closeActiveGrid(stack)) {\n warnings.push('Encountered :::endcol with no open grid.')\n continue\n }\n\n continue\n }\n\n if (sentinel.type === 'closeSection') {\n if (!closeThroughSection(stack))\n warnings.push('Encountered :::end or :::endsection with no open section.')\n\n continue\n }\n }\n\n if (isHeading(node)) {\n const currentFrame = top(stack)\n\n if (isGridName(currentFrame.name)) {\n const parentDepth = currentFrame.parentHeadingDepth\n\n // Same-level heading as the parent section remains inside the grid.\n // Only a true ascent above the parent depth auto-closes the grid.\n if (typeof parentDepth === 'number' && node.depth < parentDepth) {\n closeTop(stack)\n }\n }\n\n currentHeadingDepth = node.depth\n append(node)\n continue\n }\n\n append(node)\n }\n\n while (stack.length > 1) {\n warnings.push(`Auto-closing unclosed layout block: ${top(stack).name}`)\n stack.pop()\n }\n\n tree.children = rebuiltRoot.children\n\n for (const warning of warnings) file.message(warning)\n }\n}\n"],"names":["isParagraph","node","type","isHeading","isText","getParagraphText","children","every","map","child","value","join","trim","getSentinel","text","name","makeDirective","parentHeadingDepth","cellHeadingDepth","attributes","data","vlCellHeadingDepth","vlParentHeadingDepth","getChildren","top","arr","length","isGridName","findNearestSectionIndex","stack","i","findNearestGridIndex","closeTop","pop","closeActiveGrid","gridIndex","closeActiveGridInsideSection","sectionIndex","closeThroughSection","remarkLayoutSentinels","tree","file","input","rebuiltRoot","warnings","currentHeadingDepth","append","push","sentinel","next","parentDepth","cellDepth","currentFrame","depth","warning","message"],"mappings":"AAoBA,SAASA,YAAYC,IAAa;IAChC,OAAOA,KAAKC,IAAI,KAAK;AACvB;AAEA,SAASC,UAAUF,IAAa;IAC9B,OAAOA,KAAKC,IAAI,KAAK;AACvB;AAEA,SAASE,OAAOH,IAAmC;IACjD,OAAOA,KAAKC,IAAI,KAAK;AACvB;AAEA,SAASG,iBAAiBJ,IAAe;IACvC,IAAI,CAACA,KAAKK,QAAQ,CAACC,KAAK,CAACH,SAAS,OAAO;IACzC,OAAOH,KAAKK,QAAQ,CACjBE,GAAG,CAAC,CAACC,QAAUA,MAAMC,KAAK,EAC1BC,IAAI,CAAC,IACLC,IAAI;AACT;AAEA,SAASC,YAAYZ,IAAa;IAChC,IAAI,CAACD,YAAYC,OAAO,OAAO;IAE/B,MAAMa,OAAOT,iBAAiBJ;IAC9B,IAAI,CAACa,MAAM,OAAO;IAElB,IAAIA,SAAS,uBAAuB,OAAO;QAAEC,MAAM;QAAWb,MAAM;IAAO;IAC3E,IAAIY,SAAS,oBAAoB,OAAO;QAAEC,MAAM;QAAQb,MAAM;IAAO;IACrE,IAAIY,SAAS,oBAAoB,OAAO;QAAEC,MAAM;QAAQb,MAAM;IAAO;IACrE,IAAIY,SAAS,gBAAgB,OAAO;QAAEZ,MAAM;IAAQ;IACpD,IAAIY,SAAS,qBAAqB,OAAO;QAAEZ,MAAM;IAAY;IAC7D,IAAIY,SAAS,wBAAwB,OAAO;QAAEZ,MAAM;IAAe;IAEnE,OAAO;AACT;AAEA,SAASc,cACPD,IAAgB,EAChBE,kBAA2B,EAC3BC,gBAAyB;IAEzB,OAAO;QACLH;QACAb,MAAM;QACNiB,YAAY,CAAC;QACbb,UAAU,EAAE;QACZc,MAAM;YACJC,oBAAoBH;YACpBI,sBAAsBL;QACxB;IACF;AACF;AAEA,SAASM,YAAYtB,IAAgB;IACnC,OAAOA,KAAKK,QAAQ;AACtB;AAEA,SAASkB,IAAOC,GAAQ;IACtB,OAAOA,GAAG,CAACA,IAAIC,MAAM,GAAG,EAAE;AAC5B;AAEA,SAASC,WAAWZ,IAAyB;IAC3C,OAAOA,SAAS,UAAUA,SAAS;AACrC;AAEA,SAASa,wBAAwBC,KAAoB;IACnD,IAAK,IAAIC,IAAID,MAAMH,MAAM,GAAG,GAAGI,KAAK,GAAG,EAAEA,EAAG,IAAID,KAAK,CAACC,EAAE,EAAEf,SAAS,WAAW,OAAOe;IAErF,OAAO,CAAC;AACV;AAEA,SAASC,qBAAqBF,KAAoB;IAChD,IAAK,IAAIC,IAAID,MAAMH,MAAM,GAAG,GAAGI,KAAK,GAAG,EAAEA,EAAG,IAAIH,WAAWE,KAAK,CAACC,EAAE,EAAEf,OAAO,OAAOe;IAEnF,OAAO,CAAC;AACV;AAEA,SAASE,SAASH,KAAoB;IACpC,IAAIA,MAAMH,MAAM,GAAG,GAAGG,MAAMI,GAAG;AACjC;AAEA,SAASC,gBAAgBL,KAAoB;IAC3C,MAAMM,YAAYJ,qBAAqBF;IACvC,IAAIM,YAAY,GAAG,OAAO;IAE1B,MAAON,MAAMH,MAAM,GAAG,KAAKS,UAAWN,MAAMI,GAAG;IAE/C,OAAO;AACT;AAEA,SAASG,6BAA6BP,KAAoB;IACxD,MAAMM,YAAYJ,qBAAqBF;IACvC,MAAMQ,eAAeT,wBAAwBC;IAE7C,IAAIM,YAAY,KAAKE,eAAe,GAAG,OAAO;IAC9C,IAAIF,YAAYE,cAAc,OAAO;IAErC,MAAOR,MAAMH,MAAM,GAAG,KAAKS,UAAWN,MAAMI,GAAG;IAE/C,OAAO;AACT;AAEA,SAASK,oBAAoBT,KAAoB;IAC/C,MAAMQ,eAAeT,wBAAwBC;IAC7C,IAAIQ,eAAe,GAAG,OAAO;IAE7B,MAAOR,MAAMH,MAAM,GAAG,KAAKW,aAAcR,MAAMI,GAAG;IAElD,OAAO;AACT;AAEA,OAAO,MAAMM,wBAA0C;IACrD,OAAO,CAACC,MAAYC;QAClB,MAAMC,QAAQ;eAAIF,KAAKlC,QAAQ;SAAC;QAChC,MAAMqC,cAAoB;YAAE,GAAGH,IAAI;YAAElC,UAAU,EAAE;QAAC;QAClD,MAAMuB,QAAuB;YAAC;gBAAEd,MAAM;gBAAQd,MAAM0C;YAAY;SAAE;QAClE,MAAMC,WAAqB,EAAE;QAE7B,IAAIC;QAEJ,MAAMC,SAAS,CAAC7C,OAAkBsB,YAAYC,IAAIK,OAAO5B,IAAI,EAAE8C,IAAI,CAAC9C;QAEpE,KAAK,MAAMA,QAAQyC,MAAO;YACxB,MAAMM,WAAWnC,YAAYZ;YAE7B,IAAI+C,UAAU;gBACZ,IAAIA,SAAS9C,IAAI,KAAK,QAAQ;oBAC5B,IAAI8C,SAASjC,IAAI,KAAK,WAAW;wBAC/B,MAAMkC,OAAOjC,cAAc;wBAC3B8B,OAAOG;wBACPpB,MAAMkB,IAAI,CAAC;4BAAEhC,MAAM;4BAAWd,MAAMgD;wBAAK;wBACzC;oBACF;oBAEA,kEAAkE;oBAClE,8CAA8C;oBAC9Cb,6BAA6BP;oBAE7B,MAAMqB,cAAcL,uBAAuB;oBAC3C,MAAMM,YAAYD,cAAc;oBAChC,MAAMD,OAAOjC,cAAcgC,SAASjC,IAAI,EAAEmC,aAAaC;oBAEvDL,OAAOG;oBACPpB,MAAMkB,IAAI,CAAC;wBACThC,MAAMiC,SAASjC,IAAI;wBACnBG,kBAAkBiC;wBAClBlD,MAAMgD;wBACNhC,oBAAoBiC;oBACtB;oBACA;gBACF;gBAEA,IAAIF,SAAS9C,IAAI,KAAK,SAAS;oBAC7B,IAAI2B,MAAMH,MAAM,KAAK,GAAG;wBACtBkB,SAASG,IAAI,CAAC;wBACd;oBACF;oBAEAf,SAASH;oBACT;gBACF;gBAEA,IAAImB,SAAS9C,IAAI,KAAK,aAAa;oBACjC,IAAI,CAACgC,gBAAgBL,QAAQ;wBAC3Be,SAASG,IAAI,CAAC;wBACd;oBACF;oBAEA;gBACF;gBAEA,IAAIC,SAAS9C,IAAI,KAAK,gBAAgB;oBACpC,IAAI,CAACoC,oBAAoBT,QACvBe,SAASG,IAAI,CAAC;oBAEhB;gBACF;YACF;YAEA,IAAI5C,UAAUF,OAAO;gBACnB,MAAMmD,eAAe5B,IAAIK;gBAEzB,IAAIF,WAAWyB,aAAarC,IAAI,GAAG;oBACjC,MAAMmC,cAAcE,aAAanC,kBAAkB;oBAEnD,oEAAoE;oBACpE,kEAAkE;oBAClE,IAAI,OAAOiC,gBAAgB,YAAYjD,KAAKoD,KAAK,GAAGH,aAAa;wBAC/DlB,SAASH;oBACX;gBACF;gBAEAgB,sBAAsB5C,KAAKoD,KAAK;gBAChCP,OAAO7C;gBACP;YACF;YAEA6C,OAAO7C;QACT;QAEA,MAAO4B,MAAMH,MAAM,GAAG,EAAG;YACvBkB,SAASG,IAAI,CAAC,CAAC,oCAAoC,EAAEvB,IAAIK,OAAOd,IAAI,EAAE;YACtEc,MAAMI,GAAG;QACX;QAEAO,KAAKlC,QAAQ,GAAGqC,YAAYrC,QAAQ;QAEpC,KAAK,MAAMgD,WAAWV,SAAUH,KAAKc,OAAO,CAACD;IAC/C;AACF,EAAC"}
@@ -1,3 +0,0 @@
1
- import type { Root } from 'mdast';
2
- import type { Plugin } from 'unified';
3
- export declare const remarkNormalizeLayoutSyntax: Plugin<[], Root>;
@@ -1,7 +0,0 @@
1
- /**
2
- * @import {} from 'mdast-util-directive'
3
- */ /**
4
- * Props for the markdown block component wrapper.
5
- */ export { };
6
-
7
- //# sourceMappingURL=types.d.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/core/types.d.ts"],"sourcesContent":["/**\n * @import {} from 'mdast-util-directive'\n */\n\nimport type { JSX, ReactNode } from 'react'\n\nexport type MarkdownRendererScope = 'blocks' | 'field'\n\n/**\n * Options that control how fenced code blocks are rendered inside markdown content.\n *\n * By default, code blocks use the plugin's enhanced rendering mode:\n * - `highlightLines` defaults to `false`\n * - `lineNumbers` defaults to `true`\n * - `prettyCodeBlocks` defaults to `true`\n * - `theme` defaults to `'github-dark'`\n *\n * These options are passed through the markdown rendering pipeline and primarily\n * affect Shiki-rendered code fences.\n */\nexport type RenderMarkdownOptions = {\n /**\n * Whether to preserve Shiki-provided per-line background highlighting.\n *\n * Defaults to `false`.\n *\n * When disabled, background styles are stripped from highlighted lines and token\n * spans so code blocks integrate more cleanly with the surrounding site design.\n */\n highlightLines?: boolean\n\n /**\n * Whether to show line numbers for fenced code blocks.\n *\n * Defaults to `true`.\n */\n lineNumbers?: boolean\n\n /**\n * Whether to apply the plugin's enhanced code block formatting.\n *\n * Defaults to `true`.\n *\n * When enabled, the renderer normalizes Shiki output for better integration with\n * markdown prose styling. This includes adjustments such as background removal,\n * spacing cleanup, line layout normalization, and other structural fixes needed\n * for features like line numbers and consistent empty-line rendering.\n *\n * Set this to `false` if you want to preserve raw Shiki block styling as much as\n * possible.\n */\n prettyCodeBlocks?: boolean\n\n /**\n * The Shiki theme to use for syntax highlighting.\n *\n * Defaults to `'github-dark'`.\n *\n * Note that this plugin is optimized around themes that still look good when block\n * backgrounds are removed or reduced. Some light themes may require additional\n * customization to maintain good contrast and readability.\n */\n theme?: string\n}\n\n/**\n * The result of compiling markdown into sanitized HTML.\n */\nexport type RenderMarkdownResult = {\n /**\n * The rendered HTML output.\n */\n html: string\n\n /**\n * Non-fatal warnings produced during rendering.\n */\n warnings: string[]\n}\n\n/**\n * Preset visual styles for rendered markdown content.\n */\nexport type MarkdownVariant = 'blog' | 'compact' | 'docs' | 'unstyled'\n\n/**\n * Preset typography sizes for rendered markdown content.\n */\nexport type MarkdownSize = 'lg' | 'md' | 'sm'\n\n/**\n * Core markdown presentation configuration.\n *\n * This type represents the configurable styling and behavior layer that can be\n * sourced from plugin defaults, globals, collection defaults, or block-level\n * overrides. It intentionally excludes runtime-only renderer props such as\n * `markdown`, `as`, and fallback nodes.\n */\nexport type MarkdownConfig = {\n /**\n * Whether to center the rendered markdown container within its wrapper.\n *\n * Defaults to `false`.\n */\n centered?: boolean\n\n /**\n * Additional classes applied to the rendered markdown element itself.\n */\n className?: string\n\n /**\n * Additional classes applied to column elements within the rendered markdown, if applicable.\n */\n columnClassName?: string\n\n /**\n * Whether to apply horizontal gutter padding to the outer wrapper.\n *\n * Defaults to `false`.\n */\n enableGutter?: boolean\n\n /**\n * Whether fenced code blocks should extend beyond the normal content width\n * on larger screens.\n *\n * Defaults to `false`.\n */\n fullBleedCode?: boolean\n\n /**\n * Optional content rendered above the markdown body.\n */\n lead?: ReactNode\n\n /**\n * Whether heading colors should be slightly muted.\n *\n * Defaults to `false`.\n */\n mutedHeadings?: boolean\n\n /**\n * Options that control fenced code block rendering.\n */\n options?: RenderMarkdownOptions\n\n /**\n * Additional classes applied to section elements within the rendered markdown, if applicable.\n */\n sectionClassName?: string\n\n /**\n * Typography size preset for the rendered markdown.\n *\n * Defaults to `'lg'`.\n */\n size?: MarkdownSize\n\n /**\n * Visual style preset for the rendered markdown.\n *\n * Defaults to `'blog'`.\n */\n variant?: MarkdownVariant\n\n /**\n * Additional classes applied to the outer wrapper element.\n */\n wrapperClassName?: string\n}\n\n/**\n * Runtime-only props shared by markdown renderer components.\n */\nexport type BaseMarkdownRendererProps = {\n /**\n * The HTML tag used for the rendered markdown container.\n *\n * Defaults to `'article'`.\n */\n as?: keyof JSX.IntrinsicElements\n\n /**\n * Content rendered when the markdown input is empty or missing.\n */\n emptyFallback?: ReactNode\n\n /**\n * Content rendered when markdown compilation fails and a fallback is desired.\n */\n errorFallback?: ReactNode\n\n /**\n * The markdown source string to render.\n */\n markdown?: null | string\n}\n\n/**\n * Props for the main markdown renderer component.\n *\n * This merges persisted/configurable markdown presentation settings with the\n * runtime-only rendering props required by the component itself.\n */\nexport type MarkdownRendererProps = {\n collectionSlug?: string\n scope?: MarkdownRendererScope\n } & BaseMarkdownRendererProps & MarkdownConfig\n\n/**\n * Options available while rendering an individual fenced code block.\n */\nexport interface CodeBlockOptions extends RenderMarkdownOptions {\n /**\n * The parsed language identifier for the fenced code block, if present.\n */\n lang?: string\n}\n\n/**\n * Stored Payload block data for a markdown block instance.\n */\nexport interface MarkdownBlockData {\n /**\n * Optional block display name assigned by Payload.\n */\n blockName?: null | string\n\n /**\n * The Payload block slug.\n */\n blockType: '@valkyrianlabs/markdown-block'\n\n /**\n * Markdown source content for this block.\n */\n content: string\n\n /**\n * Optional Payload-generated block identifier.\n */\n id?: null | string\n}\n\n/**\n * Props for the markdown block component wrapper.\n */\nexport interface MarkdownBlockProps {\n /**\n * Stored block data from Payload.\n */\n block: MarkdownBlockData\n\n /**\n * The slug of the collection this block is rendered within, if applicable.\n */\n collectionSlug?: string\n\n /**\n * Default markdown configuration, typically sourced from global or collection-level settings.\n */\n defaults?: MarkdownConfig\n\n /**\n * Block-specific markdown configuration overrides.\n */\n overrides?: MarkdownConfig\n}\n"],"names":[],"mappings":"AAAA;;CAEC,GAoPD;;CAEC,GACD,WAoBC"}