comment-mode 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -8
- package/dist/index.d.mts +36 -3
- package/dist/index.d.ts +36 -3
- package/dist/index.js +414 -148
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +415 -150
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ function AuthProvider(props) {
|
|
|
17
17
|
const [accessToken, setAccessToken] = react.useState(null);
|
|
18
18
|
const [isReady, setIsReady] = react.useState(false);
|
|
19
19
|
const [displayName, setDisplayNameState] = react.useState("");
|
|
20
|
+
const [avatarUrl, setAvatarUrl] = react.useState(null);
|
|
20
21
|
const apiBaseUrl = (_a = config.apiBaseUrl) != null ? _a : DEFAULT_API_BASE_URL;
|
|
21
22
|
react.useEffect(() => {
|
|
22
23
|
let cancelled = false;
|
|
@@ -29,8 +30,13 @@ function AuthProvider(props) {
|
|
|
29
30
|
const userName = ((_c = meta == null ? void 0 : meta.user_name) == null ? void 0 : _c.trim()) || ((_d = meta == null ? void 0 : meta.preferred_username) == null ? void 0 : _d.trim());
|
|
30
31
|
const emailPrefix = (_f = (_e = u.email) == null ? void 0 : _e.split("@")[0]) == null ? void 0 : _f.trim();
|
|
31
32
|
return fullName || userName || emailPrefix || "";
|
|
33
|
+
}, getAvatarUrlFromUser2 = function(u) {
|
|
34
|
+
var _a2;
|
|
35
|
+
const meta = u.user_metadata;
|
|
36
|
+
const url = (_a2 = meta == null ? void 0 : meta.avatar_url) == null ? void 0 : _a2.trim();
|
|
37
|
+
return url || null;
|
|
32
38
|
};
|
|
33
|
-
var getDisplayNameFromUser = getDisplayNameFromUser2;
|
|
39
|
+
var getDisplayNameFromUser = getDisplayNameFromUser2, getAvatarUrlFromUser = getAvatarUrlFromUser2;
|
|
34
40
|
const response = await fetch(`${apiBaseUrl}/auth/config`);
|
|
35
41
|
if (!response.ok) {
|
|
36
42
|
throw new Error(`Failed to load auth config: ${response.status}`);
|
|
@@ -50,16 +56,19 @@ function AuthProvider(props) {
|
|
|
50
56
|
setUser({ id: session.user.id, email: session.user.email });
|
|
51
57
|
setAccessToken(session.access_token);
|
|
52
58
|
setDisplayNameState(getDisplayNameFromUser2(session.user));
|
|
59
|
+
setAvatarUrl(getAvatarUrlFromUser2(session.user));
|
|
53
60
|
}
|
|
54
61
|
client.auth.onAuthStateChange((_event, session2) => {
|
|
55
62
|
if (!session2 || !session2.user) {
|
|
56
63
|
setUser(null);
|
|
57
64
|
setAccessToken(null);
|
|
58
65
|
setDisplayNameState("");
|
|
66
|
+
setAvatarUrl(null);
|
|
59
67
|
} else {
|
|
60
68
|
setUser({ id: session2.user.id, email: session2.user.email });
|
|
61
69
|
setAccessToken(session2.access_token);
|
|
62
70
|
setDisplayNameState(getDisplayNameFromUser2(session2.user));
|
|
71
|
+
setAvatarUrl(getAvatarUrlFromUser2(session2.user));
|
|
63
72
|
}
|
|
64
73
|
});
|
|
65
74
|
} catch (err) {
|
|
@@ -104,6 +113,7 @@ function AuthProvider(props) {
|
|
|
104
113
|
setUser(null);
|
|
105
114
|
setAccessToken(null);
|
|
106
115
|
setDisplayNameState("");
|
|
116
|
+
setAvatarUrl(null);
|
|
107
117
|
}, [supabase]);
|
|
108
118
|
const value = react.useMemo(
|
|
109
119
|
() => ({
|
|
@@ -112,6 +122,7 @@ function AuthProvider(props) {
|
|
|
112
122
|
accessToken,
|
|
113
123
|
isReady,
|
|
114
124
|
displayName,
|
|
125
|
+
avatarUrl,
|
|
115
126
|
signInWithEmail,
|
|
116
127
|
signInWithGitHub,
|
|
117
128
|
signOut
|
|
@@ -122,6 +133,7 @@ function AuthProvider(props) {
|
|
|
122
133
|
accessToken,
|
|
123
134
|
isReady,
|
|
124
135
|
displayName,
|
|
136
|
+
avatarUrl,
|
|
125
137
|
signInWithEmail,
|
|
126
138
|
signInWithGitHub,
|
|
127
139
|
signOut
|
|
@@ -136,6 +148,49 @@ function useAuthInternal() {
|
|
|
136
148
|
}
|
|
137
149
|
return ctx;
|
|
138
150
|
}
|
|
151
|
+
|
|
152
|
+
// src/selector.ts
|
|
153
|
+
function getSelector(element, root) {
|
|
154
|
+
if (element === root) return ":scope";
|
|
155
|
+
const id = element.id;
|
|
156
|
+
if (id && /^[a-zA-Z][\w-]*$/.test(id) && !id.toLowerCase().startsWith("radix")) {
|
|
157
|
+
try {
|
|
158
|
+
const matches = root.querySelectorAll(`#${escapeSelectorId(id)}`);
|
|
159
|
+
if (matches.length === 1 && matches[0] === element) return `#${escapeSelectorId(id)}`;
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const path = [];
|
|
164
|
+
let current = element;
|
|
165
|
+
while (current && current !== root) {
|
|
166
|
+
let selector = current.tagName.toLowerCase();
|
|
167
|
+
if (current.id && /^[a-zA-Z][\w-]*$/.test(current.id)) {
|
|
168
|
+
selector += `#${escapeSelectorId(current.id)}`;
|
|
169
|
+
path.unshift(selector);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
const parent = current.parentElement;
|
|
173
|
+
if (!parent) break;
|
|
174
|
+
const siblings = Array.from(parent.children).filter(
|
|
175
|
+
(el) => el.tagName === current.tagName
|
|
176
|
+
);
|
|
177
|
+
const index = siblings.indexOf(current);
|
|
178
|
+
if (siblings.length > 1) selector += `:nth-of-type(${index + 1})`;
|
|
179
|
+
path.unshift(selector);
|
|
180
|
+
current = parent;
|
|
181
|
+
}
|
|
182
|
+
return path.join(" > ");
|
|
183
|
+
}
|
|
184
|
+
function escapeSelectorId(id) {
|
|
185
|
+
return CSS.escape(id);
|
|
186
|
+
}
|
|
187
|
+
function isElementVisible(el) {
|
|
188
|
+
const rect = el.getBoundingClientRect();
|
|
189
|
+
if (rect.width === 0 && rect.height === 0) return false;
|
|
190
|
+
const style = window.getComputedStyle(el);
|
|
191
|
+
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
139
194
|
var CommentsContext = react.createContext(void 0);
|
|
140
195
|
function CommentsProvider(props) {
|
|
141
196
|
var _a;
|
|
@@ -148,6 +203,7 @@ function CommentsProvider(props) {
|
|
|
148
203
|
const [commentModeEnabled, setCommentModeEnabled] = react.useState(true);
|
|
149
204
|
const [hoveredRect, setHoveredRect] = react.useState(null);
|
|
150
205
|
const [pendingAnchor, setPendingAnchor] = react.useState(null);
|
|
206
|
+
const pendingAnchorElementRef = react.useRef(null);
|
|
151
207
|
const surfaceRef = react.useRef(null);
|
|
152
208
|
const surfaceClickHandlerRef = react.useRef(null);
|
|
153
209
|
const onPinClickRef = react.useRef(null);
|
|
@@ -173,11 +229,17 @@ function CommentsProvider(props) {
|
|
|
173
229
|
}
|
|
174
230
|
const data = await response.json();
|
|
175
231
|
if (cancelled) return;
|
|
176
|
-
const mapped = (_b = (_a2 = data.threads) == null ? void 0 : _a2.map((t) =>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
232
|
+
const mapped = (_b = (_a2 = data.threads) == null ? void 0 : _a2.map((t) => {
|
|
233
|
+
var _a3, _b2;
|
|
234
|
+
return {
|
|
235
|
+
id: t.id,
|
|
236
|
+
anchor: { x: t.anchorX, y: t.anchorY },
|
|
237
|
+
anchorSelector: (_a3 = t.anchorSelector) != null ? _a3 : null,
|
|
238
|
+
anchorRelative: typeof t.anchorRelativeX === "number" && typeof t.anchorRelativeY === "number" ? { x: t.anchorRelativeX, y: t.anchorRelativeY } : null,
|
|
239
|
+
status: "open",
|
|
240
|
+
firstCommentAuthorAvatarUrl: (_b2 = t.firstCommentAuthorAvatarUrl) != null ? _b2 : null
|
|
241
|
+
};
|
|
242
|
+
})) != null ? _b : [];
|
|
181
243
|
setThreads(mapped);
|
|
182
244
|
} catch (err) {
|
|
183
245
|
if (cancelled) return;
|
|
@@ -195,11 +257,30 @@ function CommentsProvider(props) {
|
|
|
195
257
|
};
|
|
196
258
|
}, [apiBaseUrl, config.projectSlug, config.surfaceId, accessToken, isAuthReady]);
|
|
197
259
|
const createThread = react.useCallback(
|
|
198
|
-
async (anchor, initialCommentBody, initialAuthorName) => {
|
|
260
|
+
async (anchor, initialCommentBody, initialAuthorName, anchorElement, initialAuthorAvatarUrl) => {
|
|
261
|
+
var _a2, _b, _c;
|
|
262
|
+
const root = surfaceRef.current;
|
|
263
|
+
const anchorSelector = root && anchorElement && root.contains(anchorElement) ? getSelector(anchorElement, root) : null;
|
|
264
|
+
let anchorRelative = null;
|
|
265
|
+
if (root && anchorElement && anchorSelector) {
|
|
266
|
+
const surfaceRect = root.getBoundingClientRect();
|
|
267
|
+
const elRect = anchorElement.getBoundingClientRect();
|
|
268
|
+
if (elRect.width > 0 && elRect.height > 0) {
|
|
269
|
+
const clickX = surfaceRect.left + anchor.x * surfaceRect.width;
|
|
270
|
+
const clickY = surfaceRect.top + anchor.y * surfaceRect.height;
|
|
271
|
+
anchorRelative = {
|
|
272
|
+
x: Math.max(0, Math.min(1, (clickX - elRect.left) / elRect.width)),
|
|
273
|
+
y: Math.max(0, Math.min(1, (clickY - elRect.top) / elRect.height))
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
199
277
|
const optimisticThread = {
|
|
200
278
|
id: `${Date.now()}`,
|
|
201
279
|
anchor,
|
|
202
|
-
|
|
280
|
+
anchorSelector: anchorSelector != null ? anchorSelector : void 0,
|
|
281
|
+
anchorRelative: anchorRelative != null ? anchorRelative : void 0,
|
|
282
|
+
status: "open",
|
|
283
|
+
firstCommentAuthorAvatarUrl: initialAuthorAvatarUrl != null ? initialAuthorAvatarUrl : null
|
|
203
284
|
};
|
|
204
285
|
setThreads((prev) => [...prev, optimisticThread]);
|
|
205
286
|
try {
|
|
@@ -216,8 +297,12 @@ function CommentsProvider(props) {
|
|
|
216
297
|
surfaceId: config.surfaceId,
|
|
217
298
|
anchorX: anchor.x,
|
|
218
299
|
anchorY: anchor.y,
|
|
300
|
+
anchorSelector: anchorSelector != null ? anchorSelector : null,
|
|
301
|
+
anchorRelativeX: (_a2 = anchorRelative == null ? void 0 : anchorRelative.x) != null ? _a2 : null,
|
|
302
|
+
anchorRelativeY: (_b = anchorRelative == null ? void 0 : anchorRelative.y) != null ? _b : null,
|
|
219
303
|
initialCommentBody: initialCommentBody != null ? initialCommentBody : null,
|
|
220
|
-
initialAuthorName: initialAuthorName != null ? initialAuthorName : null
|
|
304
|
+
initialAuthorName: initialAuthorName != null ? initialAuthorName : null,
|
|
305
|
+
initialAuthorAvatarUrl: initialAuthorAvatarUrl != null ? initialAuthorAvatarUrl : null
|
|
221
306
|
})
|
|
222
307
|
});
|
|
223
308
|
if (!response.ok) {
|
|
@@ -226,7 +311,8 @@ function CommentsProvider(props) {
|
|
|
226
311
|
const data = await response.json();
|
|
227
312
|
const persistedThread = {
|
|
228
313
|
...optimisticThread,
|
|
229
|
-
id: data.id
|
|
314
|
+
id: data.id,
|
|
315
|
+
firstCommentAuthorAvatarUrl: (_c = initialAuthorAvatarUrl != null ? initialAuthorAvatarUrl : optimisticThread.firstCommentAuthorAvatarUrl) != null ? _c : null
|
|
230
316
|
};
|
|
231
317
|
setThreads(
|
|
232
318
|
(prev) => prev.map((t) => t === optimisticThread ? persistedThread : t)
|
|
@@ -260,13 +346,14 @@ function CommentsProvider(props) {
|
|
|
260
346
|
}
|
|
261
347
|
const data = await response.json();
|
|
262
348
|
const mapped = (_b = (_a2 = data.comments) == null ? void 0 : _a2.map((c) => {
|
|
263
|
-
var _a3;
|
|
349
|
+
var _a3, _b2;
|
|
264
350
|
return {
|
|
265
351
|
id: c.id,
|
|
266
352
|
threadId: c.threadId,
|
|
267
353
|
body: c.body,
|
|
268
354
|
createdAt: c.createdAt,
|
|
269
|
-
authorName: (_a3 = c.authorName) != null ? _a3 : null
|
|
355
|
+
authorName: (_a3 = c.authorName) != null ? _a3 : null,
|
|
356
|
+
authorAvatarUrl: (_b2 = c.authorAvatarUrl) != null ? _b2 : null
|
|
270
357
|
};
|
|
271
358
|
})) != null ? _b : [];
|
|
272
359
|
setCommentsByThread((prev) => ({
|
|
@@ -282,7 +369,7 @@ function CommentsProvider(props) {
|
|
|
282
369
|
[apiBaseUrl, accessToken]
|
|
283
370
|
);
|
|
284
371
|
const addComment = react.useCallback(
|
|
285
|
-
async (threadId, body, authorName) => {
|
|
372
|
+
async (threadId, body, authorName, authorAvatarUrl) => {
|
|
286
373
|
const trimmed = body.trim();
|
|
287
374
|
if (!trimmed) {
|
|
288
375
|
throw new Error("Comment body is empty");
|
|
@@ -291,7 +378,8 @@ function CommentsProvider(props) {
|
|
|
291
378
|
id: `${Date.now()}`,
|
|
292
379
|
threadId,
|
|
293
380
|
body: trimmed,
|
|
294
|
-
authorName: authorName != null ? authorName : null
|
|
381
|
+
authorName: authorName != null ? authorName : null,
|
|
382
|
+
authorAvatarUrl: authorAvatarUrl != null ? authorAvatarUrl : null
|
|
295
383
|
};
|
|
296
384
|
setCommentsByThread((prev) => {
|
|
297
385
|
var _a2;
|
|
@@ -307,7 +395,7 @@ function CommentsProvider(props) {
|
|
|
307
395
|
"Content-Type": "application/json",
|
|
308
396
|
...accessToken ? { Authorization: `Bearer ${accessToken}` } : {}
|
|
309
397
|
},
|
|
310
|
-
body: JSON.stringify({ threadId, body: trimmed, authorName })
|
|
398
|
+
body: JSON.stringify({ threadId, body: trimmed, authorName, authorAvatarUrl: authorAvatarUrl != null ? authorAvatarUrl : null })
|
|
311
399
|
});
|
|
312
400
|
if (!response.ok) {
|
|
313
401
|
throw new Error(`Failed to create comment: ${response.status}`);
|
|
@@ -317,7 +405,9 @@ function CommentsProvider(props) {
|
|
|
317
405
|
id: data.id,
|
|
318
406
|
threadId,
|
|
319
407
|
body: trimmed,
|
|
320
|
-
createdAt: data.createdAt
|
|
408
|
+
createdAt: data.createdAt,
|
|
409
|
+
authorName: authorName != null ? authorName : null,
|
|
410
|
+
authorAvatarUrl: authorAvatarUrl != null ? authorAvatarUrl : null
|
|
321
411
|
};
|
|
322
412
|
setCommentsByThread((prev) => {
|
|
323
413
|
var _a2;
|
|
@@ -384,6 +474,7 @@ function CommentsProvider(props) {
|
|
|
384
474
|
surfaceClickHandlerRef,
|
|
385
475
|
pendingAnchor,
|
|
386
476
|
setPendingAnchor,
|
|
477
|
+
pendingAnchorElementRef,
|
|
387
478
|
onPinClickRef
|
|
388
479
|
}),
|
|
389
480
|
[
|
|
@@ -430,22 +521,33 @@ function useComments() {
|
|
|
430
521
|
deleteThread: ctx.deleteThread
|
|
431
522
|
};
|
|
432
523
|
}
|
|
433
|
-
var
|
|
524
|
+
var PIN_SIZE = 28;
|
|
525
|
+
var PIN_BASE_STYLE = {
|
|
434
526
|
position: "absolute",
|
|
435
527
|
transform: "translate(-50%, -50%)",
|
|
436
|
-
width:
|
|
437
|
-
height:
|
|
528
|
+
width: PIN_SIZE,
|
|
529
|
+
height: PIN_SIZE,
|
|
438
530
|
borderRadius: "999px",
|
|
439
|
-
background: "#f97316",
|
|
440
|
-
border: "2px solid #fff",
|
|
441
|
-
boxShadow: "0 4px 10px rgba(0,0,0,0.25)",
|
|
442
531
|
display: "flex",
|
|
443
532
|
alignItems: "center",
|
|
444
533
|
justifyContent: "center",
|
|
534
|
+
cursor: "pointer"
|
|
535
|
+
};
|
|
536
|
+
var PIN_DOT_STYLE = {
|
|
537
|
+
...PIN_BASE_STYLE,
|
|
538
|
+
background: "#f97316",
|
|
539
|
+
border: "2px solid #fff",
|
|
540
|
+
boxShadow: "0 4px 10px rgba(0,0,0,0.25)",
|
|
445
541
|
color: "#fff",
|
|
446
542
|
fontSize: 10,
|
|
447
|
-
fontWeight: 600
|
|
448
|
-
|
|
543
|
+
fontWeight: 600
|
|
544
|
+
};
|
|
545
|
+
var PIN_AVATAR_STYLE = {
|
|
546
|
+
...PIN_BASE_STYLE,
|
|
547
|
+
border: "2px solid #fff",
|
|
548
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.2)",
|
|
549
|
+
overflow: "hidden",
|
|
550
|
+
backgroundColor: "#e5e7eb"
|
|
449
551
|
};
|
|
450
552
|
function CommentSurface(props) {
|
|
451
553
|
const {
|
|
@@ -457,6 +559,67 @@ function CommentSurface(props) {
|
|
|
457
559
|
onPinClickRef
|
|
458
560
|
} = useCommentsInternal();
|
|
459
561
|
const { threads } = useComments();
|
|
562
|
+
const [resolvedPinPositions, setResolvedPinPositions] = react.useState({});
|
|
563
|
+
const recalcPinPositions = react.useCallback(() => {
|
|
564
|
+
const root = surfaceRef.current;
|
|
565
|
+
if (!root) return;
|
|
566
|
+
const surfaceRect = root.getBoundingClientRect();
|
|
567
|
+
if (surfaceRect.width === 0 && surfaceRect.height === 0) return;
|
|
568
|
+
const next = {};
|
|
569
|
+
threads.forEach((thread) => {
|
|
570
|
+
if (thread.anchorSelector) {
|
|
571
|
+
try {
|
|
572
|
+
const el = root.querySelector(thread.anchorSelector);
|
|
573
|
+
if (!el || !(el instanceof HTMLElement)) {
|
|
574
|
+
next[thread.id] = "hide";
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
if (!isElementVisible(el)) {
|
|
578
|
+
next[thread.id] = "hide";
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
const elRect = el.getBoundingClientRect();
|
|
582
|
+
const rel = thread.anchorRelative;
|
|
583
|
+
const rx = rel && typeof rel.x === "number" ? rel.x : 0.5;
|
|
584
|
+
const ry = rel && typeof rel.y === "number" ? rel.y : 0.5;
|
|
585
|
+
const left = (elRect.left - surfaceRect.left + rx * elRect.width) / surfaceRect.width;
|
|
586
|
+
const top = (elRect.top - surfaceRect.top + ry * elRect.height) / surfaceRect.height;
|
|
587
|
+
next[thread.id] = { left, top };
|
|
588
|
+
} catch {
|
|
589
|
+
next[thread.id] = "hide";
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
setResolvedPinPositions(next);
|
|
594
|
+
}, [threads, surfaceRef]);
|
|
595
|
+
react.useLayoutEffect(() => {
|
|
596
|
+
recalcPinPositions();
|
|
597
|
+
}, [recalcPinPositions]);
|
|
598
|
+
react.useLayoutEffect(() => {
|
|
599
|
+
const root = surfaceRef.current;
|
|
600
|
+
if (!root) return;
|
|
601
|
+
const scrollables = [root];
|
|
602
|
+
const walk = (el) => {
|
|
603
|
+
if (el === root) return;
|
|
604
|
+
const style = window.getComputedStyle(el);
|
|
605
|
+
const overflow = style.overflow + style.overflowX + style.overflowY;
|
|
606
|
+
if (overflow.includes("scroll") || overflow.includes("auto")) {
|
|
607
|
+
scrollables.push(el);
|
|
608
|
+
}
|
|
609
|
+
if (el instanceof HTMLElement && el.children.length) {
|
|
610
|
+
Array.from(el.children).forEach(walk);
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
walk(root);
|
|
614
|
+
const handleScroll = () => recalcPinPositions();
|
|
615
|
+
scrollables.forEach((el) => el.addEventListener("scroll", handleScroll, { passive: true }));
|
|
616
|
+
const ro = new ResizeObserver(handleScroll);
|
|
617
|
+
ro.observe(root);
|
|
618
|
+
return () => {
|
|
619
|
+
scrollables.forEach((el) => el.removeEventListener("scroll", handleScroll));
|
|
620
|
+
ro.disconnect();
|
|
621
|
+
};
|
|
622
|
+
}, [recalcPinPositions, surfaceRef]);
|
|
460
623
|
const handleMouseMove = react.useCallback(
|
|
461
624
|
(e) => {
|
|
462
625
|
if (!commentModeEnabled) return;
|
|
@@ -508,42 +671,58 @@ function CommentSurface(props) {
|
|
|
508
671
|
zIndex: 1
|
|
509
672
|
},
|
|
510
673
|
children: [
|
|
511
|
-
threads.map((thread) =>
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
674
|
+
threads.map((thread) => {
|
|
675
|
+
const resolved = resolvedPinPositions[thread.id];
|
|
676
|
+
if (resolved === "hide") return null;
|
|
677
|
+
const left = typeof resolved === "object" ? resolved.left : thread.anchor.x;
|
|
678
|
+
const top = typeof resolved === "object" ? resolved.top : thread.anchor.y;
|
|
679
|
+
const pinStyle = {
|
|
680
|
+
...thread.firstCommentAuthorAvatarUrl ? PIN_AVATAR_STYLE : PIN_DOT_STYLE,
|
|
681
|
+
left: `${left * 100}%`,
|
|
682
|
+
top: `${top * 100}%`,
|
|
683
|
+
pointerEvents: "auto"
|
|
684
|
+
};
|
|
685
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
686
|
+
"div",
|
|
687
|
+
{
|
|
688
|
+
"data-commentator-pin": true,
|
|
689
|
+
role: "button",
|
|
690
|
+
tabIndex: 0,
|
|
691
|
+
onClick: (e) => {
|
|
692
|
+
var _a;
|
|
526
693
|
e.stopPropagation();
|
|
527
|
-
(_a = onPinClickRef.current) == null ? void 0 : _a.call(onPinClickRef, thread.id,
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
694
|
+
(_a = onPinClickRef.current) == null ? void 0 : _a.call(onPinClickRef, thread.id, e.clientX, e.clientY);
|
|
695
|
+
},
|
|
696
|
+
onKeyDown: (e) => {
|
|
697
|
+
var _a;
|
|
698
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
699
|
+
e.preventDefault();
|
|
700
|
+
e.stopPropagation();
|
|
701
|
+
(_a = onPinClickRef.current) == null ? void 0 : _a.call(onPinClickRef, thread.id, 0, 0);
|
|
702
|
+
}
|
|
703
|
+
},
|
|
704
|
+
style: pinStyle,
|
|
705
|
+
children: thread.firstCommentAuthorAvatarUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
706
|
+
"img",
|
|
707
|
+
{
|
|
708
|
+
src: thread.firstCommentAuthorAvatarUrl,
|
|
709
|
+
alt: "",
|
|
710
|
+
width: PIN_SIZE,
|
|
711
|
+
height: PIN_SIZE,
|
|
712
|
+
style: { display: "block", width: PIN_SIZE, height: PIN_SIZE, objectFit: "cover" }
|
|
713
|
+
}
|
|
714
|
+
) : "\u25CF"
|
|
535
715
|
},
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
)),
|
|
716
|
+
thread.id
|
|
717
|
+
);
|
|
718
|
+
}),
|
|
540
719
|
pendingAnchor && /* @__PURE__ */ jsxRuntime.jsx(
|
|
541
720
|
"div",
|
|
542
721
|
{
|
|
543
722
|
"aria-hidden": true,
|
|
544
723
|
"data-commentator-pin": true,
|
|
545
724
|
style: {
|
|
546
|
-
...
|
|
725
|
+
...PIN_DOT_STYLE,
|
|
547
726
|
left: `${pendingAnchor.x * 100}%`,
|
|
548
727
|
top: `${pendingAnchor.y * 100}%`,
|
|
549
728
|
cursor: "default",
|
|
@@ -569,11 +748,12 @@ function CommentSettings() {
|
|
|
569
748
|
const {
|
|
570
749
|
user,
|
|
571
750
|
displayName,
|
|
751
|
+
avatarUrl,
|
|
572
752
|
signOut,
|
|
573
753
|
isReady: isAuthReady,
|
|
574
754
|
signInWithGitHub
|
|
575
755
|
} = useCommentAuth();
|
|
576
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
756
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
577
757
|
"div",
|
|
578
758
|
{
|
|
579
759
|
style: {
|
|
@@ -585,90 +765,79 @@ function CommentSettings() {
|
|
|
585
765
|
flexDirection: "column",
|
|
586
766
|
gap: 8
|
|
587
767
|
},
|
|
588
|
-
children:
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
{
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
),
|
|
610
|
-
user && /* @__PURE__ */ jsxRuntime.jsx(
|
|
611
|
-
"button",
|
|
612
|
-
{
|
|
613
|
-
type: "button",
|
|
614
|
-
onClick: () => signOut().catch(() => {
|
|
615
|
-
}),
|
|
616
|
-
style: {
|
|
617
|
-
borderRadius: 999,
|
|
618
|
-
border: "1px solid #e5e7eb",
|
|
619
|
-
backgroundColor: "#ffffff",
|
|
620
|
-
padding: "4px 10px",
|
|
621
|
-
fontSize: 11,
|
|
622
|
-
color: "#374151",
|
|
623
|
-
cursor: "pointer"
|
|
624
|
-
},
|
|
625
|
-
children: "Sign out"
|
|
768
|
+
children: user ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
769
|
+
"div",
|
|
770
|
+
{
|
|
771
|
+
style: {
|
|
772
|
+
display: "flex",
|
|
773
|
+
alignItems: "center",
|
|
774
|
+
gap: 8,
|
|
775
|
+
fontSize: 12,
|
|
776
|
+
color: "#6b7280"
|
|
777
|
+
},
|
|
778
|
+
children: [
|
|
779
|
+
avatarUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
780
|
+
"img",
|
|
781
|
+
{
|
|
782
|
+
src: avatarUrl,
|
|
783
|
+
alt: "",
|
|
784
|
+
width: 24,
|
|
785
|
+
height: 24,
|
|
786
|
+
style: {
|
|
787
|
+
borderRadius: "50%",
|
|
788
|
+
flexShrink: 0
|
|
626
789
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
790
|
+
}
|
|
791
|
+
),
|
|
792
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: displayName || user.email || "unknown user" }),
|
|
793
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
794
|
+
"button",
|
|
795
|
+
{
|
|
796
|
+
type: "button",
|
|
797
|
+
onClick: () => signOut().catch(() => {
|
|
798
|
+
}),
|
|
799
|
+
style: {
|
|
800
|
+
borderRadius: 999,
|
|
801
|
+
border: "1px solid #e5e7eb",
|
|
802
|
+
backgroundColor: "#ffffff",
|
|
803
|
+
padding: "4px 10px",
|
|
804
|
+
fontSize: 11,
|
|
805
|
+
color: "#374151",
|
|
806
|
+
cursor: "pointer"
|
|
807
|
+
},
|
|
808
|
+
children: "Sign out"
|
|
809
|
+
}
|
|
810
|
+
)
|
|
811
|
+
]
|
|
812
|
+
}
|
|
813
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 4 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
814
|
+
"button",
|
|
815
|
+
{
|
|
816
|
+
type: "button",
|
|
817
|
+
onClick: () => signInWithGitHub().catch(() => {
|
|
818
|
+
}),
|
|
819
|
+
disabled: !isAuthReady,
|
|
820
|
+
style: {
|
|
821
|
+
width: "100%",
|
|
822
|
+
padding: "8px 12px",
|
|
823
|
+
borderRadius: 10,
|
|
824
|
+
border: "1px solid #e5e7eb",
|
|
825
|
+
backgroundColor: "#24292f",
|
|
826
|
+
color: "#fff",
|
|
827
|
+
fontSize: 13,
|
|
828
|
+
fontWeight: 500,
|
|
829
|
+
cursor: isAuthReady ? "pointer" : "default",
|
|
830
|
+
display: "flex",
|
|
831
|
+
alignItems: "center",
|
|
832
|
+
justifyContent: "center",
|
|
833
|
+
gap: 8
|
|
834
|
+
},
|
|
835
|
+
children: [
|
|
836
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.17 6.839 9.49.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.464-1.11-1.464-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.831.092-.646.35-1.086.636-1.336-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0112 6.836c.85.004 1.705.114 2.504.336 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.578.688.48C19.138 20.167 22 16.418 22 12c0-5.523-4.477-10-10-10z" }) }),
|
|
837
|
+
"Sign in with GitHub"
|
|
838
|
+
]
|
|
839
|
+
}
|
|
840
|
+
) })
|
|
672
841
|
}
|
|
673
842
|
);
|
|
674
843
|
}
|
|
@@ -716,13 +885,15 @@ function CommentOverlay(props) {
|
|
|
716
885
|
surfaceClickHandlerRef,
|
|
717
886
|
pendingAnchor,
|
|
718
887
|
setPendingAnchor,
|
|
888
|
+
pendingAnchorElementRef,
|
|
719
889
|
onPinClickRef
|
|
720
890
|
} = useCommentsInternal();
|
|
721
891
|
const {
|
|
722
892
|
user,
|
|
723
893
|
isReady: isAuthReady,
|
|
724
894
|
signInWithGitHub,
|
|
725
|
-
displayName
|
|
895
|
+
displayName,
|
|
896
|
+
avatarUrl
|
|
726
897
|
} = useCommentAuth();
|
|
727
898
|
const [activeThreadId, setActiveThreadId] = react.useState(null);
|
|
728
899
|
const [draft, setDraft] = react.useState("");
|
|
@@ -743,18 +914,19 @@ function CommentOverlay(props) {
|
|
|
743
914
|
}, [activeThreadId, pendingAnchor, commentsByThread, loadComments]);
|
|
744
915
|
const handleSurfaceClick = react.useCallback(
|
|
745
916
|
(event) => {
|
|
746
|
-
var _a2;
|
|
917
|
+
var _a2, _b;
|
|
747
918
|
setShowSettings(false);
|
|
748
919
|
const rect = (_a2 = surfaceRef.current) == null ? void 0 : _a2.getBoundingClientRect();
|
|
749
920
|
if (!rect) return;
|
|
750
921
|
const x = (event.clientX - rect.left) / rect.width;
|
|
751
922
|
const y = (event.clientY - rect.top) / rect.height;
|
|
752
923
|
setPendingAnchor({ x, y });
|
|
924
|
+
pendingAnchorElementRef.current = (_b = event.target) != null ? _b : null;
|
|
753
925
|
setActiveThreadId(null);
|
|
754
926
|
setDraft("");
|
|
755
927
|
setPanelPosition(computePanelPosition(event.clientX, event.clientY));
|
|
756
928
|
},
|
|
757
|
-
[setPendingAnchor, surfaceRef]
|
|
929
|
+
[setPendingAnchor, surfaceRef, pendingAnchorElementRef]
|
|
758
930
|
);
|
|
759
931
|
react.useEffect(() => {
|
|
760
932
|
surfaceClickHandlerRef.current = handleSurfaceClick;
|
|
@@ -782,6 +954,19 @@ function CommentOverlay(props) {
|
|
|
782
954
|
setDraft("");
|
|
783
955
|
setPanelPosition(null);
|
|
784
956
|
}, [commentModeEnabled, setCommentModeEnabled, setHoveredRect, setPendingAnchor]);
|
|
957
|
+
react.useEffect(() => {
|
|
958
|
+
const onKeyDown = (e) => {
|
|
959
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "m") {
|
|
960
|
+
const target = e.target;
|
|
961
|
+
const isEditable = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
|
|
962
|
+
if (isEditable) return;
|
|
963
|
+
e.preventDefault();
|
|
964
|
+
handleToggle();
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
window.addEventListener("keydown", onKeyDown);
|
|
968
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
969
|
+
}, [handleToggle]);
|
|
785
970
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
786
971
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
787
972
|
"div",
|
|
@@ -845,7 +1030,36 @@ function CommentOverlay(props) {
|
|
|
845
1030
|
fontSize: 14,
|
|
846
1031
|
color: "#4b5563"
|
|
847
1032
|
},
|
|
848
|
-
children:
|
|
1033
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1034
|
+
"svg",
|
|
1035
|
+
{
|
|
1036
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1037
|
+
fill: "none",
|
|
1038
|
+
viewBox: "0 0 24 24",
|
|
1039
|
+
strokeWidth: 1.5,
|
|
1040
|
+
stroke: "currentColor",
|
|
1041
|
+
style: { width: 18, height: 18 },
|
|
1042
|
+
"aria-hidden": true,
|
|
1043
|
+
children: [
|
|
1044
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1045
|
+
"path",
|
|
1046
|
+
{
|
|
1047
|
+
strokeLinecap: "round",
|
|
1048
|
+
strokeLinejoin: "round",
|
|
1049
|
+
d: "M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z"
|
|
1050
|
+
}
|
|
1051
|
+
),
|
|
1052
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1053
|
+
"path",
|
|
1054
|
+
{
|
|
1055
|
+
strokeLinecap: "round",
|
|
1056
|
+
strokeLinejoin: "round",
|
|
1057
|
+
d: "M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
|
|
1058
|
+
}
|
|
1059
|
+
)
|
|
1060
|
+
]
|
|
1061
|
+
}
|
|
1062
|
+
)
|
|
849
1063
|
}
|
|
850
1064
|
)
|
|
851
1065
|
]
|
|
@@ -894,15 +1108,40 @@ function CommentOverlay(props) {
|
|
|
894
1108
|
marginBottom: 4
|
|
895
1109
|
},
|
|
896
1110
|
children: [
|
|
897
|
-
/* @__PURE__ */ jsxRuntime.
|
|
898
|
-
"
|
|
1111
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1112
|
+
"div",
|
|
899
1113
|
{
|
|
900
1114
|
style: {
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1115
|
+
display: "flex",
|
|
1116
|
+
alignItems: "center",
|
|
1117
|
+
gap: 8
|
|
904
1118
|
},
|
|
905
|
-
children:
|
|
1119
|
+
children: [
|
|
1120
|
+
user && avatarUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1121
|
+
"img",
|
|
1122
|
+
{
|
|
1123
|
+
src: avatarUrl,
|
|
1124
|
+
alt: "",
|
|
1125
|
+
width: 24,
|
|
1126
|
+
height: 24,
|
|
1127
|
+
style: {
|
|
1128
|
+
borderRadius: "50%",
|
|
1129
|
+
flexShrink: 0
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
),
|
|
1133
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1134
|
+
"span",
|
|
1135
|
+
{
|
|
1136
|
+
style: {
|
|
1137
|
+
fontSize: 13,
|
|
1138
|
+
fontWeight: 600,
|
|
1139
|
+
color: "#111827"
|
|
1140
|
+
},
|
|
1141
|
+
children: user ? activeThreadId ? "Thread" : "New comment" : "Sign in to comment"
|
|
1142
|
+
}
|
|
1143
|
+
)
|
|
1144
|
+
]
|
|
906
1145
|
}
|
|
907
1146
|
),
|
|
908
1147
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
@@ -1009,19 +1248,24 @@ function CommentOverlay(props) {
|
|
|
1009
1248
|
"form",
|
|
1010
1249
|
{
|
|
1011
1250
|
onSubmit: async (event) => {
|
|
1251
|
+
var _a2;
|
|
1012
1252
|
event.preventDefault();
|
|
1013
1253
|
if (!draft.trim()) return;
|
|
1014
1254
|
try {
|
|
1015
1255
|
if (activeThreadId) {
|
|
1016
|
-
await addComment(activeThreadId, draft, displayName);
|
|
1256
|
+
await addComment(activeThreadId, draft, displayName, avatarUrl != null ? avatarUrl : null);
|
|
1017
1257
|
} else if (pendingAnchor) {
|
|
1258
|
+
const element = (_a2 = pendingAnchorElementRef.current) != null ? _a2 : void 0;
|
|
1018
1259
|
const thread = await createThread(
|
|
1019
1260
|
pendingAnchor,
|
|
1020
1261
|
draft,
|
|
1021
|
-
displayName || null
|
|
1262
|
+
displayName || null,
|
|
1263
|
+
element,
|
|
1264
|
+
avatarUrl != null ? avatarUrl : null
|
|
1022
1265
|
);
|
|
1023
1266
|
setActiveThreadId(thread.id);
|
|
1024
1267
|
setPendingAnchor(null);
|
|
1268
|
+
pendingAnchorElementRef.current = null;
|
|
1025
1269
|
}
|
|
1026
1270
|
setDraft("");
|
|
1027
1271
|
} catch (err) {
|
|
@@ -1039,6 +1283,7 @@ function CommentOverlay(props) {
|
|
|
1039
1283
|
placeholder: "Add a comment...",
|
|
1040
1284
|
style: {
|
|
1041
1285
|
width: "100%",
|
|
1286
|
+
color: "#000000",
|
|
1042
1287
|
resize: "none",
|
|
1043
1288
|
fontSize: 13,
|
|
1044
1289
|
fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, sans-serif",
|
|
@@ -1105,11 +1350,32 @@ function CommentOverlay(props) {
|
|
|
1105
1350
|
)
|
|
1106
1351
|
] });
|
|
1107
1352
|
}
|
|
1353
|
+
function Commentator(props) {
|
|
1354
|
+
const {
|
|
1355
|
+
config,
|
|
1356
|
+
position = "right",
|
|
1357
|
+
surfaceStyle,
|
|
1358
|
+
surfaceClassName,
|
|
1359
|
+
children
|
|
1360
|
+
} = props;
|
|
1361
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(CommentProvider, { config, children: [
|
|
1362
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1363
|
+
CommentSurface,
|
|
1364
|
+
{
|
|
1365
|
+
style: { minHeight: "100%", position: "relative", ...surfaceStyle },
|
|
1366
|
+
className: surfaceClassName,
|
|
1367
|
+
children
|
|
1368
|
+
}
|
|
1369
|
+
),
|
|
1370
|
+
/* @__PURE__ */ jsxRuntime.jsx(CommentOverlay, { position })
|
|
1371
|
+
] });
|
|
1372
|
+
}
|
|
1108
1373
|
|
|
1109
1374
|
exports.CommentOverlay = CommentOverlay;
|
|
1110
1375
|
exports.CommentProvider = CommentProvider;
|
|
1111
1376
|
exports.CommentSettings = CommentSettings;
|
|
1112
1377
|
exports.CommentSurface = CommentSurface;
|
|
1378
|
+
exports.Commentator = Commentator;
|
|
1113
1379
|
exports.useCommentAuth = useCommentAuth;
|
|
1114
1380
|
exports.useComments = useComments;
|
|
1115
1381
|
//# sourceMappingURL=index.js.map
|