@vectojs/markdown 0.16.1 → 0.18.0

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.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Typographic replacements: `--`/`---` to en/em dash, `...` to `…`, `(c)`/`(r)`/
3
+ * `(tm)` to `©`/`®`/`™`, `+-` to `±`, and repeated `!`/`,` collapsing —
4
+ * `markdown-it`'s `typographer: true` set, minus smart quotes (see below).
5
+ *
6
+ * Ported as a **pure text transform** rather than a new tokenizer or `marked`
7
+ * extension, because that is what it is upstream too: `markdown-it`'s own
8
+ * `replacements` rule runs as a `core` pass over already-tokenized `text`
9
+ * content, not a grammar rule, and every substitution here is describable the
10
+ * same way — a regex over a string that changes no token boundaries. Applying
11
+ * it as the last step before a `text`-bearing span is pushed keeps this
12
+ * completely orthogonal to every other inline arm: a bold/italic/code run's
13
+ * content transforms identically to a plain paragraph's, because it is the same
14
+ * function call, not a special case duplicated per arm.
15
+ *
16
+ * ## Off by default, unlike every other construct in this package
17
+ *
18
+ * `markdown-it` itself defaults `typographer` to `false`, and this mirrors
19
+ * that rather than picking a different default for parity's own sake: the
20
+ * transform is lossy (a real `--` a caller wanted to keep literal, e.g. a CLI
21
+ * flag or a code-adjacent range, becomes an en dash with no way back short of
22
+ * disabling the whole feature) and every other construct in this package
23
+ * (subscript, superscript, ins/mark, emoji, footnotes) is instead
24
+ * unconditionally-on syntax recognition with no lossy default to weigh.
25
+ * `theme.typographer` (default `false`) is the gate, checked once per paragraph
26
+ * of text collection rather than per span, so a caller who never opts in pays
27
+ * nothing beyond the one boolean check `collectSpans` already does today for
28
+ * `inherited`.
29
+ *
30
+ * ## Smart quotes are deliberately NOT ported
31
+ *
32
+ * `markdown-it`'s `smartquotes` rule curls straight quotes into `‘’“”` by
33
+ * walking the FULL inline-token sequence of one block with a stack that
34
+ * matches an opening quote to its closing partner, consulting the previous and
35
+ * next token's own trailing/leading character across token boundaries (see
36
+ * `references/markdown-it/lib/rules_core/smartquotes.mjs`'s `process_inlines`).
37
+ * That is not a per-span text transform — it is a second pass over
38
+ * `collectSpans`' entire OUTPUT array, with cross-span state (the open-quote
39
+ * stack) and lookback/lookahead into neighboring spans' text. Porting it here
40
+ * would mean walking `out` after the fact, which every call site of
41
+ * `collectSpans`/`applyTypography` would have to remember to do, and getting it
42
+ * wrong reads as a rendering defect (mismatched curly quotes) rather than a
43
+ * missing feature. Left unimplemented; a caller wanting curled quotes still
44
+ * gets straight ones, the same honest fallback every unsupported construct in
45
+ * this package gets.
46
+ */
47
+ /**
48
+ * Apply typographic substitutions to one run of plain text.
49
+ *
50
+ * Order matters and mirrors `markdown-it`'s own rule (`replace_scoped` before
51
+ * `replace_rare`, and within the latter: `+-`, then `...`, then the
52
+ * `?`/`!`-adjacent ellipsis correction, then `!!!!`/`,,`, then em-dash, then
53
+ * en-dash):
54
+ *
55
+ * - `+-` before `...`: neither can produce the other's trigger character, so
56
+ * order between them is actually inert, but matching upstream's order keeps
57
+ * this auditable against it rather than needing its own independent proof.
58
+ * - The em-dash pass runs before the en-dash pass. `---` is three hyphens; the
59
+ * en-dash patterns below both require a NON-hyphen on the dash-adjacent side
60
+ * (`(?=[^-]|$)` / preceded by whitespace or a non-hyphen-non-space), so `---`
61
+ * itself never matches either en-dash pattern regardless of order — but a
62
+ * FOUR-hyphen run (`----`) would: the em-dash regex only consumes exactly
63
+ * three of the four hyphens (`(^|[^-])---(?=[^-]|$)` requires its OWN
64
+ * boundary hyphens to be non-hyphen), leaving a leftover single hyphens on
65
+ * either side that the leftover isn't itself `--`. Verified empirically
66
+ * against `markdown-it`'s reference implementation that `----` and `---`
67
+ * both resolve to one em dash: `----` is not decomposed into em+en, and
68
+ * running en-dash first would have changed that (the outer pair of the four
69
+ * hyphens would each independently look like the START of a `--` run before
70
+ * the em-dash pass ever saw the middle two as a `---`).
71
+ */
72
+ export declare function applyTypography(text: string): string;
package/dist/theme.d.ts CHANGED
@@ -62,6 +62,57 @@ export interface MarkdownTheme {
62
62
  * a failure rather than reading as prose.
63
63
  */
64
64
  mathFallbackColor?: string;
65
+ /**
66
+ * Background fill painted behind `==marked==` text (`markdown-it-mark`),
67
+ * consumed as {@link TextStyle.highlightColor}.
68
+ *
69
+ * A fixed default rather than derived from another theme key, unlike
70
+ * {@link footnoteColor}'s link-color derivation: CSS `mark`'s UA-stylesheet
71
+ * default (`background-color: Mark`, a yellow highlight) is not related to
72
+ * any other color in this theme, so there is nothing sensible to derive it
73
+ * from.
74
+ */
75
+ markHighlightColor?: string;
76
+ /**
77
+ * Accent/border color for a `:::kind` container, keyed by the lowercased
78
+ * `kind` word (`:::warning` → `containerColors.warning`).
79
+ *
80
+ * A `Record`, not one flat key per kind, because the vocabulary of kinds is
81
+ * open — `:::caution`, `:::success` and a project's own house style all
82
+ * have to resolve to *something* without a signature change here. Looked up
83
+ * through {@link containerColor} rather than read directly, which is what
84
+ * applies {@link containerDefaultColor} for a kind absent from the map (or
85
+ * for a bare `:::` with no kind at all).
86
+ *
87
+ * The four defaults mirror the common `note`/`tip`/`warning`/`danger`
88
+ * vocabulary of `markdown-it-container`/Docusaurus/mdBook admonitions;
89
+ * `info` aliases `note`'s color, since the two are used interchangeably
90
+ * across those tools and a project picking one is not expressing a second,
91
+ * distinct semantic.
92
+ */
93
+ containerColors?: Readonly<Record<string, string>>;
94
+ /**
95
+ * Accent/border color for a container whose `kind` is absent from
96
+ * {@link containerColors} — including a bare `:::` with no kind at all.
97
+ * Deliberately neutral (slate) rather than an error color: an unrecognised
98
+ * kind is a project's own vocabulary the theme does not know about, not a
99
+ * mistake.
100
+ */
101
+ containerDefaultColor?: string;
102
+ /**
103
+ * Background fill painted behind a `:::` container's full content area,
104
+ * one flat value for every kind rather than a per-kind tint.
105
+ *
106
+ * Real callout components (Docusaurus admonitions, mdBook, GitHub's own
107
+ * `[!NOTE]`) vary the ACCENT (border/label) by kind but keep one neutral
108
+ * background across all of them — the color is what signals severity, and a
109
+ * differently-tinted background per kind would fight the accent bar for
110
+ * that job rather than support it. Translucent so it composites against
111
+ * whatever surface a container is nested in (a container inside a
112
+ * blockquote inside a list), matching {@link codeBgColor}'s and
113
+ * {@link markHighlightColor}'s own translucent-overlay convention.
114
+ */
115
+ containerBgColor?: string;
65
116
  /** Code-block keyword color. */
66
117
  syntaxKeywordColor?: string;
67
118
  /** Code-block string-literal color. */
@@ -70,6 +121,19 @@ export interface MarkdownTheme {
70
121
  syntaxCommentColor?: string;
71
122
  /** Code-block numeric-literal color. */
72
123
  syntaxNumberColor?: string;
124
+ /**
125
+ * Enable `markdown-it`-style typographic substitutions: `--`/`---` to en/em
126
+ * dash, `...` to an ellipsis, `(c)`/`(r)`/`(tm)` to their symbols, `+-` to
127
+ * `±`, and straight quotes to curly ones (intra-run only — see
128
+ * {@link applyTypography}'s doc for why cross-boundary pairing is out of
129
+ * scope).
130
+ *
131
+ * Off by default, matching `markdown-it`'s own `typographer` option: these
132
+ * substitutions rewrite characters the author did not literally type, so
133
+ * applying them unconditionally would silently change a document's source
134
+ * rather than only its rendering.
135
+ */
136
+ typographer?: boolean;
73
137
  /** Body font. */
74
138
  bodyFont?: string;
75
139
  /** Monospace font for code. */
@@ -104,6 +168,47 @@ export interface MarkdownTheme {
104
168
  * superscript is therefore not expressible — see `markdown-footnote.ts`.
105
169
  */
106
170
  footnoteMarkerScale?: number;
171
+ /**
172
+ * Size of a subscript run (`H~2~O`'s `2`), as a multiple of the size of the
173
+ * run it sits in.
174
+ *
175
+ * Mirrors `markdown-it-sub`'s ~0.75em. Relative rather than absolute for the
176
+ * same reason as {@link footnoteMarkerScale}: a subscript inside a heading
177
+ * scales with the heading rather than reserving a body-sized glyph.
178
+ */
179
+ subscriptScale?: number;
180
+ /**
181
+ * Baseline shift for a subscript run, in em of the size of the run it sits
182
+ * in (the *unscaled* surrounding run, matching CSS `vertical-align: sub`,
183
+ * which is relative to the parent's font size rather than the subscript's
184
+ * own reduced one).
185
+ *
186
+ * Sign matches `TextStyle.baselineShift`: negative moves the run down. `-0.15`
187
+ * sits in markdown-it's ~-0.15em to -0.2em range; nothing in that range reaches
188
+ * the line-growth threshold at the default {@link subscriptScale}, so a lone
189
+ * subscript run does not grow its line (see `DEC-0001`'s degenerate case).
190
+ */
191
+ subscriptShift?: number;
192
+ /**
193
+ * Size of a superscript run (`19^th^`'s `th`), as a multiple of the size of
194
+ * the run it sits in. Mirrors `subscriptScale`; see that doc for why relative.
195
+ */
196
+ superscriptScale?: number;
197
+ /**
198
+ * Baseline shift for a superscript run, in em of the size of the run it sits
199
+ * in (the *unscaled* surrounding run — see {@link subscriptShift} for why).
200
+ *
201
+ * Positive, unlike `subscriptShift`: `TextStyle.baselineShift` is positive =
202
+ * up. `0.2` mirrors `subscriptShift`'s magnitude and, measured against
203
+ * `shiftedExtent()` at the default {@link superscriptScale}, is the largest
204
+ * shift that stays inside the line's existing growth slack for a lone raised
205
+ * run (see `DEC-0001`'s degenerate case) — `0.25` and up already force
206
+ * growth at this scale, which was measured directly rather than assumed:
207
+ * an earlier draft of this default (`0.3`, markdown-it's own superscript
208
+ * figure) was picked from that library's CSS without checking it against
209
+ * this engine's `shiftedExtent()` math, and it does force growth here.
210
+ */
211
+ superscriptShift?: number;
107
212
  /** Code-block line height in px. */
108
213
  codeLineHeight?: number;
109
214
  /**
@@ -127,6 +232,19 @@ export interface MarkdownTheme {
127
232
  quoteBorderWidth?: number;
128
233
  /** Vertical gap in px between blocks inside a blockquote. */
129
234
  quoteInnerGap?: number;
235
+ /**
236
+ * Left indent in px of a `:::` container's contents, from its accent
237
+ * border. Mirrors {@link quoteIndent} — a container is visually a
238
+ * blockquote with a label and a per-kind color, not a structurally
239
+ * different shape.
240
+ */
241
+ containerIndent?: number;
242
+ /** Width in px of a `:::` container's accent border. Mirrors {@link quoteBorderWidth}. */
243
+ containerBorderWidth?: number;
244
+ /** Vertical gap in px between blocks inside a `:::` container. Mirrors {@link quoteInnerGap}. */
245
+ containerInnerGap?: number;
246
+ /** Corner radius in px of a `:::` container's background fill. */
247
+ containerRadius?: number;
130
248
  /** Corner radius in px of an image. */
131
249
  imageRadius?: number;
132
250
  /**
@@ -177,3 +295,12 @@ export declare function resolveTheme(theme?: MarkdownTheme): Required<MarkdownTh
177
295
  * theme that supplied fewer than six sizes.
178
296
  */
179
297
  export declare function headingSize(theme: Required<MarkdownTheme>, depth: number): number;
298
+ /**
299
+ * Accent/border color for a `:::kind` container, looked up case-insensitively
300
+ * (`:::Warning` and `:::warning` resolve identically — a container's `kind` is
301
+ * a fixed vocabulary word, not case-sensitive prose) against
302
+ * {@link MarkdownTheme.containerColors}. Falls back to
303
+ * {@link MarkdownTheme.containerDefaultColor} for a kind the map does not
304
+ * carry, and for a bare `:::` with no kind (`kind` is `undefined`).
305
+ */
306
+ export declare function containerColor(theme: Required<MarkdownTheme>, kind: string | undefined): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectojs/markdown",
3
- "version": "0.16.1",
3
+ "version": "0.18.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -41,7 +41,7 @@
41
41
  "scripts": {
42
42
  "build": "(cd ../ui && bun run build) && (cd ../tex && bun run build) && node scripts/build-worker.js && tsup src/index.ts --format cjs,esm --clean && tsc -p tsconfig.build.json",
43
43
  "test": "vitest run",
44
- "test:e2e": "bun e2e/blockquote-layout.e2e.ts && bun e2e/stream-controller.e2e.ts && bun e2e/lazy-math.e2e.ts && bun e2e/paragraph-image-repaint.e2e.ts && bun e2e/inline-image.e2e.ts && bun e2e/selection-fidelity.e2e.ts && bun e2e/code-atlas-dpr.e2e.ts && bun e2e/set-max-width.e2e.ts && bun e2e/block-affordances.e2e.ts && bun e2e/single-tilde-ink.e2e.ts"
44
+ "test:e2e": "bun e2e/blockquote-layout.e2e.ts && bun e2e/stream-controller.e2e.ts && bun e2e/lazy-math.e2e.ts && bun e2e/paragraph-image-repaint.e2e.ts && bun e2e/inline-image.e2e.ts && bun e2e/selection-fidelity.e2e.ts && bun e2e/code-atlas-dpr.e2e.ts && bun e2e/set-max-width.e2e.ts && bun e2e/block-affordances.e2e.ts && bun e2e/single-tilde-ink.e2e.ts && bun e2e/superscript-ink.e2e.ts && bun e2e/ins-mark-ink.e2e.ts && bun e2e/container-ink.e2e.ts && bun e2e/abbr-ink.e2e.ts"
45
45
  },
46
46
  "dependencies": {
47
47
  "@vectojs/tex": "^0.1.0",