quoin-editor 0.4.1 → 1.0.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.
Files changed (231) hide show
  1. package/CHANGELOG.md +205 -0
  2. package/MIGRATION.md +233 -0
  3. package/README.md +78 -715
  4. package/dist/ai.cjs +1107 -0
  5. package/dist/ai.cjs.map +1 -0
  6. package/dist/ai.d.cts +68 -0
  7. package/dist/ai.d.ts +68 -0
  8. package/dist/ai.js +1107 -0
  9. package/dist/ai.js.map +1 -0
  10. package/dist/catalogue.cjs +59 -0
  11. package/dist/catalogue.cjs.map +1 -0
  12. package/dist/catalogue.d.cts +39 -0
  13. package/dist/catalogue.d.ts +39 -0
  14. package/dist/catalogue.js +59 -0
  15. package/dist/catalogue.js.map +1 -0
  16. package/dist/chunk-2QCRZ7OL.cjs +319 -0
  17. package/dist/chunk-2QCRZ7OL.cjs.map +1 -0
  18. package/dist/chunk-2VDK27IF.cjs +6666 -0
  19. package/dist/chunk-2VDK27IF.cjs.map +1 -0
  20. package/dist/chunk-47MLKSI2.js +326 -0
  21. package/dist/chunk-47MLKSI2.js.map +1 -0
  22. package/dist/chunk-5DNCCN6X.cjs +326 -0
  23. package/dist/chunk-5DNCCN6X.cjs.map +1 -0
  24. package/dist/chunk-AEJXZBVR.cjs +1378 -0
  25. package/dist/chunk-AEJXZBVR.cjs.map +1 -0
  26. package/dist/chunk-CDELOHDY.cjs +239 -0
  27. package/dist/chunk-CDELOHDY.cjs.map +1 -0
  28. package/dist/chunk-E75EHRPA.cjs +175 -0
  29. package/dist/chunk-E75EHRPA.cjs.map +1 -0
  30. package/dist/chunk-EL2OEJQC.cjs +562 -0
  31. package/dist/chunk-EL2OEJQC.cjs.map +1 -0
  32. package/dist/chunk-GLLXHMH2.cjs +25 -0
  33. package/dist/chunk-GLLXHMH2.cjs.map +1 -0
  34. package/dist/chunk-GTTPVJSD.cjs +3286 -0
  35. package/dist/chunk-GTTPVJSD.cjs.map +1 -0
  36. package/dist/chunk-HELJTLNC.cjs +100 -0
  37. package/dist/chunk-HELJTLNC.cjs.map +1 -0
  38. package/dist/chunk-HJIQT3S5.js +4047 -0
  39. package/dist/chunk-HJIQT3S5.js.map +1 -0
  40. package/dist/chunk-HZSSEYJS.cjs +504 -0
  41. package/dist/chunk-HZSSEYJS.cjs.map +1 -0
  42. package/dist/chunk-JDPTZUBW.js +184 -0
  43. package/dist/chunk-JDPTZUBW.js.map +1 -0
  44. package/dist/chunk-JEIFJHEI.js +14 -0
  45. package/dist/chunk-JEIFJHEI.js.map +1 -0
  46. package/dist/chunk-K574XHMM.js +25 -0
  47. package/dist/chunk-K574XHMM.js.map +1 -0
  48. package/dist/chunk-KAVU6T6J.js +249 -0
  49. package/dist/chunk-KAVU6T6J.js.map +1 -0
  50. package/dist/chunk-KXOBZGQO.js +1378 -0
  51. package/dist/chunk-KXOBZGQO.js.map +1 -0
  52. package/dist/chunk-LCQSG4M6.js +3335 -0
  53. package/dist/chunk-LCQSG4M6.js.map +1 -0
  54. package/dist/chunk-MQ2XQ4MX.js +100 -0
  55. package/dist/chunk-MQ2XQ4MX.js.map +1 -0
  56. package/dist/chunk-ND5XJVK2.cjs +3335 -0
  57. package/dist/chunk-ND5XJVK2.cjs.map +1 -0
  58. package/dist/chunk-NNDYYEW5.js +504 -0
  59. package/dist/chunk-NNDYYEW5.js.map +1 -0
  60. package/dist/chunk-NOKWNK2O.js +319 -0
  61. package/dist/chunk-NOKWNK2O.js.map +1 -0
  62. package/dist/chunk-OMOBMXD5.cjs +57 -0
  63. package/dist/chunk-OMOBMXD5.cjs.map +1 -0
  64. package/dist/chunk-PMWCQSQX.js +239 -0
  65. package/dist/chunk-PMWCQSQX.js.map +1 -0
  66. package/dist/chunk-POBM7MGR.js +30 -0
  67. package/dist/chunk-POBM7MGR.js.map +1 -0
  68. package/dist/chunk-PWUEPDA3.cjs +598 -0
  69. package/dist/chunk-PWUEPDA3.cjs.map +1 -0
  70. package/dist/chunk-PZ4GT5JO.cjs +4047 -0
  71. package/dist/chunk-PZ4GT5JO.cjs.map +1 -0
  72. package/dist/chunk-QAW5NH6S.cjs +14 -0
  73. package/dist/chunk-QAW5NH6S.cjs.map +1 -0
  74. package/dist/chunk-RDG4VI6E.cjs +706 -0
  75. package/dist/chunk-RDG4VI6E.cjs.map +1 -0
  76. package/dist/chunk-RUDWMKYX.js +562 -0
  77. package/dist/chunk-RUDWMKYX.js.map +1 -0
  78. package/dist/chunk-SG37UBDO.js +706 -0
  79. package/dist/chunk-SG37UBDO.js.map +1 -0
  80. package/dist/chunk-SLVDAHHK.cjs +30 -0
  81. package/dist/chunk-SLVDAHHK.cjs.map +1 -0
  82. package/dist/chunk-T7SW6OWV.js +598 -0
  83. package/dist/chunk-T7SW6OWV.js.map +1 -0
  84. package/dist/chunk-TC4DARU2.js +175 -0
  85. package/dist/chunk-TC4DARU2.js.map +1 -0
  86. package/dist/chunk-WQHV3MRE.cjs +184 -0
  87. package/dist/chunk-WQHV3MRE.cjs.map +1 -0
  88. package/dist/chunk-WXMYDXPN.cjs +33 -0
  89. package/dist/chunk-WXMYDXPN.cjs.map +1 -0
  90. package/dist/chunk-XEBWC7ZL.js +57 -0
  91. package/dist/chunk-XEBWC7ZL.js.map +1 -0
  92. package/dist/chunk-ZC24WB7Y.cjs +249 -0
  93. package/dist/chunk-ZC24WB7Y.cjs.map +1 -0
  94. package/dist/chunk-ZGZEJCRV.js +6666 -0
  95. package/dist/chunk-ZGZEJCRV.js.map +1 -0
  96. package/dist/chunk-ZHOSSWUM.js +33 -0
  97. package/dist/chunk-ZHOSSWUM.js.map +1 -0
  98. package/dist/chunk-ZS2WA357.js +3286 -0
  99. package/dist/chunk-ZS2WA357.js.map +1 -0
  100. package/dist/comments.cjs +993 -0
  101. package/dist/comments.cjs.map +1 -0
  102. package/dist/comments.d.cts +88 -0
  103. package/dist/comments.d.ts +88 -0
  104. package/dist/comments.js +993 -0
  105. package/dist/comments.js.map +1 -0
  106. package/dist/diff.cjs +343 -0
  107. package/dist/diff.cjs.map +1 -0
  108. package/dist/diff.d.cts +67 -0
  109. package/dist/diff.d.ts +67 -0
  110. package/dist/diff.js +343 -0
  111. package/dist/diff.js.map +1 -0
  112. package/dist/docx.cjs +854 -0
  113. package/dist/docx.cjs.map +1 -0
  114. package/dist/docx.d.cts +27 -0
  115. package/dist/docx.d.ts +27 -0
  116. package/dist/docx.js +854 -0
  117. package/dist/docx.js.map +1 -0
  118. package/dist/embed-provider-jXwlRmnp.d.cts +19 -0
  119. package/dist/embed-provider-jXwlRmnp.d.ts +19 -0
  120. package/dist/embed.cjs +17 -0
  121. package/dist/embed.cjs.map +1 -0
  122. package/dist/embed.d.cts +56 -0
  123. package/dist/embed.d.ts +56 -0
  124. package/dist/embed.js +17 -0
  125. package/dist/embed.js.map +1 -0
  126. package/dist/emoji-data.cjs +1968 -0
  127. package/dist/emoji-data.cjs.map +1 -0
  128. package/dist/emoji-data.js +1968 -0
  129. package/dist/emoji-data.js.map +1 -0
  130. package/dist/emoji-extension-C12gDPm6.d.cts +46 -0
  131. package/dist/emoji-extension-DpQ43HjE.d.ts +46 -0
  132. package/dist/emoji.cjs +18 -0
  133. package/dist/emoji.cjs.map +1 -0
  134. package/dist/emoji.d.cts +31 -0
  135. package/dist/emoji.d.ts +31 -0
  136. package/dist/emoji.js +18 -0
  137. package/dist/emoji.js.map +1 -0
  138. package/dist/engine.cjs +119 -0
  139. package/dist/engine.cjs.map +1 -0
  140. package/dist/engine.d.cts +144 -0
  141. package/dist/engine.d.ts +144 -0
  142. package/dist/engine.js +119 -0
  143. package/dist/engine.js.map +1 -0
  144. package/dist/find-extension-DKqLLSuP.d.ts +41 -0
  145. package/dist/find-extension-_sbZEt3R.d.cts +41 -0
  146. package/dist/find.cjs +20 -0
  147. package/dist/find.cjs.map +1 -0
  148. package/dist/find.d.cts +44 -0
  149. package/dist/find.d.ts +44 -0
  150. package/dist/find.js +20 -0
  151. package/dist/find.js.map +1 -0
  152. package/dist/headless.cjs +151 -518
  153. package/dist/headless.cjs.map +1 -1
  154. package/dist/headless.d.cts +102 -69
  155. package/dist/headless.d.ts +102 -69
  156. package/dist/headless.js +149 -467
  157. package/dist/headless.js.map +1 -1
  158. package/dist/index-CgD72kHB.d.cts +65 -0
  159. package/dist/index-DNYbTK3w.d.ts +65 -0
  160. package/dist/index.cjs +183 -2753
  161. package/dist/index.cjs.map +1 -1
  162. package/dist/index.d.cts +345 -253
  163. package/dist/index.d.ts +345 -253
  164. package/dist/index.js +168 -2696
  165. package/dist/index.js.map +1 -1
  166. package/dist/math.cjs +18 -0
  167. package/dist/math.cjs.map +1 -0
  168. package/dist/math.d.cts +49 -0
  169. package/dist/math.d.ts +49 -0
  170. package/dist/math.js +18 -0
  171. package/dist/math.js.map +1 -0
  172. package/dist/mention.cjs +18 -0
  173. package/dist/mention.cjs.map +1 -0
  174. package/dist/mention.d.cts +50 -0
  175. package/dist/mention.d.ts +50 -0
  176. package/dist/mention.js +18 -0
  177. package/dist/mention.js.map +1 -0
  178. package/dist/presence.cjs +565 -0
  179. package/dist/presence.cjs.map +1 -0
  180. package/dist/presence.d.cts +30 -0
  181. package/dist/presence.d.ts +30 -0
  182. package/dist/presence.js +565 -0
  183. package/dist/presence.js.map +1 -0
  184. package/dist/registry-CWBOSAHm.d.cts +121 -0
  185. package/dist/registry-CWBOSAHm.d.ts +121 -0
  186. package/dist/stats-extension-Bly88uio.d.ts +40 -0
  187. package/dist/stats-extension-CJPijvUb.d.cts +40 -0
  188. package/dist/stats.cjs +19 -0
  189. package/dist/stats.cjs.map +1 -0
  190. package/dist/stats.d.cts +19 -0
  191. package/dist/stats.d.ts +19 -0
  192. package/dist/stats.js +19 -0
  193. package/dist/stats.js.map +1 -0
  194. package/dist/styles.css +1 -1
  195. package/dist/table-extension-BTLxFy2S.d.cts +57 -0
  196. package/dist/table-extension-Dzf4k6hI.d.ts +57 -0
  197. package/dist/table.cjs +50 -0
  198. package/dist/table.cjs.map +1 -0
  199. package/dist/table.d.cts +57 -0
  200. package/dist/table.d.ts +57 -0
  201. package/dist/table.js +50 -0
  202. package/dist/table.js.map +1 -0
  203. package/dist/to-html-C5t7xyaM.d.ts +21 -0
  204. package/dist/to-html-CNCITCln.d.cts +21 -0
  205. package/dist/toc-extension-B3-s6h2x.d.cts +25 -0
  206. package/dist/toc-extension-DWm5alVj.d.ts +25 -0
  207. package/dist/toc.cjs +18 -0
  208. package/dist/toc.cjs.map +1 -0
  209. package/dist/toc.d.cts +24 -0
  210. package/dist/toc.d.ts +24 -0
  211. package/dist/toc.js +18 -0
  212. package/dist/toc.js.map +1 -0
  213. package/dist/types-Cz7XJLaK.d.cts +366 -0
  214. package/dist/types-DULc8wwg.d.cts +120 -0
  215. package/dist/types-DULc8wwg.d.ts +120 -0
  216. package/dist/types-a1CRBlEh.d.ts +366 -0
  217. package/dist/view-controller-DSHw0ltQ.d.cts +118 -0
  218. package/dist/view-controller-UbpzblGl.d.ts +118 -0
  219. package/dist/view.cjs +23 -0
  220. package/dist/view.cjs.map +1 -0
  221. package/dist/view.d.cts +40 -0
  222. package/dist/view.d.ts +40 -0
  223. package/dist/view.js +23 -0
  224. package/dist/view.js.map +1 -0
  225. package/dist/yjs.cjs +1026 -0
  226. package/dist/yjs.cjs.map +1 -0
  227. package/dist/yjs.d.cts +22 -0
  228. package/dist/yjs.d.ts +22 -0
  229. package/dist/yjs.js +1026 -0
  230. package/dist/yjs.js.map +1 -0
  231. package/package.json +219 -20
@@ -0,0 +1,993 @@
1
+ 'use client';"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
+
3
+
4
+ var _chunkGLLXHMH2cjs = require('./chunk-GLLXHMH2.cjs');
5
+
6
+
7
+ var _chunkWXMYDXPNcjs = require('./chunk-WXMYDXPN.cjs');
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+ var _chunk2VDK27IFcjs = require('./chunk-2VDK27IF.cjs');
20
+
21
+
22
+
23
+
24
+ var _chunkGTTPVJSDcjs = require('./chunk-GTTPVJSD.cjs');
25
+ require('./chunk-OMOBMXD5.cjs');
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+ var _chunkPZ4GT5JOcjs = require('./chunk-PZ4GT5JO.cjs');
40
+ require('./chunk-2QCRZ7OL.cjs');
41
+
42
+
43
+
44
+
45
+
46
+
47
+ var _chunkND5XJVK2cjs = require('./chunk-ND5XJVK2.cjs');
48
+
49
+ // src/extensions/comments/comments-extension.tsx
50
+ var _lucidereact = require('lucide-react');
51
+
52
+ // src/extensions/comments/comment-anchors.ts
53
+ var idsOf = (node) => _nullishCoalesce(_optionalChain([node, 'optionalAccess', _2 => _2.marks, 'access', _3 => _3.flatMap, 'call', _4 => _4((mark) => mark.type === "comment" && _optionalChain([mark, 'access', _5 => _5.attrs, 'optionalAccess', _6 => _6.id]) ? [mark.attrs.id] : [])]), () => ( []));
54
+ function addRegion(anchors, block, region, inline2) {
55
+ let position = 0;
56
+ for (const node of inline2) {
57
+ const from = position;
58
+ position += _chunkND5XJVK2cjs.nodeLength.call(void 0, node);
59
+ for (const id of idsOf(node)) {
60
+ const ranges = _nullishCoalesce(anchors.get(id), () => ( []));
61
+ const last = ranges[ranges.length - 1];
62
+ const continues = _optionalChain([last, 'optionalAccess', _7 => _7.block]) === block && last.region === region && last.to === from;
63
+ if (continues) ranges[ranges.length - 1] = { ...last, to: position };
64
+ else ranges.push({ block, region, from, to: position });
65
+ anchors.set(id, ranges);
66
+ }
67
+ }
68
+ }
69
+ var read = /* @__PURE__ */ new WeakMap();
70
+ function commentAnchors(doc) {
71
+ let anchors = read.get(doc);
72
+ if (anchors === void 0) {
73
+ const found = /* @__PURE__ */ new Map();
74
+ for (const block of doc.blocks) {
75
+ for (const [region, inline2] of Object.entries(block.regions)) addRegion(found, block.id, region, inline2);
76
+ }
77
+ anchors = found;
78
+ read.set(doc, anchors);
79
+ }
80
+ return anchors;
81
+ }
82
+ var atomLabel = (node) => node.kind === "atom" ? _nullishCoalesce(node.attrs.label, () => ( "")) : "";
83
+ function anchorText(doc, ranges) {
84
+ return ranges.map(({ block, region, from, to }) => {
85
+ const inline2 = _nullishCoalesce(_optionalChain([_chunkND5XJVK2cjs.blockById.call(void 0, doc, block), 'optionalAccess', _8 => _8.regions, 'access', _9 => _9[region]]), () => ( []));
86
+ return _chunkND5XJVK2cjs.inlineText.call(void 0, _chunkND5XJVK2cjs.sliceInline.call(void 0, inline2, from, to), atomLabel);
87
+ }).join(" ");
88
+ }
89
+ function commentIdsAt(doc, { block, region, offset }) {
90
+ const inline2 = _nullishCoalesce(_optionalChain([_chunkND5XJVK2cjs.blockById.call(void 0, doc, block), 'optionalAccess', _10 => _10.regions, 'access', _11 => _11[region]]), () => ( []));
91
+ const ids = /* @__PURE__ */ new Set();
92
+ let position = 0;
93
+ for (const node of inline2) {
94
+ const end = position + _chunkND5XJVK2cjs.nodeLength.call(void 0, node);
95
+ if (position <= offset && offset <= end && end > position) idsOf(node).forEach((id) => ids.add(id));
96
+ position = end;
97
+ }
98
+ return [...ids].sort();
99
+ }
100
+ function threadRemoval(state, id) {
101
+ const tr = new (0, _chunkPZ4GT5JOcjs.Transaction)(state).setOrigin("command");
102
+ for (const { block, region, from, to } of _nullishCoalesce(commentAnchors(state.doc).get(id), () => ( []))) {
103
+ tr.step(_chunkPZ4GT5JOcjs.removeMarkStep.call(void 0, block, region, from, to, { type: "comment", attrs: { id } }));
104
+ }
105
+ return tr;
106
+ }
107
+
108
+ // src/extensions/comments/pending-ranges.ts
109
+ function mapPendingRanges(tr, ranges, state) {
110
+ return ranges.flatMap((range) => {
111
+ const from = tr.mapPos({ block: range.block, region: range.region, offset: range.from }, 1);
112
+ const to = tr.mapPos({ block: range.block, region: range.region, offset: range.to }, -1);
113
+ const { index } = state.doc;
114
+ if (!index.has(from.block) || !index.has(to.block) || _chunkPZ4GT5JOcjs.comparePos.call(void 0, state.doc, from, to) >= 0) return [];
115
+ return _chunkPZ4GT5JOcjs.markRanges.call(void 0, { ...state, selection: _chunkPZ4GT5JOcjs.textSelection.call(void 0, from, to) });
116
+ });
117
+ }
118
+
119
+ // src/extensions/comments/comments-plugin.ts
120
+ var isEnded = (ended, id, current) => ended.some((thread) => thread.id === id && thread.seen === current);
121
+ var commentsKey = _chunkPZ4GT5JOcjs.createPluginKey.call(void 0, "comments");
122
+ var COMMENTS = "comments";
123
+ var IDLE = { pending: [], active: null, open: null, ended: [] };
124
+ function act(value, action) {
125
+ switch (action.type) {
126
+ case "pending":
127
+ return { ...value, pending: [...value.pending, action.pending] };
128
+ case "settled": {
129
+ const pending = value.pending.filter(({ key }) => key !== action.key);
130
+ if (action.open === void 0) return { ...value, pending };
131
+ return { ...value, pending, active: _nullishCoalesce(action.open.ids[0], () => ( null)), open: action.open };
132
+ }
133
+ case "activate":
134
+ return value.active === action.id ? value : { ...value, active: action.id };
135
+ case "open":
136
+ return { ...value, active: action.open.ids.length === 1 ? action.open.ids[0] : value.active, open: action.open };
137
+ case "close":
138
+ return value.open === null ? value : { ...value, active: null, open: null };
139
+ case "forget": {
140
+ const active = value.active === action.id ? null : value.active;
141
+ const open = _optionalChain([value, 'access', _12 => _12.open, 'optionalAccess', _13 => _13.ids, 'access', _14 => _14.includes, 'call', _15 => _15(action.id)]) ? null : value.open;
142
+ const ended = [...value.ended.filter(({ id }) => id !== action.id), { id: action.id, seen: action.seen }];
143
+ return { ...value, active, open, ended };
144
+ }
145
+ }
146
+ }
147
+ function afterEdit(tr, value, state) {
148
+ if (!tr.docChanged || value.pending.length === 0) return value;
149
+ const pending = value.pending.map((anchor) => ({ ...anchor, ranges: mapPendingRanges(tr, anchor.ranges, state) }));
150
+ return { ...value, pending };
151
+ }
152
+ function afterMove(tr, value, state) {
153
+ const { open } = value;
154
+ if (open === null || open.focus || !tr.selectionSet || _chunkPZ4GT5JOcjs.foreignOrigins.includes(tr.origin)) return value;
155
+ const anchors = commentAnchors(state.doc);
156
+ return open.ids.some((id) => anchors.has(id)) ? value : { ...value, active: null, open: null };
157
+ }
158
+ var commentsPlugin = {
159
+ key: commentsKey,
160
+ init: () => IDLE,
161
+ apply(tr, value, _oldState, newState) {
162
+ const edited = afterMove(tr, afterEdit(tr, value, newState), newState);
163
+ const action = tr.getMeta(COMMENTS);
164
+ return action === void 0 ? edited : act(edited, action);
165
+ }
166
+ };
167
+
168
+ // src/extensions/comments/comment-create.ts
169
+ var nextKey = 0;
170
+ var hasCommentableText = (state) => _optionalChain([state, 'access', _16 => _16.selection, 'optionalAccess', _17 => _17.kind]) === "text" && _chunkPZ4GT5JOcjs.markRanges.call(void 0, state).length > 0;
171
+ var requestComment = (state, dispatch) => {
172
+ const { selection } = state;
173
+ if (_optionalChain([selection, 'optionalAccess', _18 => _18.kind]) !== "text" || _chunkPZ4GT5JOcjs.getPluginState.call(void 0, state, commentsKey).pending.length > 0) return false;
174
+ const ranges = _chunkPZ4GT5JOcjs.markRanges.call(void 0, state);
175
+ if (ranges.length === 0) return false;
176
+ if (dispatch === void 0) return true;
177
+ const pending = { key: ++nextKey, ranges, selection };
178
+ const action = { type: "pending", pending };
179
+ dispatch(new (0, _chunkPZ4GT5JOcjs.Transaction)(state).setMeta(COMMENTS, action).setMeta("addToHistory", false));
180
+ return true;
181
+ };
182
+ function settledTransaction(editor, key, id) {
183
+ const pending = _chunkPZ4GT5JOcjs.getPluginState.call(void 0, editor.state, commentsKey).pending.find((anchor) => anchor.key === key);
184
+ const tr = editor.createTransaction().setOrigin("command");
185
+ const ranges = id === null ? [] : _nullishCoalesce(_optionalChain([pending, 'optionalAccess', _19 => _19.ranges]), () => ( []));
186
+ for (const { block, region, from, to } of ranges) {
187
+ tr.step(_chunkPZ4GT5JOcjs.addMarkStep.call(void 0, block, region, from, to, { type: "comment", attrs: { id } }));
188
+ }
189
+ const untouched = pending !== void 0 && _chunkPZ4GT5JOcjs.sameSelection.call(void 0, editor.state.selection, pending.selection);
190
+ const open = id !== null && ranges.length > 0 && untouched ? { ids: [id], focus: true } : void 0;
191
+ const action = { type: "settled", key, open };
192
+ return tr.setMeta(COMMENTS, action);
193
+ }
194
+ function create(editor, pending, onCreate, link) {
195
+ const input = { anchorText: anchorText(editor.state.doc, pending.ranges), blockId: pending.ranges[0].block };
196
+ const settle = (id, error) => {
197
+ if (link.mounts === 0) return;
198
+ const tr = settledTransaction(editor, pending.key, id);
199
+ editor.dispatch(tr);
200
+ if (id === null) link.report(_chunk2VDK27IFcjs.toError.call(void 0, error));
201
+ else if (!tr.docChanged) link.report(new Error(`Comment thread ${id} has no text: it was deleted meanwhile`));
202
+ };
203
+ new Promise((resolve) => resolve(onCreate(input))).then(
204
+ (id) => typeof id === "string" && id !== "" ? settle(id) : settle(null, new Error("onCreate gave no thread id")),
205
+ (error) => settle(null, error)
206
+ );
207
+ }
208
+ function watchCreates(editor, onCreate, link) {
209
+ return editor.subscribe((_, tr) => {
210
+ const action = _optionalChain([tr, 'optionalAccess', _20 => _20.getMeta, 'call', _21 => _21(COMMENTS)]);
211
+ if (_optionalChain([action, 'optionalAccess', _22 => _22.type]) === "pending") create(editor, action.pending, onCreate, link);
212
+ });
213
+ }
214
+
215
+ // src/extensions/comments/comment-open.ts
216
+ function openIds(state, threads, ids) {
217
+ const { ended } = _chunkPZ4GT5JOcjs.getPluginState.call(void 0, state, commentsKey);
218
+ return ids.filter((id) => {
219
+ const thread = threads.find(id);
220
+ return _optionalChain([thread, 'optionalAccess', _23 => _23.resolved]) === false && !isEnded(ended, id, thread);
221
+ });
222
+ }
223
+ function commentsTransaction(state, action) {
224
+ return new (0, _chunkPZ4GT5JOcjs.Transaction)(state).setMeta(COMMENTS, action).setMeta("addToHistory", false);
225
+ }
226
+ function commentCommand(threads) {
227
+ return (state, dispatch) => {
228
+ if (requestComment(state, dispatch)) return true;
229
+ const { selection } = state;
230
+ if (_optionalChain([selection, 'optionalAccess', _24 => _24.kind]) !== "text" || !_chunkPZ4GT5JOcjs.isCollapsed.call(void 0, selection)) return false;
231
+ const ids = openIds(state, threads, commentIdsAt(state.doc, selection.head));
232
+ if (ids.length === 0) return false;
233
+ _optionalChain([dispatch, 'optionalCall', _25 => _25(commentsTransaction(state, { type: "open", open: { ids, focus: true } }))]);
234
+ return true;
235
+ };
236
+ }
237
+
238
+ // src/extensions/comments/comments-labels.ts
239
+ var DATE = new Intl.DateTimeFormat("en", { dateStyle: "medium", timeStyle: "short" });
240
+ function englishDate(createdAt) {
241
+ const date = new Date(createdAt);
242
+ return Number.isNaN(date.getTime()) ? createdAt : DATE.format(date);
243
+ }
244
+ var englishCommentsLabels = {
245
+ comment: "Comment",
246
+ comments: "Comments",
247
+ showComments: (count) => `Comments (${count})`,
248
+ thread: (anchorText2) => `Comment on "${anchorText2}"`,
249
+ threadsHere: "Comments on this text",
250
+ textRemoved: "Text removed",
251
+ addComment: "Add a comment",
252
+ reply: "Reply",
253
+ send: "Send",
254
+ resolve: "Resolve",
255
+ delete: "Delete",
256
+ close: "Close",
257
+ commentCount: (count) => `${count} ${count === 1 ? "comment" : "comments"}`,
258
+ postedAt: englishDate
259
+ };
260
+ function resolveCommentsLabels(overrides) {
261
+ const given = Object.entries(_nullishCoalesce(overrides, () => ( {}))).filter(([, value]) => value !== void 0);
262
+ return given.length === 0 ? englishCommentsLabels : { ...englishCommentsLabels, ...Object.fromEntries(given) };
263
+ }
264
+
265
+ // src/extensions/comments/comments-link.ts
266
+ var links = /* @__PURE__ */ new WeakMap();
267
+ function linkOf(editor) {
268
+ let link = links.get(editor);
269
+ if (link === void 0) {
270
+ link = { mounts: 0, report: (error) => console.error(error), stopWatching: null };
271
+ links.set(editor, link);
272
+ }
273
+ return link;
274
+ }
275
+
276
+ // src/extensions/comments/CommentsOverlay.tsx
277
+ var _react = require('react');
278
+
279
+ // src/extensions/comments/CommentMarkers.tsx
280
+
281
+
282
+ // src/extensions/comments/rail-layout.ts
283
+ function stackTops(items, gap) {
284
+ let next = 0;
285
+ return items.map(({ top, height }) => {
286
+ const placed = Math.max(_nullishCoalesce(top, () => ( next)), next);
287
+ next = placed + height + gap;
288
+ return placed;
289
+ });
290
+ }
291
+
292
+ // src/extensions/comments/use-block-aligned.ts
293
+ function topOf(controller, root, block) {
294
+ const shell = block === "" ? void 0 : controller.blockElement(block);
295
+ if (shell === void 0) return null;
296
+ return shell.getBoundingClientRect().top - root.getBoundingClientRect().top - root.clientTop + root.scrollTop;
297
+ }
298
+ var HEIGHT = "--quoin-comments-height";
299
+ function place(controller, box, gap) {
300
+ const root = box.parentElement;
301
+ if (root === null) return;
302
+ const items = Array.from(box.querySelectorAll("[data-rail-item]"));
303
+ const tops = stackTops(
304
+ items.map((item) => ({ top: topOf(controller, root, _nullishCoalesce(item.dataset.block, () => ( ""))), height: item.offsetHeight })),
305
+ gap
306
+ );
307
+ items.forEach((item, i) => item.style.transform = `translateY(${tops[i]}px)`);
308
+ const bottom = Math.max(0, ...items.map((item, i) => tops[i] + item.offsetHeight));
309
+ root.style.setProperty(HEIGHT, `${bottom}px`);
310
+ }
311
+ function useBlockAligned(controller, box, gap, key) {
312
+ _chunkGTTPVJSDcjs.useIsomorphicLayoutEffect.call(void 0, () => {
313
+ const element = box.current;
314
+ const view = _optionalChain([element, 'optionalAccess', _26 => _26.ownerDocument, 'access', _27 => _27.defaultView]);
315
+ if (!element || !view) return void 0;
316
+ const update = () => place(controller, element, gap);
317
+ update();
318
+ let frame = 0;
319
+ const later = () => {
320
+ view.cancelAnimationFrame(frame);
321
+ frame = view.requestAnimationFrame(update);
322
+ };
323
+ const unsubscribe = controller.editor.subscribe(later);
324
+ const observer = new ResizeObserver(later);
325
+ if (element.parentElement) observer.observe(element.parentElement);
326
+ element.querySelectorAll("[data-rail-item]").forEach((item) => observer.observe(item));
327
+ return () => {
328
+ view.cancelAnimationFrame(frame);
329
+ unsubscribe();
330
+ observer.disconnect();
331
+ _optionalChain([element, 'access', _28 => _28.parentElement, 'optionalAccess', _29 => _29.style, 'access', _30 => _30.removeProperty, 'call', _31 => _31(HEIGHT)]);
332
+ };
333
+ }, [controller, box, gap, key]);
334
+ }
335
+
336
+ // src/extensions/comments/CommentMarkers.tsx
337
+ var _jsxruntime = require('react/jsx-runtime');
338
+ var GAP = 4;
339
+ function groupsOf(entries) {
340
+ const groups = /* @__PURE__ */ new Map();
341
+ for (const { thread, ranges } of entries) {
342
+ const block = _nullishCoalesce(_optionalChain([ranges, 'access', _32 => _32[0], 'optionalAccess', _33 => _33.block]), () => ( ""));
343
+ groups.set(block, [..._nullishCoalesce(groups.get(block), () => ( [])), thread.id]);
344
+ }
345
+ const removed = groups.get("");
346
+ groups.delete("");
347
+ return [...groups, ...removed ? [["", removed]] : []].map(([block, ids]) => ({ block, ids }));
348
+ }
349
+ function CommentMarkers({ env, box, entries, onOpen }) {
350
+ const groups = groupsOf(entries);
351
+ useBlockAligned(env.controller, box, GAP, groups.map(({ block, ids }) => `${block}:${ids}`).join(" "));
352
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: box, className: "quoin-comments-markers", children: groups.map(({ block, ids }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
353
+ "button",
354
+ {
355
+ type: "button",
356
+ "data-rail-item": "",
357
+ "data-block": block,
358
+ "aria-label": env.labels.showComments(ids.length),
359
+ className: _chunk2VDK27IFcjs.cn.call(void 0, "quoin-comments-marker", _chunk2VDK27IFcjs.FOCUS_RING),
360
+ onClick: (event) => onOpen(ids[0], event.currentTarget),
361
+ children: [
362
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.MessageSquare, { "aria-hidden": "true" }),
363
+ ids.length
364
+ ]
365
+ },
366
+ block
367
+ )) });
368
+ }
369
+
370
+ // src/extensions/comments/ThreadCard.tsx
371
+
372
+
373
+ // src/extensions/comments/ThreadView.tsx
374
+
375
+
376
+ // src/extensions/comments/comment-actions.ts
377
+ async function called(link, call) {
378
+ try {
379
+ await call();
380
+ return true;
381
+ } catch (error) {
382
+ link.report(_chunk2VDK27IFcjs.toError.call(void 0, error));
383
+ return false;
384
+ }
385
+ }
386
+ async function endThread(editor, link, call, id, threads) {
387
+ if (!await called(link, () => call(id)) || link.mounts === 0) return false;
388
+ const action = { type: "forget", id, seen: _optionalChain([threads, 'optionalAccess', _34 => _34.find, 'call', _35 => _35(id)]) };
389
+ editor.dispatch(threadRemoval(editor.state, id).setMeta(COMMENTS, action));
390
+ return true;
391
+ }
392
+ function sendReply(link, call, id, body) {
393
+ return called(link, () => call(id, body));
394
+ }
395
+
396
+ // src/extensions/comments/CommentAvatar.tsx
397
+
398
+
399
+ var initials = (name) => name.trim().split(/\s+/).slice(0, 2).map((word) => _nullishCoalesce(_optionalChain([Array, 'access', _36 => _36.from, 'call', _37 => _37(word), 'access', _38 => _38[0], 'optionalAccess', _39 => _39.toUpperCase, 'call', _40 => _40()]), () => ( ""))).join("");
400
+ function CommentAvatar({ author }) {
401
+ const picture = _chunkGLLXHMH2cjs.webAddress.call(void 0, author.avatarUrl);
402
+ const [failed, setFailed] = _react.useState.call(void 0, null);
403
+ if (picture !== null && picture !== failed) {
404
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
405
+ "img",
406
+ {
407
+ src: picture,
408
+ alt: "",
409
+ loading: "lazy",
410
+ referrerPolicy: "no-referrer",
411
+ draggable: false,
412
+ className: "size-6 shrink-0 rounded-full object-cover",
413
+ onError: () => setFailed(picture)
414
+ }
415
+ );
416
+ }
417
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { "aria-hidden": "true", className: "quoin-comments-initials", children: initials(author.name) });
418
+ }
419
+
420
+ // src/extensions/comments/CommentItem.tsx
421
+
422
+ function CommentItem({ comment, labels }) {
423
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { className: "flex gap-2", children: [
424
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommentAvatar, { author: comment.author }),
425
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 flex-1", children: [
426
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "flex flex-wrap items-baseline gap-x-2 text-sm", children: [
427
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "font-medium", children: comment.author.name }),
428
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "time", { dateTime: comment.createdAt, className: "text-xs text-muted-foreground", children: labels.postedAt(comment.createdAt) })
429
+ ] }),
430
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "quoin-comments-body text-sm", children: comment.body })
431
+ ] })
432
+ ] });
433
+ }
434
+
435
+ // src/extensions/comments/ReplyBox.tsx
436
+
437
+
438
+
439
+ var REPLY_FIELD = "data-comments-field";
440
+ function ReplyBox({ env, threadId, first }) {
441
+ const { controller, host, labels, link } = env;
442
+ const [body, setBody] = _react.useState.call(void 0, "");
443
+ const [sending, setSending] = _react.useState.call(void 0, false);
444
+ const alive = _react.useRef.call(void 0, true);
445
+ _react.useEffect.call(void 0, () => {
446
+ alive.current = true;
447
+ return () => {
448
+ alive.current = false;
449
+ };
450
+ }, []);
451
+ const label = first ? labels.addComment : labels.reply;
452
+ const text = body.trim();
453
+ const send = async () => {
454
+ if (text === "" || sending) return;
455
+ setSending(true);
456
+ const sent = await sendReply(link, host.onReply, threadId, text);
457
+ if (!alive.current) return;
458
+ setSending(false);
459
+ if (sent) setBody("");
460
+ };
461
+ const onSubmit = (event) => {
462
+ event.preventDefault();
463
+ void send();
464
+ };
465
+ const onKeyDown = (event) => {
466
+ if (event.nativeEvent.isComposing || event.key !== "Enter") return;
467
+ if (controller.isMac ? !event.metaKey : !event.ctrlKey) return;
468
+ event.preventDefault();
469
+ void send();
470
+ };
471
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "flex items-start gap-2", onSubmit, children: [
472
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommentAvatar, { author: host.currentUser }),
473
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
474
+ "textarea",
475
+ {
476
+ ...{ [REPLY_FIELD]: "" },
477
+ "aria-label": label,
478
+ placeholder: label,
479
+ rows: 2,
480
+ value: body,
481
+ onChange: (event) => setBody(event.target.value),
482
+ onKeyDown,
483
+ className: "quoin-comments-field"
484
+ }
485
+ ),
486
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
487
+ _chunk2VDK27IFcjs.Button,
488
+ {
489
+ type: "submit",
490
+ variant: "ghost",
491
+ size: "icon-sm",
492
+ "aria-label": labels.send,
493
+ "aria-disabled": text === "" || sending || void 0,
494
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.SendHorizontal, {})
495
+ }
496
+ )
497
+ ] });
498
+ }
499
+
500
+ // src/extensions/comments/ThreadView.tsx
501
+
502
+ function ThreadView({ env, id, thread, onEnded }) {
503
+ const { controller, host, labels, link } = env;
504
+ const readOnly = _chunkGTTPVJSDcjs.useReadOnly.call(void 0, controller);
505
+ const [busy, setBusy] = _react.useState.call(void 0, false);
506
+ const alive = _react.useRef.call(void 0, true);
507
+ const root = _react.useRef.call(void 0, null);
508
+ _react.useEffect.call(void 0, () => {
509
+ alive.current = true;
510
+ return () => {
511
+ alive.current = false;
512
+ };
513
+ }, []);
514
+ const comments = _nullishCoalesce(_optionalChain([thread, 'optionalAccess', _41 => _41.comments]), () => ( []));
515
+ const end = async (call) => {
516
+ if (busy) return;
517
+ setBusy(true);
518
+ const ended = await endThread(controller.editor, link, call, id, host.threads);
519
+ if (alive.current) setBusy(false);
520
+ const active = document.activeElement;
521
+ const stayed = active === null || active === document.body || _optionalChain([root, 'access', _42 => _42.current, 'optionalAccess', _43 => _43.contains, 'call', _44 => _44(active)]) === true;
522
+ if (ended && stayed) onEnded();
523
+ };
524
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { ref: root, className: "flex flex-col gap-3", children: [
525
+ comments.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ol", { className: "flex flex-col gap-3", children: comments.map((comment) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommentItem, { comment, labels }, comment.id)) }),
526
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ReplyBox, { env, threadId: id, first: comments.length === 0 }),
527
+ !readOnly && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex justify-end gap-1", children: [
528
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
529
+ _chunk2VDK27IFcjs.Button,
530
+ {
531
+ type: "button",
532
+ variant: "ghost",
533
+ size: "xs",
534
+ "aria-disabled": busy || void 0,
535
+ onClick: () => void end(host.onResolve),
536
+ children: labels.resolve
537
+ }
538
+ ),
539
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
540
+ _chunk2VDK27IFcjs.Button,
541
+ {
542
+ type: "button",
543
+ variant: "ghost",
544
+ size: "xs",
545
+ "aria-disabled": busy || void 0,
546
+ onClick: () => void end(host.onDelete),
547
+ children: labels.delete
548
+ }
549
+ )
550
+ ] })
551
+ ] });
552
+ }
553
+
554
+ // src/extensions/comments/ThreadCard.tsx
555
+
556
+ function ThreadCard({ env, entry, active, expanded, onToggle }) {
557
+ const { labels, controller } = env;
558
+ const { thread, anchorText: anchorText2, ranges } = entry;
559
+ const header = _react.useRef.call(void 0, null);
560
+ const [first] = thread.comments;
561
+ const removed = ranges.length === 0;
562
+ const backToHeader = () => {
563
+ if (_optionalChain([header, 'access', _45 => _45.current, 'optionalAccess', _46 => _46.isConnected])) header.current.focus();
564
+ else controller.focus();
565
+ };
566
+ const onKeyDown = (event) => {
567
+ if (event.key !== "Escape" || !expanded) return;
568
+ event.preventDefault();
569
+ event.stopPropagation();
570
+ onToggle(null);
571
+ _optionalChain([header, 'access', _47 => _47.current, 'optionalAccess', _48 => _48.focus, 'call', _49 => _49()]);
572
+ };
573
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "quoin-comments-card", "data-active": active || void 0, onKeyDown, children: [
574
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
575
+ "button",
576
+ {
577
+ ref: header,
578
+ type: "button",
579
+ "aria-expanded": expanded,
580
+ className: _chunk2VDK27IFcjs.cn.call(void 0, "flex w-full flex-col items-start gap-1 rounded-sm text-start", _chunk2VDK27IFcjs.FOCUS_RING),
581
+ onClick: () => onToggle(expanded ? null : thread.id),
582
+ children: [
583
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: removed ? "text-xs text-muted-foreground italic" : "quoin-comments-quote", children: removed ? labels.textRemoved : anchorText2 }),
584
+ first !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "line-clamp-2 text-sm", children: [
585
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "font-medium", children: first.author.name }),
586
+ " ",
587
+ first.body
588
+ ] }),
589
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-xs text-muted-foreground", children: labels.commentCount(thread.comments.length) })
590
+ ]
591
+ }
592
+ ),
593
+ expanded && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-3", role: "group", "aria-label": removed ? labels.textRemoved : labels.thread(anchorText2), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ThreadView, { env, id: thread.id, thread, onEnded: backToHeader }) })
594
+ ] });
595
+ }
596
+
597
+ // src/extensions/comments/CommentsRail.tsx
598
+
599
+ var GAP2 = 8;
600
+ var layoutKey = (entries, value) => `${value.active} ${value.open !== null} ${entries.map(({ thread, ranges }) => `${thread.id}:${_optionalChain([ranges, 'access', _50 => _50[0], 'optionalAccess', _51 => _51.block])}`)}`;
601
+ function CommentsRail({ env, box, entries, value, onToggle }) {
602
+ useBlockAligned(env.controller, box, GAP2, layoutKey(entries, value));
603
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: box, className: "quoin-comments-rail", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { "aria-label": env.labels.comments, children: entries.map((entry) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "li", { "data-rail-item": "", "data-block": _nullishCoalesce(_optionalChain([entry, 'access', _52 => _52.ranges, 'access', _53 => _53[0], 'optionalAccess', _54 => _54.block]), () => ( "")), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
604
+ ThreadCard,
605
+ {
606
+ env,
607
+ entry,
608
+ active: value.active === entry.thread.id,
609
+ expanded: value.active === entry.thread.id && value.open === null,
610
+ onToggle
611
+ }
612
+ ) }, entry.thread.id)) }) });
613
+ }
614
+
615
+ // src/extensions/comments/CommentsSheet.tsx
616
+ var _reactdialog = require('@radix-ui/react-dialog'); var DialogPrimitive = _interopRequireWildcard(_reactdialog);
617
+
618
+
619
+
620
+ function CommentsSheet({ env, entries, value, onToggle, onClose, returnFocus }) {
621
+ const { labels } = env;
622
+ const content = _react.useRef.call(void 0, null);
623
+ const outside = _react.useRef.call(void 0, false);
624
+ const focusOpened = (event) => {
625
+ const opened = _optionalChain([content, 'access', _55 => _55.current, 'optionalAccess', _56 => _56.querySelector, 'call', _57 => _57('[aria-expanded="true"]')]);
626
+ if (!opened) return;
627
+ event.preventDefault();
628
+ opened.focus();
629
+ };
630
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
631
+ DialogPrimitive.Root,
632
+ {
633
+ open: true,
634
+ modal: false,
635
+ onOpenChange: (open) => {
636
+ if (!open) onClose();
637
+ },
638
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Portal, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
639
+ DialogPrimitive.Content,
640
+ {
641
+ ref: content,
642
+ "aria-describedby": void 0,
643
+ className: "quoin quoin-comments-sheet",
644
+ onOpenAutoFocus: focusOpened,
645
+ onInteractOutside: () => {
646
+ outside.current = true;
647
+ },
648
+ onCloseAutoFocus: (event) => {
649
+ event.preventDefault();
650
+ if (!outside.current) returnFocus();
651
+ },
652
+ children: [
653
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-between gap-2", children: [
654
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Title, { className: "text-sm font-semibold", children: labels.comments }),
655
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2VDK27IFcjs.Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": labels.close, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.XIcon, {}) }) })
656
+ ] }),
657
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { "aria-label": labels.comments, className: "flex flex-col gap-2", children: entries.map((entry) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "li", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
658
+ ThreadCard,
659
+ {
660
+ env,
661
+ entry,
662
+ active: value.active === entry.thread.id,
663
+ expanded: value.active === entry.thread.id,
664
+ onToggle
665
+ }
666
+ ) }, entry.thread.id)) })
667
+ ]
668
+ }
669
+ ) })
670
+ }
671
+ );
672
+ }
673
+
674
+ // src/extensions/comments/rail-entries.ts
675
+ var NONE = [];
676
+ function railEntries(doc, threads, ended = []) {
677
+ const anchors = commentAnchors(doc);
678
+ const entries = threads.filter((thread) => !thread.resolved && !isEnded(ended, thread.id, thread)).map((thread) => {
679
+ const ranges = _nullishCoalesce(anchors.get(thread.id), () => ( NONE));
680
+ return { thread, ranges, anchorText: anchorText(doc, ranges) };
681
+ });
682
+ const place2 = ({ ranges: [first] }) => first === void 0 ? [Infinity, 0] : [_chunkND5XJVK2cjs.indexOfBlock.call(void 0, doc, first.block), first.from];
683
+ return entries.map((entry, order) => ({ entry, order, at: place2(entry) })).sort((a, b) => a.at[0] - b.at[0] || a.at[1] - b.at[1] || a.order - b.order).map(({ entry }) => entry);
684
+ }
685
+
686
+ // src/extensions/comments/ThreadPopover.tsx
687
+
688
+
689
+ // src/extensions/comments/ThreadChooser.tsx
690
+
691
+ function ThreadChooser({ env, choices, onChoose }) {
692
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { "aria-label": env.labels.threadsHere, className: "flex flex-col gap-1", children: choices.map(({ id, anchorText: anchorText2, preview }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "li", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
693
+ "button",
694
+ {
695
+ type: "button",
696
+ className: "quoin-comments-choice",
697
+ onClick: () => onChoose(id),
698
+ children: [
699
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "quoin-comments-quote", children: anchorText2 }),
700
+ preview && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "line-clamp-1 text-sm", children: preview })
701
+ ]
702
+ }
703
+ ) }, id)) });
704
+ }
705
+
706
+ // src/extensions/comments/ThreadPopover.tsx
707
+
708
+ var docOf = (state) => state.doc;
709
+ function focusIsOurs(controller, content) {
710
+ const active = _nullishCoalesce(_optionalChain([content, 'optionalAccess', _58 => _58.ownerDocument, 'access', _59 => _59.activeElement]), () => ( null));
711
+ return active === null || active === active.ownerDocument.body || _chunkWXMYDXPNcjs.ownsNode.call(void 0, controller, active);
712
+ }
713
+ function ThreadPopover({ env, open, threads, onChoose, onClose }) {
714
+ const { controller, labels } = env;
715
+ const doc = _chunkGTTPVJSDcjs.useEditorState.call(void 0, controller, docOf);
716
+ const anchors = commentAnchors(doc);
717
+ const { ids } = open;
718
+ const first = ids.map((id) => _optionalChain([anchors, 'access', _60 => _60.get, 'call', _61 => _61(id), 'optionalAccess', _62 => _62[0]])).find(Boolean);
719
+ const latest = _react.useRef.call(void 0, first);
720
+ _chunkGTTPVJSDcjs.useIsomorphicLayoutEffect.call(void 0, () => {
721
+ if (first) latest.current = first;
722
+ });
723
+ const anchor = _react.useMemo.call(void 0,
724
+ () => ({
725
+ current: _chunk2VDK27IFcjs.virtualAnchor.call(void 0,
726
+ () => latest.current ? _chunk2VDK27IFcjs.rangeRect.call(void 0, controller, latest.current) : null,
727
+ () => latest.current && controller.registry.get(latest.current.block, latest.current.region)
728
+ )
729
+ }),
730
+ [controller]
731
+ );
732
+ const content = _react.useRef.call(void 0, null);
733
+ const focusField = () => {
734
+ const target = _optionalChain([content, 'access', _63 => _63.current, 'optionalAccess', _64 => _64.querySelector, 'call', _65 => _65(`[${REPLY_FIELD}], button`)]);
735
+ if (focusIsOurs(controller, content.current) && !_optionalChain([content, 'access', _66 => _66.current, 'optionalAccess', _67 => _67.contains, 'call', _68 => _68(content.current.ownerDocument.activeElement)])) {
736
+ _optionalChain([target, 'optionalAccess', _69 => _69.focus, 'call', _70 => _70()]);
737
+ }
738
+ };
739
+ _chunkGTTPVJSDcjs.useIsomorphicLayoutEffect.call(void 0, () => {
740
+ if (open.focus) focusField();
741
+ }, [open]);
742
+ if (first === void 0 && latest.current === void 0) return null;
743
+ const textOf = (id) => anchorText(doc, _nullishCoalesce(anchors.get(id), () => ( []))) || labels.textRemoved;
744
+ const single = ids.length === 1;
745
+ const gone = single && !anchors.has(ids[0]);
746
+ const backToText = () => controller.focus();
747
+ const focusInside = (event) => {
748
+ event.preventDefault();
749
+ if (open.focus) focusField();
750
+ };
751
+ const onEscape = (event) => {
752
+ event.preventDefault();
753
+ event.stopPropagation();
754
+ const inside = _nullishCoalesce(_optionalChain([content, 'access', _71 => _71.current, 'optionalAccess', _72 => _72.contains, 'call', _73 => _73(content.current.ownerDocument.activeElement)]), () => ( false));
755
+ onClose();
756
+ if (inside) backToText();
757
+ };
758
+ const choices = ids.map((id) => ({ id, anchorText: textOf(id), preview: _nullishCoalesce(_optionalChain([threads, 'access', _74 => _74.find, 'call', _75 => _75(id), 'optionalAccess', _76 => _76.comments, 'access', _77 => _77[0], 'optionalAccess', _78 => _78.body]), () => ( "")) }));
759
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
760
+ _chunk2VDK27IFcjs.Popover,
761
+ {
762
+ open: true,
763
+ modal: false,
764
+ onOpenChange: (next) => {
765
+ if (!next) onClose();
766
+ },
767
+ children: [
768
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2VDK27IFcjs.PopoverAnchor, { virtualRef: anchor }),
769
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
770
+ _chunk2VDK27IFcjs.PopoverContent,
771
+ {
772
+ ref: content,
773
+ "aria-label": gone ? labels.textRemoved : single ? labels.thread(textOf(ids[0])) : labels.threadsHere,
774
+ side: "bottom",
775
+ align: "start",
776
+ className: "w-80 p-3",
777
+ onOpenAutoFocus: focusInside,
778
+ onCloseAutoFocus: (event) => event.preventDefault(),
779
+ onEscapeKeyDown: onEscape,
780
+ children: [
781
+ gone && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mb-2 text-xs text-muted-foreground italic", children: labels.textRemoved }),
782
+ single ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ThreadView, { env, id: ids[0], thread: threads.find(ids[0]), onEnded: backToText }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ThreadChooser, { env, choices, onChoose })
783
+ ]
784
+ },
785
+ ids.join(" ")
786
+ )
787
+ ]
788
+ }
789
+ );
790
+ }
791
+
792
+ // src/extensions/comments/use-anchor-clicks.ts
793
+
794
+ function idsUnder(root, target) {
795
+ const ids = [];
796
+ let element = target instanceof Element ? target.closest("[data-comment]") : null;
797
+ while (element !== null && root.contains(element)) {
798
+ const id = element.getAttribute("data-comment");
799
+ if (id) ids.push(id);
800
+ element = _nullishCoalesce(_optionalChain([element, 'access', _79 => _79.parentElement, 'optionalAccess', _80 => _80.closest, 'call', _81 => _81("[data-comment]")]), () => ( null));
801
+ }
802
+ return ids;
803
+ }
804
+ function useAnchorClicks(controller, threads) {
805
+ _react.useEffect.call(void 0, () => {
806
+ const onClick = (event) => {
807
+ const root = controller.root;
808
+ if (root === null || event.defaultPrevented || !_optionalChain([root, 'access', _82 => _82.ownerDocument, 'access', _83 => _83.getSelection, 'call', _84 => _84(), 'optionalAccess', _85 => _85.isCollapsed])) return;
809
+ const { editor } = controller;
810
+ const ids = openIds(editor.state, threads, idsUnder(root, event.target));
811
+ if (ids.length === 0) return;
812
+ editor.dispatch(commentsTransaction(editor.state, { type: "open", open: { ids, focus: false } }));
813
+ };
814
+ document.addEventListener("click", onClick);
815
+ return () => document.removeEventListener("click", onClick);
816
+ }, [controller, threads]);
817
+ }
818
+
819
+ // src/extensions/comments/use-canvas-wide.ts
820
+
821
+ var WIDE_CANVAS = 800;
822
+ function useCanvasWide(box) {
823
+ const [wide, setWide] = _react.useState.call(void 0, false);
824
+ _chunkGTTPVJSDcjs.useIsomorphicLayoutEffect.call(void 0, () => {
825
+ const canvas = _optionalChain([box, 'access', _86 => _86.current, 'optionalAccess', _87 => _87.parentElement]);
826
+ if (!canvas) return void 0;
827
+ const measure = () => setWide(canvas.offsetWidth >= WIDE_CANVAS);
828
+ measure();
829
+ const observer = new ResizeObserver(measure);
830
+ observer.observe(canvas);
831
+ return () => observer.disconnect();
832
+ }, [box]);
833
+ return wide;
834
+ }
835
+
836
+ // src/extensions/comments/use-threads.ts
837
+
838
+ function useThreads(threads) {
839
+ return _react.useSyncExternalStore.call(void 0, threads.subscribe, threads.get, threads.get);
840
+ }
841
+
842
+ // src/extensions/comments/CommentsOverlay.tsx
843
+
844
+ var commentsOf = (state) => _chunkPZ4GT5JOcjs.getPluginState.call(void 0, state, commentsKey);
845
+ var docOf2 = (state) => state.doc;
846
+ function CommentsOverlay({ controller, host, labels }) {
847
+ const { onError } = _chunk2VDK27IFcjs.useQuoin.call(void 0, );
848
+ const link = linkOf(controller.editor);
849
+ _chunkGTTPVJSDcjs.useIsomorphicLayoutEffect.call(void 0, () => {
850
+ link.report = onError;
851
+ }, [link, onError]);
852
+ useAnchorClicks(controller, host.threads);
853
+ const threads = useThreads(host.threads);
854
+ const value = _chunkGTTPVJSDcjs.useEditorState.call(void 0, controller, commentsOf);
855
+ const doc = _chunkGTTPVJSDcjs.useEditorState.call(void 0, controller, docOf2);
856
+ const entries = _react.useMemo.call(void 0, () => railEntries(doc, threads, value.ended), [doc, threads, value.ended]);
857
+ const box = _react.useRef.call(void 0, null);
858
+ const wide = useCanvasWide(box);
859
+ const [sheet, setSheet] = _react.useState.call(void 0, false);
860
+ const opener = _react.useRef.call(void 0, null);
861
+ _react.useEffect.call(void 0, () => {
862
+ if (wide) setSheet(false);
863
+ }, [wide]);
864
+ const env = _react.useMemo.call(void 0, () => ({ controller, host, labels, link }), [controller, host, labels, link]);
865
+ const act2 = _react.useCallback.call(void 0,
866
+ (action) => controller.editor.dispatch(commentsTransaction(controller.editor.state, action)),
867
+ [controller]
868
+ );
869
+ const toggle = _react.useCallback.call(void 0, (id) => act2({ type: "activate", id }), [act2]);
870
+ const openSheet = (id, marker) => {
871
+ opener.current = marker;
872
+ toggle(id);
873
+ setSheet(true);
874
+ };
875
+ const returnFocus = () => {
876
+ if (_optionalChain([opener, 'access', _88 => _88.current, 'optionalAccess', _89 => _89.isConnected])) opener.current.focus();
877
+ else controller.focus();
878
+ };
879
+ const closeSheet = () => {
880
+ setSheet(false);
881
+ toggle(null);
882
+ };
883
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
884
+ wide ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommentsRail, { env, box, entries, value, onToggle: toggle }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommentMarkers, { env, box, entries, onOpen: openSheet }),
885
+ !wide && sheet && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
886
+ CommentsSheet,
887
+ {
888
+ env,
889
+ entries,
890
+ value,
891
+ onToggle: toggle,
892
+ onClose: closeSheet,
893
+ returnFocus
894
+ }
895
+ ),
896
+ value.open && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
897
+ ThreadPopover,
898
+ {
899
+ env,
900
+ open: value.open,
901
+ threads: host.threads,
902
+ onChoose: (id) => act2({ type: "open", open: { ids: [id], focus: true } }),
903
+ onClose: () => act2({ type: "close" })
904
+ }
905
+ )
906
+ ] });
907
+ }
908
+
909
+ // src/extensions/comments/comments-decorations.ts
910
+ var PENDING = { class: "quoin-comment-pending" };
911
+ var ACTIVE = { class: "quoin-comment-active" };
912
+ var inline = (ranges, attrs) => ranges.map((range) => ({ kind: "inline", ...range, attrs }));
913
+ var drawn = /* @__PURE__ */ new WeakMap();
914
+ function commentsDecorations(state) {
915
+ const value = _chunkPZ4GT5JOcjs.getPluginState.call(void 0, state, commentsKey);
916
+ const last = drawn.get(value);
917
+ if (_optionalChain([last, 'optionalAccess', _90 => _90.doc]) === state.doc) return last.decorations;
918
+ const active = value.active === null ? [] : _nullishCoalesce(commentAnchors(state.doc).get(value.active), () => ( []));
919
+ const decorations = [...value.pending.flatMap(({ ranges }) => inline(ranges, PENDING)), ...inline(active, ACTIVE)];
920
+ drawn.set(value, { doc: state.doc, decorations });
921
+ return decorations;
922
+ }
923
+
924
+ // src/extensions/comments/comments-extension.tsx
925
+
926
+ var commentItem = (labels) => ({
927
+ id: "comment",
928
+ title: labels.comment,
929
+ icon: _lucidereact.MessageSquarePlus,
930
+ shortcut: "Mod-Alt-m",
931
+ available: (state) => hasCommentableText(state) && _chunkPZ4GT5JOcjs.getPluginState.call(void 0, state, commentsKey).pending.length === 0,
932
+ // Focus goes back to the text first: the button leaves the toolbar while the thread is being asked for.
933
+ run: (controller) => {
934
+ controller.focus();
935
+ controller.run(requestComment);
936
+ }
937
+ });
938
+ function commentsExtension(options) {
939
+ const { labels: overrides, ...host } = options;
940
+ const labels = resolveCommentsLabels(overrides);
941
+ function Overlay({ controller }) {
942
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommentsOverlay, { controller, host, labels });
943
+ }
944
+ const ui = { bubbleItems: [commentItem(labels)], overlays: [Overlay] };
945
+ return _chunkPZ4GT5JOcjs.defineExtension.call(void 0, {
946
+ name: "comments",
947
+ plugins: [commentsPlugin],
948
+ decorations: commentsDecorations,
949
+ keymap: { "Mod-Alt-m": commentCommand(host.threads) },
950
+ // One watcher per editor however many views mount it at once, so the host is asked once per thread.
951
+ onMount(editor) {
952
+ const link = linkOf(editor);
953
+ if (link.mounts++ === 0) link.stopWatching = watchCreates(editor, host.onCreate, link);
954
+ return () => {
955
+ if (--link.mounts > 0) return;
956
+ _optionalChain([link, 'access', _91 => _91.stopWatching, 'optionalCall', _92 => _92()]);
957
+ link.stopWatching = null;
958
+ };
959
+ },
960
+ ui
961
+ });
962
+ }
963
+
964
+ // src/extensions/comments/comment-threads.ts
965
+ var NO_THREADS = [];
966
+ function createCommentThreads(initial = NO_THREADS) {
967
+ let threads = initial;
968
+ let byId = null;
969
+ const listeners = /* @__PURE__ */ new Set();
970
+ return {
971
+ get: () => threads,
972
+ set(next) {
973
+ if (next === threads) return;
974
+ threads = next;
975
+ byId = null;
976
+ for (const listener of [...listeners]) listener();
977
+ },
978
+ find(id) {
979
+ byId ??= new Map(threads.map((thread) => [thread.id, thread]));
980
+ return byId.get(id);
981
+ },
982
+ subscribe(listener) {
983
+ listeners.add(listener);
984
+ return () => listeners.delete(listener);
985
+ }
986
+ };
987
+ }
988
+
989
+
990
+
991
+
992
+ exports.commentsExtension = commentsExtension; exports.createCommentThreads = createCommentThreads; exports.englishCommentsLabels = englishCommentsLabels;
993
+ //# sourceMappingURL=comments.cjs.map