@godxjp/markdown 33.21.0 → 33.22.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/README.md CHANGED
@@ -82,6 +82,34 @@ focusable only while it overflows, so a wide table scrolls instead of widening t
82
82
  | `highlight={false}` | Leave fenced code as plain text — a host `pre` that runs its own highlighter. A host `pre` otherwise receives the tokenised `<code>`. |
83
83
  | `allowedElements` / `unwrapDisallowed` | Narrow a body (an activity feed: `strong`, `em`, `del`, `code`). Only removes. |
84
84
  | `shortCellLength` | A table cell holding one short token (no whitespace, ≤ 24 characters by default) gets `data-short`; `Prose` keeps it on one line. `false` turns it off. |
85
+ | `directives` | Host renderers for container directives the kit does not model, by name — see "Directive blocks". |
86
+
87
+ ### Directive blocks
88
+
89
+ A container directive the kit does not model — `:::poll[…]{…}`, a `::::form` holding polls — renders
90
+ its content in a `div.ui-prose-directive` (the label as a paragraph). A host gives it meaning by
91
+ registering a renderer for its name:
92
+
93
+ ```tsx
94
+ <Markdown
95
+ directives={{
96
+ // { name, label, attributes, source, body, children }: label / source / body as written
97
+ // (free of a containing callout's `> `), children = the rendered body without the label.
98
+ poll: (block) => {
99
+ const poll = parsePoll(block.source); // the host's own grammar and validation
100
+ return poll ? <PollCard poll={poll} /> : undefined; // undefined: render it as before
101
+ },
102
+ form: (block) => <SurveyForm title={block.label}>{block.children}</SurveyForm>,
103
+ }}
104
+ >
105
+ {page.body}
106
+ </Markdown>
107
+ ```
108
+
109
+ The kit validates nothing inside a directive; `toggle`, `columns` and `column` are its own and
110
+ cannot be registered. The block's parts come from the same reader as the codec's
111
+ (`readDirective(source)` in `@godxjp/markdown/codec` returns `{ name, label, attributes, source,
112
+ body }`), so the editor and the page agree on what a block says.
85
113
 
86
114
  Images: wrap the body in `<Prose imagePreview>` and every body image opens the kit preview, paging
87
115
  through the others — no `img` override needed. Images in table cells keep min(natural width, 20rem),
@@ -131,8 +159,13 @@ set of parsers, so a body means the same thing in the editor, on a server and on
131
159
  special, a literal `$x$` in text is written `\$x$`; a lone `$` (a price) is never escaped.
132
160
  - **`asset:` images** — `![alt](asset:id)` round-trips as written (the renderer resolves it through
133
161
  `resolveUrl`).
134
- - **Raw blocks** — anything the document does not model (raw HTML, footnote definitions, link
135
- reference definitions, an unknown or malformed directive, a fence with a meta string) is kept as
162
+ - **Directive blocks** — any other container directive (`:::poll[label]{id=x anonymous}` … `:::`,
163
+ nesting by fence length) is one `directive{name, source}` node holding its canonical source, so
164
+ `normalize` is idempotent on it and the editor keeps it as one block. Attribute values with a
165
+ character outside `[\w.-]` are written quoted (`closes="2026-11-10T09:00"`); `{#x}` / `{.x}` are
166
+ written `id=x` / `class=x`.
167
+ - **Raw blocks** — anything else the document does not model (raw HTML, footnote definitions, link
168
+ reference definitions, a malformed toggle or column row, a fence with a meta string) is kept as
136
169
  Markdown that parses back to the same thing. Mermaid is an ordinary ` ```mermaid ` fence.
137
170
 
138
171
  ### Codec
@@ -154,6 +187,29 @@ Pure: no React, no DOM, no editor — it runs on a server and in a Cloudflare Wo
154
187
  `- [ ]` / `- [x]` todos; GFM tables with padded cells and an alignment row; a callout's body after a
155
188
  `>` blank line; one blank line between blocks; LF; a trailing newline; an empty document is `""`.
156
189
 
190
+ ## Loading KaTeX and highlight.js on demand (`@godxjp/markdown/lazy`)
191
+
192
+ KaTeX with its stylesheet and fonts, and highlight.js, are most of this package's weight. The
193
+ default entry bundles them so the first render is final everywhere. A client-rendered app imports
194
+ the same component from `/lazy` instead:
195
+
196
+ ```tsx
197
+ import { Markdown } from "@godxjp/markdown/lazy"; // and drop the global katex.css import
198
+ ```
199
+
200
+ Each engine is then a separate chunk, fetched the first time a rendered body needs it (math, or a
201
+ fence with a language) — KaTeX's chunk brings `katex.css` with it — and the body re-renders once it
202
+ arrives. Until then math shows its TeX source as code and fences are plain, the same as
203
+ `highlight={false}`. Measured with Vite on a host that imports only `Markdown`: the entry goes
204
+ from 560 KB JS (173 KB gzip) + 23.5 KB CSS to 220 KB JS (70 KB gzip) and no CSS; KaTeX is a
205
+ 262 KB (78 KB gzip) chunk + the CSS, highlight.js an 81 KB (26 KB gzip) chunk.
206
+
207
+ **Why the default stays eager.** A server render or a Worker is synchronous and cannot wait for an
208
+ `import()`, and the output must not depend on what happened to be loaded. With `/lazy`, a server
209
+ (or a client hydrating server HTML) awaits `preloadMarkdownRuntime(body)` before rendering, so its
210
+ HTML matches the eager entry's byte for byte; `RENDERER_VERSION` describes that finished output
211
+ from both entries.
212
+
157
213
  ## Stored versions
158
214
 
159
215
  Record `MARKDOWN_FORMAT` (`"md"`) and `RENDERER_VERSION` on every saved version.
@@ -0,0 +1,79 @@
1
+ "use client";
2
+
3
+ // src/katex-schema.ts
4
+ var KATEX_OPTIONS = {
5
+ trust: false,
6
+ strict: "error",
7
+ maxSize: 10,
8
+ output: "htmlAndMathml"
9
+ };
10
+ var KATEX_CLASSES = `accent accent-body accent-full amsrm angl anglpad arraycolsep base boldsymbol
11
+ boxpad brace-center brace-left brace-right cancel-lap cancel-pad cd-arrow-pad cd-label-left
12
+ cd-label-right cd-vert-arrow cjk_fallback clap col-align-c col-align-l col-align-r colorbox com
13
+ delim-size1 delim-size4 delimcenter delimsizing eqn-num fbox fcolorbox fix fleqn fontsize-ensurer
14
+ frac-line halfarrow-left halfarrow-right hbox hdashline hide-tail hline inner katex katex-display
15
+ katex-error katex-html katex-mathml large-op leqno llap mainrm mathbb mathbf mathboldfrak mathboldsf
16
+ mathcal mathfrak mathit mathitsf mathnormal mathrm mathscr mathsf mathsfit mathtt mbin mclose mfrac
17
+ minner mml-eqn-num mop mopen mord mover mpunct mrel mspace msupsub mtable mtight mtr-glue mult
18
+ munder newline nobreak nulldelimiter op-limits op-symbol overlay overline overline-line pstrut
19
+ reset-size1 reset-size10 reset-size11 reset-size2 reset-size3 reset-size4 reset-size5 reset-size6
20
+ reset-size7 reset-size8 reset-size9 rlap root rule size1 size10 size11 size2 size3 size4 size5
21
+ size6 size7 size8 size9 sizing small-op smash sout sqrt stretchy strut svg-align tag text textbb
22
+ textbf textboldfrak textboldsf textfrak textit textitsf textrm textscr textsf texttt thinbox
23
+ underline underline-line vbox vertical-separator vlist vlist-r vlist-s vlist-t vlist-t2 x-arrow
24
+ x-arrow-pad`.split(/\s+/);
25
+ var KATEX_STYLE = /^(?:\s*(?:background-color|border(?:-(?:top|right|bottom|left))?(?:-(?:width|style|color))?|bottom|color|height|left|margin(?:-(?:top|right|bottom|left))?|max-width|min-width|padding(?:-(?:top|right|bottom|left))?|position|right|top|vertical-align|width)\s*:\s*[-#.%\w ]+;?)*\s*$/i;
26
+ var MATHML_TAGS = `math semantics annotation mrow mi mn mo ms mtext mspace mpadded mphantom mstyle
27
+ menclose mfrac msqrt mroot msub msup msubsup munder mover munderover mtable mtr mtd mlabeledtr`.split(
28
+ /\s+/
29
+ );
30
+ var katexSchema = {
31
+ tagNames: [...MATHML_TAGS, "svg", "path", "line"],
32
+ attributes: {
33
+ span: [
34
+ ["className", ...KATEX_CLASSES],
35
+ ["style", KATEX_STYLE],
36
+ ["ariaHidden", "true"]
37
+ ],
38
+ math: [
39
+ ["xmlns", "http://www.w3.org/1998/Math/MathML"],
40
+ ["display", "block", "inline"]
41
+ ],
42
+ annotation: [["encoding", "application/x-tex"]],
43
+ mi: ["mathvariant"],
44
+ mo: ["stretchy", "fence", "separator", "minsize", "maxsize", "lspace", "rspace", "accent"],
45
+ mfrac: ["linethickness"],
46
+ mtable: ["rowspacing", "rowlines", "columnalign", "columnspacing", "columnlines", "width"],
47
+ mtd: ["columnalign"],
48
+ mstyle: ["scriptlevel", "displaystyle", "mathcolor", "mathsize", "mathbackground"],
49
+ mover: ["accent"],
50
+ munder: ["accentunder"],
51
+ munderover: ["accent", "accentunder"],
52
+ mpadded: [
53
+ "width",
54
+ "height",
55
+ "depth",
56
+ "lspace",
57
+ "voffset",
58
+ "mathbackground",
59
+ ["style", KATEX_STYLE]
60
+ ],
61
+ mspace: ["width", "height", "depth", "mathbackground"],
62
+ menclose: ["notation", "mathbackground"],
63
+ svg: [
64
+ ["xmlns", "http://www.w3.org/2000/svg"],
65
+ "width",
66
+ "height",
67
+ "viewBox",
68
+ "preserveAspectRatio",
69
+ ["style", KATEX_STYLE]
70
+ ],
71
+ path: ["d"],
72
+ line: ["x1", "y1", "x2", "y2", "strokeWidth"]
73
+ }
74
+ };
75
+
76
+ export {
77
+ KATEX_OPTIONS,
78
+ katexSchema
79
+ };
@@ -0,0 +1,21 @@
1
+ "use client";
2
+
3
+ // src/code-tokens.ts
4
+ var CODE_TOKENS = [
5
+ "comment",
6
+ "keyword",
7
+ "string",
8
+ "string-expression",
9
+ "function",
10
+ "constant",
11
+ "parameter",
12
+ "punctuation",
13
+ "link",
14
+ "inserted",
15
+ "deleted",
16
+ "changed"
17
+ ];
18
+
19
+ export {
20
+ CODE_TOKENS
21
+ };
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import {
3
+ KATEX_OPTIONS
4
+ } from "./chunk-AKKOCR2Y.js";
5
+
6
+ // src/math.ts
7
+ import rehypeKatex from "rehype-katex";
8
+ function rehypeMath() {
9
+ return rehypeKatex(KATEX_OPTIONS);
10
+ }
11
+
12
+ export {
13
+ rehypeMath
14
+ };