comark-comments 0.0.0-stage → 0.7.4

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 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.
@@ -0,0 +1,10 @@
1
+ import { a as Entry, i as DEFERRED, n as CommentsOptions, o as Mark, r as _default, s as ROOT, t as CommentsMeta } from "./index-Do0sHGVr.mjs";
2
+ import { NodeHandler } from "comark";
3
+ //#region src/html.d.ts
4
+ /**
5
+ * The HTML renderer for `:suggestion` and `:comment`. Pass it as `components`; it inlines the styles once per
6
+ * document, and the handwriting font only when a suggestion draws with `pen`.
7
+ */
8
+ export declare const components: Record<"suggestion" | "comment" | typeof ROOT | typeof DEFERRED, NodeHandler>;
9
+ //#endregion
10
+ export { type CommentsMeta, type CommentsOptions, type Entry, type Mark, _default as default };
package/dist/html.mjs ADDED
@@ -0,0 +1,278 @@
1
+ import { a as hash, c as transform, i as childrenOf, l as wrapParagraphs, n as DEFERRED, o as isElement, r as ROOT, s as nativeAttributes, t as src_default } from "./src-CCwYg7qg.mjs";
2
+ import { resolveAttributes } from "comark/render";
3
+ import { escapeHtml } from "comark/utils";
4
+ //#region ../annotate/dist/font-Bq-VpE6W.mjs
5
+ const caveat = "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";
6
+ //#endregion
7
+ //#region ../zoom/dist/theme.mjs
8
+ const tokens = [
9
+ [
10
+ "background",
11
+ "ui-bg",
12
+ "background",
13
+ "#fff",
14
+ "#0a0a0a"
15
+ ],
16
+ [
17
+ "foreground",
18
+ "ui-text-highlighted",
19
+ "foreground",
20
+ "#0a0a0a",
21
+ "#fafafa"
22
+ ],
23
+ [
24
+ "muted",
25
+ "ui-text-muted",
26
+ "muted-foreground",
27
+ "#737373",
28
+ "#a1a1a1"
29
+ ],
30
+ [
31
+ "border",
32
+ "ui-border",
33
+ "border",
34
+ "#e5e5e5",
35
+ "rgb(255 255 255/.1)"
36
+ ],
37
+ [
38
+ "accent",
39
+ "ui-bg-elevated",
40
+ "accent",
41
+ "#f5f5f5",
42
+ "#262626"
43
+ ],
44
+ [
45
+ "ring",
46
+ "ui-primary",
47
+ "ring",
48
+ "#a1a1a1",
49
+ "#737373"
50
+ ]
51
+ ];
52
+ const resolve = (scheme) => tokens.map((token) => `--_comark-${token[0]}:var(--comark-${token[0]},var(--${token[1]},var(--${token[2]},${token[scheme]})))`).join(";");
53
+ /**
54
+ * Resolves the `--comark-*` tokens on `selector`, falling back to Nuxt UI's variables, then shadcn/ui's, then shadcn's
55
+ * neutral theme. Nuxt UI's corners are twice its `--ui-radius`, so the radius halves shadcn's to double it back.
56
+ * They resolve on the component rather than `:root`, so a `.dark` class anywhere above it switches the theme, and a
57
+ * `--comark-*` set on any ancestor still inherits down. `:where()` keeps them at zero specificity.
58
+ */
59
+ function theme(selector) {
60
+ const where = `:where(${selector})`;
61
+ 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)}}}`;
62
+ }
63
+ //#endregion
64
+ //#region src/styles.ts
65
+ const icon = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.2' stroke-linejoin='round'%3E%3Cpath d='M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z'/%3E%3C/svg%3E")`;
66
+ const parts = ".cr,.cr-sg,.cr-cm,.cr-bub,.cr-card";
67
+ const pen = ".cr-sg[data-mark=\"pen\"]";
68
+ const fontCss = `@font-face{font-family:comark-caveat;src:url(data:font/woff2;base64,${caveat}) format("woff2");font-display:block}`;
69
+ /**
70
+ * The marks, bubbles, and cards, on the shared `--comark-*` tokens. Override `--cr-ins`, `--cr-del`, and
71
+ * `--cr-comment`. The rules sit in the `comark` layer, so any unlayered rule of the host's wins.
72
+ */
73
+ const css = `@layer comark{${[
74
+ theme(parts),
75
+ `:where(${parts}){--_cr-ins:var(--cr-ins,#259f56);--_cr-del:var(--cr-del,var(--destructive,#ee3533));--_cr-comment:var(--cr-comment,#f5a524);--_cr-icon:var(--cr-icon,${icon})}`,
76
+ `@media (prefers-color-scheme:dark){:where(${parts}){--_cr-ins:var(--cr-ins,#59d38c);--_cr-del:var(--cr-del,var(--destructive,#fd736d));--_cr-comment:var(--cr-comment,#fbbf24)}}`,
77
+ ".cr-sg :is(del,ins)::before,.cr-sg :is(del,ins)::after{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}",
78
+ ".cr-sg del::before{content:\" [removed: \"}.cr-sg ins::before{content:\" [added: \"}.cr-sg :is(del,ins)::after{content:\"] \"}",
79
+ ".cr-sg,.cr-cm{border-radius:.25rem;transition:box-shadow .12s}",
80
+ ".cr-sg :is(del,ins){padding:.0625rem .1875rem;border-radius:.25rem;-webkit-box-decoration-break:clone;box-decoration-break:clone}",
81
+ ".cr-sg del{color:color-mix(in oklab,var(--_cr-del) 70%,var(--_comark-foreground));background:color-mix(in srgb,var(--_cr-del) 11%,transparent);text-decoration:line-through 1.5px color-mix(in srgb,var(--_cr-del) 75%,transparent)}",
82
+ ".cr-sg ins{color:color-mix(in oklab,var(--_cr-ins) 60%,var(--_comark-foreground));background:color-mix(in srgb,var(--_cr-ins) 13%,transparent);text-decoration:none}",
83
+ ".cr-sg del+ins{margin-left:.125rem}",
84
+ `${pen}{position:relative;display:inline-block;padding-top:1.05em}`,
85
+ ".cr-keep{white-space:nowrap}",
86
+ `${pen} del{position:relative;padding:0;background:none;color:inherit;text-decoration:none}`,
87
+ `${pen} .cr-strike{position:absolute;left:-.08em;top:50%;width:calc(100% + .16em);height:.7em;transform:translateY(-40%);overflow:visible;fill:none;stroke:var(--_cr-del);stroke-width:2.25;stroke-linecap:round}`,
88
+ `${pen} .cr-strike path{vector-effect:non-scaling-stroke}`,
89
+ `${pen} ins{position:absolute;left:0;top:-.05em;margin:0;padding:0;background:none;transform:rotate(-2.5deg);transform-origin:left bottom;white-space:nowrap;color:var(--_cr-del);font:400 1.5em/1 comark-caveat,cursive}`,
90
+ `${pen}[data-kind="insert"] ins{transform:translateX(-50%) rotate(-2.5deg);transform-origin:center}`,
91
+ `${pen} .cr-caret{display:inline-block;position:relative;width:0}`,
92
+ `${pen} .cr-caret svg{position:absolute;left:-.32em;top:.18em;width:.64em;height:.5em;overflow:visible;fill:none;stroke:var(--_cr-del);stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round}`,
93
+ ".cr-cm{color:inherit;background:color-mix(in srgb,var(--_cr-comment) 22%,transparent);border-bottom:2px solid color-mix(in srgb,var(--_cr-comment) 80%,transparent);border-radius:.125rem;padding:0 .0625rem}",
94
+ ".cr-bub{display:inline;margin-left:.25em;padding:.25em .5em .25em 1.75em;vertical-align:.1em;border:1px solid var(--_comark-border);border-radius:999px;background:var(--_comark-background) var(--_cr-icon) no-repeat .42em 50%/1em;color:var(--_comark-muted);font:600 .6875rem/1 var(--_comark-font);font-variant-numeric:tabular-nums;cursor:pointer;box-shadow:0 1px 2px rgb(0 0 0/.05);transition:color .12s,border-color .12s}",
95
+ ".cr-bub:empty{padding-right:.3em}",
96
+ ".cr-tg{position:absolute;width:1px;height:1px;margin:0;opacity:0;pointer-events:none}",
97
+ ".cr-tg:focus-visible+.cr-bub{outline:2px solid var(--_comark-ring);outline-offset:2px}",
98
+ ".cr-tg:checked+.cr-bub,.cr-bub:hover,.cr-bub:has(+.cr-card:hover){color:var(--_comark-foreground);border-color:var(--_comark-ring)}",
99
+ ":is(.cr-cm,.cr-sg):has(+.cr-tg:checked,+.cr-tg+.cr-bub:hover,+.cr-tg+.cr-bub+.cr-card:hover){box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-foreground) 12%,transparent)}",
100
+ ".cr-card{display:none;box-sizing:border-box;padding:.5rem .75rem;border:1px solid var(--_comark-border);border-radius:var(--_comark-radius);background:var(--_comark-background);color:var(--_comark-foreground);font:400 .8125rem/1.5 var(--_comark-font);text-align:left;text-indent:0;white-space:normal;transition:border-color .12s,box-shadow .12s}",
101
+ ".cr-entry{display:block}.cr-entry+.cr-entry{margin-top:.5rem;padding-top:.5rem;border-top:1px solid var(--_comark-border)}",
102
+ ".cr-entry b{margin-right:.375rem;font-weight:600}",
103
+ ".cr-av{display:inline-grid;place-items:center;width:1.125rem;height:1.125rem;margin-right:.375rem;border-radius:999px;background:var(--cr-av);color:#fff;font:600 .5625rem/1 var(--_comark-font);vertical-align:calc(.722cap - .5625rem)}",
104
+ "img.cr-av{display:inline-block;background:#fff;object-fit:cover;outline:1px solid color-mix(in srgb,var(--_comark-foreground) 12%,transparent);outline-offset:-1px}",
105
+ ".cr-tg:checked+.cr-bub+.cr-card{display:block;float:left;clear:both;width:100%;margin:.5rem 0}",
106
+ ".cr{container:cr/inline-size;display:flow-root}",
107
+ "@container cr (min-width:50rem){.cr>*{margin-right:19.5rem!important}.cr-card,.cr-tg:checked+.cr-bub+.cr-card{display:block;position:relative;float:right;clear:right;width:17.5rem;margin:0 -19.5rem .5rem 0}.cr-tg:checked+.cr-bub+.cr-card,.cr-bub:hover+.cr-card,.cr-card:hover{border-color:var(--_comark-ring);box-shadow:0 4px 16px rgb(0 0 0/.08)}}",
108
+ "@media print{.cr>*{margin-right:12.5rem!important}.cr-card{display:block!important;float:right!important;clear:right;width:11.5rem!important;margin:0 -12.5rem .375rem 0!important;font-size:.6875rem;box-shadow:none!important}.cr-bub{display:none}}"
109
+ ].join("")}}`;
110
+ //#endregion
111
+ //#region src/html.ts
112
+ const styled = /* @__PURE__ */ new WeakSet();
113
+ const fonted = /* @__PURE__ */ new WeakSet();
114
+ function once(set, state, html) {
115
+ if (set.has(state.context)) return "";
116
+ set.add(state.context);
117
+ return html;
118
+ }
119
+ const styles = (state) => once(styled, state, `<style data-comark-comments>${css}</style>`);
120
+ const attr = (value) => escapeHtml(value, { "\"": "&quot;" });
121
+ const valueOf = (value) => value === void 0 || value === null ? "" : value instanceof Object ? JSON.stringify(value) : String(value);
122
+ const classOf = (name, attrs) => attr([name, valueOf(attrs.class)].filter(Boolean).join(" "));
123
+ const attributes = (attrs, omit = []) => Object.entries(nativeAttributes(attrs)).filter(([key, value]) => /^[a-zA-Z_][a-zA-Z0-9:._-]*$/.test(key) && !omit.includes(key.toLowerCase()) && value !== void 0 && value !== null).map(([key, value]) => ` ${key}="${attr(valueOf(value))}"`).join("");
124
+ const read = (state, key) => state[key];
125
+ const namespaces = /* @__PURE__ */ new WeakMap();
126
+ function idFor(uid, state) {
127
+ let namespace = namespaces.get(state.context);
128
+ if (!namespace) {
129
+ namespace = Array.from(crypto.getRandomValues(/* @__PURE__ */ new Uint32Array(4)), (part) => part.toString(16).padStart(8, "0")).join("");
130
+ namespaces.set(state.context, namespace);
131
+ }
132
+ return `${uid}-${namespace}`;
133
+ }
134
+ const STROKES = [
135
+ "M1 6.5C24 4.8 61 6.9 99 3.9",
136
+ "M2 4.6C30 6.4 66 3.6 98 5.8",
137
+ "M1 5.9C33 3.8 70 6.6 99 4.4"
138
+ ];
139
+ const CARET = "<span class=\"cr-caret\" aria-hidden=\"true\"><svg viewBox=\"0 0 10 8\"><path d=\"M1 7.4L5.2 1.2 9.1 7\"/></svg></span>";
140
+ const COLORS = [
141
+ "#d97757",
142
+ "#2563eb",
143
+ "#7c3aed",
144
+ "#059669",
145
+ "#db2777",
146
+ "#0891b2",
147
+ "#ca8a04",
148
+ "#4f46e5"
149
+ ];
150
+ function who(by, avatar) {
151
+ const name = by.replace(/^@/, "");
152
+ if (!name) return "";
153
+ if (avatar) return `<img class="cr-av" src="${attr(avatar)}" alt="" width="18" height="18"><b>${escapeHtml(name)}</b>`;
154
+ const initial = [...new Intl.Segmenter().segment(name)][0]?.segment.toUpperCase() ?? "";
155
+ return `<span class="cr-av" style="--cr-av:${COLORS[Number.parseInt(hash(name.toLowerCase()), 36) % COLORS.length]}" aria-hidden="true">${escapeHtml(initial)}</span><b>${escapeHtml(name)}</b>`;
156
+ }
157
+ function thread(attrs, state) {
158
+ const base = read(attrs, "uid");
159
+ if (!base) return "";
160
+ const uid = idFor(base, state);
161
+ const entries = attrs.thread;
162
+ const card = entries.map((entry) => `<span class="cr-entry">${who(entry.by, entry.avatar)}${escapeHtml(entry.note)}</span>`).join("");
163
+ return `&#8288;<input class="cr-tg" type="checkbox" id="${attr(uid)}" aria-label="${attr(read(attrs, "label") ?? "")}"><label class="cr-bub" for="${attr(uid)}">${entries.length > 1 ? entries.length : ""}</label><span class="cr-card" role="note">${card}</span>`;
164
+ }
165
+ const plain = async (node, state) => {
166
+ const body = await state.flow(node, state);
167
+ const native = attributes(node[1]);
168
+ return native ? `<span${native}>${body}</span>` : body;
169
+ };
170
+ const suggestion = async (node, state) => {
171
+ const attrs = node[1];
172
+ if (attrs.plain) return plain(node, state);
173
+ const from = read(attrs, "from") ?? "";
174
+ const body = node.length > 2 ? await state.flow(node, state) : "";
175
+ const pen = attrs.mark === "pen";
176
+ const kind = from && body ? "replace" : from ? "delete" : "insert";
177
+ const stroke = STROKES[Number(read(attrs, "stroke") ?? 0) % STROKES.length];
178
+ const del = from ? `<del>${escapeHtml(from)}${pen ? `<svg class="cr-strike" viewBox="0 0 100 10" preserveAspectRatio="none" aria-hidden="true"><path d="${stroke}"/></svg>` : ""}</del>` : "";
179
+ const ins = body ? `${pen && !from ? CARET : ""}<ins>${body}</ins>` : "";
180
+ const mark = `<span class="${classOf("cr-sg", attrs)}" data-mark="${pen ? "pen" : "track"}" data-kind="${kind}"${attributes(attrs, [
181
+ "class",
182
+ "data-mark",
183
+ "data-kind"
184
+ ])}>${del}${ins}</span>`;
185
+ const tail = thread(attrs, state);
186
+ return styles(state) + (pen ? once(fonted, state, `<style data-comark-comments-font>${fontCss}</style>`) : "") + (pen && tail ? `<span class="cr-keep">${mark}${tail}</span>` : mark + tail);
187
+ };
188
+ const comment = async (node, state) => {
189
+ const attrs = node[1];
190
+ if (attrs.plain) return plain(node, state);
191
+ return `${styles(state)}<mark class="${classOf("cr-cm", attrs)}"${attributes(attrs, ["class"])}>${await state.flow(node, state)}</mark>${thread(attrs, state)}`;
192
+ };
193
+ const root = async (node, state) => `${styles(state)}<div class="cr">${await state.flow(node, state)}</div>`;
194
+ const deferred = async (node, state) => {
195
+ const { comments: settings } = node[1].$;
196
+ const nodes = structuredClone(childrenOf(node));
197
+ wrapParagraphs(nodes);
198
+ const rendered = /* @__PURE__ */ new WeakMap();
199
+ const fragments = [];
200
+ const marker = `\uE000${idFor("comments", state)}:`;
201
+ const slots = new RegExp(`${marker}(\\d+)\uE001`, "g");
202
+ const isReply = (child) => child[0] === "comment" && (Object.hasOwn(child[1], "reply") || Object.hasOwn(child[1], ":reply"));
203
+ const emptyReplyParagraph = (element) => {
204
+ const children = childrenOf(element);
205
+ return element[0] === "p" && children.some((child) => isElement(child) && isReply(child)) && children.every((child) => !Array.isArray(child) ? !child.trim() : isElement(child) && isReply(child) && childrenOf(child).every((text) => !Array.isArray(text) && !text.trim()));
206
+ };
207
+ const one = state.one;
208
+ const flow = state.flow;
209
+ state.flow = async (element, current, parent) => {
210
+ let html = "";
211
+ for (const child of childrenOf(element)) html += await current.one(child, current, parent ?? element);
212
+ return html;
213
+ };
214
+ state.one = async (child, current, parent, atLineStart) => {
215
+ if (isElement(child) && (child[0] === "comment" || child[0] === "suggestion")) {
216
+ const previous = current.renderData;
217
+ const attrs = resolveAttributes(child[1], previous, { parseJson: true });
218
+ rendered.set(child, attrs);
219
+ if (Object.keys(child[1]).some((key) => key !== "$")) current.renderData = {
220
+ ...previous,
221
+ props: attrs
222
+ };
223
+ let body;
224
+ try {
225
+ body = await current.flow(child, current);
226
+ } finally {
227
+ current.renderData = previous;
228
+ }
229
+ const slot = fragments.length;
230
+ fragments.push({
231
+ node: child,
232
+ body,
233
+ reply: isReply(child)
234
+ });
235
+ return `${marker}${slot}\uE001`;
236
+ }
237
+ const html = await one(child, current, parent, atLineStart);
238
+ return isElement(child) && emptyReplyParagraph(child) ? "" : html;
239
+ };
240
+ let html;
241
+ try {
242
+ html = await state.render(nodes);
243
+ } finally {
244
+ state.one = one;
245
+ state.flow = flow;
246
+ }
247
+ transform(nodes, {
248
+ ...settings,
249
+ data: state.renderData,
250
+ rendered
251
+ });
252
+ const margin = isElement(nodes[0]) && nodes[0][0] === "comments";
253
+ const leading = margin ? styles(state) : "";
254
+ const replacements = [];
255
+ const fill = (value) => value.replace(slots, (_, index) => replacements[Number(index)]);
256
+ for (const fragment of fragments) {
257
+ const body = fill(fragment.body);
258
+ const handler = fragment.node[0] === "suggestion" ? suggestion : comment;
259
+ replacements.push(fragment.reply ? body : await handler(fragment.node, {
260
+ ...state,
261
+ flow: async () => body
262
+ }));
263
+ }
264
+ html = fill(html);
265
+ return margin ? `${leading}<div class="cr">${html}</div>` : html;
266
+ };
267
+ /**
268
+ * The HTML renderer for `:suggestion` and `:comment`. Pass it as `components`; it inlines the styles once per
269
+ * document, and the handwriting font only when a suggestion draws with `pen`.
270
+ */
271
+ const components = {
272
+ suggestion,
273
+ comment,
274
+ [ROOT]: root,
275
+ [DEFERRED]: deferred
276
+ };
277
+ //#endregion
278
+ export { components, src_default as default };
@@ -0,0 +1,44 @@
1
+ import "comark";
2
+ import { resolveAttributes } from "comark/render";
3
+ //#region src/read.d.ts
4
+ /** How a suggestion draws: a red strike and a green insert, or a hand-drawn strike with the new words written above. */
5
+ type Mark = "track" | "pen";
6
+ /** One message in a card: its author as written in `by`, its `note`, and the author's image from `avatars`. */
7
+ type Entry = {
8
+ by: string;
9
+ note: string;
10
+ avatar?: string;
11
+ };
12
+ /** The root node the plugin wraps a document's blocks in when any card goes in the margin. */
13
+ declare const ROOT = "comments";
14
+ /** Holds authored nodes until the renderer supplies data and inherited props. */
15
+ declare const DEFERRED = "comments-render";
16
+ //#endregion
17
+ //#region src/index.d.ts
18
+ type CommentsOptions = {
19
+ /**
20
+ * How suggestions draw unless one sets its own `mark`: `track`, a red strike and a green insert, or `pen`, a
21
+ * hand-drawn strike with the new words handwritten above. Pen falls back to track for a change longer than 24
22
+ * characters, across lines, or with code or links. Default `track`.
23
+ */
24
+ mark?: Mark;
25
+ /**
26
+ * An image per author, by the name written in `by` without `@`, such as `{ onmax: "https://github.com/onmax.png" }`.
27
+ * Names match in any case. An author without one gets an initial on a color from the name.
28
+ */
29
+ avatars?: Record<string, string>;
30
+ };
31
+ type CommentsMeta = {
32
+ /** One readable sentence per problem with a `:suggestion` or `:comment`. Other plugins add theirs too. */
33
+ issues: string[];
34
+ /** The comark-linter rule of each issue, by its sentence, so the linter reports it under its own code. */
35
+ issueRules: Record<string, string>;
36
+ };
37
+ /**
38
+ * Reads `:suggestion` and `:comment`: suggested edits and comments on a span, each with an optional note in a card in
39
+ * the margin. A `:comment{reply="id"}` anywhere in the document joins that thread. Problems are added to
40
+ * `meta.issues`.
41
+ */
42
+ declare const _default: import("comark").ComarkPluginFactory<CommentsOptions, CommentsMeta, {}>;
43
+ //#endregion
44
+ export { Entry as a, DEFERRED as i, CommentsOptions as n, Mark as o, _default as r, ROOT as s, CommentsMeta as t };
@@ -0,0 +1,2 @@
1
+ import { a as Entry, n as CommentsOptions, o as Mark, r as _default, t as CommentsMeta } from "./index-Do0sHGVr.mjs";
2
+ export { CommentsMeta, CommentsOptions, type Entry, type Mark, _default as default };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ export { t as default } from "./src-CCwYg7qg.mjs";
@@ -0,0 +1,394 @@
1
+ import { defineComarkPlugin } from "comark";
2
+ import { resolveAttributes } from "comark/render";
3
+ import { textContent } from "comark/utils";
4
+ //#region src/read.ts
5
+ /** The root node the plugin wraps a document's blocks in when any card goes in the margin. */
6
+ const ROOT = "comments";
7
+ /** Holds authored nodes until the renderer supplies data and inherited props. */
8
+ const DEFERRED = "comments-render";
9
+ const MARKS = ["track", "pen"];
10
+ const PROPS = {
11
+ suggestion: [
12
+ "from",
13
+ "by",
14
+ "note",
15
+ "mark",
16
+ "id"
17
+ ],
18
+ comment: [
19
+ "by",
20
+ "note",
21
+ "id"
22
+ ],
23
+ reply: [
24
+ "reply",
25
+ "by",
26
+ "note"
27
+ ]
28
+ };
29
+ const NATIVE = /^(?:id|class|style|data-.+|aria-.+)$/i;
30
+ /** Authored HTML attributes only; renderer control fields are always generated by the plugin. */
31
+ const nativeAttributes = (attrs) => Object.fromEntries(Object.entries(attrs).filter(([key]) => NATIVE.test(key)));
32
+ const HINTS = /* @__PURE__ */ new Map([
33
+ ["reason", "Did you mean `note`?"],
34
+ ["comment", "Did you mean `note`?"],
35
+ ["message", "Did you mean `note`?"],
36
+ ["body", "Did you mean `note`?"],
37
+ ["author", "Did you mean `by`?"],
38
+ ["user", "Did you mean `by`?"],
39
+ ["old", "Did you mean `from`?"],
40
+ ["original", "Did you mean `from`?"],
41
+ ["to", "Put the new text in the brackets."],
42
+ ["new", "Put the new text in the brackets."],
43
+ ["text", "Put the text in the brackets."],
44
+ ["reply-to", "Did you mean `reply`?"],
45
+ ["thread", "Did you mean `reply`?"]
46
+ ]);
47
+ const PEN_MAX = 24;
48
+ const HEADING = /^h[1-6]$/;
49
+ const isElement = (node) => Array.isArray(node) && node[0] !== null;
50
+ const childrenOf = (node) => node.slice(2);
51
+ const text = (value) => value === void 0 || value === null || value instanceof Object ? "" : String(value).trim();
52
+ const later = (path) => /^(?:data|props)(?:\.|$)/.test(text(path));
53
+ const pending = (raw, key) => later(raw[`:${key}`]);
54
+ const hasRenderBindings = (nodes) => nodes.some((node) => isElement(node) && ((node[0] === "comment" || node[0] === "suggestion") && Object.entries(node[1]).some(([key, value]) => key.startsWith(":") && later(value)) || hasRenderBindings(childrenOf(node))));
55
+ const isMark = (value) => MARKS.includes(value);
56
+ const words = (nodes) => nodes.map((node) => textContent(node)).join("").replace(/\s+/g, " ").trim();
57
+ const clip = (value) => value.length > 40 ? `${value.slice(0, 39)}…` : value;
58
+ const quote = (value) => JSON.stringify(clip(value));
59
+ const list = (names) => names.map((name) => name === "id" ? "`#id`" : `\`${name}\``).join(", ");
60
+ const graphemes = (value) => [...new Intl.Segmenter().segment(value)].length;
61
+ /** FNV-1a, in base 36: short, and the same every time the same text is hashed. */
62
+ function hash(source) {
63
+ let value = 2166136261;
64
+ for (let at = 0; at < source.length; at++) value = Math.imul(value ^ source.charCodeAt(at), 16777619);
65
+ return (value >>> 0).toString(36);
66
+ }
67
+ function distance(a, b) {
68
+ const row = Array.from({ length: b.length + 1 }, (_, index) => index);
69
+ for (let i = 1; i <= a.length; i++) {
70
+ let previous = row[0];
71
+ row[0] = i;
72
+ for (let j = 1; j <= b.length; j++) {
73
+ const current = row[j];
74
+ row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
75
+ previous = current;
76
+ }
77
+ }
78
+ return row[b.length];
79
+ }
80
+ function nameOf(node) {
81
+ const [tag, attrs] = node;
82
+ const body = words(childrenOf(node));
83
+ if (tag === "suggestion") {
84
+ const from = text(attrs.from);
85
+ if (from && body) return `suggestion ${quote(from)} → ${quote(body)}`;
86
+ if (from) return `suggestion removing ${quote(from)}`;
87
+ if (body) return `suggestion adding ${quote(body)}`;
88
+ return "suggestion with no text";
89
+ }
90
+ if (body) return `comment ${quote(body)}`;
91
+ const note = text(attrs.note);
92
+ return note ? `comment with the note ${quote(note)}` : "comment with no text";
93
+ }
94
+ function collect(parent, start, place, found, data, rendered) {
95
+ let moved = false;
96
+ for (let index = start; index < parent.length; index++) {
97
+ const node = parent[index];
98
+ if (!isElement(node)) continue;
99
+ const [tag, raw] = node;
100
+ if ((tag === "suggestion" || tag === "comment") && rendered && !rendered.has(node)) continue;
101
+ const attrs = rendered?.get(node) ?? resolveAttributes(raw, data, { parseJson: true });
102
+ const innerData = Object.keys(raw).some((key) => key !== "$") ? {
103
+ ...data,
104
+ props: attrs
105
+ } : data;
106
+ if (tag === "suggestion" || tag === "comment") node[1] = attrs;
107
+ if (tag === "comment" && (Object.hasOwn(raw, "reply") || Object.hasOwn(raw, ":reply"))) {
108
+ const children = childrenOf(node);
109
+ found.replies.push({
110
+ node,
111
+ raw,
112
+ text: words(children)
113
+ });
114
+ parent.splice(index, 1, ...children);
115
+ index += children.length - 1;
116
+ moved = true;
117
+ continue;
118
+ }
119
+ if (tag === "suggestion" || tag === "comment") {
120
+ const thread = {
121
+ node,
122
+ raw,
123
+ kind: tag,
124
+ name: nameOf(node),
125
+ cardless: Boolean(place.inside) || place.heading || place.cell,
126
+ inside: place.inside,
127
+ plain: false,
128
+ entries: []
129
+ };
130
+ found.threads.push(thread);
131
+ collect(node, 2, {
132
+ ...place,
133
+ inside: thread
134
+ }, found, innerData, rendered);
135
+ continue;
136
+ }
137
+ if (collect(node, 2, {
138
+ ...place,
139
+ heading: place.heading || HEADING.test(tag),
140
+ cell: place.cell || tag === "td" || tag === "th"
141
+ }, found, innerData, rendered) && tag === "p" && !words(childrenOf(node)) && !childrenOf(node).some(isElement)) {
142
+ parent.splice(index, 1);
143
+ index--;
144
+ }
145
+ }
146
+ return moved;
147
+ }
148
+ function checkProps(kind, name, rawAttrs, attrs, issues) {
149
+ const valid = PROPS[kind];
150
+ for (const raw of Object.keys(rawAttrs)) {
151
+ const key = raw.replace(/^:/, "");
152
+ if (key === "$") continue;
153
+ if (valid.includes(key) || NATIVE.test(key)) {
154
+ if (raw.startsWith(":") && attrs[key] === void 0 && !later(rawAttrs[raw])) issues.push({
155
+ rule: "comark/comments/undefined-binding",
156
+ message: `${name} has \`${raw}\` pointing at ${text(rawAttrs[raw])}, which is undefined. Fix the path or set \`${key}\` directly.`
157
+ });
158
+ continue;
159
+ }
160
+ const lower = key.toLowerCase();
161
+ const close = valid.find((prop) => lower.length >= 3 && distance(lower, prop) <= 1);
162
+ const hint = HINTS.has(lower) ? HINTS.get(lower) : close ? `Did you mean \`${close}\`?` : "";
163
+ issues.push({
164
+ rule: "comark/comments/unknown-prop",
165
+ message: `${name} has \`${key}\`, which isn't one of its props, so it's ignored.${hint ? ` ${hint}` : ""} Use ${list(valid)}.`
166
+ });
167
+ }
168
+ }
169
+ function defer(nodes, settings) {
170
+ const metadata = { comments: {
171
+ mark: settings.mark,
172
+ prefix: settings.prefix,
173
+ avatars: settings.avatars
174
+ } };
175
+ return [
176
+ DEFERRED,
177
+ { $: metadata },
178
+ ...nodes
179
+ ];
180
+ }
181
+ function entry(by, note, settings) {
182
+ const avatar = settings.avatars[by.replace(/^@/, "").toLowerCase()];
183
+ return avatar ? {
184
+ by,
185
+ note,
186
+ avatar
187
+ } : {
188
+ by,
189
+ note
190
+ };
191
+ }
192
+ /** Comark lifts an inline component that fills its paragraph; put its anchor back in a paragraph. */
193
+ function wrapParagraphs(nodes) {
194
+ for (const [index, node] of nodes.entries()) if (isElement(node) && (node[0] === "suggestion" || node[0] === "comment") && !Object.hasOwn(node[1], "reply") && !Object.hasOwn(node[1], ":reply")) nodes[index] = [
195
+ "p",
196
+ {},
197
+ node
198
+ ];
199
+ }
200
+ /**
201
+ * Reads every `:suggestion` and `:comment` in `nodes`, moves each reply into its thread, and rewrites the nodes'
202
+ * attributes into the ones the renderer draws from. Wraps the blocks in one root node when any card goes in the
203
+ * margin. Returns the problems; it never throws.
204
+ */
205
+ function transform(nodes, settings) {
206
+ const issues = [];
207
+ const found = {
208
+ threads: [],
209
+ replies: []
210
+ };
211
+ wrapParagraphs(nodes);
212
+ collect(nodes, 0, {
213
+ heading: false,
214
+ cell: false
215
+ }, found, settings.data, settings.rendered);
216
+ const ids = /* @__PURE__ */ new Map();
217
+ for (const thread of found.threads) {
218
+ const { node, kind, name } = thread;
219
+ const attrs = node[1];
220
+ checkProps(kind, name, thread.raw, attrs, issues);
221
+ const by = text(attrs.by);
222
+ const note = text(attrs.note);
223
+ const body = words(childrenOf(node));
224
+ if (kind === "suggestion") {
225
+ const from = text(attrs.from);
226
+ if (!from && !childrenOf(node).length && !(settings.parsing && pending(thread.raw, "from"))) {
227
+ thread.plain = true;
228
+ issues.push({
229
+ rule: "comark/comments/empty-suggestion",
230
+ message: `${name} has no new text and no \`from\`, so it changes nothing and renders nothing. Put the new text in its brackets, the text it replaces in \`from\`, or both.`
231
+ });
232
+ } else if (from && from === body) {
233
+ thread.plain = true;
234
+ issues.push({
235
+ rule: "comark/comments/unchanged-suggestion",
236
+ message: `${name} has the same text in \`from\` and in its brackets, so it changes nothing and renders as plain text. Change one of them, or remove the suggestion.`
237
+ });
238
+ }
239
+ if (attrs.mark !== void 0 && !MARKS.includes(text(attrs.mark))) issues.push({
240
+ rule: "comark/comments/invalid-mark",
241
+ message: `${name} has \`mark="${text(attrs.mark)}"\`, which isn't a mark, so it draws as "${settings.mark}". Write \`mark="track"\` or \`mark="pen"\`.`
242
+ });
243
+ } else if (!body && !childrenOf(node).some(isElement)) {
244
+ thread.plain = true;
245
+ issues.push({
246
+ rule: "comark/comments/missing-anchor",
247
+ message: `${name} has nothing in its brackets to point at, so it renders nothing. Put the words it's about in its brackets, as \`:comment[words]{note="…"}\`, or answer a thread with \`reply="id"\`.`
248
+ });
249
+ } else if (!note && !(settings.parsing && pending(thread.raw, "note"))) issues.push({
250
+ rule: "comark/comments/missing-note",
251
+ message: `${name} has no \`note\`, so its card has nothing to say. Add \`note="…"\` with the comment.`
252
+ });
253
+ if (thread.cardless && !thread.plain) {
254
+ const container = thread.inside;
255
+ issues.push(container ? {
256
+ rule: "comark/comments/nested-thread",
257
+ message: `${name} sits inside ${container.name}, so it has no card of its own. Move it out, after the other one.`
258
+ } : {
259
+ rule: "comark/comments/outside-margin",
260
+ message: `${name} is in a heading or a table cell, where its card can't reach the margin, so it has none. Move it to a paragraph or a list item.`
261
+ });
262
+ if (kind === "comment") thread.plain = true;
263
+ }
264
+ const id = text(attrs.id);
265
+ if (id) {
266
+ const first = ids.get(id);
267
+ if (first) issues.push({
268
+ rule: "comark/comments/duplicate-id",
269
+ message: `${name} has the id "${id}", which ${first.name} has too, so replies go to the first one. Give each comment and suggestion its own \`#id\`.`
270
+ });
271
+ else ids.set(id, thread);
272
+ if (first) thread.duplicate = true;
273
+ }
274
+ if (note && !thread.plain) thread.entries.push(entry(by, note, settings));
275
+ }
276
+ for (const { node, raw, text: written } of found.replies) {
277
+ const attrs = node[1];
278
+ const target = text(attrs.reply);
279
+ const name = `reply to ${quote(target)}`;
280
+ checkProps("reply", name, raw, attrs, issues);
281
+ if (written) issues.push({
282
+ rule: "comark/comments/reply-with-text",
283
+ message: `${name} has text in its brackets, which a reply doesn't point at, so the text stays where it is. Remove the brackets and put what it says in \`note\`.`
284
+ });
285
+ const thread = ids.get(target);
286
+ if (!thread) {
287
+ if (settings.parsing && (pending(raw, "reply") || found.threads.some((item) => pending(item.raw, "id")))) continue;
288
+ let near;
289
+ for (const id of ids.keys()) {
290
+ const far = distance(id.toLowerCase(), target.toLowerCase());
291
+ if (far <= 2 && (!near || far < near.far)) near = {
292
+ id,
293
+ far
294
+ };
295
+ }
296
+ issues.push({
297
+ rule: "comark/comments/unknown-reply",
298
+ message: `${name} matches no comment or suggestion's \`#id\`, so it renders nothing. ${near ? `Did you mean \`reply="${near.id}"\`?` : `Give the comment or suggestion it answers \`#${target || "id"}\`.`}`
299
+ });
300
+ continue;
301
+ }
302
+ const note = text(attrs.note);
303
+ if (!note) {
304
+ if (settings.parsing && pending(raw, "note")) continue;
305
+ issues.push({
306
+ rule: "comark/comments/missing-note",
307
+ message: `${name} has no \`note\`, so it renders nothing. Add \`note="…"\` with the reply.`
308
+ });
309
+ continue;
310
+ }
311
+ if (!thread.plain && !thread.cardless) thread.entries.push(entry(text(attrs.by), note, settings));
312
+ }
313
+ let cards = 0;
314
+ let pens = 0;
315
+ for (const thread of found.threads) {
316
+ const { node, kind, entries } = thread;
317
+ const attrs = node[1];
318
+ const next = nativeAttributes(attrs);
319
+ delete next.id;
320
+ const id = text(attrs.id);
321
+ if (id && !thread.duplicate) next.id = id;
322
+ if (thread.plain) {
323
+ node[1] = {
324
+ ...next,
325
+ plain: "true"
326
+ };
327
+ continue;
328
+ }
329
+ if (kind === "suggestion") {
330
+ const from = text(attrs.from);
331
+ const body = words(childrenOf(node));
332
+ const written = text(attrs.mark);
333
+ const asked = isMark(written) ? written : settings.mark;
334
+ const plain = (value) => !value.includes("\n") && graphemes(value) <= PEN_MAX;
335
+ const pen = asked === "pen" && plain(from) && plain(body) && !childrenOf(node).some((child) => Array.isArray(child) || textContent(child).includes("\n"));
336
+ next.mark = pen ? "pen" : "track";
337
+ if (pen) next.stroke = String(pens++ % 3);
338
+ if (from) next.from = from;
339
+ }
340
+ if (entries.length && !thread.cardless) {
341
+ next.uid = `${settings.prefix}-${++cards}`;
342
+ const about = kind === "comment" ? words(childrenOf(node)) : words(childrenOf(node)) || text(attrs.from);
343
+ next.label = `${entries.length} ${entries.length === 1 ? "comment" : "comments"} on “${clip(about)}”`;
344
+ next.thread = entries;
345
+ }
346
+ node[1] = next;
347
+ }
348
+ if (cards) nodes.splice(0, nodes.length, [
349
+ ROOT,
350
+ {},
351
+ ...nodes
352
+ ]);
353
+ return issues;
354
+ }
355
+ //#endregion
356
+ //#region src/index.ts
357
+ /**
358
+ * Reads `:suggestion` and `:comment`: suggested edits and comments on a span, each with an optional note in a card in
359
+ * the margin. A `:comment{reply="id"}` anywhere in the document joins that thread. Problems are added to
360
+ * `meta.issues`.
361
+ */
362
+ var src_default = defineComarkPlugin((options = {}) => {
363
+ const mark = options.mark === "pen" ? "pen" : "track";
364
+ const avatars = Object.fromEntries(Object.entries(options.avatars ?? {}).map(([name, src]) => [name.replace(/^@/, "").toLowerCase(), src]));
365
+ return {
366
+ name: "comark-comments",
367
+ post(state) {
368
+ const { tree } = state;
369
+ const settings = {
370
+ mark,
371
+ avatars,
372
+ prefix: `cr-${hash(state.markdown)}`,
373
+ data: {
374
+ frontmatter: tree.frontmatter,
375
+ meta: tree.meta,
376
+ data: {},
377
+ props: {}
378
+ },
379
+ parsing: true
380
+ };
381
+ const deferred = hasRenderBindings(tree.nodes);
382
+ const found = transform(deferred ? structuredClone(tree.nodes) : tree.nodes, settings);
383
+ if (deferred) tree.nodes = [defer(tree.nodes, settings)];
384
+ if (!found.length) return;
385
+ tree.meta.issues = [...tree.meta.issues ?? [], ...found.map((issue) => issue.message)];
386
+ tree.meta.issueRules = {
387
+ ...tree.meta.issueRules,
388
+ ...Object.fromEntries(found.map((issue) => [issue.message, issue.rule]))
389
+ };
390
+ }
391
+ };
392
+ });
393
+ //#endregion
394
+ export { hash as a, transform as c, childrenOf as i, wrapParagraphs as l, DEFERRED as n, isElement as o, ROOT as r, nativeAttributes as s, src_default as t };
package/package.json CHANGED
@@ -1,6 +1,61 @@
1
1
  {
2
2
  "name": "comark-comments",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.7.4",
4
+ "description": "Suggested edits and comment threads in Markdown, drawn as redlines or a hand-drawn pen with notes in the margin, and no script. A Comark plugin.",
5
+ "keywords": [
6
+ "comark",
7
+ "comments",
8
+ "markdown",
9
+ "mdc",
10
+ "plugin",
11
+ "review",
12
+ "suggestions",
13
+ "track-changes"
14
+ ],
15
+ "homepage": "https://comark-ui.onmax.me/comments",
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/comments"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "exports": {
30
+ ".": "./dist/index.mjs",
31
+ "./html": "./dist/html.mjs",
32
+ "./package.json": "./package.json"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public",
36
+ "provenance": true
37
+ },
38
+ "devDependencies": {
39
+ "@comark/html": "^0.8.1",
40
+ "comark": "^0.8.1",
41
+ "comark-annotate": "0.7.4",
42
+ "comark-zoom": "0.7.4"
43
+ },
44
+ "peerDependencies": {
45
+ "@comark/html": "^0.8.0",
46
+ "comark": "^0.8.0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "@comark/html": {
50
+ "optional": true
51
+ }
52
+ },
53
+ "engines": {
54
+ "node": ">=22.12.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsdown",
58
+ "dev": "tsdown --watch",
59
+ "doctor": "vite-doctor . --no-cache --max-warnings 0 --format text"
60
+ }
6
61
  }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.