comark-code-notes 0.7.6 → 0.8.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 +1 -1
- package/dist/client-Cl1M_Rli.mjs +20 -0
- package/dist/client.d.mts +2 -3
- package/dist/client.mjs +2 -11
- package/dist/html.mjs +2 -2
- package/dist/index.mjs +1 -213
- package/dist/react.mjs +2 -2
- package/dist/src-JYXNZqY7.mjs +218 -0
- package/dist/style.css +1 -1
- package/dist/styles-BsMSqaDf.mjs +157 -0
- package/dist/vue.mjs +2 -2
- package/package.json +2 -2
- package/dist/styles-zxOi3Y7k.mjs +0 -83
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ The plugin adds every problem to `meta.issues`, so a host can reject a document
|
|
|
37
37
|
|
|
38
38
|
| Renderer | Import |
|
|
39
39
|
| --- | --- |
|
|
40
|
-
| `@comark/html` | `comark-code-notes/html`: the styles are inlined
|
|
40
|
+
| `@comark/html` | `comark-code-notes/html`: the styles are inlined |
|
|
41
41
|
| `@comark/vue` | `comark-code-notes/vue` |
|
|
42
42
|
| `@comark/react` | `comark-code-notes/react` |
|
|
43
43
|
| `@comark/svelte` | `comark-code-notes/svelte` |
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { t as css } from "./styles-BsMSqaDf.mjs";
|
|
2
|
+
//#region ../../shared/styles.ts
|
|
3
|
+
/**
|
|
4
|
+
* Adds a package's styles to the page once, unless the page already carries them as a `style` or a `link` with
|
|
5
|
+
* `data-comark-<name>`, which is how the HTML renderer inlines them and how an app that imports `style.css` marks them.
|
|
6
|
+
*/
|
|
7
|
+
function addStyles$1(name, css) {
|
|
8
|
+
const attribute = `data-comark-${name}`;
|
|
9
|
+
if (document.querySelector(`style[${attribute}],link[${attribute}]`)) return;
|
|
10
|
+
const style = document.createElement("style");
|
|
11
|
+
style.setAttribute(attribute, "");
|
|
12
|
+
style.textContent = css;
|
|
13
|
+
document.head.append(style);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/client.ts
|
|
17
|
+
/** Adds the code notes styles to the page once. The Vue, React, and Svelte components call it when they mount. */
|
|
18
|
+
const addStyles = () => addStyles$1("code-notes", css);
|
|
19
|
+
//#endregion
|
|
20
|
+
export { addStyles as t };
|
package/dist/client.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
//#region src/styles.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Round numbered markers at the ends of lines and before each note, as a soft tint of
|
|
4
|
-
* page has it, or of the foreground otherwise, with the number in that color, on the shared `--comark-*` tokens.
|
|
3
|
+
* Round numbered markers at the ends of lines and before each note, as a soft tint of the primary color, with the number in that color, on the shared `--comark-*` tokens.
|
|
5
4
|
* Override `--cn-marker` and `--cn-marker-text`. The number is drawn by CSS, so copying the code never takes it along.
|
|
6
5
|
* The rules sit in the `comark` layer, so any unlayered rule of the host's wins.
|
|
7
6
|
*/
|
|
@@ -9,5 +8,5 @@ export declare const css: string;
|
|
|
9
8
|
//#endregion
|
|
10
9
|
//#region src/client.d.ts
|
|
11
10
|
/** Adds the code notes styles to the page once. The Vue, React, and Svelte components call it when they mount. */
|
|
12
|
-
export declare
|
|
11
|
+
export declare const addStyles: () => void;
|
|
13
12
|
//#endregion
|
package/dist/client.mjs
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import { t as css } from "./styles-
|
|
2
|
-
|
|
3
|
-
/** Adds the code notes styles to the page once. The Vue, React, and Svelte components call it when they mount. */
|
|
4
|
-
function addStyles() {
|
|
5
|
-
if (document.querySelector("style[data-comark-code-notes]")) return;
|
|
6
|
-
const style = document.createElement("style");
|
|
7
|
-
style.dataset.comarkCodeNotes = "";
|
|
8
|
-
style.textContent = css;
|
|
9
|
-
document.head.append(style);
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
1
|
+
import { t as css } from "./styles-BsMSqaDf.mjs";
|
|
2
|
+
import { t as addStyles } from "./client-Cl1M_Rli.mjs";
|
|
12
3
|
export { addStyles, css };
|
package/dist/html.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import src_default,
|
|
2
|
-
import { t as css } from "./styles-
|
|
1
|
+
import { n as src_default, t as NOTES_TAG } from "./src-JYXNZqY7.mjs";
|
|
2
|
+
import { t as css } from "./styles-BsMSqaDf.mjs";
|
|
3
3
|
//#region src/html.ts
|
|
4
4
|
const styled = /* @__PURE__ */ new WeakSet();
|
|
5
5
|
const notes = async ([, attrs, ...children], state) => {
|
package/dist/index.mjs
CHANGED
|
@@ -1,213 +1 @@
|
|
|
1
|
-
|
|
2
|
-
//#region src/index.ts
|
|
3
|
-
/** The node the numbered list after an annotated fence becomes. Each item starts with its marker, linking back. */
|
|
4
|
-
const NOTES_TAG = "code-notes";
|
|
5
|
-
const MARKERS = String.raw`<\d+>(?:\s*<\d+>)*`;
|
|
6
|
-
const ALONE = new RegExp(String.raw`\s*(?:(?://|#|--|;|%)\s*(${MARKERS})|(?:/\*|<!--)\s*(${MARKERS})\s*(?:\*/|-->))\s*$`);
|
|
7
|
-
const AFTER_WORDS = new RegExp(String.raw`((?://|#|--|;|%).*?\S)\s+(${MARKERS})\s*$`);
|
|
8
|
-
const BLOCK_WORDS = new RegExp(String.raw`^(.*?)(/\*|<!--)(.*?)\s+(${MARKERS})\s*(\*/|-->)\s*$`);
|
|
9
|
-
const MARKDOWN = /* @__PURE__ */ new Set([
|
|
10
|
-
"md",
|
|
11
|
-
"mdc",
|
|
12
|
-
"markdown",
|
|
13
|
-
"comark"
|
|
14
|
-
]);
|
|
15
|
-
const isElement = (node) => Array.isArray(node) && node[0] !== null;
|
|
16
|
-
const childrenOf = ([, , ...rest]) => rest;
|
|
17
|
-
const textOf = (node) => !Array.isArray(node) ? node : isElement(node) ? childrenOf(node).map(textOf).join("") : "";
|
|
18
|
-
const numbers = (markers) => [...markers.matchAll(/\d+/g)].map(([digits]) => Number(digits));
|
|
19
|
-
function hash(text) {
|
|
20
|
-
let value = 2166136261;
|
|
21
|
-
for (let at = 0; at < text.length; at++) value = Math.imul(value ^ text.charCodeAt(at), 16777619);
|
|
22
|
-
return (value >>> 0).toString(36);
|
|
23
|
-
}
|
|
24
|
-
/** Strips the markers off each line, and says where they were. */
|
|
25
|
-
function strip(content) {
|
|
26
|
-
const markers = /* @__PURE__ */ new Map();
|
|
27
|
-
return {
|
|
28
|
-
code: content.split("\n").map((line, index) => {
|
|
29
|
-
const alone = ALONE.exec(line);
|
|
30
|
-
if (alone) {
|
|
31
|
-
markers.set(index, numbers(alone[1] ?? alone[2] ?? ""));
|
|
32
|
-
return line.slice(0, alone.index);
|
|
33
|
-
}
|
|
34
|
-
const block = BLOCK_WORDS.exec(line);
|
|
35
|
-
if (block) {
|
|
36
|
-
markers.set(index, numbers(block[4] ?? ""));
|
|
37
|
-
return `${block[1] ?? ""}${block[2] ?? ""}${(block[3] ?? "").trimEnd()} ${block[5] ?? ""}`;
|
|
38
|
-
}
|
|
39
|
-
const words = AFTER_WORDS.exec(line);
|
|
40
|
-
if (!words) return line;
|
|
41
|
-
markers.set(index, numbers(words[2] ?? ""));
|
|
42
|
-
return line.slice(0, words.index) + (words[1] ?? "");
|
|
43
|
-
}).join("\n"),
|
|
44
|
-
markers
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Takes the markers out of every fence a numbered list follows, before any plugin's `post`, so Shiki highlights the
|
|
49
|
-
* code without them in any plugin order.
|
|
50
|
-
*/
|
|
51
|
-
function read(tokens) {
|
|
52
|
-
const fences = [];
|
|
53
|
-
let count = 0;
|
|
54
|
-
for (const [index, token] of tokens.entries()) {
|
|
55
|
-
if (token.type !== "fence") continue;
|
|
56
|
-
count++;
|
|
57
|
-
const language = token.info.trim().split(/[\s[{]/, 1)[0] ?? "";
|
|
58
|
-
if (MARKDOWN.has(language.toLowerCase())) continue;
|
|
59
|
-
const { code, markers } = strip(token.content);
|
|
60
|
-
if (!markers.size) continue;
|
|
61
|
-
const name = `The \`\`\`${language} fence ${count}`;
|
|
62
|
-
const notes = tokens[index + 1]?.type === "ordered_list_open";
|
|
63
|
-
if (notes) token.content = code;
|
|
64
|
-
fences.push({
|
|
65
|
-
name,
|
|
66
|
-
code: (notes ? code : token.content).replace(/\n+$/, ""),
|
|
67
|
-
markers,
|
|
68
|
-
notes,
|
|
69
|
-
order: count
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
return fences;
|
|
73
|
-
}
|
|
74
|
-
const link = (note, uid, first) => ["a", {
|
|
75
|
-
class: "cn-marker",
|
|
76
|
-
href: `#${uid}-${note}`,
|
|
77
|
-
...first && { id: `${uid}-${note}-ref` },
|
|
78
|
-
"data-note": String(note),
|
|
79
|
-
"aria-label": `Note ${note}`
|
|
80
|
-
}];
|
|
81
|
-
const marker = (note, uid, first, known) => known.has(note) ? link(note, uid, first) : ["span", {
|
|
82
|
-
class: "cn-marker",
|
|
83
|
-
"data-note": String(note)
|
|
84
|
-
}];
|
|
85
|
-
/** Adds each line's markers to its end, in Shiki's line spans or in the plain code. */
|
|
86
|
-
function draw(code, fence, uid, known) {
|
|
87
|
-
const seen = /* @__PURE__ */ new Set();
|
|
88
|
-
const markersOf = (line) => (fence.markers.get(line) ?? []).map((note) => {
|
|
89
|
-
const first = !seen.has(note);
|
|
90
|
-
seen.add(note);
|
|
91
|
-
return marker(note, uid, first, known);
|
|
92
|
-
});
|
|
93
|
-
const lines = childrenOf(code).filter((child) => isElement(child) && child[0] === "span");
|
|
94
|
-
if (lines.length) {
|
|
95
|
-
for (const [index, line] of lines.entries()) line.push(...markersOf(index));
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const drawn = textOf(code).split("\n").flatMap((line, index) => [...index ? ["\n"] : [], [
|
|
99
|
-
"span",
|
|
100
|
-
{ class: "line" },
|
|
101
|
-
line,
|
|
102
|
-
...markersOf(index)
|
|
103
|
-
]]);
|
|
104
|
-
code.splice(2, code.length - 2, ...drawn);
|
|
105
|
-
}
|
|
106
|
-
/** A list's items, with the note number each one holds. */
|
|
107
|
-
function itemsOf(list) {
|
|
108
|
-
const start = Number(list[1].start ?? 1) || 1;
|
|
109
|
-
return childrenOf(list).filter((child) => isElement(child) && child[0] === "li").map((item, index) => ({
|
|
110
|
-
item,
|
|
111
|
-
note: start + index
|
|
112
|
-
}));
|
|
113
|
-
}
|
|
114
|
-
function notesOf(list, fence, uid, issues) {
|
|
115
|
-
const start = Number(list[1].start ?? 1) || 1;
|
|
116
|
-
const items = itemsOf(list);
|
|
117
|
-
const used = new Set([...fence.markers.values()].flat());
|
|
118
|
-
const known = new Set(items.map(({ note }) => note));
|
|
119
|
-
for (const note of [...used].sort((a, b) => a - b)) if (!known.has(note)) issues.push({
|
|
120
|
-
rule: "comark/code-notes/marker-without-note",
|
|
121
|
-
message: `${fence.name}: marker <${note}> has no note, since the list after it ${items.length === 1 ? "has 1 item" : `has ${items.length} items`}. Add its note, or remove the marker.`
|
|
122
|
-
});
|
|
123
|
-
for (const note of known) if (!used.has(note)) issues.push({
|
|
124
|
-
rule: "comark/code-notes/note-without-marker",
|
|
125
|
-
message: `${fence.name}: note ${note} has no <${note}> marker in the code. Add \`// <${note}>\` at the end of its line, in the language's comment.`
|
|
126
|
-
});
|
|
127
|
-
return [
|
|
128
|
-
NOTES_TAG,
|
|
129
|
-
start === 1 ? {} : { start },
|
|
130
|
-
...items.map(({ item, note }) => {
|
|
131
|
-
return [
|
|
132
|
-
"li",
|
|
133
|
-
{ id: `${uid}-${note}` },
|
|
134
|
-
used.has(note) ? ["a", {
|
|
135
|
-
class: "cn-marker",
|
|
136
|
-
href: `#${uid}-${note}-ref`,
|
|
137
|
-
"data-note": String(note),
|
|
138
|
-
"aria-label": `Back to marker ${note}`
|
|
139
|
-
}] : ["span", {
|
|
140
|
-
class: "cn-marker",
|
|
141
|
-
"data-note": String(note)
|
|
142
|
-
}],
|
|
143
|
-
[
|
|
144
|
-
"div",
|
|
145
|
-
{},
|
|
146
|
-
...childrenOf(item)
|
|
147
|
-
]
|
|
148
|
-
];
|
|
149
|
-
})
|
|
150
|
-
];
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Turns `// <1>` at the end of a line in a fence, in the language's comment, into a numbered marker, and the numbered
|
|
154
|
-
* list right after the fence into its notes, each linked to its marker and back. Markers are stripped before Shiki
|
|
155
|
-
* highlights the code and drawn into its lines after, so put this plugin after Comark's `shiki` in `plugins`.
|
|
156
|
-
* Problems are added to `meta.issues`.
|
|
157
|
-
*/
|
|
158
|
-
var src_default = defineComarkPlugin(() => {
|
|
159
|
-
const parses = /* @__PURE__ */ new WeakMap();
|
|
160
|
-
return {
|
|
161
|
-
name: "comark-code-notes",
|
|
162
|
-
markdownItPost(state) {
|
|
163
|
-
parses.set(state, read(state.tokens));
|
|
164
|
-
},
|
|
165
|
-
post(state) {
|
|
166
|
-
const fences = parses.get(state) ?? [];
|
|
167
|
-
const { tree } = state;
|
|
168
|
-
const issues = [];
|
|
169
|
-
const names = (state.options.plugins ?? []).map((plugin) => plugin.name);
|
|
170
|
-
const shikiLater = names.indexOf("shiki") > names.indexOf("comark-code-notes");
|
|
171
|
-
let preOrder = 0;
|
|
172
|
-
const walk = (nodes, start) => {
|
|
173
|
-
for (let index = start; index < nodes.length; index++) {
|
|
174
|
-
const node = nodes[index];
|
|
175
|
-
if (!node || !isElement(node)) continue;
|
|
176
|
-
if (node[0] !== "pre") {
|
|
177
|
-
walk(node, 2);
|
|
178
|
-
continue;
|
|
179
|
-
}
|
|
180
|
-
preOrder++;
|
|
181
|
-
const fence = fences.find((candidate) => candidate.order === preOrder);
|
|
182
|
-
if (!fence || !fence.markers.size) continue;
|
|
183
|
-
if (!fence.notes) {
|
|
184
|
-
issues.push({
|
|
185
|
-
rule: "comark/code-notes/missing-notes",
|
|
186
|
-
message: `${fence.name} has markers like \`<1>\` but no numbered list right after it, so they stay in the code. Write the notes as a numbered list right after the fence.`
|
|
187
|
-
});
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
const next = nodes.findIndex((child, after) => after > index && isElement(child));
|
|
191
|
-
const list = nodes[next];
|
|
192
|
-
const code = childrenOf(node).find((child) => isElement(child) && child[0] === "code");
|
|
193
|
-
if (!list || !isElement(list) || list[0] !== "ol" || !code) continue;
|
|
194
|
-
const uid = `cn-${hash(`${fence.name}\n${fence.code}`)}`;
|
|
195
|
-
draw(code, fence, uid, new Set(itemsOf(list).map(({ note }) => note)));
|
|
196
|
-
nodes[next] = notesOf(list, fence, uid, issues);
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
walk(tree.nodes, 0);
|
|
200
|
-
if (shikiLater && fences.some((fence) => fence.notes)) issues.push({
|
|
201
|
-
rule: "comark/code-notes/shiki-order",
|
|
202
|
-
message: "Code notes: `shiki` comes after `comark-code-notes` in `plugins`, so the annotated code isn't highlighted. Put the code notes plugin after `shiki`."
|
|
203
|
-
});
|
|
204
|
-
tree.meta.issues = [...tree.meta.issues ?? [], ...issues.map((issue) => issue.message)];
|
|
205
|
-
tree.meta.issueRules = {
|
|
206
|
-
...tree.meta.issueRules,
|
|
207
|
-
...Object.fromEntries(issues.map((issue) => [issue.message, issue.rule]))
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
});
|
|
212
|
-
//#endregion
|
|
213
|
-
export { NOTES_TAG, src_default as default };
|
|
1
|
+
export { t as NOTES_TAG, n as default } from "./src-JYXNZqY7.mjs";
|
package/dist/react.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import src_default,
|
|
2
|
-
import { addStyles } from "./client.mjs";
|
|
1
|
+
import { n as src_default, t as NOTES_TAG } from "./src-JYXNZqY7.mjs";
|
|
2
|
+
import { t as addStyles } from "./client-Cl1M_Rli.mjs";
|
|
3
3
|
import { createElement, useEffect } from "react";
|
|
4
4
|
//#region src/react.ts
|
|
5
5
|
/** The notes under an annotated fence, for `@comark/react`. */
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { defineComarkPlugin } from "comark";
|
|
2
|
+
//#region ../../shared/nodes.ts
|
|
3
|
+
const isElement = (node) => Array.isArray(node) && node[0] !== null;
|
|
4
|
+
const childrenOf = ([, , ...rest]) => rest;
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region ../../shared/text.ts
|
|
7
|
+
/** FNV-1a, in base 36: short, and the same every time the same text is hashed, so ids derived from it are stable. */
|
|
8
|
+
function hash(source) {
|
|
9
|
+
let value = 2166136261;
|
|
10
|
+
for (let at = 0; at < source.length; at++) value = Math.imul(value ^ source.charCodeAt(at), 16777619);
|
|
11
|
+
return (value >>> 0).toString(36);
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/index.ts
|
|
15
|
+
/** The node the numbered list after an annotated fence becomes. Each item starts with its marker, linking back. */
|
|
16
|
+
const NOTES_TAG = "code-notes";
|
|
17
|
+
const MARKERS = String.raw`<\d+>(?:\s*<\d+>)*`;
|
|
18
|
+
const ALONE = new RegExp(String.raw`\s*(?:(?://|#|--|;|%)\s*(${MARKERS})|(?:/\*|<!--)\s*(${MARKERS})\s*(?:\*/|-->))\s*$`);
|
|
19
|
+
const AFTER_WORDS = new RegExp(String.raw`((?://|#|--|;|%).*?\S)\s+(${MARKERS})\s*$`);
|
|
20
|
+
const BLOCK_WORDS = new RegExp(String.raw`^(.*?)(/\*|<!--)(.*?)\s+(${MARKERS})\s*(\*/|-->)\s*$`);
|
|
21
|
+
const MARKDOWN = /* @__PURE__ */ new Set([
|
|
22
|
+
"md",
|
|
23
|
+
"mdc",
|
|
24
|
+
"markdown",
|
|
25
|
+
"comark"
|
|
26
|
+
]);
|
|
27
|
+
const textOf = (node) => !Array.isArray(node) ? node : isElement(node) ? childrenOf(node).map(textOf).join("") : "";
|
|
28
|
+
const numbers = (markers) => [...markers.matchAll(/\d+/g)].map(([digits]) => Number(digits));
|
|
29
|
+
/** Strips the markers off each line, and says where they were. */
|
|
30
|
+
function strip(content) {
|
|
31
|
+
const markers = /* @__PURE__ */ new Map();
|
|
32
|
+
return {
|
|
33
|
+
code: content.split("\n").map((line, index) => {
|
|
34
|
+
const alone = ALONE.exec(line);
|
|
35
|
+
if (alone) {
|
|
36
|
+
markers.set(index, numbers(alone[1] ?? alone[2] ?? ""));
|
|
37
|
+
return line.slice(0, alone.index);
|
|
38
|
+
}
|
|
39
|
+
const block = BLOCK_WORDS.exec(line);
|
|
40
|
+
if (block) {
|
|
41
|
+
markers.set(index, numbers(block[4] ?? ""));
|
|
42
|
+
return `${block[1] ?? ""}${block[2] ?? ""}${(block[3] ?? "").trimEnd()} ${block[5] ?? ""}`;
|
|
43
|
+
}
|
|
44
|
+
const words = AFTER_WORDS.exec(line);
|
|
45
|
+
if (!words) return line;
|
|
46
|
+
markers.set(index, numbers(words[2] ?? ""));
|
|
47
|
+
return line.slice(0, words.index) + (words[1] ?? "");
|
|
48
|
+
}).join("\n"),
|
|
49
|
+
markers
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Takes the markers out of every fence a numbered list follows, before any plugin's `post`, so Shiki highlights the
|
|
54
|
+
* code without them in any plugin order.
|
|
55
|
+
*/
|
|
56
|
+
function read(tokens) {
|
|
57
|
+
const fences = [];
|
|
58
|
+
let count = 0;
|
|
59
|
+
for (const [index, token] of tokens.entries()) {
|
|
60
|
+
if (token.type !== "fence") continue;
|
|
61
|
+
count++;
|
|
62
|
+
const language = token.info.trim().split(/[\s[{]/, 1)[0] ?? "";
|
|
63
|
+
if (MARKDOWN.has(language.toLowerCase())) continue;
|
|
64
|
+
const { code, markers } = strip(token.content);
|
|
65
|
+
if (!markers.size) continue;
|
|
66
|
+
const name = `The \`\`\`${language} fence ${count}`;
|
|
67
|
+
const notes = tokens[index + 1]?.type === "ordered_list_open";
|
|
68
|
+
if (notes) token.content = code;
|
|
69
|
+
fences.push({
|
|
70
|
+
name,
|
|
71
|
+
code: (notes ? code : token.content).replace(/\n+$/, ""),
|
|
72
|
+
markers,
|
|
73
|
+
notes,
|
|
74
|
+
order: count
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return fences;
|
|
78
|
+
}
|
|
79
|
+
const link = (note, uid, first) => ["a", {
|
|
80
|
+
class: "cn-marker",
|
|
81
|
+
href: `#${uid}-${note}`,
|
|
82
|
+
...first && { id: `${uid}-${note}-ref` },
|
|
83
|
+
"data-note": String(note),
|
|
84
|
+
"aria-label": `Note ${note}`
|
|
85
|
+
}];
|
|
86
|
+
const marker = (note, uid, first, known) => known.has(note) ? link(note, uid, first) : ["span", {
|
|
87
|
+
class: "cn-marker",
|
|
88
|
+
"data-note": String(note)
|
|
89
|
+
}];
|
|
90
|
+
/** Adds each line's markers to its end, in Shiki's line spans or in the plain code. */
|
|
91
|
+
function draw(code, fence, uid, known) {
|
|
92
|
+
const seen = /* @__PURE__ */ new Set();
|
|
93
|
+
const markersOf = (line) => (fence.markers.get(line) ?? []).map((note) => {
|
|
94
|
+
const first = !seen.has(note);
|
|
95
|
+
seen.add(note);
|
|
96
|
+
return marker(note, uid, first, known);
|
|
97
|
+
});
|
|
98
|
+
const lines = childrenOf(code).filter((child) => isElement(child) && child[0] === "span");
|
|
99
|
+
if (lines.length) {
|
|
100
|
+
for (const [index, line] of lines.entries()) line.push(...markersOf(index));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const drawn = textOf(code).split("\n").flatMap((line, index) => [...index ? ["\n"] : [], [
|
|
104
|
+
"span",
|
|
105
|
+
{ class: "line" },
|
|
106
|
+
line,
|
|
107
|
+
...markersOf(index)
|
|
108
|
+
]]);
|
|
109
|
+
code.splice(2, code.length - 2, ...drawn);
|
|
110
|
+
}
|
|
111
|
+
/** A list's items, with the note number each one holds. */
|
|
112
|
+
function itemsOf(list) {
|
|
113
|
+
const start = Number(list[1].start ?? 1) || 1;
|
|
114
|
+
return childrenOf(list).filter((child) => isElement(child) && child[0] === "li").map((item, index) => ({
|
|
115
|
+
item,
|
|
116
|
+
note: start + index
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
function notesOf(list, fence, uid, issues) {
|
|
120
|
+
const start = Number(list[1].start ?? 1) || 1;
|
|
121
|
+
const items = itemsOf(list);
|
|
122
|
+
const used = new Set([...fence.markers.values()].flat());
|
|
123
|
+
const known = new Set(items.map(({ note }) => note));
|
|
124
|
+
for (const note of [...used].sort((a, b) => a - b)) if (!known.has(note)) issues.push({
|
|
125
|
+
rule: "comark/code-notes/marker-without-note",
|
|
126
|
+
message: `${fence.name}: marker <${note}> has no note, since the list after it ${items.length === 1 ? "has 1 item" : `has ${items.length} items`}. Add its note, or remove the marker.`
|
|
127
|
+
});
|
|
128
|
+
for (const note of known) if (!used.has(note)) issues.push({
|
|
129
|
+
rule: "comark/code-notes/note-without-marker",
|
|
130
|
+
message: `${fence.name}: note ${note} has no <${note}> marker in the code. Add \`// <${note}>\` at the end of its line, in the language's comment.`
|
|
131
|
+
});
|
|
132
|
+
return [
|
|
133
|
+
NOTES_TAG,
|
|
134
|
+
start === 1 ? {} : { start },
|
|
135
|
+
...items.map(({ item, note }) => {
|
|
136
|
+
return [
|
|
137
|
+
"li",
|
|
138
|
+
{ id: `${uid}-${note}` },
|
|
139
|
+
used.has(note) ? ["a", {
|
|
140
|
+
class: "cn-marker",
|
|
141
|
+
href: `#${uid}-${note}-ref`,
|
|
142
|
+
"data-note": String(note),
|
|
143
|
+
"aria-label": `Back to marker ${note}`
|
|
144
|
+
}] : ["span", {
|
|
145
|
+
class: "cn-marker",
|
|
146
|
+
"data-note": String(note)
|
|
147
|
+
}],
|
|
148
|
+
[
|
|
149
|
+
"div",
|
|
150
|
+
{},
|
|
151
|
+
...childrenOf(item)
|
|
152
|
+
]
|
|
153
|
+
];
|
|
154
|
+
})
|
|
155
|
+
];
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Turns `// <1>` at the end of a line in a fence, in the language's comment, into a numbered marker, and the numbered
|
|
159
|
+
* list right after the fence into its notes, each linked to its marker and back. Markers are stripped before Shiki
|
|
160
|
+
* highlights the code and drawn into its lines after, so put this plugin after Comark's `shiki` in `plugins`.
|
|
161
|
+
* Problems are added to `meta.issues`.
|
|
162
|
+
*/
|
|
163
|
+
var src_default = defineComarkPlugin(() => {
|
|
164
|
+
const parses = /* @__PURE__ */ new WeakMap();
|
|
165
|
+
return {
|
|
166
|
+
name: "comark-code-notes",
|
|
167
|
+
markdownItPost(state) {
|
|
168
|
+
parses.set(state, read(state.tokens));
|
|
169
|
+
},
|
|
170
|
+
post(state) {
|
|
171
|
+
const fences = parses.get(state) ?? [];
|
|
172
|
+
const { tree } = state;
|
|
173
|
+
const issues = [];
|
|
174
|
+
const names = (state.options.plugins ?? []).map((plugin) => plugin.name);
|
|
175
|
+
const shikiLater = names.indexOf("shiki") > names.indexOf("comark-code-notes");
|
|
176
|
+
let preOrder = 0;
|
|
177
|
+
const walk = (nodes, start) => {
|
|
178
|
+
for (let index = start; index < nodes.length; index++) {
|
|
179
|
+
const node = nodes[index];
|
|
180
|
+
if (!node || !isElement(node)) continue;
|
|
181
|
+
if (node[0] !== "pre") {
|
|
182
|
+
walk(node, 2);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
preOrder++;
|
|
186
|
+
const fence = fences.find((candidate) => candidate.order === preOrder);
|
|
187
|
+
if (!fence || !fence.markers.size) continue;
|
|
188
|
+
if (!fence.notes) {
|
|
189
|
+
issues.push({
|
|
190
|
+
rule: "comark/code-notes/missing-notes",
|
|
191
|
+
message: `${fence.name} has markers like \`<1>\` but no numbered list right after it, so they stay in the code. Write the notes as a numbered list right after the fence.`
|
|
192
|
+
});
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
const next = nodes.findIndex((child, after) => after > index && isElement(child));
|
|
196
|
+
const list = nodes[next];
|
|
197
|
+
const code = childrenOf(node).find((child) => isElement(child) && child[0] === "code");
|
|
198
|
+
if (!list || !isElement(list) || list[0] !== "ol" || !code) continue;
|
|
199
|
+
const uid = `cn-${hash(`${fence.name}\n${fence.code}`)}`;
|
|
200
|
+
draw(code, fence, uid, new Set(itemsOf(list).map(({ note }) => note)));
|
|
201
|
+
nodes[next] = notesOf(list, fence, uid, issues);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
walk(tree.nodes, 0);
|
|
205
|
+
if (shikiLater && fences.some((fence) => fence.notes)) issues.push({
|
|
206
|
+
rule: "comark/code-notes/shiki-order",
|
|
207
|
+
message: "Code notes: `shiki` comes after `comark-code-notes` in `plugins`, so the annotated code isn't highlighted. Put the code notes plugin after `shiki`."
|
|
208
|
+
});
|
|
209
|
+
tree.meta.issues = [...tree.meta.issues ?? [], ...issues.map((issue) => issue.message)];
|
|
210
|
+
tree.meta.issueRules = {
|
|
211
|
+
...tree.meta.issueRules,
|
|
212
|
+
...Object.fromEntries(issues.map((issue) => [issue.message, issue.rule]))
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
//#endregion
|
|
218
|
+
export { src_default as n, NOTES_TAG as t };
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer comark{:where(.cn-marker,.cn-notes){--_comark-background:var(--comark-background,var(--ui-bg,var(--background,#fff)));--_comark-foreground:var(--comark-foreground,var(--ui-text-highlighted,var(--foreground,#0a0a0a)));--_comark-muted:var(--comark-muted,var(--ui-text-muted,var(--muted-foreground,#737373)));--_comark-border:var(--comark-border,var(--ui-border,var(--border,#e5e5e5)));--_comark-accent:var(--comark-accent,var(--ui-bg-elevated,var(--accent,#f5f5f5)));--_comark-ring:var(--comark-ring,var(--ui-primary,var(--ring,#a1a1a1)));--_comark-radius:var(--comark-radius,calc(var(--ui-radius,calc(var(--radius,.625rem)/2))*2));--_comark-font:var(--comark-font,var(--font-sans,ui-sans-serif,system-ui,sans-serif))}@media (prefers-color-scheme:dark){:where(.cn-marker,.cn-notes){--_comark-background:var(--comark-background,var(--ui-bg,var(--background,#0a0a0a)));--_comark-foreground:var(--comark-foreground,var(--ui-text-highlighted,var(--foreground,#fafafa)));--_comark-muted:var(--comark-muted,var(--ui-text-muted,var(--muted-foreground,#a1a1a1)));--_comark-border:var(--comark-border,var(--ui-border,var(--border,rgb(255 255 255/.1))));--_comark-accent:var(--comark-accent,var(--ui-bg-elevated,var(--accent,#262626)));--_comark-ring:var(--comark-ring,var(--ui-primary,var(--ring,#737373)))}}:where(.cn-marker){--cn-marker:var(--
|
|
1
|
+
@layer comark{:where(.cn-marker,.cn-notes){--_comark-background:var(--comark-background,var(--ui-bg,var(--background,#fff)));--_comark-foreground:var(--comark-foreground,var(--ui-text-highlighted,var(--foreground,#0a0a0a)));--_comark-muted:var(--comark-muted,var(--ui-text-muted,var(--muted-foreground,#737373)));--_comark-border:var(--comark-border,var(--ui-border,var(--border,#e5e5e5)));--_comark-accent:var(--comark-accent,var(--ui-bg-elevated,var(--accent,#f5f5f5)));--_comark-ring:var(--comark-ring,var(--ui-primary,var(--ring,#a1a1a1)));--_comark-primary:var(--comark-primary,var(--ui-primary,var(--primary,var(--_comark-foreground))));--_comark-primary-foreground:var(--comark-primary-foreground,var(--ui-text-inverted,var(--primary-foreground,var(--_comark-background))));--_comark-secondary:var(--comark-secondary,var(--ui-secondary,var(--_comark-muted)));--_comark-radius:var(--comark-radius,calc(var(--ui-radius,calc(var(--radius,.625rem)/2))*2));--_comark-font:var(--comark-font,var(--font-sans,ui-sans-serif,system-ui,sans-serif))}@media (prefers-color-scheme:dark){:where(.cn-marker,.cn-notes){--_comark-background:var(--comark-background,var(--ui-bg,var(--background,#0a0a0a)));--_comark-foreground:var(--comark-foreground,var(--ui-text-highlighted,var(--foreground,#fafafa)));--_comark-muted:var(--comark-muted,var(--ui-text-muted,var(--muted-foreground,#a1a1a1)));--_comark-border:var(--comark-border,var(--ui-border,var(--border,rgb(255 255 255/.1))));--_comark-accent:var(--comark-accent,var(--ui-bg-elevated,var(--accent,#262626)));--_comark-ring:var(--comark-ring,var(--ui-primary,var(--ring,#737373)));--_comark-primary:var(--comark-primary,var(--ui-primary,var(--primary,var(--_comark-foreground))));--_comark-primary-foreground:var(--comark-primary-foreground,var(--ui-text-inverted,var(--primary-foreground,var(--_comark-background))));--_comark-secondary:var(--comark-secondary,var(--ui-secondary,var(--_comark-muted)))}}:where(.cn-marker){--cn-marker:var(--_comark-primary);--cn-marker-text:var(--cn-marker)}.cn-marker{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;min-width:1.25rem;height:1.25rem;margin-inline-start:.5rem;padding:0 .3rem;border-radius:9999px;background:color-mix(in srgb,var(--cn-marker) 10%,var(--_comark-background));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--cn-marker) 22%,transparent);font:600 .6875rem/1 var(--_comark-font);font-variant-numeric:tabular-nums;vertical-align:.0625rem;user-select:none;transition:background-color .15s}.cn-marker{color:var(--cn-marker-text)!important;text-decoration:none!important;border:0!important}.cn-marker::after{content:attr(data-note)}a.cn-marker:hover{background:color-mix(in srgb,var(--cn-marker) 18%,var(--_comark-background))}a.cn-marker:focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-ring) 50%,transparent)}.cn-marker:target{box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-ring) 60%,transparent)}.line:has(>.cn-marker:is(:target,:focus)){border-image:conic-gradient(color-mix(in srgb,var(--cn-marker,currentColor) 14%,transparent) 0 0) fill 0//.25em 100vw}.cn-notes{margin:.75rem 0 1.5rem}.cn-notes{padding:0!important;list-style:none!important}.cn-notes>li{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:baseline;gap:.625rem;margin:.375rem 0;padding:.125rem .375rem;border-radius:calc(var(--_comark-radius) - 4px)}.cn-notes>li>.cn-marker{margin:0}.cn-notes>li>div>:first-child{margin-top:0!important}.cn-notes>li>div>:last-child{margin-bottom:0!important}.cn-notes>li:target{background:var(--_comark-accent)}}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
//#region ../zoom/dist/theme.mjs
|
|
2
|
+
const tokens = [
|
|
3
|
+
[
|
|
4
|
+
"background",
|
|
5
|
+
"ui-bg",
|
|
6
|
+
"background",
|
|
7
|
+
"#fff",
|
|
8
|
+
"#0a0a0a"
|
|
9
|
+
],
|
|
10
|
+
[
|
|
11
|
+
"foreground",
|
|
12
|
+
"ui-text-highlighted",
|
|
13
|
+
"foreground",
|
|
14
|
+
"#0a0a0a",
|
|
15
|
+
"#fafafa"
|
|
16
|
+
],
|
|
17
|
+
[
|
|
18
|
+
"muted",
|
|
19
|
+
"ui-text-muted",
|
|
20
|
+
"muted-foreground",
|
|
21
|
+
"#737373",
|
|
22
|
+
"#a1a1a1"
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
"border",
|
|
26
|
+
"ui-border",
|
|
27
|
+
"border",
|
|
28
|
+
"#e5e5e5",
|
|
29
|
+
"rgb(255 255 255/.1)"
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
"accent",
|
|
33
|
+
"ui-bg-elevated",
|
|
34
|
+
"accent",
|
|
35
|
+
"#f5f5f5",
|
|
36
|
+
"#262626"
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
"ring",
|
|
40
|
+
"ui-primary",
|
|
41
|
+
"ring",
|
|
42
|
+
"#a1a1a1",
|
|
43
|
+
"#737373"
|
|
44
|
+
]
|
|
45
|
+
];
|
|
46
|
+
const groups = {
|
|
47
|
+
status: Object.values({
|
|
48
|
+
success: [
|
|
49
|
+
"success",
|
|
50
|
+
"ui-success",
|
|
51
|
+
"success",
|
|
52
|
+
"#259f56",
|
|
53
|
+
"#59d38c"
|
|
54
|
+
],
|
|
55
|
+
danger: [
|
|
56
|
+
"danger",
|
|
57
|
+
"ui-error",
|
|
58
|
+
"destructive",
|
|
59
|
+
"#ee3533",
|
|
60
|
+
"#fd736d"
|
|
61
|
+
],
|
|
62
|
+
warning: [
|
|
63
|
+
"warning",
|
|
64
|
+
"ui-warning",
|
|
65
|
+
"",
|
|
66
|
+
"#d97706",
|
|
67
|
+
"#fbbf24"
|
|
68
|
+
],
|
|
69
|
+
info: [
|
|
70
|
+
"info",
|
|
71
|
+
"ui-info",
|
|
72
|
+
"",
|
|
73
|
+
"#2563eb",
|
|
74
|
+
"#60a5fa"
|
|
75
|
+
]
|
|
76
|
+
}),
|
|
77
|
+
primary: [
|
|
78
|
+
[
|
|
79
|
+
"primary",
|
|
80
|
+
"ui-primary",
|
|
81
|
+
"primary",
|
|
82
|
+
"var(--_comark-foreground)",
|
|
83
|
+
"var(--_comark-foreground)"
|
|
84
|
+
],
|
|
85
|
+
[
|
|
86
|
+
"primary-foreground",
|
|
87
|
+
"ui-text-inverted",
|
|
88
|
+
"primary-foreground",
|
|
89
|
+
"var(--_comark-background)",
|
|
90
|
+
"var(--_comark-background)"
|
|
91
|
+
],
|
|
92
|
+
[
|
|
93
|
+
"secondary",
|
|
94
|
+
"ui-secondary",
|
|
95
|
+
"",
|
|
96
|
+
"var(--_comark-muted)",
|
|
97
|
+
"var(--_comark-muted)"
|
|
98
|
+
]
|
|
99
|
+
],
|
|
100
|
+
shadow: [[
|
|
101
|
+
"shadow",
|
|
102
|
+
"",
|
|
103
|
+
"",
|
|
104
|
+
"0 4px 12px rgb(0 0 0/.12)",
|
|
105
|
+
"0 4px 12px rgb(0 0 0/.5)"
|
|
106
|
+
]]
|
|
107
|
+
};
|
|
108
|
+
const chain = (token, scheme) => {
|
|
109
|
+
const shadcn = token[2] ? `var(--${token[2]},${token[scheme]})` : token[scheme];
|
|
110
|
+
const nuxt = token[1] ? `var(--${token[1]},${shadcn})` : shadcn;
|
|
111
|
+
return `var(--comark-${token[0]},${nuxt})`;
|
|
112
|
+
};
|
|
113
|
+
const resolve = (list, scheme) => list.map((token) => `--_comark-${token[0]}:${chain(token, scheme)}`).join(";");
|
|
114
|
+
/**
|
|
115
|
+
* Resolves the `--comark-*` tokens on `selector`, falling back to Nuxt UI's variables, then shadcn/ui's, then shadcn's
|
|
116
|
+
* neutral theme. Nuxt UI's corners are twice its `--ui-radius`, so the radius halves shadcn's to double it back.
|
|
117
|
+
* They resolve on the component rather than `:root`, so a `.dark` class anywhere above it switches the theme, and a
|
|
118
|
+
* `--comark-*` set on any ancestor still inherits down. `:where()` keeps them at zero specificity.
|
|
119
|
+
*
|
|
120
|
+
* Every block gets the core tokens. Name `"status"` for `--comark-success`, `-danger`, `-warning`, and `-info`,
|
|
121
|
+
* `"primary"` for `--comark-primary`, `-primary-foreground`, and `-secondary`, and `"shadow"` for `--comark-shadow`, so
|
|
122
|
+
* a block that never draws them doesn't carry them.
|
|
123
|
+
*/
|
|
124
|
+
function theme(selector, ...extras) {
|
|
125
|
+
const where = `:where(${selector})`;
|
|
126
|
+
const added = extras.flatMap((name) => groups[name]);
|
|
127
|
+
const list = [...tokens, ...added];
|
|
128
|
+
const schemed = added.filter((token) => token[3] !== token[4]);
|
|
129
|
+
const classes = schemed.length ? `:where(.light,.light *)${where}{${resolve(schemed, 3)}}:where(.dark,.dark *)${where}{${resolve(schemed, 4)}}` : "";
|
|
130
|
+
return `${where}{${resolve(list, 3)};--_comark-radius:var(--comark-radius,calc(var(--ui-radius,calc(var(--radius,.625rem)/2))*2));--_comark-font:var(--comark-font,var(--font-sans,ui-sans-serif,system-ui,sans-serif))}@media (prefers-color-scheme:dark){${where}{${resolve(list, 4)}}}` + classes;
|
|
131
|
+
}
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/styles.ts
|
|
134
|
+
/**
|
|
135
|
+
* Round numbered markers at the ends of lines and before each note, as a soft tint of the primary color, with the number in that color, on the shared `--comark-*` tokens.
|
|
136
|
+
* Override `--cn-marker` and `--cn-marker-text`. The number is drawn by CSS, so copying the code never takes it along.
|
|
137
|
+
* The rules sit in the `comark` layer, so any unlayered rule of the host's wins.
|
|
138
|
+
*/
|
|
139
|
+
const css = `@layer comark{${[
|
|
140
|
+
theme(".cn-marker,.cn-notes", "primary"),
|
|
141
|
+
":where(.cn-marker){--cn-marker:var(--_comark-primary);--cn-marker-text:var(--cn-marker)}",
|
|
142
|
+
".cn-marker{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;min-width:1.25rem;height:1.25rem;margin-inline-start:.5rem;padding:0 .3rem;border-radius:9999px;background:color-mix(in srgb,var(--cn-marker) 10%,var(--_comark-background));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--cn-marker) 22%,transparent);font:600 .6875rem/1 var(--_comark-font);font-variant-numeric:tabular-nums;vertical-align:.0625rem;user-select:none;transition:background-color .15s}",
|
|
143
|
+
".cn-marker{color:var(--cn-marker-text)!important;text-decoration:none!important;border:0!important}",
|
|
144
|
+
".cn-marker::after{content:attr(data-note)}",
|
|
145
|
+
"a.cn-marker:hover{background:color-mix(in srgb,var(--cn-marker) 18%,var(--_comark-background))}",
|
|
146
|
+
"a.cn-marker:focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-ring) 50%,transparent)}",
|
|
147
|
+
".cn-marker:target{box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-ring) 60%,transparent)}",
|
|
148
|
+
".line:has(>.cn-marker:is(:target,:focus)){border-image:conic-gradient(color-mix(in srgb,var(--cn-marker,currentColor) 14%,transparent) 0 0) fill 0//.25em 100vw}",
|
|
149
|
+
".cn-notes{margin:.75rem 0 1.5rem}",
|
|
150
|
+
".cn-notes{padding:0!important;list-style:none!important}",
|
|
151
|
+
".cn-notes>li{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:baseline;gap:.625rem;margin:.375rem 0;padding:.125rem .375rem;border-radius:calc(var(--_comark-radius) - 4px)}",
|
|
152
|
+
".cn-notes>li>.cn-marker{margin:0}",
|
|
153
|
+
".cn-notes>li>div>:first-child{margin-top:0!important}.cn-notes>li>div>:last-child{margin-bottom:0!important}",
|
|
154
|
+
".cn-notes>li:target{background:var(--_comark-accent)}"
|
|
155
|
+
].join("")}}`;
|
|
156
|
+
//#endregion
|
|
157
|
+
export { css as t };
|
package/dist/vue.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import src_default,
|
|
2
|
-
import { addStyles } from "./client.mjs";
|
|
1
|
+
import { n as src_default, t as NOTES_TAG } from "./src-JYXNZqY7.mjs";
|
|
2
|
+
import { t as addStyles } from "./client-Cl1M_Rli.mjs";
|
|
3
3
|
import { defineComponent, h, onMounted } from "vue";
|
|
4
4
|
//#region src/vue.ts
|
|
5
5
|
/** The notes under an annotated fence, for `@comark/vue`. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "comark-code-notes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Numbered notes on lines of code: a // <1> marker in a fence links to the numbered list after it. A Comark plugin.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"annotations",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"react-dom": "^19.3.1",
|
|
58
58
|
"svelte": "^5.57.2",
|
|
59
59
|
"vue": "^3.5.44",
|
|
60
|
-
"comark-zoom": "0.
|
|
60
|
+
"comark-zoom": "0.8.1"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"@comark/html": "^0.8.0",
|
package/dist/styles-zxOi3Y7k.mjs
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
//#region ../zoom/dist/theme.mjs
|
|
2
|
-
const tokens = [
|
|
3
|
-
[
|
|
4
|
-
"background",
|
|
5
|
-
"ui-bg",
|
|
6
|
-
"background",
|
|
7
|
-
"#fff",
|
|
8
|
-
"#0a0a0a"
|
|
9
|
-
],
|
|
10
|
-
[
|
|
11
|
-
"foreground",
|
|
12
|
-
"ui-text-highlighted",
|
|
13
|
-
"foreground",
|
|
14
|
-
"#0a0a0a",
|
|
15
|
-
"#fafafa"
|
|
16
|
-
],
|
|
17
|
-
[
|
|
18
|
-
"muted",
|
|
19
|
-
"ui-text-muted",
|
|
20
|
-
"muted-foreground",
|
|
21
|
-
"#737373",
|
|
22
|
-
"#a1a1a1"
|
|
23
|
-
],
|
|
24
|
-
[
|
|
25
|
-
"border",
|
|
26
|
-
"ui-border",
|
|
27
|
-
"border",
|
|
28
|
-
"#e5e5e5",
|
|
29
|
-
"rgb(255 255 255/.1)"
|
|
30
|
-
],
|
|
31
|
-
[
|
|
32
|
-
"accent",
|
|
33
|
-
"ui-bg-elevated",
|
|
34
|
-
"accent",
|
|
35
|
-
"#f5f5f5",
|
|
36
|
-
"#262626"
|
|
37
|
-
],
|
|
38
|
-
[
|
|
39
|
-
"ring",
|
|
40
|
-
"ui-primary",
|
|
41
|
-
"ring",
|
|
42
|
-
"#a1a1a1",
|
|
43
|
-
"#737373"
|
|
44
|
-
]
|
|
45
|
-
];
|
|
46
|
-
const resolve = (scheme) => tokens.map((token) => `--_comark-${token[0]}:var(--comark-${token[0]},var(--${token[1]},var(--${token[2]},${token[scheme]})))`).join(";");
|
|
47
|
-
/**
|
|
48
|
-
* Resolves the `--comark-*` tokens on `selector`, falling back to Nuxt UI's variables, then shadcn/ui's, then shadcn's
|
|
49
|
-
* neutral theme. Nuxt UI's corners are twice its `--ui-radius`, so the radius halves shadcn's to double it back.
|
|
50
|
-
* They resolve on the component rather than `:root`, so a `.dark` class anywhere above it switches the theme, and a
|
|
51
|
-
* `--comark-*` set on any ancestor still inherits down. `:where()` keeps them at zero specificity.
|
|
52
|
-
*/
|
|
53
|
-
function theme(selector) {
|
|
54
|
-
const where = `:where(${selector})`;
|
|
55
|
-
return `${where}{${resolve(3)};--_comark-radius:var(--comark-radius,calc(var(--ui-radius,calc(var(--radius,.625rem)/2))*2));--_comark-font:var(--comark-font,var(--font-sans,ui-sans-serif,system-ui,sans-serif))}@media (prefers-color-scheme:dark){${where}{${resolve(4)}}}`;
|
|
56
|
-
}
|
|
57
|
-
//#endregion
|
|
58
|
-
//#region src/styles.ts
|
|
59
|
-
/**
|
|
60
|
-
* Round numbered markers at the ends of lines and before each note, as a soft tint of shadcn/ui's `--primary` when the
|
|
61
|
-
* page has it, or of the foreground otherwise, with the number in that color, on the shared `--comark-*` tokens.
|
|
62
|
-
* Override `--cn-marker` and `--cn-marker-text`. The number is drawn by CSS, so copying the code never takes it along.
|
|
63
|
-
* The rules sit in the `comark` layer, so any unlayered rule of the host's wins.
|
|
64
|
-
*/
|
|
65
|
-
const css = `@layer comark{${[
|
|
66
|
-
theme(".cn-marker,.cn-notes"),
|
|
67
|
-
":where(.cn-marker){--cn-marker:var(--primary,var(--_comark-foreground));--cn-marker-text:var(--cn-marker)}",
|
|
68
|
-
".cn-marker{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;min-width:1.25rem;height:1.25rem;margin-inline-start:.5rem;padding:0 .3rem;border-radius:999px;background:color-mix(in srgb,var(--cn-marker) 10%,var(--_comark-background));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--cn-marker) 22%,transparent);font:600 .6875rem/1 var(--_comark-font);font-variant-numeric:tabular-nums;vertical-align:.0625rem;user-select:none;transition:background-color .15s}",
|
|
69
|
-
".cn-marker{color:var(--cn-marker-text)!important;text-decoration:none!important;border:0!important}",
|
|
70
|
-
".cn-marker::after{content:attr(data-note)}",
|
|
71
|
-
"a.cn-marker:hover{background:color-mix(in srgb,var(--cn-marker) 18%,var(--_comark-background))}",
|
|
72
|
-
"a.cn-marker:focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-ring) 50%,transparent)}",
|
|
73
|
-
".cn-marker:target{box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-ring) 60%,transparent)}",
|
|
74
|
-
".line:has(>.cn-marker:is(:target,:focus)){border-image:conic-gradient(color-mix(in srgb,var(--cn-marker,var(--primary,currentColor)) 14%,transparent) 0 0) fill 0//.25em 100vw}",
|
|
75
|
-
".cn-notes{margin:.75rem 0 1.5rem}",
|
|
76
|
-
".cn-notes{padding:0!important;list-style:none!important}",
|
|
77
|
-
".cn-notes>li{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:baseline;gap:.625rem;margin:.375rem 0;padding:.125rem .375rem;border-radius:calc(var(--_comark-radius) - 4px)}",
|
|
78
|
-
".cn-notes>li>.cn-marker{margin:0}",
|
|
79
|
-
".cn-notes>li>div>:first-child{margin-top:0!important}.cn-notes>li>div>:last-child{margin-bottom:0!important}",
|
|
80
|
-
".cn-notes>li:target{background:var(--_comark-accent)}"
|
|
81
|
-
].join("")}}`;
|
|
82
|
-
//#endregion
|
|
83
|
-
export { css as t };
|