@peaceroad/markdown-it-renderer-fence 0.7.0 → 0.9.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.
Files changed (36) hide show
  1. package/README.md +179 -470
  2. package/docs/README.md +37 -0
  3. package/docs/code-highlighting-design.md +321 -0
  4. package/docs/custom-highlight-styling-guide.md +210 -0
  5. package/package.json +25 -13
  6. package/src/custom-highlight/option-validator.js +5 -5
  7. package/src/custom-highlight/payload-utils.js +4 -9
  8. package/src/custom-highlight/{shiki-keyword-rules.js → shiki-role-rules.js} +249 -54
  9. package/src/custom-highlight/{shiki-keyword.js → shiki-role.js} +107 -99
  10. package/src/custom-highlight/shiki-theme-role.js +176 -0
  11. package/src/fence/line-notes.js +27 -9
  12. package/src/fence/render-api-constants.js +1 -1
  13. package/src/fence/render-api-provider.js +61 -53
  14. package/src/fence/render-api-renderer.js +26 -10
  15. package/src/fence/render-api-runtime.js +29 -10
  16. package/src/fence/render-api.js +20 -12
  17. package/src/fence/render-markup.js +34 -24
  18. package/src/fence/render-shared.js +150 -30
  19. package/src/utils/attr-utils.js +10 -0
  20. package/theme/_shared/rf-core.css +170 -0
  21. package/theme/line-notes.css +94 -0
  22. package/theme/line-number.css +64 -0
  23. package/theme/rf-basic/README.md +117 -0
  24. package/theme/rf-basic/api/highlightjs.css +71 -0
  25. package/theme/rf-basic/api/shiki.css +67 -0
  26. package/theme/rf-basic/base.css +5 -0
  27. package/theme/rf-basic/index.css +7 -0
  28. package/theme/rf-basic/index.js +164 -0
  29. package/theme/rf-basic/markup/highlightjs.css +77 -0
  30. package/theme/rf-basic/markup/shiki.css +11 -0
  31. package/theme/rf-monochrome/README.md +84 -0
  32. package/theme/rf-monochrome/base.css +5 -0
  33. package/theme/rf-monochrome/index.css +5 -0
  34. package/theme/rf-monochrome/index.js +71 -0
  35. package/theme/rf-monochrome/markup/highlightjs.css +150 -0
  36. package/theme/rf-monochrome/markup/shiki.css +38 -0
@@ -0,0 +1,64 @@
1
+ /*! Renderer Fence line-number layout | MIT License */
2
+
3
+ :root {
4
+ --line-number-width: 2em;
5
+ --line-number-gap: 0.5em;
6
+ --line-number-rule-gap: 0.25em;
7
+ --line-number-color: var(--rf-line-number-fg, #666);
8
+ --line-number-rule-color: var(--rf-line-number-rule, #ccc);
9
+ }
10
+
11
+ pre :is(code, samp)[data-pre-start] .pre-line {
12
+ display: block;
13
+ position: relative;
14
+ padding-inline-start: calc(var(--line-number-width) + var(--line-number-rule-gap) + var(--line-number-gap));
15
+ background-image: linear-gradient(var(--line-number-rule-color), var(--line-number-rule-color));
16
+ background-repeat: no-repeat;
17
+ background-size: 1px 100%;
18
+ background-position: calc(var(--line-number-width) + var(--line-number-rule-gap)) 0;
19
+ }
20
+
21
+ pre :is(code, samp)[data-pre-start] {
22
+ white-space: normal;
23
+ }
24
+
25
+ pre:not([data-pre-wrap]) :is(code, samp)[data-pre-start] .pre-line {
26
+ white-space: pre;
27
+ }
28
+
29
+ pre[data-pre-wrap] :is(code, samp)[data-pre-start] .pre-line {
30
+ white-space: break-spaces;
31
+ overflow-wrap: anywhere;
32
+ }
33
+
34
+ pre :is(code, samp)[data-pre-start] .pre-line::before {
35
+ content: counter(pre-line-number);
36
+ position: absolute;
37
+ inset-inline-start: 0;
38
+ top: 0;
39
+ width: var(--line-number-width);
40
+ padding-inline-end: var(--line-number-rule-gap);
41
+ color: var(--line-number-color);
42
+ text-align: right;
43
+ }
44
+
45
+ pre :is(code, samp)[data-pre-start] .pre-line[data-pre-line-label]::before {
46
+ content: attr(data-pre-line-label);
47
+ }
48
+
49
+ pre :is(code, samp)[data-pre-start] .pre-line[data-pre-line-label-bold]::before {
50
+ font-weight: bold;
51
+ }
52
+
53
+ pre :is(code, samp)[data-pre-start] .pre-line::after {
54
+ content: "";
55
+ counter-increment: pre-line-number;
56
+ }
57
+
58
+ pre :is(code, samp)[data-pre-start] .pre-line.pre-line-no-number::before {
59
+ content: "";
60
+ }
61
+
62
+ pre :is(code, samp)[data-pre-start] .pre-line.pre-line-no-number::after {
63
+ counter-increment: none;
64
+ }
@@ -0,0 +1,117 @@
1
+ # rf-basic Theme
2
+
3
+ `rf-basic` is the optional first-party color preset for `@peaceroad/markdown-it-renderer-fence`.
4
+ It is a mode/provider-aware theme package: import only the CSS and JavaScript helper that matches the renderer mode you actually run.
5
+
6
+ ## Markup mode
7
+
8
+ Shiki markup mode uses the JavaScript Shiki theme object plus the shared block styling:
9
+
10
+ ```js
11
+ import { rfBasicShikiTheme } from '@peaceroad/markdown-it-renderer-fence/theme/rf-basic'
12
+ ```
13
+
14
+ ```css
15
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic/base.css";
16
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic/markup/shiki.css";
17
+ ```
18
+
19
+ highlight.js markup mode uses the same base plus highlight.js class rules:
20
+
21
+ ```css
22
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic/base.css";
23
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic/markup/highlightjs.css";
24
+ ```
25
+
26
+ ## Custom Highlight API mode
27
+
28
+ Shiki API mode has two distinct profiles. The recommended CSS-managed role profile uses the dedicated helper and `::highlight(hl-shiki-role-*)` CSS:
29
+
30
+ ```js
31
+ import { createRfBasicShikiRoleCustomHighlightOptions } from '@peaceroad/markdown-it-renderer-fence/theme/rf-basic'
32
+
33
+ const customHighlight = createRfBasicShikiRoleCustomHighlightOptions({ highlighter })
34
+ ```
35
+
36
+ ```css
37
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic/base.css";
38
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic/api/shiki.css";
39
+ ```
40
+
41
+ The generic `createRfBasicShikiCustomHighlightOptions()` helper keeps its `semantic` + embedded `scopeStyles` defaults for callers that want provider-owned payload styles. That profile needs `base.css` to define the `--rf-*` variables, but it does not depend on the role-only `api/shiki.css` selectors.
42
+
43
+ highlight.js API mode uses the highlight.js provider helper and API scope CSS:
44
+
45
+ ```js
46
+ import { createRfBasicHighlightjsCustomHighlightOptions } from '@peaceroad/markdown-it-renderer-fence/theme/rf-basic'
47
+ ```
48
+
49
+ ```css
50
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic/base.css";
51
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic/api/highlightjs.css";
52
+ ```
53
+
54
+ ## Complete preset
55
+
56
+ For demos or pages that intentionally compare providers, the complete color preset is available:
57
+
58
+ ```css
59
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic.css";
60
+ ```
61
+
62
+ It imports base layout, line-number/line-notes layout, Shiki role-mode API scopes, highlight.js API scopes, Shiki markup correction, and highlight.js markup classes.
63
+
64
+ The base palette follows `prefers-color-scheme`, but applies the CSS `color-scheme` hint only to each `pre` surface. Importing the theme does not change UA colors for the whole document. Sites with an explicit theme can override `--rf-code-color-scheme` and `--rf-samp-color-scheme` together with the palette variables.
65
+
66
+ ## Line feature customization
67
+
68
+ The renderer owns line-number markup, counter values, skip/set behavior, and line wrappers. The structural CSS owns presentation, so an application theme can change the layout without changing renderer options:
69
+
70
+ ```css
71
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-basic.css";
72
+
73
+ .docs-theme {
74
+ --line-number-width: 3ch;
75
+ --line-number-gap: 0.75ch;
76
+ --line-number-rule-gap: 0.5ch;
77
+ --line-number-color: oklch(48% 0.03 250);
78
+ --line-number-rule-color: oklch(82% 0.02 250);
79
+ }
80
+ ```
81
+
82
+ The variables are inherited, so they can be set globally or on a container that owns the rendered Markdown. The preset gives `samp` an inverted terminal palette on `pre:has(> samp)`; override the same variables on that `pre` selector as well when terminal line numbers need a different application-specific treatment.
83
+
84
+ ## Color design
85
+
86
+ The palette is neutral-first: code backgrounds stay close to monochrome, syntax roles keep high contrast, and `samp` blocks invert the code palette so terminal output remains visually distinct in both light and dark color schemes.
87
+
88
+ Role directions:
89
+
90
+ - keyword: red/coral
91
+ - string: blue
92
+ - number/literal: blue-violet
93
+ - title/type: purple/magenta
94
+ - variable: amber/brown
95
+ - tag: green/teal
96
+ - punctuation/meta: neutral
97
+
98
+ The theme favors practical readability and cross-provider consistency over exact parity with any one editor theme.
99
+
100
+ ## File roles
101
+
102
+ - `index.css`: complete color preset for demos and mixed-provider pages.
103
+ - `base.css`: public base import; it loads shared renderer-fence block/layout CSS plus package-owned line-number and line-notes layout.
104
+ - `markup/shiki.css`: Shiki markup correction for `samp` terminal surfaces.
105
+ - `markup/highlightjs.css`: highlight.js markup class rules.
106
+ - `api/highlightjs.css`: Custom Highlight API rules for highlight.js provider ranges.
107
+ - `api/shiki.css`: Custom Highlight API rules for Shiki role-mode ranges.
108
+ - `index.js`: Shiki theme object and provider option helpers.
109
+
110
+ The private `theme/_shared/rf-core.css` file is an internal source file used to avoid
111
+ duplicating block/layout CSS across themes. Import this theme's public `base.css` instead.
112
+ The theme-neutral structural files are also public as `theme/line-number.css` and `theme/line-notes.css` for consumers that do not want a preset palette.
113
+ The below-block line-note label can be localized without changing renderer HTML by overriding `--line-note-label-prefix` and `--line-note-label-suffix`.
114
+
115
+ ## License
116
+
117
+ MIT, same as the package.
@@ -0,0 +1,71 @@
1
+ /*! rf-basic highlightjs API scopes | MIT License */
2
+
3
+ ::highlight(hl-hljs-language-javascript),
4
+ ::highlight(hl-hljs-subst) {
5
+ color: var(--rf-code-fg);
6
+ }
7
+
8
+ ::highlight(hl-hljs-keyword),
9
+ ::highlight(hl-hljs-built-in),
10
+ ::highlight(hl-hljs-built_in) {
11
+ color: var(--rf-syntax-keyword);
12
+ }
13
+
14
+ ::highlight(hl-hljs-string) {
15
+ color: var(--rf-syntax-string);
16
+ }
17
+
18
+ ::highlight(hl-hljs-number) {
19
+ color: var(--rf-syntax-number);
20
+ }
21
+
22
+ ::highlight(hl-hljs-comment) {
23
+ color: var(--rf-syntax-comment);
24
+ }
25
+
26
+ ::highlight(hl-hljs-literal) {
27
+ color: var(--rf-syntax-literal);
28
+ }
29
+
30
+ ::highlight(hl-hljs-type) {
31
+ color: var(--rf-syntax-type);
32
+ }
33
+
34
+ ::highlight(hl-hljs-title),
35
+ ::highlight(hl-hljs-title-function),
36
+ ::highlight(hl-hljs-title-class),
37
+ ::highlight(hl-hljs-title-function-invoke),
38
+ ::highlight(hl-hljs-function),
39
+ ::highlight(hl-hljs-class) {
40
+ color: var(--rf-syntax-title);
41
+ }
42
+
43
+ ::highlight(hl-hljs-variable),
44
+ ::highlight(hl-hljs-variable-constant),
45
+ ::highlight(hl-hljs-variable-language),
46
+ ::highlight(hl-hljs-params),
47
+ ::highlight(hl-hljs-property) {
48
+ color: var(--rf-syntax-variable);
49
+ }
50
+
51
+ ::highlight(hl-hljs-tag),
52
+ ::highlight(hl-hljs-name),
53
+ ::highlight(hl-hljs-selector-pseudo) {
54
+ color: var(--rf-syntax-tag);
55
+ }
56
+
57
+ ::highlight(hl-hljs-attr),
58
+ ::highlight(hl-hljs-attribute),
59
+ ::highlight(hl-hljs-selector-class) {
60
+ color: var(--rf-syntax-attribute);
61
+ }
62
+
63
+ ::highlight(hl-hljs-punctuation),
64
+ ::highlight(hl-hljs-meta),
65
+ ::highlight(hl-hljs-operator) {
66
+ color: var(--rf-syntax-punctuation);
67
+ }
68
+
69
+ ::highlight(hl-hljs-symbol) {
70
+ color: var(--rf-syntax-literal);
71
+ }
@@ -0,0 +1,67 @@
1
+ /*! rf-basic Shiki role-mode API scopes | MIT License */
2
+
3
+ ::highlight(hl-shiki-role-text) {
4
+ color: var(--rf-code-fg);
5
+ }
6
+
7
+ ::highlight(hl-shiki-role-keyword),
8
+ ::highlight(hl-shiki-role-type-primitive) {
9
+ color: var(--rf-syntax-keyword);
10
+ }
11
+
12
+ ::highlight(hl-shiki-role-string),
13
+ ::highlight(hl-shiki-role-string-unquoted) {
14
+ color: var(--rf-syntax-string);
15
+ }
16
+
17
+ ::highlight(hl-shiki-role-number) {
18
+ color: var(--rf-syntax-number);
19
+ }
20
+
21
+ ::highlight(hl-shiki-role-comment),
22
+ ::highlight(hl-shiki-role-meta-shebang) {
23
+ color: var(--rf-syntax-comment);
24
+ }
25
+
26
+ ::highlight(hl-shiki-role-literal),
27
+ ::highlight(hl-shiki-role-variable-this) {
28
+ color: var(--rf-syntax-literal);
29
+ }
30
+
31
+ ::highlight(hl-shiki-role-type),
32
+ ::highlight(hl-shiki-role-type-name),
33
+ ::highlight(hl-shiki-role-title-class),
34
+ ::highlight(hl-shiki-role-namespace) {
35
+ color: var(--rf-syntax-type);
36
+ }
37
+
38
+ ::highlight(hl-shiki-role-title-function),
39
+ ::highlight(hl-shiki-role-title-function-builtin) {
40
+ color: var(--rf-syntax-title);
41
+ }
42
+
43
+ ::highlight(hl-shiki-role-variable),
44
+ ::highlight(hl-shiki-role-variable-const),
45
+ ::highlight(hl-shiki-role-variable-member),
46
+ ::highlight(hl-shiki-role-variable-plain),
47
+ ::highlight(hl-shiki-role-variable-property),
48
+ ::highlight(hl-shiki-role-variable-parameter) {
49
+ color: var(--rf-syntax-variable);
50
+ }
51
+
52
+ ::highlight(hl-shiki-role-tag) {
53
+ color: var(--rf-syntax-tag);
54
+ }
55
+
56
+ ::highlight(hl-shiki-role-attribute) {
57
+ color: var(--rf-syntax-attribute);
58
+ }
59
+
60
+ ::highlight(hl-shiki-role-punctuation),
61
+ ::highlight(hl-shiki-role-tag-delimiter) {
62
+ color: var(--rf-syntax-punctuation);
63
+ }
64
+
65
+ ::highlight(hl-shiki-role-meta) {
66
+ color: var(--rf-code-fg);
67
+ }
@@ -0,0 +1,5 @@
1
+ /*! rf-basic base | MIT License */
2
+
3
+ @import "../_shared/rf-core.css";
4
+ @import "../line-number.css";
5
+ @import "../line-notes.css";
@@ -0,0 +1,7 @@
1
+ /*! rf-basic theme | MIT License */
2
+
3
+ @import "./base.css";
4
+ @import "./api/shiki.css";
5
+ @import "./api/highlightjs.css";
6
+ @import "./markup/shiki.css";
7
+ @import "./markup/highlightjs.css";
@@ -0,0 +1,164 @@
1
+ import { rendererFenceShikiThemeScopeGroups } from '../../src/custom-highlight/shiki-theme-role.js'
2
+
3
+ const rfBasicThemeName = 'rf-basic'
4
+ const rfBasicShikiThemeName = rfBasicThemeName
5
+
6
+ const rfBasicSyntaxCssVars = Object.freeze({
7
+ background: 'var(--rf-code-bg)',
8
+ text: 'var(--rf-code-fg)',
9
+ keyword: 'var(--rf-syntax-keyword)',
10
+ string: 'var(--rf-syntax-string)',
11
+ number: 'var(--rf-syntax-number)',
12
+ comment: 'var(--rf-syntax-comment)',
13
+ type: 'var(--rf-syntax-type)',
14
+ title: 'var(--rf-syntax-title)',
15
+ variable: 'var(--rf-syntax-variable)',
16
+ literal: 'var(--rf-syntax-literal)',
17
+ tag: 'var(--rf-syntax-tag)',
18
+ attribute: 'var(--rf-syntax-attribute)',
19
+ punctuation: 'var(--rf-syntax-punctuation)',
20
+ meta: 'var(--rf-syntax-meta)',
21
+
22
+ // Backward-friendly role aliases for highlighter APIs that use these names.
23
+ constant: 'var(--rf-syntax-literal)',
24
+ builtIn: 'var(--rf-syntax-variable)',
25
+ })
26
+
27
+ const mergePalette = (palette) => palette
28
+ ? Object.assign({}, rfBasicSyntaxCssVars, palette)
29
+ : rfBasicSyntaxCssVars
30
+
31
+ const createTokenColor = (scope, foreground) => ({
32
+ scope: Array.isArray(scope) ? scope.slice() : scope,
33
+ settings: { foreground },
34
+ })
35
+
36
+ const createRfBasicShikiTheme = ({
37
+ name = rfBasicShikiThemeName,
38
+ palette = null,
39
+ } = {}) => {
40
+ const p = mergePalette(palette)
41
+ return {
42
+ name,
43
+ type: 'light',
44
+ colors: {
45
+ 'editor.foreground': p.text,
46
+ 'editor.background': p.background,
47
+ },
48
+ tokenColors: [
49
+ { settings: { foreground: p.text } },
50
+ createTokenColor(rendererFenceShikiThemeScopeGroups.comment, p.comment),
51
+ createTokenColor(rendererFenceShikiThemeScopeGroups.string, p.string),
52
+ createTokenColor(rendererFenceShikiThemeScopeGroups.number, p.number),
53
+ createTokenColor(rendererFenceShikiThemeScopeGroups.literal, p.literal),
54
+ createTokenColor(rendererFenceShikiThemeScopeGroups.keyword, p.keyword),
55
+ createTokenColor(rendererFenceShikiThemeScopeGroups.punctuation, p.punctuation),
56
+ createTokenColor(rendererFenceShikiThemeScopeGroups.title, p.title),
57
+ createTokenColor(rendererFenceShikiThemeScopeGroups.type, p.type),
58
+ createTokenColor(rendererFenceShikiThemeScopeGroups.variable, p.variable),
59
+ createTokenColor(rendererFenceShikiThemeScopeGroups.tag, p.tag),
60
+ createTokenColor(rendererFenceShikiThemeScopeGroups.attribute, p.attribute),
61
+ ],
62
+ }
63
+ }
64
+
65
+ const rfBasicShikiTheme = createRfBasicShikiTheme()
66
+
67
+ const createRfBasicShikiRoleScopeColorVars = (palette = null) => {
68
+ const p = mergePalette(palette)
69
+ return {
70
+ 'hl-shiki-role-keyword': p.keyword,
71
+ 'hl-shiki-role-type-primitive': p.keyword,
72
+ 'hl-shiki-role-number': p.number,
73
+ 'hl-shiki-role-string': p.string,
74
+ 'hl-shiki-role-string-unquoted': p.string,
75
+ 'hl-shiki-role-variable': p.variable,
76
+ 'hl-shiki-role-variable-this': p.literal,
77
+ 'hl-shiki-role-variable-const': p.variable,
78
+ 'hl-shiki-role-variable-member': p.variable,
79
+ 'hl-shiki-role-variable-plain': p.variable,
80
+ 'hl-shiki-role-variable-property': p.variable,
81
+ 'hl-shiki-role-variable-parameter': p.variable,
82
+ 'hl-shiki-role-title-function': p.title,
83
+ 'hl-shiki-role-title-function-builtin': p.title,
84
+ 'hl-shiki-role-title-class': p.type,
85
+ 'hl-shiki-role-namespace': p.type,
86
+ 'hl-shiki-role-literal': p.literal,
87
+ 'hl-shiki-role-comment': p.comment,
88
+ 'hl-shiki-role-meta-shebang': p.comment,
89
+ 'hl-shiki-role-punctuation': p.punctuation,
90
+ 'hl-shiki-role-meta': p.text,
91
+ 'hl-shiki-role-type': p.type,
92
+ 'hl-shiki-role-type-name': p.type,
93
+ 'hl-shiki-role-tag': p.tag,
94
+ 'hl-shiki-role-tag-delimiter': p.punctuation,
95
+ 'hl-shiki-role-attribute': p.attribute,
96
+ 'hl-shiki-role-text': p.text,
97
+ }
98
+ }
99
+
100
+ const rfBasicShikiRoleScopeColorVars = Object.freeze(
101
+ createRfBasicShikiRoleScopeColorVars(),
102
+ )
103
+
104
+ const createHighlightjsHighlightFn = (hljs) => {
105
+ if (!hljs || typeof hljs.highlight !== 'function') return null
106
+ return (code, lang) => {
107
+ const target = (lang && typeof hljs.getLanguage === 'function' && hljs.getLanguage(lang))
108
+ ? lang
109
+ : 'plaintext'
110
+ return hljs.highlight(code, { language: target })
111
+ }
112
+ }
113
+
114
+ const createRfBasicShikiCustomHighlightOptions = ({
115
+ highlighter,
116
+ theme = rfBasicShikiThemeName,
117
+ shikiScopeMode = 'semantic',
118
+ includeScopeStyles = shikiScopeMode === 'role' ? false : true,
119
+ ...overrides
120
+ } = {}) => ({
121
+ ...overrides,
122
+ provider: 'shiki',
123
+ highlighter,
124
+ theme,
125
+ shikiScopeMode,
126
+ includeScopeStyles,
127
+ })
128
+
129
+ const createRfBasicShikiRoleCustomHighlightOptions = (options = {}) => {
130
+ return createRfBasicShikiCustomHighlightOptions({
131
+ ...options,
132
+ shikiScopeMode: 'role',
133
+ includeScopeStyles: false,
134
+ })
135
+ }
136
+
137
+ const createRfBasicHighlightjsCustomHighlightOptions = ({
138
+ hljs,
139
+ hljsHighlight,
140
+ highlight,
141
+ includeScopeStyles = false,
142
+ ...overrides
143
+ } = {}) => ({
144
+ ...overrides,
145
+ provider: 'hljs',
146
+ includeScopeStyles,
147
+ hljsHighlight: hljsHighlight || highlight || createHighlightjsHighlightFn(hljs),
148
+ })
149
+
150
+ const rfBasicShikiThemeScopeGroups = rendererFenceShikiThemeScopeGroups
151
+
152
+ export {
153
+ createRfBasicHighlightjsCustomHighlightOptions,
154
+ createRfBasicShikiCustomHighlightOptions,
155
+ createRfBasicShikiRoleCustomHighlightOptions,
156
+ createRfBasicShikiRoleScopeColorVars,
157
+ createRfBasicShikiTheme,
158
+ rfBasicShikiRoleScopeColorVars,
159
+ rfBasicShikiTheme,
160
+ rfBasicShikiThemeName,
161
+ rfBasicShikiThemeScopeGroups,
162
+ rfBasicSyntaxCssVars,
163
+ rfBasicThemeName,
164
+ }
@@ -0,0 +1,77 @@
1
+ /*! rf-basic highlight.js markup scopes | MIT License */
2
+
3
+ .hljs-keyword,
4
+ .hljs-built_in {
5
+ color: var(--rf-syntax-keyword);
6
+ }
7
+
8
+ .hljs-string {
9
+ color: var(--rf-syntax-string);
10
+ }
11
+
12
+ .hljs-number {
13
+ color: var(--rf-syntax-number);
14
+ }
15
+
16
+ .hljs-comment {
17
+ color: var(--rf-syntax-comment);
18
+ }
19
+
20
+ .hljs-literal,
21
+ .hljs-symbol {
22
+ color: var(--rf-syntax-literal);
23
+ }
24
+
25
+ .hljs-type {
26
+ color: var(--rf-syntax-type);
27
+ }
28
+
29
+ .hljs-title,
30
+ .hljs-title.function_,
31
+ .hljs-title.class_,
32
+ .hljs-function,
33
+ .hljs-class {
34
+ color: var(--rf-syntax-title);
35
+ }
36
+
37
+ .hljs-variable,
38
+ .hljs-variable.constant_,
39
+ .hljs-params,
40
+ .hljs-property {
41
+ color: var(--rf-syntax-variable);
42
+ }
43
+
44
+ .hljs-tag,
45
+ .hljs-name {
46
+ color: var(--rf-syntax-tag);
47
+ }
48
+
49
+ .hljs-attr,
50
+ .hljs-attribute,
51
+ .hljs-selector-class {
52
+ color: var(--rf-syntax-attribute);
53
+ }
54
+
55
+ .hljs-punctuation,
56
+ .hljs-meta,
57
+ .hljs-operator {
58
+ color: var(--rf-syntax-punctuation);
59
+ }
60
+
61
+ .hljs-meta.prompt_ {
62
+ color: var(--rf-code-muted);
63
+ }
64
+
65
+ .hljs-subst,
66
+ .language-javascript {
67
+ color: var(--rf-code-fg);
68
+ }
69
+
70
+ pre:has(> samp) .hljs-meta.prompt_ {
71
+ color: var(--rf-samp-prompt);
72
+ }
73
+
74
+ pre:has(> samp) .hljs-subst,
75
+ pre:has(> samp) .language-javascript {
76
+ color: var(--rf-samp-fg);
77
+ }
@@ -0,0 +1,11 @@
1
+ /*! rf-basic Shiki markup scopes | MIT License */
2
+
3
+ /*
4
+ * Shiki writes background/color as inline styles on `<pre>`. When renderer-fence
5
+ * outputs a Shiki-highlighted `<samp>`, re-apply the rf-basic terminal surface
6
+ * so the samp syntax variables are not rendered on the normal code background.
7
+ */
8
+ pre.shiki:has(> samp) {
9
+ color: var(--rf-samp-fg) !important;
10
+ background-color: var(--rf-samp-bg) !important;
11
+ }
@@ -0,0 +1,84 @@
1
+ # rf-monochrome Theme
2
+
3
+ `rf-monochrome` is a one-color markup-mode preset for `@peaceroad/markdown-it-renderer-fence`.
4
+ It uses the shared renderer-fence code surface plus bold/italic cues instead of syntax colors. It is intended for print, photocopy-safe output, or documents that must keep code in a single text color.
5
+
6
+ ## Scope
7
+
8
+ This is intentionally a markup-mode theme. Browser Custom Highlight API rules cannot reliably apply `font-weight` or `font-style`, so API-mode monochrome would mostly be `color: currentColor` and would not provide the intended structure cues.
9
+
10
+ ## highlight.js markup
11
+
12
+ ```css
13
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-monochrome.css";
14
+ ```
15
+
16
+ or, if you want split imports:
17
+
18
+ ```css
19
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-monochrome/base.css";
20
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-monochrome/markup/highlightjs.css";
21
+ ```
22
+
23
+ ## Shiki markup
24
+
25
+ Use the Shiki theme object plus base CSS:
26
+
27
+ ```js
28
+ import { rfMonochromeShikiTheme } from '@peaceroad/markdown-it-renderer-fence/theme/rf-monochrome'
29
+ ```
30
+
31
+ ```css
32
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-monochrome/base.css";
33
+ @import "@peaceroad/markdown-it-renderer-fence/theme/rf-monochrome/markup/shiki.css";
34
+ ```
35
+
36
+ `markup/shiki.css` maps Shiki's inline `currentColor` / transparent surface back to the shared code and `samp` surfaces; the main Shiki token styling comes from `rfMonochromeShikiTheme`.
37
+
38
+ ## Design notes
39
+
40
+ - No underline by default; underline makes code harder to scan and can look like links.
41
+ - Keywords, type/class/tag-like structural tokens use bold.
42
+ - Comments use italic by default; metadata stays normal so it does not become visually indistinguishable from prose comments.
43
+ - Doc tags and ordinary function/method titles stay normal weight so they do not compete with structural keywords. Shiki may classify constructor-like tokens as `storage.type`; keeping those bold avoids a broader override that would also neutralize `const` / `let` / `var` declarations inside method bodies.
44
+ - Terminal-like `<samp>` blocks suppress token-level bold/italic so prompts, commands, and output do not look inconsistently emphasized.
45
+
46
+ Italic comments are only a default. When the rendered code inherits `lang="ja"`, `lang="zh"`, or `lang="ko"` from the document or a nearer container, the preset automatically renders comment tokens upright. CSS `:lang()` matching also covers subtags such as `ja-JP`.
47
+
48
+ You can still disable comment italics explicitly for another language or a specific container:
49
+
50
+ ```css
51
+ /* Global or scoped to the container that owns rendered Markdown. */
52
+ .docs-theme {
53
+ --rf-monochrome-comment-font-style: normal;
54
+ }
55
+ ```
56
+
57
+ For Shiki markup output, the preset CSS overrides the default inline italic style for inherited CJK languages. Create the theme with `createRfMonochromeShikiTheme({ commentFontStyle: '' })` when comments should remain upright regardless of language.
58
+
59
+ Typography defaults live on `:root` and inherit into code blocks, so an application can override them globally or on a Markdown container. Structural emphasis can be tuned without rewriting the theme. highlight.js consumers can override `--rf-monochrome-strong-font-weight` (default `700`) and `--rf-monochrome-normal-font-weight` (default `400`). Shiki accepts `createRfMonochromeShikiTheme({ structuralFontStyle: '' })` when an application wants a completely regular-weight one-color rendering. Shiki's TextMate `fontStyle` supports semantic `bold` rather than an arbitrary numeric weight, so exact `600`/`650` parity remains CSS/highlight.js-specific.
60
+
61
+ Metadata is normal by default. Sites that prefer italic preprocessor or metadata tokens can opt in:
62
+
63
+ ```css
64
+ .docs-theme {
65
+ --rf-monochrome-meta-font-style: italic;
66
+ }
67
+ ```
68
+
69
+ ## File roles
70
+
71
+ - `index.css`: complete monochrome markup preset.
72
+ - `base.css`: public base import; it loads shared renderer-fence block/layout CSS plus package-owned line-number and line-notes layout.
73
+ - `markup/highlightjs.css`: highlight.js monochrome class rules.
74
+ - `markup/shiki.css`: Shiki markup `samp` override.
75
+ - `index.js`: Shiki monochrome theme object and factory.
76
+
77
+ The private `theme/_shared/rf-core.css` file is an internal source file used to avoid
78
+ duplicating block/layout CSS across themes. Import this theme's public `base.css` instead.
79
+ The structural layouts are also available without a palette as `theme/line-number.css` and `theme/line-notes.css`.
80
+ The below-block line-note label is customizable through `--line-note-label-prefix` and `--line-note-label-suffix`.
81
+
82
+ ## License
83
+
84
+ MIT, same as the package.
@@ -0,0 +1,5 @@
1
+ /*! rf-monochrome base | MIT License */
2
+
3
+ @import "../_shared/rf-core.css";
4
+ @import "../line-number.css";
5
+ @import "../line-notes.css";
@@ -0,0 +1,5 @@
1
+ /*! rf-monochrome theme | MIT License */
2
+
3
+ @import "./base.css";
4
+ @import "./markup/highlightjs.css";
5
+ @import "./markup/shiki.css";