comark-code-notes 0.0.0-stage → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +69 -0
- package/README.md +44 -2
- package/dist/client.d.mts +13 -0
- package/dist/client.mjs +12 -0
- package/dist/html.d.mts +7 -0
- package/dist/html.mjs +18 -0
- package/dist/index.d.mts +22 -0
- package/dist/index.mjs +213 -0
- package/dist/react.d.mts +16 -0
- package/dist/react.mjs +16 -0
- package/dist/style.css +1 -0
- package/dist/styles-zxOi3Y7k.mjs +83 -0
- package/dist/svelte/CodeNotes.svelte +10 -0
- package/dist/svelte/index.d.ts +8 -0
- package/dist/svelte/index.js +6 -0
- package/dist/vue.d.mts +22 -0
- package/dist/vue.mjs +21 -0
- package/package.json +88 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 onmax
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
The icons are Lucide's (https://lucide.dev), under its license:
|
|
26
|
+
|
|
27
|
+
ISC License
|
|
28
|
+
|
|
29
|
+
Copyright (c) 2026 Lucide Icons and Contributors
|
|
30
|
+
|
|
31
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
32
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
33
|
+
copyright notice and this permission notice appear in all copies.
|
|
34
|
+
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
36
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
37
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
38
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
39
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
40
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
41
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
The following Lucide icons are derived from the Feather project:
|
|
46
|
+
|
|
47
|
+
airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out
|
|
48
|
+
|
|
49
|
+
The MIT License (MIT) (for the icons listed above)
|
|
50
|
+
|
|
51
|
+
Copyright (c) 2013-present Cole Bemis
|
|
52
|
+
|
|
53
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
54
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
55
|
+
in the Software without restriction, including without limitation the rights
|
|
56
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
57
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
58
|
+
furnished to do so, subject to the following conditions:
|
|
59
|
+
|
|
60
|
+
The above copyright notice and this permission notice shall be included in all
|
|
61
|
+
copies or substantial portions of the Software.
|
|
62
|
+
|
|
63
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
64
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
65
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
66
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
67
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
68
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
69
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,45 @@
|
|
|
1
|
-
#
|
|
1
|
+
# comark-code-notes
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://npmx.dev/package/comark-code-notes)
|
|
4
|
+
[](https://npmx.dev/package/comark-code-notes)
|
|
5
|
+
[](https://npmx.dev/package/comark-code-notes)
|
|
6
|
+
[](https://comark-ui.onmax.me/code-notes/)
|
|
7
|
+
|
|
8
|
+
Numbered notes on lines of code, as in Quarto and AsciiDoc: a `// <1>` comment at the end of a line becomes a marker, and the numbered list after the fence becomes its notes, each linked to its marker and back. A [Comark](https://comark.dev) plugin for HTML, Vue, React, and Svelte.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
pnpm add comark comark-code-notes
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { createHtmlRenderer } from "@comark/html";
|
|
16
|
+
import shiki from "@comark/html/plugins/shiki";
|
|
17
|
+
import codeNotes, { components } from "comark-code-notes/html";
|
|
18
|
+
|
|
19
|
+
const render = createHtmlRenderer({ plugins: [shiki(), codeNotes()], components });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
````md
|
|
23
|
+
```ts
|
|
24
|
+
const res = await fetch(url) // <1>
|
|
25
|
+
if (!res.ok) return 0 // <2>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
1. One request per plaza, so the counts load in parallel.
|
|
29
|
+
2. A plaza with no census yet counts as empty.
|
|
30
|
+
````
|
|
31
|
+
|
|
32
|
+
Markers sit in a line-end comment: `// <1>`, `# <1>`, `-- <1>`, `; <1>`, `/* <1> */`, or `<!-- <1> -->`. They are taken out before Shiki highlights the code and drawn into its lines after, so put `codeNotes()` after `shiki()`. The marker's number is CSS, so copying the code, by hand or with comark-code's button, leaves it out. A fence with no numbered list after it, and any ` ```md ` fence, stays as written.
|
|
33
|
+
|
|
34
|
+
The plugin adds every problem to `meta.issues`, so a host can reject a document before publishing it: markers with no list, a marker with no note, a note with no marker, and `shiki` after the plugin. Each issue names its fence and says how to fix it.
|
|
35
|
+
|
|
36
|
+
## Renderers
|
|
37
|
+
|
|
38
|
+
| Renderer | Import |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `@comark/html` | `comark-code-notes/html`: the styles are inlined once per document |
|
|
41
|
+
| `@comark/vue` | `comark-code-notes/vue` |
|
|
42
|
+
| `@comark/react` | `comark-code-notes/react` |
|
|
43
|
+
| `@comark/svelte` | `comark-code-notes/svelte` |
|
|
44
|
+
|
|
45
|
+
Each entry exports the parse plugin as `default` and the renderer's `components`. The Vue, React, and Svelte components add the styles when they mount; import `comark-code-notes/style.css` with your styles so a server-rendered page doesn't shift. The styles read the shared `--comark-*` tokens and sit in a `comark` CSS layer, so any plain rule of your own wins.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/styles.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Round numbered markers at the ends of lines and before each note, as a soft tint of shadcn/ui's `--primary` when the
|
|
4
|
+
* page has it, or of the foreground otherwise, with the number in that color, on the shared `--comark-*` tokens.
|
|
5
|
+
* Override `--cn-marker` and `--cn-marker-text`. The number is drawn by CSS, so copying the code never takes it along.
|
|
6
|
+
* The rules sit in the `comark` layer, so any unlayered rule of the host's wins.
|
|
7
|
+
*/
|
|
8
|
+
export declare const css: string;
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/client.d.ts
|
|
11
|
+
/** Adds the code notes styles to the page once. The Vue, React, and Svelte components call it when they mount. */
|
|
12
|
+
export declare function addStyles(): void;
|
|
13
|
+
//#endregion
|
package/dist/client.mjs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { t as css } from "./styles-zxOi3Y7k.mjs";
|
|
2
|
+
//#region src/client.ts
|
|
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
|
|
12
|
+
export { addStyles, css };
|
package/dist/html.d.mts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import _default, { CodeNotesAttributes, CodeNotesMeta, NOTES_TAG } from "./index.mjs";
|
|
2
|
+
import { NodeHandler } from "comark";
|
|
3
|
+
//#region src/html.d.ts
|
|
4
|
+
/** The HTML renderer for code notes. Pass it as `components`; it inlines the styles once per document. */
|
|
5
|
+
export declare const components: Record<"code-notes", NodeHandler>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { type CodeNotesAttributes, type CodeNotesMeta, NOTES_TAG, _default as default };
|
package/dist/html.mjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import src_default, { NOTES_TAG } from "./index.mjs";
|
|
2
|
+
import { t as css } from "./styles-zxOi3Y7k.mjs";
|
|
3
|
+
//#region src/html.ts
|
|
4
|
+
const styled = /* @__PURE__ */ new WeakSet();
|
|
5
|
+
const notes = async ([, attrs, ...children], state) => {
|
|
6
|
+
const styles = styled.has(state.context) ? "" : `<style data-comark-code-notes>${css}</style>`;
|
|
7
|
+
styled.add(state.context);
|
|
8
|
+
const start = Number(attrs.start);
|
|
9
|
+
return `${styles}<ol class="cn-notes"${Number.isInteger(start) && start !== 1 ? ` start="${start}"` : ""}>${await state.flow([
|
|
10
|
+
"div",
|
|
11
|
+
{},
|
|
12
|
+
...children
|
|
13
|
+
], state)}</ol>`;
|
|
14
|
+
};
|
|
15
|
+
/** The HTML renderer for code notes. Pass it as `components`; it inlines the styles once per document. */
|
|
16
|
+
const components = { "code-notes": notes };
|
|
17
|
+
//#endregion
|
|
18
|
+
export { NOTES_TAG, components, src_default as default };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
export type CodeNotesMeta = {
|
|
3
|
+
/** One readable sentence per problem with a fence's markers or notes. Other plugins add theirs too. */
|
|
4
|
+
issues: string[];
|
|
5
|
+
/** The comark-linter rule of each issue, by its sentence, so the linter reports it under its own code. */
|
|
6
|
+
issueRules: Record<string, string>;
|
|
7
|
+
};
|
|
8
|
+
/** The node the numbered list after an annotated fence becomes. Each item starts with its marker, linking back. */
|
|
9
|
+
export declare const NOTES_TAG = "code-notes";
|
|
10
|
+
/** What a `code-notes` node carries besides its items: the number of its first note. */
|
|
11
|
+
export type CodeNotesAttributes = {
|
|
12
|
+
start?: number;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Turns `// <1>` at the end of a line in a fence, in the language's comment, into a numbered marker, and the numbered
|
|
16
|
+
* list right after the fence into its notes, each linked to its marker and back. Markers are stripped before Shiki
|
|
17
|
+
* highlights the code and drawn into its lines after, so put this plugin after Comark's `shiki` in `plugins`.
|
|
18
|
+
* Problems are added to `meta.issues`.
|
|
19
|
+
*/
|
|
20
|
+
declare const _default: import("comark").ComarkPluginFactory<void, CodeNotesMeta, {}>;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { _default as default };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { defineComarkPlugin } from "comark";
|
|
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 };
|
package/dist/react.d.mts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import _default, { CodeNotesAttributes, CodeNotesMeta, NOTES_TAG } from "./index.mjs";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/react.d.ts
|
|
4
|
+
/** The notes under an annotated fence, for `@comark/react`. */
|
|
5
|
+
export declare function CodeNotes({ start, children }: CodeNotesAttributes & {
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}): import("react").DetailedReactHTMLElement<{
|
|
8
|
+
className: string;
|
|
9
|
+
start: number | undefined;
|
|
10
|
+
}, HTMLElement>;
|
|
11
|
+
/** Pass these as `components` to `@comark/react`. */
|
|
12
|
+
export declare const components: {
|
|
13
|
+
CodeNotes: typeof CodeNotes;
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { type CodeNotesAttributes, type CodeNotesMeta, NOTES_TAG, _default as default };
|
package/dist/react.mjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import src_default, { NOTES_TAG } from "./index.mjs";
|
|
2
|
+
import { addStyles } from "./client.mjs";
|
|
3
|
+
import { createElement, useEffect } from "react";
|
|
4
|
+
//#region src/react.ts
|
|
5
|
+
/** The notes under an annotated fence, for `@comark/react`. */
|
|
6
|
+
function CodeNotes({ start, children }) {
|
|
7
|
+
useEffect(addStyles, []);
|
|
8
|
+
return createElement("ol", {
|
|
9
|
+
className: "cn-notes",
|
|
10
|
+
start: start && start !== 1 ? start : void 0
|
|
11
|
+
}, children);
|
|
12
|
+
}
|
|
13
|
+
/** Pass these as `components` to `@comark/react`. */
|
|
14
|
+
const components = { CodeNotes };
|
|
15
|
+
//#endregion
|
|
16
|
+
export { CodeNotes, NOTES_TAG, components, src_default as default };
|
package/dist/style.css
ADDED
|
@@ -0,0 +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(--primary,var(--_comark-foreground));--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: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}.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,var(--primary,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,83 @@
|
|
|
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 };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<!-- The notes under an annotated fence, for `@comark/svelte`. -->
|
|
2
|
+
<script>
|
|
3
|
+
import { onMount } from "svelte";
|
|
4
|
+
import { addStyles } from "comark-code-notes/client";
|
|
5
|
+
|
|
6
|
+
let { start = undefined, children } = $props();
|
|
7
|
+
onMount(addStyles);
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<ol class="cn-notes" start={start && start !== 1 ? start : undefined}>{@render children?.()}</ol>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Component, Snippet } from "svelte";
|
|
2
|
+
import type { CodeNotesAttributes } from "comark-code-notes";
|
|
3
|
+
|
|
4
|
+
export { default, NOTES_TAG } from "comark-code-notes";
|
|
5
|
+
export type { CodeNotesAttributes, CodeNotesMeta } from "comark-code-notes";
|
|
6
|
+
|
|
7
|
+
export declare const CodeNotes: Component<CodeNotesAttributes & { children?: Snippet }>;
|
|
8
|
+
export declare const components: { CodeNotes: typeof CodeNotes };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// The notes under an annotated fence, for `@comark/svelte`. Pass `components` to it; the parse plugin comes from `comark-code-notes`.
|
|
2
|
+
import CodeNotes from "./CodeNotes.svelte";
|
|
3
|
+
|
|
4
|
+
export { default, NOTES_TAG } from "comark-code-notes";
|
|
5
|
+
export { CodeNotes };
|
|
6
|
+
export const components = { CodeNotes };
|
package/dist/vue.d.mts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import _default, { CodeNotesAttributes, CodeNotesMeta, NOTES_TAG } from "./index.mjs";
|
|
2
|
+
//#region src/vue.d.ts
|
|
3
|
+
/** The notes under an annotated fence, for `@comark/vue`. */
|
|
4
|
+
export declare const CodeNotes: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
5
|
+
start: NumberConstructor;
|
|
6
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
9
|
+
start: NumberConstructor;
|
|
10
|
+
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
11
|
+
/** Pass these as `components` to `@comark/vue`. */
|
|
12
|
+
export declare const components: {
|
|
13
|
+
CodeNotes: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
14
|
+
start: NumberConstructor;
|
|
15
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
18
|
+
start: NumberConstructor;
|
|
19
|
+
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { type CodeNotesAttributes, type CodeNotesMeta, NOTES_TAG, _default as default };
|
package/dist/vue.mjs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import src_default, { NOTES_TAG } from "./index.mjs";
|
|
2
|
+
import { addStyles } from "./client.mjs";
|
|
3
|
+
import { defineComponent, h, onMounted } from "vue";
|
|
4
|
+
//#region src/vue.ts
|
|
5
|
+
/** The notes under an annotated fence, for `@comark/vue`. */
|
|
6
|
+
const CodeNotes = defineComponent({
|
|
7
|
+
name: "CodeNotes",
|
|
8
|
+
inheritAttrs: false,
|
|
9
|
+
props: { start: Number },
|
|
10
|
+
setup(props, { slots }) {
|
|
11
|
+
onMounted(addStyles);
|
|
12
|
+
return () => h("ol", {
|
|
13
|
+
class: "cn-notes",
|
|
14
|
+
start: props.start && props.start !== 1 ? props.start : void 0
|
|
15
|
+
}, slots.default?.());
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
/** Pass these as `components` to `@comark/vue`. */
|
|
19
|
+
const components = { CodeNotes };
|
|
20
|
+
//#endregion
|
|
21
|
+
export { CodeNotes, NOTES_TAG, components, src_default as default };
|
package/package.json
CHANGED
|
@@ -1,6 +1,91 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "comark-code-notes",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.7.1",
|
|
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
|
+
"keywords": [
|
|
6
|
+
"annotations",
|
|
7
|
+
"callouts",
|
|
8
|
+
"code",
|
|
9
|
+
"comark",
|
|
10
|
+
"markdown",
|
|
11
|
+
"mdc",
|
|
12
|
+
"plugin",
|
|
13
|
+
"shiki"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://comark-ui.onmax.me/code-notes",
|
|
16
|
+
"bugs": "https://github.com/onmax/comark-ui/issues",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "onmax",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/onmax/comark-ui.git",
|
|
22
|
+
"directory": "packages/code-notes"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"sideEffects": [
|
|
29
|
+
"*.css"
|
|
30
|
+
],
|
|
31
|
+
"exports": {
|
|
32
|
+
".": "./dist/index.mjs",
|
|
33
|
+
"./client": "./dist/client.mjs",
|
|
34
|
+
"./html": "./dist/html.mjs",
|
|
35
|
+
"./react": "./dist/react.mjs",
|
|
36
|
+
"./style.css": "./dist/style.css",
|
|
37
|
+
"./svelte": {
|
|
38
|
+
"types": "./dist/svelte/index.d.ts",
|
|
39
|
+
"svelte": "./dist/svelte/index.js",
|
|
40
|
+
"default": "./dist/svelte/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./vue": "./dist/vue.mjs",
|
|
43
|
+
"./package.json": "./package.json"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public",
|
|
47
|
+
"provenance": true
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@comark/html": "^0.8.1",
|
|
51
|
+
"@comark/react": "^0.8.1",
|
|
52
|
+
"@comark/vue": "^0.8.1",
|
|
53
|
+
"@types/react": "^19.3.0",
|
|
54
|
+
"@types/react-dom": "^19.3.0",
|
|
55
|
+
"comark": "^0.8.1",
|
|
56
|
+
"react": "^19.3.1",
|
|
57
|
+
"react-dom": "^19.3.1",
|
|
58
|
+
"svelte": "^5.57.2",
|
|
59
|
+
"vue": "^3.5.44",
|
|
60
|
+
"comark-zoom": "0.7.1"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"@comark/html": "^0.8.0",
|
|
64
|
+
"comark": "^0.8.0",
|
|
65
|
+
"react": ">=18",
|
|
66
|
+
"svelte": ">=5",
|
|
67
|
+
"vue": ">=3.5"
|
|
68
|
+
},
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"@comark/html": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"react": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"svelte": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"vue": {
|
|
80
|
+
"optional": true
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"engines": {
|
|
84
|
+
"node": ">=22.12.0"
|
|
85
|
+
},
|
|
86
|
+
"scripts": {
|
|
87
|
+
"build": "tsdown",
|
|
88
|
+
"dev": "tsdown --watch",
|
|
89
|
+
"doctor": "vite-doctor . --no-cache --max-warnings 0 --format text"
|
|
90
|
+
}
|
|
6
91
|
}
|