comark-comments 0.7.6 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,66 @@ 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
+ shadow: [[
84
+ "shadow",
85
+ "",
86
+ "",
87
+ "0 4px 12px rgb(0 0 0/.12)",
88
+ "0 4px 12px rgb(0 0 0/.5)"
89
+ ]]
90
+ };
91
+ const chain = (token, scheme) => {
92
+ const shadcn = token[2] ? `var(--${token[2]},${token[scheme]})` : token[scheme];
93
+ const nuxt = token[1] ? `var(--${token[1]},${shadcn})` : shadcn;
94
+ return `var(--comark-${token[0]},${nuxt})`;
95
+ };
96
+ const resolve = (list, scheme) => list.map((token) => `--_comark-${token[0]}:${chain(token, scheme)}`).join(";");
53
97
  /**
54
98
  * Resolves the `--comark-*` tokens on `selector`, falling back to Nuxt UI's variables, then shadcn/ui's, then shadcn's
55
99
  * neutral theme. Nuxt UI's corners are twice its `--ui-radius`, so the radius halves shadcn's to double it back.
56
100
  * They resolve on the component rather than `:root`, so a `.dark` class anywhere above it switches the theme, and a
57
101
  * `--comark-*` set on any ancestor still inherits down. `:where()` keeps them at zero specificity.
102
+ *
103
+ * Every block gets the core tokens. Name `"status"` for `--comark-success`, `-danger`, `-warning`, and `-info`, and
104
+ * `"shadow"` for `--comark-shadow`, so a block that never draws them doesn't carry them.
58
105
  */
59
- function theme(selector) {
106
+ function theme(selector, ...extras) {
60
107
  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)}}}`;
108
+ const added = extras.flatMap((name) => groups[name]);
109
+ const list = [...tokens, ...added];
110
+ const classes = added.length ? `:where(.light,.light *)${where}{${resolve(added, 3)}}:where(.dark,.dark *)${where}{${resolve(added, 4)}}` : "";
111
+ 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
112
  }
63
113
  //#endregion
64
114
  //#region src/styles.ts
@@ -71,13 +121,13 @@ const fontCss = `@font-face{font-family:comark-caveat;src:url(data:font/woff2;ba
71
121
  * `--cr-comment`. The rules sit in the `comark` layer, so any unlayered rule of the host's wins.
72
122
  */
73
123
  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)}}`,
124
+ theme(parts, "status", "shadow"),
125
+ `: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})}`,
126
+ `@media (prefers-color-scheme:dark){:where(${parts}){--_cr-comment:var(--cr-comment,#fbbf24)}}`,
77
127
  ".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
128
  ".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}",
129
+ ".cr-sg,.cr-cm{border-radius:calc(var(--_comark-radius) - 6px);transition:box-shadow .12s}",
130
+ ".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
131
  ".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
132
  ".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
133
  ".cr-sg del+ins{margin-left:.125rem}",
@@ -90,8 +140,8 @@ const css = `@layer comark{${[
90
140
  `${pen}[data-kind="insert"] ins{transform:translateX(-50%) rotate(-2.5deg);transform-origin:center}`,
91
141
  `${pen} .cr-caret{display:inline-block;position:relative;width:0}`,
92
142
  `${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}",
143
+ ".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}",
144
+ ".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
145
  ".cr-bub:empty{padding-right:.3em}",
96
146
  ".cr-tg{position:absolute;width:1px;height:1px;margin:0;opacity:0;pointer-events:none}",
97
147
  ".cr-tg:focus-visible+.cr-bub{outline:2px solid var(--_comark-ring);outline-offset:2px}",
@@ -100,14 +150,18 @@ const css = `@layer comark{${[
100
150
  ".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
151
  ".cr-entry{display:block}.cr-entry+.cr-entry{margin-top:.5rem;padding-top:.5rem;border-top:1px solid var(--_comark-border)}",
102
152
  ".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)}",
153
+ ".cr-av{display:inline-grid;place-items:center;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/1 var(--_comark-font);vertical-align:calc(.722cap - .5625rem)}",
104
154
  "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
155
  ".cr-tg:checked+.cr-bub+.cr-card{display:block;float:left;clear:both;width:100%;margin:.5rem 0}",
106
156
  ".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)}}",
157
+ "@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)}}",
108
158
  "@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
159
  ].join("")}}`;
110
160
  //#endregion
161
+ //#region ../../shared/html.ts
162
+ /** A value as the inside of a double-quoted HTML attribute. */
163
+ const attr = (value) => escapeHtml(rawText(value), { "\"": """ });
164
+ //#endregion
111
165
  //#region src/html.ts
112
166
  const styled = /* @__PURE__ */ new WeakSet();
113
167
  const fonted = /* @__PURE__ */ new WeakSet();
@@ -117,7 +171,6 @@ function once(set, state, html) {
117
171
  return html;
118
172
  }
119
173
  const styles = (state) => once(styled, state, `<style data-comark-comments>${css}</style>`);
120
- const attr = (value) => escapeHtml(value, { "\"": "&quot;" });
121
174
  const valueOf = (value) => value === void 0 || value === null ? "" : value instanceof Object ? JSON.stringify(value) : String(value);
122
175
  const classOf = (name, attrs) => attr([name, valueOf(attrs.class)].filter(Boolean).join(" "));
123
176
  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 +190,22 @@ const STROKES = [
137
190
  "M1 5.9C33 3.8 70 6.6 99 4.4"
138
191
  ];
139
192
  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"
193
+ const HUES = [
194
+ 25,
195
+ 55,
196
+ 85,
197
+ 145,
198
+ 175,
199
+ 205,
200
+ 235,
201
+ 345
149
202
  ];
150
203
  function who(by, avatar) {
151
204
  const name = by.replace(/^@/, "");
152
205
  if (!name) return "";
153
206
  if (avatar) return `<img class="cr-av" src="${attr(avatar)}" alt="" width="18" height="18"><b>${escapeHtml(name)}</b>`;
154
207
  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>`;
208
+ 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
209
  }
157
210
  function thread(attrs, state) {
158
211
  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.0",
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.0",
42
+ "comark-zoom": "0.8.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@comark/html": "^0.8.0",