comark-comments 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/dist/html.mjs CHANGED
@@ -1,4 +1,4 @@
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";
1
+ import { a as transform, c as isElement, i as nativeAttributes, l as hash, n as DEFERRED, o as wrapParagraphs, r as ROOT, s as childrenOf, t as src_default, u as rawText } from "./src-BmHLb9Qo.mjs";
2
2
  import { resolveAttributes } from "comark/render";
3
3
  import { escapeHtml } from "comark/utils";
4
4
  //#region ../annotate/dist/font-Bq-VpE6W.mjs
@@ -49,16 +49,91 @@ const tokens = [
49
49
  "#737373"
50
50
  ]
51
51
  ];
52
- const resolve = (scheme) => tokens.map((token) => `--_comark-${token[0]}:var(--comark-${token[0]},var(--${token[1]},var(--${token[2]},${token[scheme]})))`).join(";");
52
+ const groups = {
53
+ status: Object.values({
54
+ success: [
55
+ "success",
56
+ "ui-success",
57
+ "success",
58
+ "#259f56",
59
+ "#59d38c"
60
+ ],
61
+ danger: [
62
+ "danger",
63
+ "ui-error",
64
+ "destructive",
65
+ "#ee3533",
66
+ "#fd736d"
67
+ ],
68
+ warning: [
69
+ "warning",
70
+ "ui-warning",
71
+ "",
72
+ "#d97706",
73
+ "#fbbf24"
74
+ ],
75
+ info: [
76
+ "info",
77
+ "ui-info",
78
+ "",
79
+ "#2563eb",
80
+ "#60a5fa"
81
+ ]
82
+ }),
83
+ primary: [
84
+ [
85
+ "primary",
86
+ "ui-primary",
87
+ "primary",
88
+ "var(--_comark-foreground)",
89
+ "var(--_comark-foreground)"
90
+ ],
91
+ [
92
+ "primary-foreground",
93
+ "ui-text-inverted",
94
+ "primary-foreground",
95
+ "var(--_comark-background)",
96
+ "var(--_comark-background)"
97
+ ],
98
+ [
99
+ "secondary",
100
+ "ui-secondary",
101
+ "",
102
+ "var(--_comark-muted)",
103
+ "var(--_comark-muted)"
104
+ ]
105
+ ],
106
+ shadow: [[
107
+ "shadow",
108
+ "",
109
+ "",
110
+ "0 4px 12px rgb(0 0 0/.12)",
111
+ "0 4px 12px rgb(0 0 0/.5)"
112
+ ]]
113
+ };
114
+ const chain = (token, scheme) => {
115
+ const shadcn = token[2] ? `var(--${token[2]},${token[scheme]})` : token[scheme];
116
+ const nuxt = token[1] ? `var(--${token[1]},${shadcn})` : shadcn;
117
+ return `var(--comark-${token[0]},${nuxt})`;
118
+ };
119
+ const resolve = (list, scheme) => list.map((token) => `--_comark-${token[0]}:${chain(token, scheme)}`).join(";");
53
120
  /**
54
121
  * Resolves the `--comark-*` tokens on `selector`, falling back to Nuxt UI's variables, then shadcn/ui's, then shadcn's
55
122
  * neutral theme. Nuxt UI's corners are twice its `--ui-radius`, so the radius halves shadcn's to double it back.
56
123
  * They resolve on the component rather than `:root`, so a `.dark` class anywhere above it switches the theme, and a
57
124
  * `--comark-*` set on any ancestor still inherits down. `:where()` keeps them at zero specificity.
125
+ *
126
+ * Every block gets the core tokens. Name `"status"` for `--comark-success`, `-danger`, `-warning`, and `-info`,
127
+ * `"primary"` for `--comark-primary`, `-primary-foreground`, and `-secondary`, and `"shadow"` for `--comark-shadow`, so
128
+ * a block that never draws them doesn't carry them.
58
129
  */
59
- function theme(selector) {
130
+ function theme(selector, ...extras) {
60
131
  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)}}}`;
132
+ const added = extras.flatMap((name) => groups[name]);
133
+ const list = [...tokens, ...added];
134
+ const schemed = added.filter((token) => token[3] !== token[4]);
135
+ const classes = schemed.length ? `:where(.light,.light *)${where}{${resolve(schemed, 3)}}:where(.dark,.dark *)${where}{${resolve(schemed, 4)}}` : "";
136
+ 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;
62
137
  }
63
138
  //#endregion
64
139
  //#region src/styles.ts
@@ -71,13 +146,13 @@ const fontCss = `@font-face{font-family:comark-caveat;src:url(data:font/woff2;ba
71
146
  * `--cr-comment`. The rules sit in the `comark` layer, so any unlayered rule of the host's wins.
72
147
  */
73
148
  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)}}`,
149
+ theme(parts, "status", "shadow"),
150
+ `:where(${parts}){--_cr-ins:var(--cr-ins,var(--_comark-success));--_cr-del:var(--cr-del,var(--_comark-danger));--_cr-comment:var(--cr-comment,#f5a524);--_cr-icon:var(--cr-icon,${icon})}`,
151
+ `@media (prefers-color-scheme:dark){:where(${parts}){--_cr-comment:var(--cr-comment,#fbbf24)}}`,
77
152
  ".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
153
  ".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}",
154
+ ".cr-sg,.cr-cm{border-radius:calc(var(--_comark-radius) - 6px);transition:box-shadow .12s}",
155
+ ".cr-sg :is(del,ins){padding:.0625rem .1875rem;border-radius:calc(var(--_comark-radius) - 6px);-webkit-box-decoration-break:clone;box-decoration-break:clone}",
81
156
  ".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
157
  ".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
158
  ".cr-sg del+ins{margin-left:.125rem}",
@@ -90,8 +165,8 @@ const css = `@layer comark{${[
90
165
  `${pen}[data-kind="insert"] ins{transform:translateX(-50%) rotate(-2.5deg);transform-origin:center}`,
91
166
  `${pen} .cr-caret{display:inline-block;position:relative;width:0}`,
92
167
  `${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}",
168
+ ".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:calc(var(--_comark-radius) - 8px);padding:0 .0625rem}",
169
+ ".cr-bub{display:inline;margin-left:.25em;padding:.25em .5em .25em 1.75em;vertical-align:.1em;border:1px solid var(--_comark-border);border-radius:9999px;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;transition:color .12s,border-color .12s}",
95
170
  ".cr-bub:empty{padding-right:.3em}",
96
171
  ".cr-tg{position:absolute;width:1px;height:1px;margin:0;opacity:0;pointer-events:none}",
97
172
  ".cr-tg:focus-visible+.cr-bub{outline:2px solid var(--_comark-ring);outline-offset:2px}",
@@ -100,14 +175,18 @@ const css = `@layer comark{${[
100
175
  ".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
176
  ".cr-entry{display:block}.cr-entry+.cr-entry{margin-top:.5rem;padding-top:.5rem;border-top:1px solid var(--_comark-border)}",
102
177
  ".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)}",
178
+ ".cr-av{display:inline-block;overflow:hidden;width:1.125rem;height:1.125rem;margin-right:.375rem;border-radius:9999px;background:color-mix(in oklab,oklch(.7 .12 var(--cr-hue)) 30%,var(--_comark-background));color:color-mix(in oklab,oklch(.55 .14 var(--cr-hue)) 60%,var(--_comark-foreground));font:600 .5625rem/2 var(--_comark-font);text-align:center;vertical-align:calc(.722cap - .5625rem)}",
104
179
  "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
180
  ".cr-tg:checked+.cr-bub+.cr-card{display:block;float:left;clear:both;width:100%;margin:.5rem 0}",
106
181
  ".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}}"
182
+ "@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:var(--_comark-shadow)}}",
183
+ "@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-av{vertical-align:calc(.611cap - .5625rem)}.cr-bub{display:none}}"
109
184
  ].join("")}}`;
110
185
  //#endregion
186
+ //#region ../../shared/html.ts
187
+ /** A value as the inside of a double-quoted HTML attribute. */
188
+ const attr = (value) => escapeHtml(rawText(value), { "\"": """ });
189
+ //#endregion
111
190
  //#region src/html.ts
112
191
  const styled = /* @__PURE__ */ new WeakSet();
113
192
  const fonted = /* @__PURE__ */ new WeakSet();
@@ -117,7 +196,6 @@ function once(set, state, html) {
117
196
  return html;
118
197
  }
119
198
  const styles = (state) => once(styled, state, `<style data-comark-comments>${css}</style>`);
120
- const attr = (value) => escapeHtml(value, { "\"": "&quot;" });
121
199
  const valueOf = (value) => value === void 0 || value === null ? "" : value instanceof Object ? JSON.stringify(value) : String(value);
122
200
  const classOf = (name, attrs) => attr([name, valueOf(attrs.class)].filter(Boolean).join(" "));
123
201
  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("");
@@ -137,22 +215,22 @@ const STROKES = [
137
215
  "M1 5.9C33 3.8 70 6.6 99 4.4"
138
216
  ];
139
217
  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"
218
+ const HUES = [
219
+ 25,
220
+ 55,
221
+ 85,
222
+ 145,
223
+ 175,
224
+ 205,
225
+ 235,
226
+ 345
149
227
  ];
150
228
  function who(by, avatar) {
151
229
  const name = by.replace(/^@/, "");
152
230
  if (!name) return "";
153
231
  if (avatar) return `<img class="cr-av" src="${attr(avatar)}" alt="" width="18" height="18"><b>${escapeHtml(name)}</b>`;
154
232
  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>`;
233
+ return `<span class="cr-av" style="--cr-hue:${HUES[Number.parseInt(hash(name.toLowerCase()), 36) % HUES.length]}" aria-hidden="true">${escapeHtml(initial)}</span><b>${escapeHtml(name)}</b>`;
156
234
  }
157
235
  function thread(attrs, state) {
158
236
  const base = read(attrs, "uid");
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export { t as default } from "./src-CCwYg7qg.mjs";
1
+ export { t as default } from "./src-BmHLb9Qo.mjs";
@@ -1,6 +1,36 @@
1
1
  import { defineComarkPlugin } from "comark";
2
2
  import { resolveAttributes } from "comark/render";
3
3
  import { textContent } from "comark/utils";
4
+ //#region ../../shared/text.ts
5
+ /**
6
+ * A prop value as text. Comark writes strings, numbers, and booleans, so an object, array, function, or missing value
7
+ * is no text. The `typeof` check, unlike `instanceof`, can't throw on a revoked proxy.
8
+ */
9
+ function scalar(value) {
10
+ switch (typeof value) {
11
+ case "string": return value;
12
+ case "number":
13
+ case "boolean":
14
+ case "bigint":
15
+ case "symbol": return String(value);
16
+ default: return;
17
+ }
18
+ }
19
+ /** A prop value as text, without its surrounding whitespace, or empty when it has none. */
20
+ const text = (value) => scalar(value)?.trim() ?? "";
21
+ /** A prop value as text exactly as written, or empty when it has none. */
22
+ const rawText = (value) => scalar(value) ?? "";
23
+ /** FNV-1a, in base 36: short, and the same every time the same text is hashed, so ids derived from it are stable. */
24
+ function hash(source) {
25
+ let value = 2166136261;
26
+ for (let at = 0; at < source.length; at++) value = Math.imul(value ^ source.charCodeAt(at), 16777619);
27
+ return (value >>> 0).toString(36);
28
+ }
29
+ //#endregion
30
+ //#region ../../shared/nodes.ts
31
+ const isElement = (node) => Array.isArray(node) && node[0] !== null;
32
+ const childrenOf = ([, , ...rest]) => rest;
33
+ //#endregion
4
34
  //#region src/read.ts
5
35
  /** The root node the plugin wraps a document's blocks in when any card goes in the margin. */
6
36
  const ROOT = "comments";
@@ -46,9 +76,6 @@ const HINTS = /* @__PURE__ */ new Map([
46
76
  ]);
47
77
  const PEN_MAX = 24;
48
78
  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
79
  const later = (path) => /^(?:data|props)(?:\.|$)/.test(text(path));
53
80
  const pending = (raw, key) => later(raw[`:${key}`]);
54
81
  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))));
@@ -58,12 +85,6 @@ const clip = (value) => value.length > 40 ? `${value.slice(0, 39)}…` : value;
58
85
  const quote = (value) => JSON.stringify(clip(value));
59
86
  const list = (names) => names.map((name) => name === "id" ? "`#id`" : `\`${name}\``).join(", ");
60
87
  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
88
  function distance(a, b) {
68
89
  const row = Array.from({ length: b.length + 1 }, (_, index) => index);
69
90
  for (let i = 1; i <= a.length; i++) {
@@ -391,4 +412,4 @@ var src_default = defineComarkPlugin((options = {}) => {
391
412
  };
392
413
  });
393
414
  //#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 };
415
+ export { transform as a, isElement as c, nativeAttributes as i, hash as l, DEFERRED as n, wrapParagraphs as o, ROOT as r, childrenOf as s, src_default as t, rawText as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "comark-comments",
3
- "version": "0.7.6",
3
+ "version": "0.8.1",
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
5
  "keywords": [
6
6
  "comark",
@@ -38,8 +38,8 @@
38
38
  "devDependencies": {
39
39
  "@comark/html": "^0.8.1",
40
40
  "comark": "^0.8.1",
41
- "comark-annotate": "0.7.6",
42
- "comark-zoom": "0.7.6"
41
+ "comark-annotate": "0.8.1",
42
+ "comark-zoom": "0.8.1"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@comark/html": "^0.8.0",