@valkyrianlabs/payload-markdown 1.3.1
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.
- package/LICENSE +21 -0
- package/README.md +222 -0
- package/dist/blocks/MarkdownBlock/Component.d.ts +2 -0
- package/dist/blocks/MarkdownBlock/Component.js +13 -0
- package/dist/blocks/MarkdownBlock/Component.js.map +1 -0
- package/dist/blocks/MarkdownBlock/config.d.ts +2 -0
- package/dist/blocks/MarkdownBlock/config.js +20 -0
- package/dist/blocks/MarkdownBlock/config.js.map +1 -0
- package/dist/blocks/MarkdownBlock/types.d.js +3 -0
- package/dist/blocks/MarkdownBlock/types.d.js.map +1 -0
- package/dist/components/MarkdownRenderer/Component.client.d.ts +5 -0
- package/dist/components/MarkdownRenderer/Component.client.js +163 -0
- package/dist/components/MarkdownRenderer/Component.client.js.map +1 -0
- package/dist/components/MarkdownRenderer/Component.d.ts +3 -0
- package/dist/components/MarkdownRenderer/Component.js +87 -0
- package/dist/components/MarkdownRenderer/Component.js.map +1 -0
- package/dist/components/MarkdownRenderer/index.css +69 -0
- package/dist/components/MarkdownRenderer/index.module.css +45 -0
- package/dist/components/MarkdownRenderer/index.module.scss +43 -0
- package/dist/components/MarkdownRenderer/index.scss +83 -0
- package/dist/components/MarkdownRenderer/types.d.js +5 -0
- package/dist/components/MarkdownRenderer/types.d.js.map +1 -0
- package/dist/core/codeConfig.d.ts +6 -0
- package/dist/core/codeConfig.js +45 -0
- package/dist/core/codeConfig.js.map +1 -0
- package/dist/core/codeToHtml.d.ts +5 -0
- package/dist/core/codeToHtml.js +180 -0
- package/dist/core/codeToHtml.js.map +1 -0
- package/dist/core/plugins/rehypeApplyLayoutClasses.d.ts +4 -0
- package/dist/core/plugins/rehypeApplyLayoutClasses.js +72 -0
- package/dist/core/plugins/rehypeApplyLayoutClasses.js.map +1 -0
- package/dist/core/plugins/rehypeStripAuthoredInlineStyles.d.ts +3 -0
- package/dist/core/plugins/rehypeStripAuthoredInlineStyles.js +17 -0
- package/dist/core/plugins/rehypeStripAuthoredInlineStyles.js.map +1 -0
- package/dist/core/plugins/remarkCompileLayouts.d.ts +3 -0
- package/dist/core/plugins/remarkCompileLayouts.js +169 -0
- package/dist/core/plugins/remarkCompileLayouts.js.map +1 -0
- package/dist/core/plugins/remarkHeadingAnchorsAndToc.d.ts +3 -0
- package/dist/core/plugins/remarkHeadingAnchorsAndToc.js +68 -0
- package/dist/core/plugins/remarkHeadingAnchorsAndToc.js.map +1 -0
- package/dist/core/plugins/remarkLayoutDirectives.d.ts +3 -0
- package/dist/core/plugins/remarkLayoutDirectives.js +26 -0
- package/dist/core/plugins/remarkLayoutDirectives.js.map +1 -0
- package/dist/core/plugins/remarkLayoutSentinels.d.ts +3 -0
- package/dist/core/plugins/remarkLayoutSentinels.js +184 -0
- package/dist/core/plugins/remarkLayoutSentinels.js.map +1 -0
- package/dist/core/plugins/remarkLiftLayoutDirectives.d.ts +3 -0
- package/dist/core/plugins/remarkLiftLayoutDirectives.js +93 -0
- package/dist/core/plugins/remarkLiftLayoutDirectives.js.map +1 -0
- package/dist/core/plugins/remarkNormalizeLayoutSyntax.d.ts +3 -0
- package/dist/core/plugins/remarkValidateDirectiveThemes.d.ts +4 -0
- package/dist/core/plugins/remarkValidateDirectiveThemes.js +28 -0
- package/dist/core/plugins/remarkValidateDirectiveThemes.js.map +1 -0
- package/dist/core/renderMarkdown.d.ts +2 -0
- package/dist/core/renderMarkdown.js +270 -0
- package/dist/core/renderMarkdown.js.map +1 -0
- package/dist/core/types.d.js +7 -0
- package/dist/core/types.d.js.map +1 -0
- package/dist/core/types.d.ts +238 -0
- package/dist/core/types.js +5 -0
- package/dist/core/types.js.map +1 -0
- package/dist/directives/attributes.d.ts +14 -0
- package/dist/directives/attributes.js +121 -0
- package/dist/directives/attributes.js.map +1 -0
- package/dist/directives/definitions/callout.d.ts +6 -0
- package/dist/directives/definitions/callout.js +107 -0
- package/dist/directives/definitions/callout.js.map +1 -0
- package/dist/directives/definitions/card.d.ts +4 -0
- package/dist/directives/definitions/card.js +120 -0
- package/dist/directives/definitions/card.js.map +1 -0
- package/dist/directives/definitions/cards.d.ts +7 -0
- package/dist/directives/definitions/cards.js +72 -0
- package/dist/directives/definitions/cards.js.map +1 -0
- package/dist/directives/definitions/cell.d.ts +4 -0
- package/dist/directives/definitions/cell.js +44 -0
- package/dist/directives/definitions/cell.js.map +1 -0
- package/dist/directives/definitions/columns.d.ts +4 -0
- package/dist/directives/definitions/columns.js +89 -0
- package/dist/directives/definitions/columns.js.map +1 -0
- package/dist/directives/definitions/details.d.ts +2 -0
- package/dist/directives/definitions/details.js +76 -0
- package/dist/directives/definitions/details.js.map +1 -0
- package/dist/directives/definitions/section.d.ts +2 -0
- package/dist/directives/definitions/section.js +32 -0
- package/dist/directives/definitions/section.js.map +1 -0
- package/dist/directives/definitions/steps.d.ts +2 -0
- package/dist/directives/definitions/steps.js +242 -0
- package/dist/directives/definitions/steps.js.map +1 -0
- package/dist/directives/definitions/tab.d.ts +8 -0
- package/dist/directives/definitions/tab.js +59 -0
- package/dist/directives/definitions/tab.js.map +1 -0
- package/dist/directives/definitions/tabs.d.ts +2 -0
- package/dist/directives/definitions/tabs.js +197 -0
- package/dist/directives/definitions/tabs.js.map +1 -0
- package/dist/directives/definitions/toc.d.ts +7 -0
- package/dist/directives/definitions/toc.js +59 -0
- package/dist/directives/definitions/toc.js.map +1 -0
- package/dist/directives/diagnostics.d.ts +8 -0
- package/dist/directives/diagnostics.js +167 -0
- package/dist/directives/diagnostics.js.map +1 -0
- package/dist/directives/headingAnchors.d.ts +9 -0
- package/dist/directives/headingAnchors.js +54 -0
- package/dist/directives/headingAnchors.js.map +1 -0
- package/dist/directives/index.d.ts +5 -0
- package/dist/directives/index.js +6 -0
- package/dist/directives/index.js.map +1 -0
- package/dist/directives/registry.d.ts +20 -0
- package/dist/directives/registry.js +152 -0
- package/dist/directives/registry.js.map +1 -0
- package/dist/directives/renderData.d.ts +3 -0
- package/dist/directives/renderData.js +11 -0
- package/dist/directives/renderData.js.map +1 -0
- package/dist/directives/themes.d.ts +25 -0
- package/dist/directives/themes.js +274 -0
- package/dist/directives/themes.js.map +1 -0
- package/dist/directives/types.d.ts +72 -0
- package/dist/directives/types.js +3 -0
- package/dist/directives/types.js.map +1 -0
- package/dist/editor/MarkdownCodeMirror/Component.client.d.ts +8 -0
- package/dist/editor/MarkdownCodeMirror/Component.client.js +78 -0
- package/dist/editor/MarkdownCodeMirror/Component.client.js.map +1 -0
- package/dist/editor/MarkdownCodeMirror/Component.d.ts +9 -0
- package/dist/editor/MarkdownCodeMirror/Component.js +10 -0
- package/dist/editor/MarkdownCodeMirror/Component.js.map +1 -0
- package/dist/editor/MarkdownCodeMirror.d.ts +8 -0
- package/dist/editor/MarkdownCodeMirror.js +74 -0
- package/dist/editor/MarkdownCodeMirror.js.map +1 -0
- package/dist/editor/MarkdownEditor.d.ts +10 -0
- package/dist/editor/MarkdownEditor.js +22 -0
- package/dist/editor/MarkdownEditor.js.map +1 -0
- package/dist/editor/directives/completions.d.ts +5 -0
- package/dist/editor/directives/completions.js +93 -0
- package/dist/editor/directives/completions.js.map +1 -0
- package/dist/editor/directives/diagnostics.d.ts +1 -0
- package/dist/editor/directives/diagnostics.js +12 -0
- package/dist/editor/directives/diagnostics.js.map +1 -0
- package/dist/editor/themes/payload.d.ts +27 -0
- package/dist/editor/themes/payload.js +269 -0
- package/dist/editor/themes/payload.js.map +1 -0
- package/dist/editor/themes/support/highlighters.d.ts +20 -0
- package/dist/editor/themes/support/highlighters.js +1141 -0
- package/dist/editor/themes/support/highlighters.js.map +1 -0
- package/dist/editor/themes/support/lang.d.ts +40 -0
- package/dist/editor/themes/support/lang.js +201 -0
- package/dist/editor/themes/support/lang.js.map +1 -0
- package/dist/exports/advanced.d.ts +3 -0
- package/dist/exports/advanced.js +5 -0
- package/dist/exports/advanced.js.map +1 -0
- package/dist/exports/client.d.ts +1 -0
- package/dist/exports/client.js +2 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/server.d.ts +3 -0
- package/dist/exports/server.js +5 -0
- package/dist/exports/server.js.map +1 -0
- package/dist/field/BlocksParams/config.d.ts +7 -0
- package/dist/field/BlocksParams/config.js +149 -0
- package/dist/field/BlocksParams/config.js.map +1 -0
- package/dist/field/CodeBlock/config.d.ts +7 -0
- package/dist/field/CodeBlock/config.js +321 -0
- package/dist/field/CodeBlock/config.js.map +1 -0
- package/dist/field/CodeBlockConfig/config.d.ts +7 -0
- package/dist/field/CodeBlockConfig/config.js +306 -0
- package/dist/field/CodeBlockConfig/config.js.map +1 -0
- package/dist/field/CodeBlockParams/config.d.ts +7 -0
- package/dist/field/CodeBlockParams/config.js +321 -0
- package/dist/field/CodeBlockParams/config.js.map +1 -0
- package/dist/field/Config/config.d.ts +7 -0
- package/dist/field/Config/config.js +149 -0
- package/dist/field/Config/config.js.map +1 -0
- package/dist/field/MarkdownField/Component.d.ts +2 -0
- package/dist/field/MarkdownField/Component.js +42 -0
- package/dist/field/MarkdownField/Component.js.map +1 -0
- package/dist/field/MarkdownField/config.d.ts +3 -0
- package/dist/field/MarkdownField/config.js +20 -0
- package/dist/field/MarkdownField/config.js.map +1 -0
- package/dist/field/Tailwind/config.d.ts +9 -0
- package/dist/field/Tailwind/config.js +13 -0
- package/dist/field/Tailwind/config.js.map +1 -0
- package/dist/field/TailwindField/config.d.ts +9 -0
- package/dist/field/TailwindField/config.js +13 -0
- package/dist/field/TailwindField/config.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/index.d.ts +36 -0
- package/dist/runtime/index.js +124 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/styles/directiveSurface.d.ts +11 -0
- package/dist/styles/directiveSurface.js +38 -0
- package/dist/styles/directiveSurface.js.map +1 -0
- package/dist/types/core.d.ts +285 -0
- package/dist/types/core.js +5 -0
- package/dist/types/core.js.map +1 -0
- package/dist/types/layoutToken.d.ts +1 -0
- package/dist/types/layoutToken.js +3 -0
- package/dist/types/layoutToken.js.map +1 -0
- package/dist/types/mdast.d.js +5 -0
- package/dist/types/mdast.d.js.map +1 -0
- package/dist/types.d.js +3 -0
- package/dist/types.d.js.map +1 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +181 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Valkyrian Labs (Cooper Larson)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+

|
|
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>
|
|
4
|
+
|
|
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>
|
|
6
|
+
|
|
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>
|
|
8
|
+
|
|
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>
|
|
10
|
+
|
|
11
|
+
# Payload Markdown
|
|
12
|
+
|
|
13
|
+
Structured Markdown editing and rendering for Payload CMS.
|
|
14
|
+
|
|
15
|
+
`@valkyrianlabs/payload-markdown` gives Payload a Markdown-first authoring system with a CodeMirror editor, Shiki-powered code blocks, registry-backed directives, named themes, tabs, cards, table-of-contents generation, autocomplete, diagnostics, and server-first rendering.
|
|
16
|
+
|
|
17
|
+
No bloated rich text editor.
|
|
18
|
+
No JSON-shaped content prison.
|
|
19
|
+
No MDX ceremony for common docs/blog layouts.
|
|
20
|
+
|
|
21
|
+
Just portable Markdown that renders like a real system.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
`pnpm add @valkyrianlabs/payload-markdown`
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## [📖 Explore the Docs](https://docs.valkyrianlabs.com/plugins/payload-markdown)
|
|
32
|
+
|
|
33
|
+
Full setup, directive syntax, theme configuration, code block options, editor behavior, and migration notes live in the docs.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Why this exists
|
|
38
|
+
|
|
39
|
+
Most CMS content systems eventually force you into one of two weak paths:
|
|
40
|
+
|
|
41
|
+
- heavy rich text editors with fragile JSON-shaped content
|
|
42
|
+
- bare Markdown fields with no structure, no layout, and no serious authoring support
|
|
43
|
+
|
|
44
|
+
This plugin takes the third path:
|
|
45
|
+
|
|
46
|
+
- Markdown stays the source of truth
|
|
47
|
+
- structure lives directly in the content
|
|
48
|
+
- rendering is production-ready by default
|
|
49
|
+
- directives provide layout without turning content into a page-builder blob
|
|
50
|
+
- themes provide clean visual control without runtime Tailwind roulette
|
|
51
|
+
- autocomplete and diagnostics make authoring fast instead of fussy
|
|
52
|
+
|
|
53
|
+
**Write fast. Render clean. Stay in control.**
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## What you get
|
|
58
|
+
|
|
59
|
+
- **Drop-in fields** — Markdown fields for Payload collections
|
|
60
|
+
- **Markdown blocks** — block support for Payload layouts
|
|
61
|
+
- **Editor UX** — CodeMirror-powered editing
|
|
62
|
+
- **Code rendering** — Shiki-powered highlighting
|
|
63
|
+
- **Server-first output** — clean rendering without client ceremony
|
|
64
|
+
- **Structured directives** — callouts, details, TOCs, steps, cards, tabs, and layouts
|
|
65
|
+
- **Autocomplete** — directive snippets and placeholders
|
|
66
|
+
- **Diagnostics** — lightweight authoring warnings
|
|
67
|
+
- **Heading anchors** — automatic IDs and table-of-contents support
|
|
68
|
+
- **Themes** — themeable directive output with stable hooks
|
|
69
|
+
- **Scoped config** — global and collection-level overrides
|
|
70
|
+
- **Portable storage** — clean Markdown source
|
|
71
|
+
- **AI-friendly workflow** — content that agents and humans can edit sanely
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
`payload-markdown` renders structured Markdown directly inside the Payload admin preview, including callouts, details, TOCs, steps, cards, tabs, themes, and code blocks — without turning your content into JSON-shaped sludge.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Directive system
|
|
80
|
+
|
|
81
|
+
Payload Markdown supports structured directives for real content layouts:
|
|
82
|
+
|
|
83
|
+
- `:::callout`
|
|
84
|
+
- `:::details`
|
|
85
|
+
- `:::toc`
|
|
86
|
+
- `:::steps`
|
|
87
|
+
- `:::cards`
|
|
88
|
+
- `:::card`
|
|
89
|
+
- `:::tabs`
|
|
90
|
+
- `:::tab`
|
|
91
|
+
- `:::section`
|
|
92
|
+
- `:::2col`
|
|
93
|
+
- `:::3col`
|
|
94
|
+
- `:::cell`
|
|
95
|
+
|
|
96
|
+
Directives are plain Markdown. They stay readable in Git, easy to review in PRs, and simple for AI/editor tooling to maintain.
|
|
97
|
+
|
|
98
|
+
See the docs for directive syntax, supported attributes, nesting behavior, themes, and examples:
|
|
99
|
+
|
|
100
|
+
[Directive documentation →](https://docs.valkyrianlabs.com/plugins/payload-markdown/directives)
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Themes
|
|
105
|
+
|
|
106
|
+
Directive themes are first-class.
|
|
107
|
+
|
|
108
|
+
Themes live beside `config`, not inside it. Theme objects use `classes`, not `className`.
|
|
109
|
+
|
|
110
|
+
Default themes are included automatically. You only define custom themes when you want to extend or override the built-ins.
|
|
111
|
+
|
|
112
|
+
Themes can be configured globally or scoped per collection, then selected directly from Markdown using directive attributes.
|
|
113
|
+
|
|
114
|
+
Stable classes and data attributes are emitted for overrides, including `data-directive`, `data-theme`, and `vl-md-*` hook classes.
|
|
115
|
+
|
|
116
|
+
[Theme documentation →](https://docs.valkyrianlabs.com/plugins/payload-markdown/configuration/themes)
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Code config
|
|
121
|
+
|
|
122
|
+
Code block rendering has its own top-level `code` namespace.
|
|
123
|
+
|
|
124
|
+
Use it to configure Shiki languages, the Shiki theme, line numbers, enhanced rendering, and full-bleed code behavior.
|
|
125
|
+
|
|
126
|
+
Legacy `config.options` still works, but `code` is the preferred API.
|
|
127
|
+
|
|
128
|
+
Migration mapping:
|
|
129
|
+
|
|
130
|
+
- `config.options.langs` → `code.langs`
|
|
131
|
+
- `config.options.lineNumbers` → `code.lineNumbers`
|
|
132
|
+
- `config.options.theme` → `code.shikiTheme`
|
|
133
|
+
- `config.options.enhancedCodeBlocks` → `code.enhanced`
|
|
134
|
+
- `config.fullBleedCode` → `code.fullBleed`
|
|
135
|
+
|
|
136
|
+
[Code block documentation →](https://docs.valkyrianlabs.com/plugins/payload-markdown/configuration/code)
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Quick setup
|
|
141
|
+
|
|
142
|
+
Register the plugin in your Payload config, enable it for one or more collections, then render Markdown content with the server renderer.
|
|
143
|
+
|
|
144
|
+
The full setup guide covers:
|
|
145
|
+
|
|
146
|
+
- plugin registration
|
|
147
|
+
- collection configuration
|
|
148
|
+
- field mode
|
|
149
|
+
- block mode
|
|
150
|
+
- server rendering
|
|
151
|
+
- scoped config
|
|
152
|
+
- themes
|
|
153
|
+
- code block options
|
|
154
|
+
|
|
155
|
+
[Quick start →](https://docs.valkyrianlabs.com/plugins/payload-markdown/getting-started)
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Editor experience
|
|
160
|
+
|
|
161
|
+
The editor is built on CodeMirror and includes:
|
|
162
|
+
|
|
163
|
+
- Markdown syntax highlighting
|
|
164
|
+
- directive autocomplete
|
|
165
|
+
- directive snippets
|
|
166
|
+
- snippet placeholders/tabstops
|
|
167
|
+
- theme-aware attribute suggestions
|
|
168
|
+
- lightweight diagnostics for malformed directives
|
|
169
|
+
- warnings for unknown directives, invalid variants, invalid themes, malformed attrs, and common structural issues
|
|
170
|
+
|
|
171
|
+
The goal is simple: author Markdown like text, but get enough tooling that complex docs stay pleasant.
|
|
172
|
+
|
|
173
|
+
[Editor documentation →](https://docs.valkyrianlabs.com/plugins/payload-markdown/editor)
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Tailwind setup
|
|
178
|
+
|
|
179
|
+
For best rendering defaults, enable Tailwind Typography and scan the plugin output.
|
|
180
|
+
|
|
181
|
+
Required pieces:
|
|
182
|
+
|
|
183
|
+
- install `@tailwindcss/typography`
|
|
184
|
+
- enable the typography plugin
|
|
185
|
+
- add the plugin `dist` directory to Tailwind sources
|
|
186
|
+
|
|
187
|
+
Theme class strings defined in your app config should also live in scanned source files.
|
|
188
|
+
|
|
189
|
+
Runtime arbitrary Tailwind classes inside CMS-authored Markdown are not the recommended styling path. Use directive `theme="..."` values and configure named themes in source.
|
|
190
|
+
|
|
191
|
+
[Tailwind setup →](https://docs.valkyrianlabs.com/plugins/payload-markdown/getting-started/tailwind)
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Built for docs, blogs, and technical content
|
|
196
|
+
|
|
197
|
+
Use one Markdown field to author:
|
|
198
|
+
|
|
199
|
+
- release notes
|
|
200
|
+
- documentation pages
|
|
201
|
+
- technical blog posts
|
|
202
|
+
- plugin docs
|
|
203
|
+
- install guides
|
|
204
|
+
- API walkthroughs
|
|
205
|
+
- landing-page sections
|
|
206
|
+
|
|
207
|
+
The content stays readable in Git and editable in Payload.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Philosophy
|
|
212
|
+
|
|
213
|
+
- Markdown should stay the source of truth
|
|
214
|
+
- content should remain portable
|
|
215
|
+
- structure should be readable in plain text
|
|
216
|
+
- rich layouts should not require a page builder
|
|
217
|
+
- defaults should look good without locking you in
|
|
218
|
+
- styling should be centralized, themeable, and overridable
|
|
219
|
+
- the renderer should respect its container
|
|
220
|
+
- AI and human editors should both be able to work with the content
|
|
221
|
+
|
|
222
|
+
If that aligns with how you build, this will feel right.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { MarkdownRenderer } from '../../components/MarkdownRenderer/Component.js';
|
|
3
|
+
import { resolveMarkdownBlockDefaults } from '../../runtime/index.js';
|
|
4
|
+
export const MarkdownBlockComponent = ({ collectionSlug, content })=>{
|
|
5
|
+
const resolvedConfig = resolveMarkdownBlockDefaults(collectionSlug);
|
|
6
|
+
return /*#__PURE__*/ _jsx(MarkdownRenderer, {
|
|
7
|
+
markdown: content,
|
|
8
|
+
...resolvedConfig,
|
|
9
|
+
scope: "blocks"
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=Component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/MarkdownBlock/Component.tsx"],"sourcesContent":["import type { MarkdownBlockProps } from '../../types/core.js'\n\nimport { MarkdownRenderer } from '../../components/MarkdownRenderer/Component.js'\nimport { resolveMarkdownBlockDefaults } from '../../runtime/index.js'\n\nexport const MarkdownBlockComponent = ({ collectionSlug, content }: MarkdownBlockProps) => {\n const resolvedConfig = resolveMarkdownBlockDefaults(collectionSlug)\n\n return <MarkdownRenderer markdown={content} {...resolvedConfig} scope='blocks' />\n}\n"],"names":["MarkdownRenderer","resolveMarkdownBlockDefaults","MarkdownBlockComponent","collectionSlug","content","resolvedConfig","markdown","scope"],"mappings":";AAEA,SAASA,gBAAgB,QAAQ,iDAAgD;AACjF,SAASC,4BAA4B,QAAQ,yBAAwB;AAErE,OAAO,MAAMC,yBAAyB,CAAC,EAAEC,cAAc,EAAEC,OAAO,EAAsB;IACpF,MAAMC,iBAAiBJ,6BAA6BE;IAEpD,qBAAO,KAACH;QAAiBM,UAAUF;QAAU,GAAGC,cAAc;QAAEE,OAAM;;AACxE,EAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { vlMdConfig } from '../../field/Config/config.js';
|
|
2
|
+
import { markdownField } from '../../field/MarkdownField/config.js';
|
|
3
|
+
export const MarkdownBlock = {
|
|
4
|
+
slug: 'vlMdBlock',
|
|
5
|
+
fields: [
|
|
6
|
+
vlMdConfig(),
|
|
7
|
+
markdownField({
|
|
8
|
+
name: 'content',
|
|
9
|
+
label: 'Markdown Content',
|
|
10
|
+
required: true
|
|
11
|
+
})
|
|
12
|
+
],
|
|
13
|
+
interfaceName: 'MarkdownBlock',
|
|
14
|
+
labels: {
|
|
15
|
+
plural: 'Markdown Blocks',
|
|
16
|
+
singular: 'Markdown Block'
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/MarkdownBlock/config.ts"],"sourcesContent":["import type { Block } from 'payload'\n\nimport { vlMdConfig } from '../../field/Config/config.js'\nimport { markdownField } from '../../field/MarkdownField/config.js'\n\nexport const MarkdownBlock: Block = {\n slug: 'vlMdBlock',\n fields: [\n vlMdConfig(),\n markdownField({\n name: 'content',\n label: 'Markdown Content',\n required: true,\n }),\n ],\n interfaceName: 'MarkdownBlock',\n labels: {\n plural: 'Markdown Blocks',\n singular: 'Markdown Block',\n },\n}\n"],"names":["vlMdConfig","markdownField","MarkdownBlock","slug","fields","name","label","required","interfaceName","labels","plural","singular"],"mappings":"AAEA,SAASA,UAAU,QAAQ,+BAA8B;AACzD,SAASC,aAAa,QAAQ,sCAAqC;AAEnE,OAAO,MAAMC,gBAAuB;IAClCC,MAAM;IACNC,QAAQ;QACNJ;QACAC,cAAc;YACZI,MAAM;YACNC,OAAO;YACPC,UAAU;QACZ;KACD;IACDC,eAAe;IACfC,QAAQ;QACNC,QAAQ;QACRC,UAAU;IACZ;AACF,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
function extractCodeText(pre) {
|
|
4
|
+
const code = pre.querySelector('code');
|
|
5
|
+
if (!code) return '';
|
|
6
|
+
const lines = Array.from(code.querySelectorAll('.line'));
|
|
7
|
+
if (lines.length === 0) return code.textContent ?? '';
|
|
8
|
+
return lines.map((line)=>{
|
|
9
|
+
const clone = line.cloneNode(true);
|
|
10
|
+
clone.querySelectorAll('.md-line-number').forEach((node)=>node.remove());
|
|
11
|
+
clone.querySelectorAll('.md-empty-line').forEach((node)=>node.remove());
|
|
12
|
+
return clone.textContent ?? '';
|
|
13
|
+
}).join('\n');
|
|
14
|
+
}
|
|
15
|
+
function getTabsContainer(element) {
|
|
16
|
+
return element?.closest('[data-directive="tabs"]');
|
|
17
|
+
}
|
|
18
|
+
function setActiveTab(tabs, value) {
|
|
19
|
+
const triggers = Array.from(tabs.querySelectorAll('[data-tab-trigger]'));
|
|
20
|
+
const panels = Array.from(tabs.querySelectorAll('[data-tab-panel]'));
|
|
21
|
+
for (const trigger of triggers){
|
|
22
|
+
const active = trigger.getAttribute('data-tab-value') === value;
|
|
23
|
+
trigger.setAttribute('aria-selected', active ? 'true' : 'false');
|
|
24
|
+
trigger.setAttribute('tabindex', active ? '0' : '-1');
|
|
25
|
+
trigger.classList.toggle('vl-md-tabs-trigger--active', active);
|
|
26
|
+
}
|
|
27
|
+
for (const panel of panels){
|
|
28
|
+
const active = panel.getAttribute('data-tab-value') === value;
|
|
29
|
+
panel.toggleAttribute('hidden', !active);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function getEnabledTabTriggers(tabs) {
|
|
33
|
+
return Array.from(tabs.querySelectorAll('[data-tab-trigger]')).filter((trigger)=>!trigger.hasAttribute('disabled'));
|
|
34
|
+
}
|
|
35
|
+
function focusTabTrigger(triggers, index) {
|
|
36
|
+
const trigger = triggers[index];
|
|
37
|
+
if (!trigger) return;
|
|
38
|
+
trigger.focus();
|
|
39
|
+
}
|
|
40
|
+
function getNextTabIndex(currentIndex, total, direction) {
|
|
41
|
+
return (currentIndex + direction + total) % total;
|
|
42
|
+
}
|
|
43
|
+
export function MarkdownRendererClient({ containerId }) {
|
|
44
|
+
useEffect(()=>{
|
|
45
|
+
const root = document.getElementById(containerId);
|
|
46
|
+
if (!root) return;
|
|
47
|
+
const timeoutIds = new Set();
|
|
48
|
+
const pres = root.querySelectorAll('pre');
|
|
49
|
+
pres.forEach((pre)=>{
|
|
50
|
+
if (pre.querySelector('[data-md-copy-button]')) return;
|
|
51
|
+
const button = document.createElement('button');
|
|
52
|
+
button.type = 'button';
|
|
53
|
+
button.setAttribute('data-md-copy-button', 'true');
|
|
54
|
+
button.setAttribute('data-md-copy-label', 'Copy');
|
|
55
|
+
button.setAttribute('aria-label', 'Copy code block');
|
|
56
|
+
button.textContent = 'Copy';
|
|
57
|
+
button.style.position = 'absolute';
|
|
58
|
+
button.style.top = '0.6rem';
|
|
59
|
+
button.style.right = '0.6rem';
|
|
60
|
+
button.style.zIndex = '1';
|
|
61
|
+
button.style.border = '1px solid rgba(255,255,255,0.12)';
|
|
62
|
+
button.style.borderRadius = '0.5rem';
|
|
63
|
+
button.style.background = 'rgba(24,24,27,0.9)';
|
|
64
|
+
button.style.color = '#e5e7eb';
|
|
65
|
+
button.style.fontSize = '0.75rem';
|
|
66
|
+
button.style.fontWeight = '500';
|
|
67
|
+
button.style.lineHeight = '1';
|
|
68
|
+
button.style.padding = '0.45rem 0.65rem';
|
|
69
|
+
button.style.cursor = 'pointer';
|
|
70
|
+
button.style.userSelect = 'none';
|
|
71
|
+
const preStyle = window.getComputedStyle(pre);
|
|
72
|
+
if (preStyle.position === 'static') pre.style.position = 'relative';
|
|
73
|
+
pre.appendChild(button);
|
|
74
|
+
});
|
|
75
|
+
const resetButtonLabel = (button, originalLabel)=>{
|
|
76
|
+
const timeoutId = window.setTimeout(()=>{
|
|
77
|
+
button.textContent = originalLabel;
|
|
78
|
+
timeoutIds.delete(timeoutId);
|
|
79
|
+
}, 2000);
|
|
80
|
+
timeoutIds.add(timeoutId);
|
|
81
|
+
};
|
|
82
|
+
const handleClick = async (event)=>{
|
|
83
|
+
const target = event.target;
|
|
84
|
+
const button = target?.closest('[data-md-copy-button]');
|
|
85
|
+
if (!button || !root.contains(button)) return;
|
|
86
|
+
const pre = button.closest('pre');
|
|
87
|
+
if (!pre) return;
|
|
88
|
+
const text = extractCodeText(pre);
|
|
89
|
+
if (!text) return;
|
|
90
|
+
const originalLabel = button.getAttribute('data-md-copy-label') || button.textContent || 'Copy';
|
|
91
|
+
try {
|
|
92
|
+
await navigator.clipboard.writeText(text);
|
|
93
|
+
button.textContent = 'Copied';
|
|
94
|
+
resetButtonLabel(button, originalLabel);
|
|
95
|
+
} catch {
|
|
96
|
+
button.textContent = 'Failed';
|
|
97
|
+
resetButtonLabel(button, originalLabel);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const handleTabsClick = (event)=>{
|
|
101
|
+
const target = event.target;
|
|
102
|
+
const trigger = target?.closest('[data-tab-trigger]');
|
|
103
|
+
if (!trigger || !root.contains(trigger) || trigger.hasAttribute('disabled')) return;
|
|
104
|
+
const tabs = getTabsContainer(trigger);
|
|
105
|
+
const value = trigger.getAttribute('data-tab-value');
|
|
106
|
+
if (!tabs || !value) return;
|
|
107
|
+
setActiveTab(tabs, value);
|
|
108
|
+
trigger.focus();
|
|
109
|
+
};
|
|
110
|
+
const handleTabsKeydown = (event)=>{
|
|
111
|
+
const target = event.target;
|
|
112
|
+
const trigger = target?.closest('[data-tab-trigger]');
|
|
113
|
+
if (!trigger || !root.contains(trigger) || trigger.hasAttribute('disabled')) return;
|
|
114
|
+
const tabs = getTabsContainer(trigger);
|
|
115
|
+
if (!tabs) return;
|
|
116
|
+
const triggers = getEnabledTabTriggers(tabs);
|
|
117
|
+
const currentIndex = triggers.indexOf(trigger);
|
|
118
|
+
if (currentIndex < 0) return;
|
|
119
|
+
if (event.key === 'ArrowRight') {
|
|
120
|
+
event.preventDefault();
|
|
121
|
+
focusTabTrigger(triggers, getNextTabIndex(currentIndex, triggers.length, 1));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (event.key === 'ArrowLeft') {
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
focusTabTrigger(triggers, getNextTabIndex(currentIndex, triggers.length, -1));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (event.key === 'Home') {
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
focusTabTrigger(triggers, 0);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (event.key === 'End') {
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
focusTabTrigger(triggers, triggers.length - 1);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (event.key !== 'Enter' && event.key !== ' ') return;
|
|
140
|
+
const value = trigger.getAttribute('data-tab-value');
|
|
141
|
+
if (!value) return;
|
|
142
|
+
event.preventDefault();
|
|
143
|
+
setActiveTab(tabs, value);
|
|
144
|
+
};
|
|
145
|
+
root.addEventListener('click', handleClick);
|
|
146
|
+
root.addEventListener('click', handleTabsClick);
|
|
147
|
+
root.addEventListener('keydown', handleTabsKeydown);
|
|
148
|
+
return ()=>{
|
|
149
|
+
root.removeEventListener('click', handleClick);
|
|
150
|
+
root.removeEventListener('click', handleTabsClick);
|
|
151
|
+
root.removeEventListener('keydown', handleTabsKeydown);
|
|
152
|
+
timeoutIds.forEach((timeoutId)=>{
|
|
153
|
+
window.clearTimeout(timeoutId);
|
|
154
|
+
});
|
|
155
|
+
timeoutIds.clear();
|
|
156
|
+
};
|
|
157
|
+
}, [
|
|
158
|
+
containerId
|
|
159
|
+
]);
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
//# sourceMappingURL=Component.client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/MarkdownRenderer/Component.client.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect } from 'react'\n\ntype MarkdownRendererClientProps = {\n containerId: string\n}\n\nfunction extractCodeText(pre: HTMLElement): string {\n const code = pre.querySelector('code')\n if (!code) return ''\n\n const lines = Array.from(code.querySelectorAll<HTMLElement>('.line'))\n if (lines.length === 0) return code.textContent ?? ''\n\n return lines\n .map((line) => {\n const clone = line.cloneNode(true) as HTMLElement\n\n clone.querySelectorAll('.md-line-number').forEach((node) => node.remove())\n clone.querySelectorAll('.md-empty-line').forEach((node) => node.remove())\n\n return clone.textContent ?? ''\n })\n .join('\\n')\n}\n\nfunction getTabsContainer(element: HTMLElement | null): HTMLElement | null {\n return element?.closest('[data-directive=\"tabs\"]') as HTMLElement | null\n}\n\nfunction setActiveTab(tabs: HTMLElement, value: string) {\n const triggers = Array.from(tabs.querySelectorAll<HTMLElement>('[data-tab-trigger]'))\n const panels = Array.from(tabs.querySelectorAll<HTMLElement>('[data-tab-panel]'))\n\n for (const trigger of triggers) {\n const active = trigger.getAttribute('data-tab-value') === value\n\n trigger.setAttribute('aria-selected', active ? 'true' : 'false')\n trigger.setAttribute('tabindex', active ? '0' : '-1')\n trigger.classList.toggle('vl-md-tabs-trigger--active', active)\n }\n\n for (const panel of panels) {\n const active = panel.getAttribute('data-tab-value') === value\n\n panel.toggleAttribute('hidden', !active)\n }\n}\n\nfunction getEnabledTabTriggers(tabs: HTMLElement): HTMLElement[] {\n return Array.from(tabs.querySelectorAll<HTMLElement>('[data-tab-trigger]')).filter(\n (trigger) => !trigger.hasAttribute('disabled'),\n )\n}\n\nfunction focusTabTrigger(triggers: HTMLElement[], index: number) {\n const trigger = triggers[index]\n if (!trigger) return\n\n trigger.focus()\n}\n\nfunction getNextTabIndex(currentIndex: number, total: number, direction: -1 | 1): number {\n return (currentIndex + direction + total) % total\n}\n\nexport function MarkdownRendererClient({ containerId }: MarkdownRendererClientProps) {\n useEffect(() => {\n const root = document.getElementById(containerId)\n if (!root) return\n\n const timeoutIds = new Set<number>()\n\n const pres = root.querySelectorAll('pre')\n\n pres.forEach((pre) => {\n if (pre.querySelector('[data-md-copy-button]')) return\n\n const button = document.createElement('button')\n button.type = 'button'\n button.setAttribute('data-md-copy-button', 'true')\n button.setAttribute('data-md-copy-label', 'Copy')\n button.setAttribute('aria-label', 'Copy code block')\n button.textContent = 'Copy'\n\n button.style.position = 'absolute'\n button.style.top = '0.6rem'\n button.style.right = '0.6rem'\n button.style.zIndex = '1'\n button.style.border = '1px solid rgba(255,255,255,0.12)'\n button.style.borderRadius = '0.5rem'\n button.style.background = 'rgba(24,24,27,0.9)'\n button.style.color = '#e5e7eb'\n button.style.fontSize = '0.75rem'\n button.style.fontWeight = '500'\n button.style.lineHeight = '1'\n button.style.padding = '0.45rem 0.65rem'\n button.style.cursor = 'pointer'\n button.style.userSelect = 'none'\n\n const preStyle = window.getComputedStyle(pre)\n if (preStyle.position === 'static') pre.style.position = 'relative'\n\n pre.appendChild(button)\n })\n\n const resetButtonLabel = (button: HTMLElement, originalLabel: string) => {\n const timeoutId = window.setTimeout(() => {\n button.textContent = originalLabel\n timeoutIds.delete(timeoutId)\n }, 2000)\n\n timeoutIds.add(timeoutId)\n }\n\n const handleClick = async (event: Event) => {\n const target = event.target as HTMLElement | null\n const button = target?.closest('[data-md-copy-button]') as HTMLElement | null\n if (!button || !root.contains(button)) return\n\n const pre = button.closest('pre')\n if (!pre) return\n\n const text = extractCodeText(pre)\n if (!text) return\n\n const originalLabel =\n button.getAttribute('data-md-copy-label') || button.textContent || 'Copy'\n\n try {\n await navigator.clipboard.writeText(text)\n button.textContent = 'Copied'\n resetButtonLabel(button, originalLabel)\n } catch {\n button.textContent = 'Failed'\n resetButtonLabel(button, originalLabel)\n }\n }\n\n const handleTabsClick = (event: Event) => {\n const target = event.target as HTMLElement | null\n const trigger = target?.closest('[data-tab-trigger]') as HTMLElement | null\n if (!trigger || !root.contains(trigger) || trigger.hasAttribute('disabled')) return\n\n const tabs = getTabsContainer(trigger)\n const value = trigger.getAttribute('data-tab-value')\n if (!tabs || !value) return\n\n setActiveTab(tabs, value)\n trigger.focus()\n }\n\n const handleTabsKeydown = (event: KeyboardEvent) => {\n const target = event.target as HTMLElement | null\n const trigger = target?.closest('[data-tab-trigger]') as HTMLElement | null\n if (!trigger || !root.contains(trigger) || trigger.hasAttribute('disabled')) return\n\n const tabs = getTabsContainer(trigger)\n if (!tabs) return\n\n const triggers = getEnabledTabTriggers(tabs)\n const currentIndex = triggers.indexOf(trigger)\n if (currentIndex < 0) return\n\n if (event.key === 'ArrowRight') {\n event.preventDefault()\n focusTabTrigger(triggers, getNextTabIndex(currentIndex, triggers.length, 1))\n return\n }\n\n if (event.key === 'ArrowLeft') {\n event.preventDefault()\n focusTabTrigger(triggers, getNextTabIndex(currentIndex, triggers.length, -1))\n return\n }\n\n if (event.key === 'Home') {\n event.preventDefault()\n focusTabTrigger(triggers, 0)\n return\n }\n\n if (event.key === 'End') {\n event.preventDefault()\n focusTabTrigger(triggers, triggers.length - 1)\n return\n }\n\n if (event.key !== 'Enter' && event.key !== ' ') return\n\n const value = trigger.getAttribute('data-tab-value')\n if (!value) return\n\n event.preventDefault()\n setActiveTab(tabs, value)\n }\n\n root.addEventListener('click', handleClick)\n root.addEventListener('click', handleTabsClick)\n root.addEventListener('keydown', handleTabsKeydown)\n\n return () => {\n root.removeEventListener('click', handleClick)\n root.removeEventListener('click', handleTabsClick)\n root.removeEventListener('keydown', handleTabsKeydown)\n\n timeoutIds.forEach((timeoutId) => {\n window.clearTimeout(timeoutId)\n })\n\n timeoutIds.clear()\n }\n }, [containerId])\n\n return null\n}\n"],"names":["useEffect","extractCodeText","pre","code","querySelector","lines","Array","from","querySelectorAll","length","textContent","map","line","clone","cloneNode","forEach","node","remove","join","getTabsContainer","element","closest","setActiveTab","tabs","value","triggers","panels","trigger","active","getAttribute","setAttribute","classList","toggle","panel","toggleAttribute","getEnabledTabTriggers","filter","hasAttribute","focusTabTrigger","index","focus","getNextTabIndex","currentIndex","total","direction","MarkdownRendererClient","containerId","root","document","getElementById","timeoutIds","Set","pres","button","createElement","type","style","position","top","right","zIndex","border","borderRadius","background","color","fontSize","fontWeight","lineHeight","padding","cursor","userSelect","preStyle","window","getComputedStyle","appendChild","resetButtonLabel","originalLabel","timeoutId","setTimeout","delete","add","handleClick","event","target","contains","text","navigator","clipboard","writeText","handleTabsClick","handleTabsKeydown","indexOf","key","preventDefault","addEventListener","removeEventListener","clearTimeout","clear"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { MarkdownRendererProps } from '../../types/core.js';
|
|
2
|
+
import './index.css';
|
|
3
|
+
export declare function MarkdownRenderer(rawProps: MarkdownRendererProps): Promise<string | number | bigint | boolean | Iterable<import("react").ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { resolveFullBleedCode } from '../../core/codeConfig.js';
|
|
4
|
+
import { compileMarkdown } from '../../core/renderMarkdown.js';
|
|
5
|
+
import { mergeMarkdownRenderConfigs, resolveMarkdownBlockDefaults, resolveMarkdownFieldDefaults } from '../../runtime/index.js';
|
|
6
|
+
import { DIRECTIVE_SURFACE_RENDERER_PRE_CLASS } from '../../styles/directiveSurface.js';
|
|
7
|
+
import { MarkdownRendererClient } from './Component.client.js';
|
|
8
|
+
import './index.css';
|
|
9
|
+
const cx = (...values)=>values.filter(Boolean).join(' ');
|
|
10
|
+
const MARKDOWN_BASE_CLASS_NAME = cx('prose w-full max-w-none mx-0 p-0 text-foreground dark:prose-invert', // headings
|
|
11
|
+
'prose-headings:font-semibold prose-headings:tracking-tight', 'prose-h1:scroll-mt-24 prose-h2:scroll-mt-24 prose-h3:scroll-mt-24', // text
|
|
12
|
+
'prose-p:leading-7 prose-p:text-foreground/90', 'prose-strong:text-foreground', // links
|
|
13
|
+
'prose-a:font-medium prose-a:text-cyan-400 no-underline transition-colors hover:prose-a:text-cyan-300', // hr
|
|
14
|
+
'prose-hr:my-8 prose-hr:border-border', // lists
|
|
15
|
+
'[&_ul]:my-3 [&_ol]:my-3', // only elements immediately before lists
|
|
16
|
+
'[&_p:has(+ul)]:mb-3 [&_p:has(+ol)]:mb-3', '[&_h2:has(+ul)]:mb-3 [&_h2:has(+ol)]:mb-3', '[&_h3:has(+ul)]:mb-3 [&_h3:has(+ol)]:mb-3', // tune list top spacing by predecessor type
|
|
17
|
+
'[&_p+ul]:mt-0 [&_p+ol]:mt-0', '[&_h2+ul]:mt-2 [&_h2+ol]:mt-2', '[&_h3+ul]:mt-2 [&_h3+ol]:mt-2', '[&_ul]:pl-5 [&_ol]:pl-5', '[&_li]:my-0', '[&_li+li]:mt-1.5', '[&_li>p]:my-0', '[&_li>ul]:mt-1.5 [&_li>ol]:mt-1.5', '[&_ul_ul]:my-1 [&_ul_ol]:my-1 [&_ol_ul]:my-1 [&_ol_ol]:my-1', '[&_li::marker]:text-foreground/55', // task lists
|
|
18
|
+
'[&_.contains-task-list]:list-none [&_.contains-task-list]:pl-0', // blockquote
|
|
19
|
+
'prose-blockquote:my-6 prose-blockquote:border-l-2 prose-blockquote:border-border prose-blockquote:pl-4 prose-blockquote:text-foreground/75', // tables
|
|
20
|
+
'prose-table:my-6 prose-table:w-full', 'prose-th:border-b prose-th:border-border prose-th:pb-2 prose-th:text-left prose-th:font-semibold', 'prose-td:border-b prose-td:border-border/60 prose-td:py-2', // media
|
|
21
|
+
'prose-img:rounded-xl', // inline code
|
|
22
|
+
'prose-code:rounded prose-code:bg-black/5 prose-code:px-1 prose-code:py-0.5 prose-code:text-[0.9em] prose-code:font-medium dark:prose-code:bg-white/10', 'prose-code:before:content-none prose-code:after:content-none', // fenced code
|
|
23
|
+
'prose-pre:my-6 prose-pre:overflow-x-auto prose-pre:rounded-xl', DIRECTIVE_SURFACE_RENDERER_PRE_CLASS, 'prose-pre:px-0 prose-pre:py-0', '[&_pre]:my-6 [&_pre]:p-0', '[&_pre_code]:block [&_pre_code]:m-0 [&_pre_code]:py-2.5 [&_pre_code]:bg-[#18191c]', '[&_pre_.shiki]:my-6 [&_pre_.shiki]:rounded-xl [&_pre_.shiki]:px-4');
|
|
24
|
+
const MARKDOWN_VARIANT_CLASS_NAMES = {
|
|
25
|
+
blog: cx('prose-h1:mb-5 prose-h1:text-4xl md:prose-h1:text-5xl', 'prose-h2:mt-10 prose-h2:mb-3 prose-h2:text-3xl', 'prose-h3:mt-7 prose-h3:mb-2 prose-h3:text-2xl', 'prose-p:text-[1.02rem]', 'prose-blockquote:text-[1.02rem]'),
|
|
26
|
+
docs: cx('prose-h1:mb-4 prose-h1:text-3xl md:prose-h1:text-4xl', 'prose-h2:mt-8 prose-h2:mb-2 prose-h2:text-2xl', 'prose-h3:mt-6 prose-h3:mb-2 prose-h3:text-xl', 'prose-p:text-[0.98rem]', 'prose-li:text-[0.98rem]', 'prose-code:text-[0.875em]'),
|
|
27
|
+
compact: cx('prose-h1:mb-3 prose-h1:text-3xl', 'prose-h2:mt-6 prose-h2:mb-2 prose-h2:text-2xl', 'prose-h3:mt-5 prose-h3:mb-1 prose-h3:text-xl', 'prose-p:leading-6 prose-p:text-[0.95rem]', 'prose-ul:my-3 prose-ol:my-3', 'prose-pre:my-5'),
|
|
28
|
+
unstyled: ''
|
|
29
|
+
};
|
|
30
|
+
const MARKDOWN_SIZE_CLASS_NAMES = {
|
|
31
|
+
lg: 'prose-lg',
|
|
32
|
+
md: 'prose-base',
|
|
33
|
+
sm: 'prose-sm'
|
|
34
|
+
};
|
|
35
|
+
function buildWrapperClassName({ enableGutter, wrapperClassName }) {
|
|
36
|
+
return cx('w-full mx-0', enableGutter && 'px-5 sm:px-6 lg:px-8', wrapperClassName);
|
|
37
|
+
}
|
|
38
|
+
function buildMarkdownClassName({ className, fullBleedCode, mutedHeadings, size, variant }) {
|
|
39
|
+
if (variant === 'unstyled') return className ?? '';
|
|
40
|
+
return cx(MARKDOWN_BASE_CLASS_NAME, MARKDOWN_VARIANT_CLASS_NAMES[variant ?? 'blog'], MARKDOWN_SIZE_CLASS_NAMES[size ?? 'lg'], mutedHeadings && 'prose-headings:text-foreground/90', fullBleedCode && 'lg:[&_pre]:mx-[-2rem] lg:[&_pre_shiki]:rounded-[1.25rem] lg:[&_pre]:rounded-[1.25rem]', className);
|
|
41
|
+
}
|
|
42
|
+
function resolveScopedDefaults(scope, collectionSlug) {
|
|
43
|
+
return scope === 'blocks' ? resolveMarkdownBlockDefaults(collectionSlug) : resolveMarkdownFieldDefaults(collectionSlug);
|
|
44
|
+
}
|
|
45
|
+
export async function MarkdownRenderer(rawProps) {
|
|
46
|
+
const { as = 'article', collectionSlug, emptyFallback = null, errorFallback, lead, markdown = '', scope = 'field' } = rawProps;
|
|
47
|
+
if (!markdown || !markdown.trim()) return emptyFallback;
|
|
48
|
+
const resolvedProps = mergeMarkdownRenderConfigs(resolveScopedDefaults(scope, collectionSlug), rawProps) ?? rawProps;
|
|
49
|
+
const { className, enableGutter = false, mutedHeadings = false, size = 'lg', variant = 'blog', wrapperClassName } = resolvedProps;
|
|
50
|
+
const fullBleedCode = resolveFullBleedCode(resolvedProps) ?? false;
|
|
51
|
+
const result = await compileMarkdown(markdown, resolvedProps);
|
|
52
|
+
const Tag = as;
|
|
53
|
+
const containerId = `payload-markdown-${randomUUID()}`;
|
|
54
|
+
if (result.warnings.length > 0 && errorFallback) return errorFallback;
|
|
55
|
+
const resolvedWrapperClassName = buildWrapperClassName({
|
|
56
|
+
enableGutter,
|
|
57
|
+
wrapperClassName
|
|
58
|
+
});
|
|
59
|
+
const resolvedMarkdownClassName = buildMarkdownClassName({
|
|
60
|
+
className,
|
|
61
|
+
fullBleedCode,
|
|
62
|
+
mutedHeadings,
|
|
63
|
+
size,
|
|
64
|
+
variant
|
|
65
|
+
});
|
|
66
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
67
|
+
className: resolvedWrapperClassName,
|
|
68
|
+
children: [
|
|
69
|
+
/*#__PURE__*/ _jsx(MarkdownRendererClient, {
|
|
70
|
+
containerId: containerId
|
|
71
|
+
}),
|
|
72
|
+
lead ? /*#__PURE__*/ _jsx("div", {
|
|
73
|
+
className: "mb-8",
|
|
74
|
+
children: lead
|
|
75
|
+
}) : null,
|
|
76
|
+
/*#__PURE__*/ _jsx(Tag, {
|
|
77
|
+
className: resolvedMarkdownClassName,
|
|
78
|
+
dangerouslySetInnerHTML: {
|
|
79
|
+
__html: result.html
|
|
80
|
+
},
|
|
81
|
+
id: containerId
|
|
82
|
+
})
|
|
83
|
+
]
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//# sourceMappingURL=Component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/MarkdownRenderer/Component.tsx"],"sourcesContent":["import { randomUUID } from 'node:crypto'\n\nimport type {\n MarkdownRendererProps,\n MarkdownRendererScope,\n MarkdownSize,\n MarkdownVariant,\n} from '../../types/core.js'\n\nimport { resolveFullBleedCode } from '../../core/codeConfig.js'\nimport { compileMarkdown } from '../../core/renderMarkdown.js'\nimport {\n mergeMarkdownRenderConfigs,\n resolveMarkdownBlockDefaults,\n resolveMarkdownFieldDefaults,\n} from '../../runtime/index.js'\nimport { DIRECTIVE_SURFACE_RENDERER_PRE_CLASS } from '../../styles/directiveSurface.js'\nimport { MarkdownRendererClient } from './Component.client.js'\nimport './index.css'\n\nconst cx = (...values: Array<false | null | string | undefined>) => values.filter(Boolean).join(' ')\n\nconst MARKDOWN_BASE_CLASS_NAME = cx(\n 'prose w-full max-w-none mx-0 p-0 text-foreground dark:prose-invert',\n\n // headings\n 'prose-headings:font-semibold prose-headings:tracking-tight',\n 'prose-h1:scroll-mt-24 prose-h2:scroll-mt-24 prose-h3:scroll-mt-24',\n\n // text\n 'prose-p:leading-7 prose-p:text-foreground/90',\n 'prose-strong:text-foreground',\n\n // links\n 'prose-a:font-medium prose-a:text-cyan-400 no-underline transition-colors hover:prose-a:text-cyan-300',\n\n // hr\n 'prose-hr:my-8 prose-hr:border-border',\n\n // lists\n '[&_ul]:my-3 [&_ol]:my-3',\n\n // only elements immediately before lists\n '[&_p:has(+ul)]:mb-3 [&_p:has(+ol)]:mb-3',\n '[&_h2:has(+ul)]:mb-3 [&_h2:has(+ol)]:mb-3',\n '[&_h3:has(+ul)]:mb-3 [&_h3:has(+ol)]:mb-3',\n\n // tune list top spacing by predecessor type\n '[&_p+ul]:mt-0 [&_p+ol]:mt-0',\n '[&_h2+ul]:mt-2 [&_h2+ol]:mt-2',\n '[&_h3+ul]:mt-2 [&_h3+ol]:mt-2',\n\n '[&_ul]:pl-5 [&_ol]:pl-5',\n '[&_li]:my-0',\n '[&_li+li]:mt-1.5',\n '[&_li>p]:my-0',\n '[&_li>ul]:mt-1.5 [&_li>ol]:mt-1.5',\n '[&_ul_ul]:my-1 [&_ul_ol]:my-1 [&_ol_ul]:my-1 [&_ol_ol]:my-1',\n '[&_li::marker]:text-foreground/55',\n\n // task lists\n '[&_.contains-task-list]:list-none [&_.contains-task-list]:pl-0',\n\n // blockquote\n 'prose-blockquote:my-6 prose-blockquote:border-l-2 prose-blockquote:border-border prose-blockquote:pl-4 prose-blockquote:text-foreground/75',\n\n // tables\n 'prose-table:my-6 prose-table:w-full',\n 'prose-th:border-b prose-th:border-border prose-th:pb-2 prose-th:text-left prose-th:font-semibold',\n 'prose-td:border-b prose-td:border-border/60 prose-td:py-2',\n\n // media\n 'prose-img:rounded-xl',\n\n // inline code\n 'prose-code:rounded prose-code:bg-black/5 prose-code:px-1 prose-code:py-0.5 prose-code:text-[0.9em] prose-code:font-medium dark:prose-code:bg-white/10',\n 'prose-code:before:content-none prose-code:after:content-none',\n\n // fenced code\n 'prose-pre:my-6 prose-pre:overflow-x-auto prose-pre:rounded-xl',\n DIRECTIVE_SURFACE_RENDERER_PRE_CLASS,\n 'prose-pre:px-0 prose-pre:py-0',\n '[&_pre]:my-6 [&_pre]:p-0',\n '[&_pre_code]:block [&_pre_code]:m-0 [&_pre_code]:py-2.5 [&_pre_code]:bg-[#18191c]',\n '[&_pre_.shiki]:my-6 [&_pre_.shiki]:rounded-xl [&_pre_.shiki]:px-4',\n)\n\nconst MARKDOWN_VARIANT_CLASS_NAMES: Record<MarkdownVariant, string> = {\n blog: cx(\n 'prose-h1:mb-5 prose-h1:text-4xl md:prose-h1:text-5xl',\n 'prose-h2:mt-10 prose-h2:mb-3 prose-h2:text-3xl',\n 'prose-h3:mt-7 prose-h3:mb-2 prose-h3:text-2xl',\n 'prose-p:text-[1.02rem]',\n 'prose-blockquote:text-[1.02rem]',\n ),\n\n docs: cx(\n 'prose-h1:mb-4 prose-h1:text-3xl md:prose-h1:text-4xl',\n 'prose-h2:mt-8 prose-h2:mb-2 prose-h2:text-2xl',\n 'prose-h3:mt-6 prose-h3:mb-2 prose-h3:text-xl',\n 'prose-p:text-[0.98rem]',\n 'prose-li:text-[0.98rem]',\n 'prose-code:text-[0.875em]',\n ),\n\n compact: cx(\n 'prose-h1:mb-3 prose-h1:text-3xl',\n 'prose-h2:mt-6 prose-h2:mb-2 prose-h2:text-2xl',\n 'prose-h3:mt-5 prose-h3:mb-1 prose-h3:text-xl',\n 'prose-p:leading-6 prose-p:text-[0.95rem]',\n 'prose-ul:my-3 prose-ol:my-3',\n 'prose-pre:my-5',\n ),\n\n unstyled: '',\n}\n\nconst MARKDOWN_SIZE_CLASS_NAMES: Record<MarkdownSize, string> = {\n lg: 'prose-lg',\n md: 'prose-base',\n sm: 'prose-sm',\n}\n\nfunction buildWrapperClassName({\n enableGutter,\n wrapperClassName,\n}: Pick<MarkdownRendererProps, 'enableGutter' | 'wrapperClassName'>): string {\n return cx(\n 'w-full mx-0',\n enableGutter && 'px-5 sm:px-6 lg:px-8',\n wrapperClassName,\n )\n}\n\nfunction buildMarkdownClassName({\n className,\n fullBleedCode,\n mutedHeadings,\n size,\n variant,\n}: Pick<\n MarkdownRendererProps,\n 'className' | 'fullBleedCode' | 'mutedHeadings' | 'size' | 'variant'\n>): string {\n if (variant === 'unstyled') return className ?? ''\n\n return cx(\n MARKDOWN_BASE_CLASS_NAME,\n MARKDOWN_VARIANT_CLASS_NAMES[variant ?? 'blog'],\n MARKDOWN_SIZE_CLASS_NAMES[size ?? 'lg'],\n mutedHeadings && 'prose-headings:text-foreground/90',\n fullBleedCode &&\n 'lg:[&_pre]:mx-[-2rem] lg:[&_pre_shiki]:rounded-[1.25rem] lg:[&_pre]:rounded-[1.25rem]',\n className,\n )\n}\n\nfunction resolveScopedDefaults(scope: MarkdownRendererScope, collectionSlug?: string) {\n return scope === 'blocks'\n ? resolveMarkdownBlockDefaults(collectionSlug)\n : resolveMarkdownFieldDefaults(collectionSlug)\n}\n\nexport async function MarkdownRenderer(rawProps: MarkdownRendererProps) {\n const {\n as = 'article',\n collectionSlug,\n emptyFallback = null,\n errorFallback,\n lead,\n markdown = '',\n scope = 'field',\n } = rawProps\n\n if (!markdown || !markdown.trim()) return emptyFallback\n\n const resolvedProps =\n mergeMarkdownRenderConfigs(resolveScopedDefaults(scope, collectionSlug), rawProps) ?? rawProps\n\n const {\n className,\n enableGutter = false,\n mutedHeadings = false,\n size = 'lg',\n variant = 'blog',\n wrapperClassName,\n } = resolvedProps\n const fullBleedCode = resolveFullBleedCode(resolvedProps) ?? false\n\n const result = await compileMarkdown(markdown, resolvedProps)\n const Tag = as\n const containerId = `payload-markdown-${randomUUID()}`\n\n if (result.warnings.length > 0 && errorFallback) return errorFallback\n\n const resolvedWrapperClassName = buildWrapperClassName({\n enableGutter,\n wrapperClassName,\n })\n\n const resolvedMarkdownClassName = buildMarkdownClassName({\n className,\n fullBleedCode,\n mutedHeadings,\n size,\n variant,\n })\n\n return (\n <div className={resolvedWrapperClassName}>\n <MarkdownRendererClient containerId={containerId} />\n {lead ? <div className=\"mb-8\">{lead}</div> : null}\n\n <Tag\n className={resolvedMarkdownClassName}\n dangerouslySetInnerHTML={{ __html: result.html }}\n id={containerId}\n />\n </div>\n )\n}\n"],"names":["randomUUID","resolveFullBleedCode","compileMarkdown","mergeMarkdownRenderConfigs","resolveMarkdownBlockDefaults","resolveMarkdownFieldDefaults","DIRECTIVE_SURFACE_RENDERER_PRE_CLASS","MarkdownRendererClient","cx","values","filter","Boolean","join","MARKDOWN_BASE_CLASS_NAME","MARKDOWN_VARIANT_CLASS_NAMES","blog","docs","compact","unstyled","MARKDOWN_SIZE_CLASS_NAMES","lg","md","sm","buildWrapperClassName","enableGutter","wrapperClassName","buildMarkdownClassName","className","fullBleedCode","mutedHeadings","size","variant","resolveScopedDefaults","scope","collectionSlug","MarkdownRenderer","rawProps","as","emptyFallback","errorFallback","lead","markdown","trim","resolvedProps","result","Tag","containerId","warnings","length","resolvedWrapperClassName","resolvedMarkdownClassName","div","dangerouslySetInnerHTML","__html","html","id"],"mappings":"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"}
|