review-lens-react 0.1.0 → 0.1.2
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/review-lens-react.js +494 -275
- package/dist/review-lens-react.umd.cjs +1 -1
- package/dist/styles.css +1 -1
- package/dist/types.d.ts +12 -0
- package/package.json +1 -1
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { createContext as
|
|
3
|
-
const
|
|
1
|
+
import { jsx as i, jsxs as f, Fragment as Y } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as V, useMemo as M, useState as R, useCallback as P, useEffect as T, useContext as Z, useRef as ee, useLayoutEffect as te } from "react";
|
|
3
|
+
const ne = [
|
|
4
4
|
"https://www.googleapis.com/auth/spreadsheets",
|
|
5
5
|
"https://www.googleapis.com/auth/userinfo.email"
|
|
6
|
-
].join(" "),
|
|
7
|
-
function
|
|
6
|
+
].join(" "), oe = "https://www.googleapis.com/oauth2/v3/userinfo";
|
|
7
|
+
function re(e) {
|
|
8
8
|
const n = e.feedbackSheetName ?? "Feedback", t = e.usersSheetName ?? "Users";
|
|
9
9
|
let r, o;
|
|
10
|
-
async function
|
|
11
|
-
return r ?? (r =
|
|
10
|
+
async function c() {
|
|
11
|
+
return r ?? (r = ce(e.googleClientId)), r;
|
|
12
12
|
}
|
|
13
|
-
async function
|
|
14
|
-
const
|
|
15
|
-
`https://sheets.googleapis.com/v4/spreadsheets/${e.spreadsheetId}${
|
|
13
|
+
async function h(a, d) {
|
|
14
|
+
const l = await c(), u = await fetch(
|
|
15
|
+
`https://sheets.googleapis.com/v4/spreadsheets/${e.spreadsheetId}${a}`,
|
|
16
16
|
{
|
|
17
|
-
...
|
|
17
|
+
...d,
|
|
18
18
|
headers: {
|
|
19
|
-
Authorization: `Bearer ${
|
|
19
|
+
Authorization: `Bearer ${l}`,
|
|
20
20
|
"Content-Type": "application/json",
|
|
21
|
-
...
|
|
21
|
+
...d == null ? void 0 : d.headers
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
);
|
|
25
|
-
if (!
|
|
26
|
-
throw new Error(`Google Sheets request failed with ${
|
|
27
|
-
return
|
|
25
|
+
if (!u.ok)
|
|
26
|
+
throw new Error(`Google Sheets request failed with ${u.status}`);
|
|
27
|
+
return u.json();
|
|
28
28
|
}
|
|
29
|
-
async function
|
|
30
|
-
return (await
|
|
31
|
-
`/values/${encodeURIComponent(
|
|
29
|
+
async function w(a) {
|
|
30
|
+
return (await h(
|
|
31
|
+
`/values/${encodeURIComponent(a)}`
|
|
32
32
|
)).values ?? [];
|
|
33
33
|
}
|
|
34
34
|
return {
|
|
35
35
|
async getCurrentUser() {
|
|
36
36
|
if (!o) {
|
|
37
|
-
const
|
|
38
|
-
headers: { Authorization: `Bearer ${
|
|
37
|
+
const a = await c(), d = await fetch(oe, {
|
|
38
|
+
headers: { Authorization: `Bearer ${a}` }
|
|
39
39
|
});
|
|
40
|
-
if (!
|
|
41
|
-
throw new Error(`Google userinfo request failed with ${
|
|
42
|
-
o = (await
|
|
40
|
+
if (!d.ok)
|
|
41
|
+
throw new Error(`Google userinfo request failed with ${d.status}`);
|
|
42
|
+
o = (await d.json()).email;
|
|
43
43
|
}
|
|
44
44
|
if (!o)
|
|
45
45
|
throw new Error("Google account did not return an email address");
|
|
46
46
|
return { email: o };
|
|
47
47
|
},
|
|
48
|
-
async getPermissions(
|
|
49
|
-
const [{ email:
|
|
50
|
-
(
|
|
51
|
-
var
|
|
52
|
-
return ((
|
|
48
|
+
async getPermissions(a) {
|
|
49
|
+
const [{ email: d }, l] = await Promise.all([this.getCurrentUser(), w(t)]), u = z(l), y = d.toLowerCase(), p = u.find(
|
|
50
|
+
(b) => {
|
|
51
|
+
var m;
|
|
52
|
+
return ((m = b.email) == null ? void 0 : m.toLowerCase()) === y && b.active !== "false" && (!b.projectKey || b.projectKey === a);
|
|
53
53
|
}
|
|
54
54
|
);
|
|
55
|
-
return
|
|
55
|
+
return de((p == null ? void 0 : p.role) ?? "designer");
|
|
56
56
|
},
|
|
57
|
-
async listFeedback(
|
|
58
|
-
return
|
|
59
|
-
(
|
|
60
|
-
).sort((
|
|
57
|
+
async listFeedback(a) {
|
|
58
|
+
return z(await w(n)).map(K).filter((l) => l !== null).filter(
|
|
59
|
+
(l) => l.projectKey === a.projectKey && l.contentId === a.contentId && l.normalizedPath === a.normalizedPath
|
|
60
|
+
).sort((l, u) => u.createdAt.localeCompare(l.createdAt));
|
|
61
61
|
},
|
|
62
|
-
async createFeedback(
|
|
63
|
-
const
|
|
64
|
-
...
|
|
62
|
+
async createFeedback(a) {
|
|
63
|
+
const d = (/* @__PURE__ */ new Date()).toISOString(), l = {
|
|
64
|
+
...a,
|
|
65
65
|
id: crypto.randomUUID(),
|
|
66
66
|
status: "open",
|
|
67
|
-
createdAt:
|
|
68
|
-
updatedAt:
|
|
67
|
+
createdAt: d,
|
|
68
|
+
updatedAt: d
|
|
69
69
|
};
|
|
70
|
-
return await
|
|
70
|
+
return await h(`/values/${encodeURIComponent(n)}:append?valueInputOption=RAW`, {
|
|
71
71
|
method: "POST",
|
|
72
|
-
body: JSON.stringify({ values: [
|
|
73
|
-
}),
|
|
72
|
+
body: JSON.stringify({ values: [se(l)] })
|
|
73
|
+
}), l;
|
|
74
74
|
},
|
|
75
|
-
async resolveFeedback(
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
78
|
-
throw new Error(`Feedback ${
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
`/values/${encodeURIComponent(n)}!A${
|
|
75
|
+
async resolveFeedback(a, d) {
|
|
76
|
+
const l = await w(n), u = l[0] ?? ie, y = u.indexOf("id"), p = u.indexOf("status"), b = u.indexOf("updatedAt"), m = u.indexOf("resolvedAt"), k = u.indexOf("resolvedBy"), v = l.findIndex((N, x) => x > 0 && N[y] === a);
|
|
77
|
+
if (v < 1)
|
|
78
|
+
throw new Error(`Feedback ${a} was not found`);
|
|
79
|
+
const S = [...l[v]], F = (/* @__PURE__ */ new Date()).toISOString();
|
|
80
|
+
S[p] = "resolved", S[b] = F, S[m] = F, S[k] = d, await h(
|
|
81
|
+
`/values/${encodeURIComponent(n)}!A${v + 1}:Q${v + 1}?valueInputOption=RAW`,
|
|
82
82
|
{
|
|
83
83
|
method: "PUT",
|
|
84
|
-
body: JSON.stringify({ values: [
|
|
84
|
+
body: JSON.stringify({ values: [S] })
|
|
85
85
|
}
|
|
86
86
|
);
|
|
87
|
-
const
|
|
88
|
-
if (
|
|
89
|
-
throw new Error(`Feedback ${
|
|
90
|
-
return
|
|
87
|
+
const C = K(q(u, S));
|
|
88
|
+
if (!C)
|
|
89
|
+
throw new Error(`Feedback ${a} could not be parsed after resolving`);
|
|
90
|
+
return C;
|
|
91
91
|
}
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
|
-
const
|
|
94
|
+
const ie = [
|
|
95
95
|
"id",
|
|
96
96
|
"projectKey",
|
|
97
97
|
"contentId",
|
|
@@ -109,7 +109,7 @@ const Y = [
|
|
|
109
109
|
"resolvedAt",
|
|
110
110
|
"resolvedBy"
|
|
111
111
|
];
|
|
112
|
-
function
|
|
112
|
+
function se(e) {
|
|
113
113
|
return [
|
|
114
114
|
e.id,
|
|
115
115
|
e.projectKey,
|
|
@@ -129,14 +129,14 @@ function Q(e) {
|
|
|
129
129
|
e.resolvedBy ?? ""
|
|
130
130
|
];
|
|
131
131
|
}
|
|
132
|
-
function
|
|
132
|
+
function z(e) {
|
|
133
133
|
const [n, ...t] = e;
|
|
134
|
-
return n ? t.map((r) =>
|
|
134
|
+
return n ? t.map((r) => q(n, r)) : [];
|
|
135
135
|
}
|
|
136
|
-
function
|
|
136
|
+
function q(e, n) {
|
|
137
137
|
return Object.fromEntries(e.map((t, r) => [t, n[r] ?? ""]));
|
|
138
138
|
}
|
|
139
|
-
function
|
|
139
|
+
function K(e) {
|
|
140
140
|
return e.id ? {
|
|
141
141
|
id: e.id,
|
|
142
142
|
projectKey: e.projectKey,
|
|
@@ -145,23 +145,12 @@ function T(e) {
|
|
|
145
145
|
originalUrl: e.originalUrl,
|
|
146
146
|
selector: e.selector,
|
|
147
147
|
selectorStrategy: e.selectorStrategy === "stable-attribute" ? "stable-attribute" : "css-path",
|
|
148
|
-
elementFingerprint:
|
|
148
|
+
elementFingerprint: G(e.elementFingerprintJson, {
|
|
149
149
|
tagName: "",
|
|
150
150
|
width: 0,
|
|
151
151
|
height: 0
|
|
152
152
|
}),
|
|
153
|
-
cssSnapshot:
|
|
154
|
-
margin: "",
|
|
155
|
-
padding: "",
|
|
156
|
-
border: "",
|
|
157
|
-
fontFamily: "",
|
|
158
|
-
fontSize: "",
|
|
159
|
-
lineHeight: "",
|
|
160
|
-
color: "",
|
|
161
|
-
backgroundColor: "",
|
|
162
|
-
width: 0,
|
|
163
|
-
height: 0
|
|
164
|
-
}),
|
|
153
|
+
cssSnapshot: ae(e.cssSnapshotJson),
|
|
165
154
|
comment: e.comment,
|
|
166
155
|
status: e.status === "resolved" ? "resolved" : "open",
|
|
167
156
|
authorEmail: e.authorEmail,
|
|
@@ -171,34 +160,61 @@ function T(e) {
|
|
|
171
160
|
resolvedBy: e.resolvedBy || void 0
|
|
172
161
|
} : null;
|
|
173
162
|
}
|
|
174
|
-
function
|
|
163
|
+
function G(e, n) {
|
|
175
164
|
try {
|
|
176
165
|
return e ? JSON.parse(e) : n;
|
|
177
166
|
} catch {
|
|
178
167
|
return n;
|
|
179
168
|
}
|
|
180
169
|
}
|
|
181
|
-
function
|
|
170
|
+
function ae(e) {
|
|
171
|
+
const n = G(e, {});
|
|
172
|
+
return {
|
|
173
|
+
margin: n.margin ?? "",
|
|
174
|
+
marginTop: n.marginTop ?? "",
|
|
175
|
+
marginRight: n.marginRight ?? "",
|
|
176
|
+
marginBottom: n.marginBottom ?? "",
|
|
177
|
+
marginLeft: n.marginLeft ?? "",
|
|
178
|
+
padding: n.padding ?? "",
|
|
179
|
+
paddingTop: n.paddingTop ?? "",
|
|
180
|
+
paddingRight: n.paddingRight ?? "",
|
|
181
|
+
paddingBottom: n.paddingBottom ?? "",
|
|
182
|
+
paddingLeft: n.paddingLeft ?? "",
|
|
183
|
+
border: n.border ?? "",
|
|
184
|
+
borderTopWidth: n.borderTopWidth ?? "",
|
|
185
|
+
borderRightWidth: n.borderRightWidth ?? "",
|
|
186
|
+
borderBottomWidth: n.borderBottomWidth ?? "",
|
|
187
|
+
borderLeftWidth: n.borderLeftWidth ?? "",
|
|
188
|
+
fontFamily: n.fontFamily ?? "",
|
|
189
|
+
fontSize: n.fontSize ?? "",
|
|
190
|
+
lineHeight: n.lineHeight ?? "",
|
|
191
|
+
color: n.color ?? "",
|
|
192
|
+
backgroundColor: n.backgroundColor ?? "",
|
|
193
|
+
width: n.width ?? 0,
|
|
194
|
+
height: n.height ?? 0
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function de(e) {
|
|
182
198
|
return e === "admin" ? ["create", "read", "resolve"] : e === "developer" ? ["read", "resolve"] : ["create", "read"];
|
|
183
199
|
}
|
|
184
|
-
async function
|
|
185
|
-
return await
|
|
200
|
+
async function ce(e) {
|
|
201
|
+
return await le(), new Promise((n, t) => {
|
|
186
202
|
var o;
|
|
187
203
|
const r = (o = window.google) == null ? void 0 : o.accounts.oauth2.initTokenClient({
|
|
188
204
|
client_id: e,
|
|
189
|
-
scope:
|
|
190
|
-
callback: (
|
|
191
|
-
if (
|
|
192
|
-
t(new Error(
|
|
205
|
+
scope: ne,
|
|
206
|
+
callback: (c) => {
|
|
207
|
+
if (c.error || !c.access_token) {
|
|
208
|
+
t(new Error(c.error ?? "Google OAuth did not return an access token"));
|
|
193
209
|
return;
|
|
194
210
|
}
|
|
195
|
-
n(
|
|
211
|
+
n(c.access_token);
|
|
196
212
|
}
|
|
197
213
|
});
|
|
198
214
|
r == null || r.requestAccessToken({ prompt: "" });
|
|
199
215
|
});
|
|
200
216
|
}
|
|
201
|
-
function
|
|
217
|
+
function le() {
|
|
202
218
|
var e;
|
|
203
219
|
return (e = window.google) != null && e.accounts.oauth2 ? Promise.resolve() : new Promise((n, t) => {
|
|
204
220
|
const r = document.querySelector(
|
|
@@ -214,116 +230,116 @@ function ee() {
|
|
|
214
230
|
o.src = "https://accounts.google.com/gsi/client", o.async = !0, o.defer = !0, o.onload = () => n(), o.onerror = () => t(new Error("Google Identity failed to load")), document.head.append(o);
|
|
215
231
|
});
|
|
216
232
|
}
|
|
217
|
-
function
|
|
233
|
+
function he(e) {
|
|
218
234
|
return new URL(e, window.location.href).pathname.replace(/\/+$/, "") || "/";
|
|
219
235
|
}
|
|
220
|
-
const J =
|
|
221
|
-
function
|
|
222
|
-
const t =
|
|
223
|
-
googleClientId:
|
|
224
|
-
spreadsheetId:
|
|
236
|
+
const J = V(null);
|
|
237
|
+
function Ce({ config: e, children: n }) {
|
|
238
|
+
const t = M(() => e.adapter ? e.adapter : re({
|
|
239
|
+
googleClientId: D(e.googleClientId, "googleClientId"),
|
|
240
|
+
spreadsheetId: D(e.spreadsheetId, "spreadsheetId"),
|
|
225
241
|
feedbackSheetName: e.sheetName ?? "Feedback"
|
|
226
|
-
}), [e.adapter, e.googleClientId, e.sheetName, e.spreadsheetId]), r = e.currentUrl ?? window.location.href, o = (e.normalizeUrl ??
|
|
227
|
-
const
|
|
242
|
+
}), [e.adapter, e.googleClientId, e.sheetName, e.spreadsheetId]), r = e.currentUrl ?? window.location.href, o = (e.normalizeUrl ?? he)(r), [c, h] = R(), [w, a] = R([]), [d, l] = R([]), u = P(async () => {
|
|
243
|
+
const m = await t.listFeedback({
|
|
228
244
|
projectKey: e.projectKey,
|
|
229
245
|
contentId: e.contentId,
|
|
230
246
|
normalizedPath: o
|
|
231
247
|
});
|
|
232
|
-
|
|
248
|
+
l(m);
|
|
233
249
|
}, [t, e.contentId, e.projectKey, o]);
|
|
234
|
-
|
|
235
|
-
let
|
|
236
|
-
async function
|
|
237
|
-
const [
|
|
250
|
+
T(() => {
|
|
251
|
+
let m = !0;
|
|
252
|
+
async function k() {
|
|
253
|
+
const [v, S] = await Promise.all([
|
|
238
254
|
t.getCurrentUser(),
|
|
239
255
|
t.getPermissions(e.projectKey)
|
|
240
256
|
]);
|
|
241
|
-
|
|
257
|
+
m && (h(v), a(S), await u());
|
|
242
258
|
}
|
|
243
|
-
return
|
|
244
|
-
|
|
259
|
+
return k(), () => {
|
|
260
|
+
m = !1;
|
|
245
261
|
};
|
|
246
|
-
}, [t, e.projectKey,
|
|
247
|
-
const y =
|
|
248
|
-
async (
|
|
249
|
-
const
|
|
250
|
-
return
|
|
262
|
+
}, [t, e.projectKey, u]);
|
|
263
|
+
const y = P(
|
|
264
|
+
async (m) => {
|
|
265
|
+
const k = await t.createFeedback(m);
|
|
266
|
+
return l((v) => [k, ...v]), k;
|
|
251
267
|
},
|
|
252
268
|
[t]
|
|
253
|
-
),
|
|
254
|
-
async (
|
|
255
|
-
const
|
|
256
|
-
return
|
|
257
|
-
(
|
|
258
|
-
),
|
|
269
|
+
), p = P(
|
|
270
|
+
async (m) => {
|
|
271
|
+
const k = await t.resolveFeedback(m, (c == null ? void 0 : c.email) ?? "");
|
|
272
|
+
return l(
|
|
273
|
+
(v) => v.map((S) => S.id === m ? k : S)
|
|
274
|
+
), k;
|
|
259
275
|
},
|
|
260
|
-
[t,
|
|
261
|
-
),
|
|
276
|
+
[t, c == null ? void 0 : c.email]
|
|
277
|
+
), b = M(
|
|
262
278
|
() => ({
|
|
263
279
|
config: e,
|
|
264
280
|
adapter: t,
|
|
265
|
-
currentUser:
|
|
266
|
-
permissions:
|
|
267
|
-
feedback:
|
|
281
|
+
currentUser: c,
|
|
282
|
+
permissions: w,
|
|
283
|
+
feedback: d,
|
|
268
284
|
normalizedPath: o,
|
|
269
|
-
refreshFeedback:
|
|
285
|
+
refreshFeedback: u,
|
|
270
286
|
createFeedback: y,
|
|
271
|
-
resolveFeedback:
|
|
287
|
+
resolveFeedback: p
|
|
272
288
|
}),
|
|
273
289
|
[
|
|
274
290
|
t,
|
|
275
291
|
e,
|
|
276
292
|
y,
|
|
277
|
-
|
|
278
|
-
l,
|
|
279
|
-
o,
|
|
280
|
-
b,
|
|
293
|
+
c,
|
|
281
294
|
d,
|
|
282
|
-
|
|
295
|
+
o,
|
|
296
|
+
w,
|
|
297
|
+
u,
|
|
298
|
+
p
|
|
283
299
|
]
|
|
284
300
|
);
|
|
285
|
-
return /* @__PURE__ */
|
|
301
|
+
return /* @__PURE__ */ i(J.Provider, { value: b, children: n });
|
|
286
302
|
}
|
|
287
|
-
function
|
|
288
|
-
const e =
|
|
303
|
+
function ue() {
|
|
304
|
+
const e = Z(J);
|
|
289
305
|
if (!e)
|
|
290
306
|
throw new Error("useReviewLens must be used inside ReviewLensProvider");
|
|
291
307
|
return e;
|
|
292
308
|
}
|
|
293
|
-
function
|
|
309
|
+
function D(e, n) {
|
|
294
310
|
if (!e)
|
|
295
311
|
throw new Error(`review-lens-react requires config.${n} when no adapter is provided`);
|
|
296
312
|
return e;
|
|
297
313
|
}
|
|
298
|
-
const
|
|
314
|
+
const pe = [
|
|
299
315
|
"data-review-id",
|
|
300
316
|
"data-testid",
|
|
301
317
|
"data-test-id",
|
|
302
318
|
"aria-label",
|
|
303
319
|
"name"
|
|
304
320
|
];
|
|
305
|
-
function
|
|
306
|
-
const n = e.getBoundingClientRect(), t =
|
|
321
|
+
function _(e) {
|
|
322
|
+
const n = e.getBoundingClientRect(), t = me(e);
|
|
307
323
|
return {
|
|
308
324
|
selector: t.selector,
|
|
309
325
|
selectorStrategy: t.strategy,
|
|
310
|
-
fingerprint:
|
|
311
|
-
cssSnapshot:
|
|
326
|
+
fingerprint: fe(e, n),
|
|
327
|
+
cssSnapshot: we(e, n),
|
|
312
328
|
rect: n
|
|
313
329
|
};
|
|
314
330
|
}
|
|
315
|
-
function
|
|
316
|
-
for (const n of
|
|
331
|
+
function me(e) {
|
|
332
|
+
for (const n of pe) {
|
|
317
333
|
const t = e.getAttribute(n);
|
|
318
334
|
if (t)
|
|
319
335
|
return {
|
|
320
|
-
selector: `[${n}="${
|
|
336
|
+
selector: `[${n}="${O(t)}"]`,
|
|
321
337
|
strategy: "stable-attribute"
|
|
322
338
|
};
|
|
323
339
|
}
|
|
324
|
-
return e.id ? { selector: `#${
|
|
340
|
+
return e.id ? { selector: `#${O(e.id)}`, strategy: "stable-attribute" } : { selector: ge(e), strategy: "css-path" };
|
|
325
341
|
}
|
|
326
|
-
function
|
|
342
|
+
function ge(e) {
|
|
327
343
|
const n = [];
|
|
328
344
|
let t = e;
|
|
329
345
|
for (; t && t.nodeType === Node.ELEMENT_NODE && t !== document.body; ) {
|
|
@@ -332,14 +348,14 @@ function se(e) {
|
|
|
332
348
|
n.unshift(o);
|
|
333
349
|
break;
|
|
334
350
|
}
|
|
335
|
-
const
|
|
336
|
-
(
|
|
337
|
-
),
|
|
338
|
-
n.unshift(
|
|
351
|
+
const c = t.tagName, h = Array.from(r.children).filter(
|
|
352
|
+
(a) => a.tagName === c
|
|
353
|
+
), w = h.indexOf(t) + 1;
|
|
354
|
+
n.unshift(h.length > 1 ? `${o}:nth-of-type(${w})` : o), t = r;
|
|
339
355
|
}
|
|
340
356
|
return n.join(" > ");
|
|
341
357
|
}
|
|
342
|
-
function
|
|
358
|
+
function fe(e, n) {
|
|
343
359
|
var t;
|
|
344
360
|
return {
|
|
345
361
|
tagName: e.tagName.toLowerCase(),
|
|
@@ -351,22 +367,34 @@ function ae(e, n) {
|
|
|
351
367
|
height: Math.round(n.height)
|
|
352
368
|
};
|
|
353
369
|
}
|
|
354
|
-
function
|
|
370
|
+
function we(e, n) {
|
|
355
371
|
const t = window.getComputedStyle(e);
|
|
356
372
|
return {
|
|
357
373
|
margin: j(t.marginTop, t.marginRight, t.marginBottom, t.marginLeft),
|
|
374
|
+
marginTop: t.marginTop,
|
|
375
|
+
marginRight: t.marginRight,
|
|
376
|
+
marginBottom: t.marginBottom,
|
|
377
|
+
marginLeft: t.marginLeft,
|
|
358
378
|
padding: j(
|
|
359
379
|
t.paddingTop,
|
|
360
380
|
t.paddingRight,
|
|
361
381
|
t.paddingBottom,
|
|
362
382
|
t.paddingLeft
|
|
363
383
|
),
|
|
384
|
+
paddingTop: t.paddingTop,
|
|
385
|
+
paddingRight: t.paddingRight,
|
|
386
|
+
paddingBottom: t.paddingBottom,
|
|
387
|
+
paddingLeft: t.paddingLeft,
|
|
364
388
|
border: j(
|
|
365
389
|
t.borderTopWidth,
|
|
366
390
|
t.borderRightWidth,
|
|
367
391
|
t.borderBottomWidth,
|
|
368
392
|
t.borderLeftWidth
|
|
369
393
|
),
|
|
394
|
+
borderTopWidth: t.borderTopWidth,
|
|
395
|
+
borderRightWidth: t.borderRightWidth,
|
|
396
|
+
borderBottomWidth: t.borderBottomWidth,
|
|
397
|
+
borderLeftWidth: t.borderLeftWidth,
|
|
370
398
|
fontFamily: t.fontFamily,
|
|
371
399
|
fontSize: t.fontSize,
|
|
372
400
|
lineHeight: t.lineHeight,
|
|
@@ -379,10 +407,10 @@ function ie(e, n) {
|
|
|
379
407
|
function j(e, n, t, r) {
|
|
380
408
|
return e === n && n === t && t === r ? e : `${e} ${n} ${t} ${r}`;
|
|
381
409
|
}
|
|
382
|
-
function
|
|
410
|
+
function O(e) {
|
|
383
411
|
return typeof CSS < "u" && typeof CSS.escape == "function" ? CSS.escape(e) : e.replace(/["\\]/g, "\\$&");
|
|
384
412
|
}
|
|
385
|
-
function
|
|
413
|
+
function Le({
|
|
386
414
|
open: e,
|
|
387
415
|
onOpenChange: n,
|
|
388
416
|
placement: t = "top-right",
|
|
@@ -390,159 +418,302 @@ function fe({
|
|
|
390
418
|
}) {
|
|
391
419
|
const {
|
|
392
420
|
config: o,
|
|
393
|
-
currentUser:
|
|
394
|
-
feedback:
|
|
395
|
-
normalizedPath:
|
|
396
|
-
permissions:
|
|
397
|
-
createFeedback:
|
|
398
|
-
resolveFeedback:
|
|
399
|
-
} =
|
|
400
|
-
() =>
|
|
401
|
-
[
|
|
421
|
+
currentUser: c,
|
|
422
|
+
feedback: h,
|
|
423
|
+
normalizedPath: w,
|
|
424
|
+
permissions: a,
|
|
425
|
+
createFeedback: d,
|
|
426
|
+
resolveFeedback: l
|
|
427
|
+
} = ue(), [u, y] = R(), [p, b] = R(), [m, k] = R(""), [v, S] = R(), [F, C] = R("review"), N = !!c, x = a.includes("create"), Q = a.includes("resolve"), B = M(
|
|
428
|
+
() => h.filter((s) => r || s.status !== "resolved"),
|
|
429
|
+
[h, r]
|
|
402
430
|
);
|
|
403
|
-
|
|
404
|
-
e || (y(void 0),
|
|
405
|
-
}, [e])
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
if (
|
|
409
|
-
return
|
|
410
|
-
|
|
411
|
-
|
|
431
|
+
T(() => {
|
|
432
|
+
e || (y(void 0), b(void 0), k(""), C("review"));
|
|
433
|
+
}, [e]), T(() => {
|
|
434
|
+
N || (y(void 0), b(void 0));
|
|
435
|
+
}, [N]), T(() => {
|
|
436
|
+
if (!e)
|
|
437
|
+
return;
|
|
438
|
+
function s(g) {
|
|
439
|
+
g.key === "Escape" && (g.preventDefault(), n == null || n(!1));
|
|
440
|
+
}
|
|
441
|
+
return window.addEventListener("keydown", s), () => {
|
|
442
|
+
window.removeEventListener("keydown", s);
|
|
443
|
+
};
|
|
444
|
+
}, [n, e]);
|
|
445
|
+
const $ = P((s) => {
|
|
446
|
+
const g = s.target instanceof Element ? s.target : null;
|
|
447
|
+
if (g)
|
|
448
|
+
return g.closest("[data-review-lens-ui]") ? null : g;
|
|
449
|
+
const L = document.elementFromPoint(s.clientX, s.clientY);
|
|
450
|
+
return !L || L.closest("[data-review-lens-ui]") ? null : L;
|
|
412
451
|
}, []);
|
|
413
|
-
if (
|
|
414
|
-
if (!e ||
|
|
452
|
+
if (T(() => {
|
|
453
|
+
if (!e || !N)
|
|
415
454
|
return;
|
|
416
|
-
function
|
|
417
|
-
const
|
|
418
|
-
|
|
455
|
+
function s(L) {
|
|
456
|
+
const A = $(L);
|
|
457
|
+
y(A ? _(A) : void 0);
|
|
419
458
|
}
|
|
420
|
-
function
|
|
421
|
-
const
|
|
422
|
-
|
|
459
|
+
function g(L) {
|
|
460
|
+
const A = $(L);
|
|
461
|
+
A && (L.preventDefault(), L.stopPropagation(), b(_(A)), C("review"));
|
|
423
462
|
}
|
|
424
|
-
return window.addEventListener("mousemove",
|
|
425
|
-
window.removeEventListener("mousemove",
|
|
463
|
+
return window.addEventListener("mousemove", s, !0), window.addEventListener("click", g, !0), () => {
|
|
464
|
+
window.removeEventListener("mousemove", s, !0), window.removeEventListener("click", g, !0);
|
|
426
465
|
};
|
|
427
|
-
}, [
|
|
466
|
+
}, [N, $, p, e]), !e)
|
|
428
467
|
return null;
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
468
|
+
const I = u ?? p, X = !!p;
|
|
469
|
+
function W(s) {
|
|
470
|
+
S(s), b(void 0), C("feedback");
|
|
471
|
+
const g = H(s.selector);
|
|
472
|
+
g && (g.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }), window.requestAnimationFrame(() => {
|
|
473
|
+
y(_(g));
|
|
474
|
+
}));
|
|
475
|
+
}
|
|
476
|
+
async function U() {
|
|
477
|
+
!p || !m.trim() || !c || !x || (await d({
|
|
432
478
|
projectKey: o.projectKey,
|
|
433
479
|
contentId: o.contentId,
|
|
434
|
-
normalizedPath:
|
|
480
|
+
normalizedPath: w,
|
|
435
481
|
originalUrl: o.currentUrl ?? window.location.href,
|
|
436
|
-
selector:
|
|
437
|
-
selectorStrategy:
|
|
438
|
-
elementFingerprint:
|
|
439
|
-
cssSnapshot:
|
|
440
|
-
comment:
|
|
441
|
-
authorEmail:
|
|
442
|
-
}),
|
|
482
|
+
selector: p.selector,
|
|
483
|
+
selectorStrategy: p.selectorStrategy,
|
|
484
|
+
elementFingerprint: p.fingerprint,
|
|
485
|
+
cssSnapshot: p.cssSnapshot,
|
|
486
|
+
comment: m.trim(),
|
|
487
|
+
authorEmail: c.email
|
|
488
|
+
}), k(""), b(void 0), y(void 0), C("feedback"));
|
|
443
489
|
}
|
|
444
|
-
return /* @__PURE__ */
|
|
445
|
-
|
|
446
|
-
/* @__PURE__ */
|
|
447
|
-
|
|
490
|
+
return /* @__PURE__ */ f("div", { className: "review-lens-root", "data-review-lens-ui": !0, children: [
|
|
491
|
+
N && I ? /* @__PURE__ */ i(ve, { target: I, locked: !!p }) : null,
|
|
492
|
+
N ? /* @__PURE__ */ i(
|
|
493
|
+
be,
|
|
448
494
|
{
|
|
449
|
-
feedback:
|
|
450
|
-
selectedFeedback:
|
|
451
|
-
onSelect:
|
|
495
|
+
feedback: B,
|
|
496
|
+
selectedFeedback: v,
|
|
497
|
+
onSelect: W
|
|
452
498
|
}
|
|
453
|
-
),
|
|
454
|
-
/* @__PURE__ */
|
|
455
|
-
/* @__PURE__ */
|
|
456
|
-
/* @__PURE__ */
|
|
457
|
-
/* @__PURE__ */
|
|
458
|
-
/* @__PURE__ */
|
|
499
|
+
) : null,
|
|
500
|
+
/* @__PURE__ */ f("aside", { className: `review-lens-panel review-lens-panel--${t}`, "data-review-lens-ui": !0, children: [
|
|
501
|
+
/* @__PURE__ */ f("header", { className: "review-lens-panel__header", children: [
|
|
502
|
+
/* @__PURE__ */ f("div", { children: [
|
|
503
|
+
/* @__PURE__ */ i("p", { className: "review-lens-kicker", children: "Review Lens" }),
|
|
504
|
+
/* @__PURE__ */ i("h2", { children: F === "feedback" ? "Feedback" : p ? "Element locked" : "Inspecting" })
|
|
459
505
|
] }),
|
|
460
|
-
/* @__PURE__ */
|
|
506
|
+
/* @__PURE__ */ i("button", { type: "button", onClick: () => n == null ? void 0 : n(!1), children: "Close" })
|
|
461
507
|
] }),
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
508
|
+
/* @__PURE__ */ f("div", { className: "review-lens-panel__body", children: [
|
|
509
|
+
/* @__PURE__ */ f("div", { className: "review-lens-mode-switch", role: "tablist", "aria-label": "Review Lens mode", children: [
|
|
510
|
+
/* @__PURE__ */ i(
|
|
511
|
+
"button",
|
|
512
|
+
{
|
|
513
|
+
type: "button",
|
|
514
|
+
role: "tab",
|
|
515
|
+
"aria-selected": F === "review",
|
|
516
|
+
onClick: () => C("review"),
|
|
517
|
+
children: "Review"
|
|
518
|
+
}
|
|
519
|
+
),
|
|
520
|
+
/* @__PURE__ */ f(
|
|
521
|
+
"button",
|
|
522
|
+
{
|
|
523
|
+
type: "button",
|
|
524
|
+
role: "tab",
|
|
525
|
+
"aria-selected": F === "feedback",
|
|
526
|
+
onClick: () => C("feedback"),
|
|
527
|
+
children: [
|
|
528
|
+
"Feedback ",
|
|
529
|
+
/* @__PURE__ */ i("span", { children: B.length })
|
|
530
|
+
]
|
|
531
|
+
}
|
|
532
|
+
)
|
|
533
|
+
] }),
|
|
534
|
+
F === "review" ? /* @__PURE__ */ f("div", { className: "review-lens-review-pane", role: "tabpanel", children: [
|
|
535
|
+
/* @__PURE__ */ f("div", { className: "review-lens-inspection", children: [
|
|
536
|
+
N ? null : /* @__PURE__ */ i("p", { children: "Authenticate with Google to inspect this page." }),
|
|
537
|
+
N && I ? /* @__PURE__ */ i(ke, { target: I }) : null,
|
|
538
|
+
N && !I ? /* @__PURE__ */ i("p", { children: "Move over the app to inspect." }) : null
|
|
539
|
+
] }),
|
|
540
|
+
X ? /* @__PURE__ */ f(
|
|
541
|
+
"form",
|
|
542
|
+
{
|
|
543
|
+
className: "review-lens-feedback-form",
|
|
544
|
+
onSubmit: (s) => {
|
|
545
|
+
s.preventDefault(), U();
|
|
546
|
+
},
|
|
547
|
+
children: [
|
|
548
|
+
/* @__PURE__ */ i("label", { htmlFor: "review-lens-comment", children: "New feedback" }),
|
|
549
|
+
/* @__PURE__ */ i(
|
|
550
|
+
"textarea",
|
|
551
|
+
{
|
|
552
|
+
id: "review-lens-comment",
|
|
553
|
+
value: m,
|
|
554
|
+
disabled: !x,
|
|
555
|
+
onChange: (s) => k(s.target.value),
|
|
556
|
+
onKeyDown: (s) => {
|
|
557
|
+
s.key === "Enter" && s.metaKey && (s.preventDefault(), U());
|
|
558
|
+
},
|
|
559
|
+
placeholder: x ? "Describe the UX issue..." : "You do not have permission to comment."
|
|
560
|
+
}
|
|
561
|
+
),
|
|
562
|
+
x ? /* @__PURE__ */ f("p", { className: "review-lens-feedback-form__hint", children: [
|
|
563
|
+
"Press ",
|
|
564
|
+
/* @__PURE__ */ i("kbd", { children: "Command" }),
|
|
565
|
+
" + ",
|
|
566
|
+
/* @__PURE__ */ i("kbd", { children: "Enter" }),
|
|
567
|
+
" to submit."
|
|
568
|
+
] }) : null,
|
|
569
|
+
/* @__PURE__ */ i("div", { className: "review-lens-actions", children: /* @__PURE__ */ i("button", { type: "submit", disabled: !m.trim() || !x, children: "Save feedback" }) })
|
|
570
|
+
]
|
|
571
|
+
}
|
|
572
|
+
) : null
|
|
573
|
+
] }) : /* @__PURE__ */ f("div", { className: "review-lens-comments", children: [
|
|
574
|
+
/* @__PURE__ */ f("div", { className: "review-lens-comments__header", children: [
|
|
575
|
+
/* @__PURE__ */ i("h3", { children: "Page feedback" }),
|
|
576
|
+
/* @__PURE__ */ i("span", { children: B.length })
|
|
577
|
+
] }),
|
|
578
|
+
/* @__PURE__ */ f("div", { className: "review-lens-comments__list", children: [
|
|
579
|
+
B.length === 0 ? /* @__PURE__ */ i("p", { children: "No feedback for this view." }) : null,
|
|
580
|
+
B.map((s) => /* @__PURE__ */ f(
|
|
581
|
+
"article",
|
|
474
582
|
{
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
h.id
|
|
503
|
-
))
|
|
583
|
+
tabIndex: 0,
|
|
584
|
+
className: (v == null ? void 0 : v.id) === s.id ? "review-lens-comment review-lens-comment--selected" : "review-lens-comment",
|
|
585
|
+
onClick: () => W(s),
|
|
586
|
+
onKeyDown: (g) => {
|
|
587
|
+
(g.key === "Enter" || g.key === " ") && (g.preventDefault(), W(s));
|
|
588
|
+
},
|
|
589
|
+
children: [
|
|
590
|
+
/* @__PURE__ */ f("div", { className: "review-lens-comment__content", children: [
|
|
591
|
+
/* @__PURE__ */ i("p", { children: s.comment }),
|
|
592
|
+
/* @__PURE__ */ i("span", { children: s.authorEmail })
|
|
593
|
+
] }),
|
|
594
|
+
s.status === "open" && Q ? /* @__PURE__ */ i("div", { className: "review-lens-comment__actions", children: /* @__PURE__ */ i(
|
|
595
|
+
"button",
|
|
596
|
+
{
|
|
597
|
+
type: "button",
|
|
598
|
+
onClick: (g) => {
|
|
599
|
+
g.stopPropagation(), l(s.id);
|
|
600
|
+
},
|
|
601
|
+
children: "Resolve"
|
|
602
|
+
}
|
|
603
|
+
) }) : null
|
|
604
|
+
]
|
|
605
|
+
},
|
|
606
|
+
s.id
|
|
607
|
+
))
|
|
608
|
+
] })
|
|
609
|
+
] })
|
|
504
610
|
] })
|
|
505
611
|
] })
|
|
506
612
|
] });
|
|
507
613
|
}
|
|
508
|
-
function
|
|
509
|
-
|
|
614
|
+
function ve({ target: e, locked: n }) {
|
|
615
|
+
const t = Se(e);
|
|
616
|
+
return /* @__PURE__ */ f(
|
|
510
617
|
"div",
|
|
511
618
|
{
|
|
512
619
|
className: n ? "review-lens-highlight review-lens-highlight--locked" : "review-lens-highlight",
|
|
513
620
|
style: {
|
|
514
|
-
top:
|
|
515
|
-
left:
|
|
516
|
-
width:
|
|
517
|
-
height:
|
|
518
|
-
}
|
|
621
|
+
top: t.margin.top,
|
|
622
|
+
left: t.margin.left,
|
|
623
|
+
width: t.margin.width,
|
|
624
|
+
height: t.margin.height
|
|
625
|
+
},
|
|
626
|
+
children: [
|
|
627
|
+
/* @__PURE__ */ i(
|
|
628
|
+
"div",
|
|
629
|
+
{
|
|
630
|
+
className: "review-lens-highlight__border",
|
|
631
|
+
style: {
|
|
632
|
+
top: t.border.top - t.margin.top,
|
|
633
|
+
left: t.border.left - t.margin.left,
|
|
634
|
+
width: t.border.width,
|
|
635
|
+
height: t.border.height
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
),
|
|
639
|
+
/* @__PURE__ */ i(
|
|
640
|
+
"div",
|
|
641
|
+
{
|
|
642
|
+
className: "review-lens-highlight__padding",
|
|
643
|
+
style: {
|
|
644
|
+
top: t.padding.top - t.margin.top,
|
|
645
|
+
left: t.padding.left - t.margin.left,
|
|
646
|
+
width: t.padding.width,
|
|
647
|
+
height: t.padding.height
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
),
|
|
651
|
+
/* @__PURE__ */ i(
|
|
652
|
+
"div",
|
|
653
|
+
{
|
|
654
|
+
className: "review-lens-highlight__content",
|
|
655
|
+
style: {
|
|
656
|
+
top: t.content.top - t.margin.top,
|
|
657
|
+
left: t.content.left - t.margin.left,
|
|
658
|
+
width: t.content.width,
|
|
659
|
+
height: t.content.height
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
),
|
|
663
|
+
/* @__PURE__ */ f("div", { className: "review-lens-highlight__label", children: [
|
|
664
|
+
Math.round(e.rect.width),
|
|
665
|
+
" x ",
|
|
666
|
+
Math.round(e.rect.height)
|
|
667
|
+
] })
|
|
668
|
+
]
|
|
519
669
|
}
|
|
520
670
|
);
|
|
521
671
|
}
|
|
522
|
-
function
|
|
672
|
+
function be({
|
|
523
673
|
feedback: e,
|
|
524
674
|
selectedFeedback: n,
|
|
525
675
|
onSelect: t
|
|
526
676
|
}) {
|
|
527
|
-
return /* @__PURE__ */
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
677
|
+
return /* @__PURE__ */ i(Y, { children: e.map((r) => /* @__PURE__ */ i(
|
|
678
|
+
ye,
|
|
679
|
+
{
|
|
680
|
+
feedback: r,
|
|
681
|
+
selected: (n == null ? void 0 : n.id) === r.id,
|
|
682
|
+
onSelect: t
|
|
683
|
+
},
|
|
684
|
+
r.id
|
|
685
|
+
)) });
|
|
686
|
+
}
|
|
687
|
+
function ye({
|
|
688
|
+
feedback: e,
|
|
689
|
+
selected: n,
|
|
690
|
+
onSelect: t
|
|
691
|
+
}) {
|
|
692
|
+
const r = ee(null);
|
|
693
|
+
return te(() => {
|
|
694
|
+
let o = 0;
|
|
695
|
+
const c = () => {
|
|
696
|
+
o = 0;
|
|
697
|
+
const w = r.current, a = H(e.selector), d = a == null ? void 0 : a.getBoundingClientRect();
|
|
698
|
+
!w || !d || (w.style.top = `${d.top}px`, w.style.left = `${d.right}px`, w.hidden = d.bottom < 0 || d.top > window.innerHeight);
|
|
699
|
+
}, h = () => {
|
|
700
|
+
o || (o = window.requestAnimationFrame(c));
|
|
701
|
+
};
|
|
702
|
+
return c(), window.addEventListener("scroll", h, !0), window.addEventListener("resize", h), () => {
|
|
703
|
+
o && window.cancelAnimationFrame(o), window.removeEventListener("scroll", h, !0), window.removeEventListener("resize", h);
|
|
704
|
+
};
|
|
705
|
+
}, [e.selector]), /* @__PURE__ */ i(
|
|
706
|
+
"button",
|
|
707
|
+
{
|
|
708
|
+
ref: r,
|
|
709
|
+
type: "button",
|
|
710
|
+
className: n ? "review-lens-marker review-lens-marker--selected" : "review-lens-marker",
|
|
711
|
+
onClick: () => t(e),
|
|
712
|
+
"aria-label": `Open feedback from ${e.authorEmail}`
|
|
713
|
+
}
|
|
714
|
+
);
|
|
544
715
|
}
|
|
545
|
-
function
|
|
716
|
+
function ke({ target: e }) {
|
|
546
717
|
const n = [
|
|
547
718
|
["Selector", e.selector],
|
|
548
719
|
["Size", `${e.cssSnapshot.width} x ${e.cssSnapshot.height}`],
|
|
@@ -554,23 +725,71 @@ function de({ target: e }) {
|
|
|
554
725
|
["Color", e.cssSnapshot.color],
|
|
555
726
|
["Background", e.cssSnapshot.backgroundColor]
|
|
556
727
|
];
|
|
557
|
-
return /* @__PURE__ */
|
|
558
|
-
/* @__PURE__ */
|
|
559
|
-
/* @__PURE__ */
|
|
728
|
+
return /* @__PURE__ */ i("dl", { className: "review-lens-metrics", children: n.map(([t, r]) => /* @__PURE__ */ f("div", { children: [
|
|
729
|
+
/* @__PURE__ */ i("dt", { children: t }),
|
|
730
|
+
/* @__PURE__ */ i("dd", { children: r })
|
|
560
731
|
] }, t)) });
|
|
561
732
|
}
|
|
562
|
-
function
|
|
733
|
+
function H(e) {
|
|
563
734
|
try {
|
|
564
735
|
return document.querySelector(e);
|
|
565
736
|
} catch {
|
|
566
737
|
return null;
|
|
567
738
|
}
|
|
568
739
|
}
|
|
740
|
+
function Se(e) {
|
|
741
|
+
const n = {
|
|
742
|
+
top: E(e.cssSnapshot.marginTop),
|
|
743
|
+
right: E(e.cssSnapshot.marginRight),
|
|
744
|
+
bottom: E(e.cssSnapshot.marginBottom),
|
|
745
|
+
left: E(e.cssSnapshot.marginLeft)
|
|
746
|
+
}, t = {
|
|
747
|
+
top: E(e.cssSnapshot.borderTopWidth),
|
|
748
|
+
right: E(e.cssSnapshot.borderRightWidth),
|
|
749
|
+
bottom: E(e.cssSnapshot.borderBottomWidth),
|
|
750
|
+
left: E(e.cssSnapshot.borderLeftWidth)
|
|
751
|
+
}, r = {
|
|
752
|
+
top: E(e.cssSnapshot.paddingTop),
|
|
753
|
+
right: E(e.cssSnapshot.paddingRight),
|
|
754
|
+
bottom: E(e.cssSnapshot.paddingBottom),
|
|
755
|
+
left: E(e.cssSnapshot.paddingLeft)
|
|
756
|
+
}, o = {
|
|
757
|
+
top: e.rect.top,
|
|
758
|
+
left: e.rect.left,
|
|
759
|
+
width: Math.max(e.rect.width, 0),
|
|
760
|
+
height: Math.max(e.rect.height, 0)
|
|
761
|
+
}, c = {
|
|
762
|
+
top: o.top - n.top,
|
|
763
|
+
left: o.left - n.left,
|
|
764
|
+
width: o.width + n.left + n.right,
|
|
765
|
+
height: o.height + n.top + n.bottom
|
|
766
|
+
}, h = {
|
|
767
|
+
top: o.top + t.top,
|
|
768
|
+
left: o.left + t.left,
|
|
769
|
+
width: Math.max(o.width - t.left - t.right, 0),
|
|
770
|
+
height: Math.max(o.height - t.top - t.bottom, 0)
|
|
771
|
+
}, w = {
|
|
772
|
+
top: h.top + r.top,
|
|
773
|
+
left: h.left + r.left,
|
|
774
|
+
width: Math.max(h.width - r.left - r.right, 0),
|
|
775
|
+
height: Math.max(h.height - r.top - r.bottom, 0)
|
|
776
|
+
};
|
|
777
|
+
return {
|
|
778
|
+
margin: c,
|
|
779
|
+
border: o,
|
|
780
|
+
padding: h,
|
|
781
|
+
content: w
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
function E(e) {
|
|
785
|
+
const n = Number.parseFloat(e || "0");
|
|
786
|
+
return Number.isFinite(n) ? n : 0;
|
|
787
|
+
}
|
|
569
788
|
export {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
789
|
+
Le as ReviewLensOverlay,
|
|
790
|
+
Ce as ReviewLensProvider,
|
|
791
|
+
_ as buildElementTarget,
|
|
792
|
+
re as createGoogleSheetsAdapter,
|
|
793
|
+
he as normalizeReviewUrl,
|
|
794
|
+
ue as useReviewLens
|
|
576
795
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(w,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],r):(w=typeof globalThis<"u"?globalThis:w||self,r(w.ReviewLensReact={},w.jsxRuntime,w.React))})(this,(function(w,r,p){"use strict";const J=["https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email"].join(" "),D="https://www.googleapis.com/oauth2/v3/userinfo";function T(e){const n=e.feedbackSheetName??"Feedback",t=e.usersSheetName??"Users";let o,s;async function a(){return o??(o=X(e.googleClientId)),o}async function y(c,l){const i=await a(),d=await fetch(`https://sheets.googleapis.com/v4/spreadsheets/${e.spreadsheetId}${c}`,{...l,headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json",...l==null?void 0:l.headers}});if(!d.ok)throw new Error(`Google Sheets request failed with ${d.status}`);return d.json()}async function S(c){return(await y(`/values/${encodeURIComponent(c)}`)).values??[]}return{async getCurrentUser(){if(!s){const c=await a(),l=await fetch(D,{headers:{Authorization:`Bearer ${c}`}});if(!l.ok)throw new Error(`Google userinfo request failed with ${l.status}`);s=(await l.json()).email}if(!s)throw new Error("Google account did not return an email address");return{email:s}},async getPermissions(c){const[{email:l},i]=await Promise.all([this.getCurrentUser(),S(t)]),d=U(i),k=l.toLowerCase(),u=d.find(g=>{var f;return((f=g.email)==null?void 0:f.toLowerCase())===k&&g.active!=="false"&&(!g.projectKey||g.projectKey===c)});return _((u==null?void 0:u.role)??"designer")},async listFeedback(c){return U(await S(n)).map(x).filter(i=>i!==null).filter(i=>i.projectKey===c.projectKey&&i.contentId===c.contentId&&i.normalizedPath===c.normalizedPath).sort((i,d)=>d.createdAt.localeCompare(i.createdAt))},async createFeedback(c){const l=new Date().toISOString(),i={...c,id:crypto.randomUUID(),status:"open",createdAt:l,updatedAt:l};return await y(`/values/${encodeURIComponent(n)}:append?valueInputOption=RAW`,{method:"POST",body:JSON.stringify({values:[W(i)]})}),i},async resolveFeedback(c,l){const i=await S(n),d=i[0]??H,k=d.indexOf("id"),u=d.indexOf("status"),g=d.indexOf("updatedAt"),f=d.indexOf("resolvedAt"),v=d.indexOf("resolvedBy"),m=i.findIndex((A,N)=>N>0&&A[k]===c);if(m<1)throw new Error(`Feedback ${c} was not found`);const b=[...i[m]],E=new Date().toISOString();b[u]="resolved",b[g]=E,b[f]=E,b[v]=l,await y(`/values/${encodeURIComponent(n)}!A${m+1}:Q${m+1}?valueInputOption=RAW`,{method:"PUT",body:JSON.stringify({values:[b]})});const P=x(O(d,b));if(!P)throw new Error(`Feedback ${c} could not be parsed after resolving`);return P}}}const H=["id","projectKey","contentId","normalizedPath","originalUrl","selector","selectorStrategy","elementFingerprintJson","cssSnapshotJson","comment","status","authorEmail","createdAt","updatedAt","resolvedAt","resolvedBy"];function W(e){return[e.id,e.projectKey,e.contentId,e.normalizedPath,e.originalUrl,e.selector,e.selectorStrategy,JSON.stringify(e.elementFingerprint),JSON.stringify(e.cssSnapshot),e.comment,e.status,e.authorEmail,e.createdAt,e.updatedAt,e.resolvedAt??"",e.resolvedBy??""]}function U(e){const[n,...t]=e;return n?t.map(o=>O(n,o)):[]}function O(e,n){return Object.fromEntries(e.map((t,o)=>[t,n[o]??""]))}function x(e){return e.id?{id:e.id,projectKey:e.projectKey,contentId:e.contentId,normalizedPath:e.normalizedPath,originalUrl:e.originalUrl,selector:e.selector,selectorStrategy:e.selectorStrategy==="stable-attribute"?"stable-attribute":"css-path",elementFingerprint:z(e.elementFingerprintJson,{tagName:"",width:0,height:0}),cssSnapshot:z(e.cssSnapshotJson,{margin:"",padding:"",border:"",fontFamily:"",fontSize:"",lineHeight:"",color:"",backgroundColor:"",width:0,height:0}),comment:e.comment,status:e.status==="resolved"?"resolved":"open",authorEmail:e.authorEmail,createdAt:e.createdAt,updatedAt:e.updatedAt,resolvedAt:e.resolvedAt||void 0,resolvedBy:e.resolvedBy||void 0}:null}function z(e,n){try{return e?JSON.parse(e):n}catch{return n}}function _(e){return e==="admin"?["create","read","resolve"]:e==="developer"?["read","resolve"]:["create","read"]}async function X(e){return await Y(),new Promise((n,t)=>{var s;const o=(s=window.google)==null?void 0:s.accounts.oauth2.initTokenClient({client_id:e,scope:J,callback:a=>{if(a.error||!a.access_token){t(new Error(a.error??"Google OAuth did not return an access token"));return}n(a.access_token)}});o==null||o.requestAccessToken({prompt:""})})}function Y(){var e;return(e=window.google)!=null&&e.accounts.oauth2?Promise.resolve():new Promise((n,t)=>{const o=document.querySelector('script[src="https://accounts.google.com/gsi/client"]');if(o){o.addEventListener("load",()=>n(),{once:!0}),o.addEventListener("error",()=>t(new Error("Google Identity failed to load")),{once:!0});return}const s=document.createElement("script");s.src="https://accounts.google.com/gsi/client",s.async=!0,s.defer=!0,s.onload=()=>n(),s.onerror=()=>t(new Error("Google Identity failed to load")),document.head.append(s)})}function B(e){return new URL(e,window.location.href).pathname.replace(/\/+$/,"")||"/"}const K=p.createContext(null);function Q({config:e,children:n}){const t=p.useMemo(()=>e.adapter?e.adapter:T({googleClientId:q(e.googleClientId,"googleClientId"),spreadsheetId:q(e.spreadsheetId,"spreadsheetId"),feedbackSheetName:e.sheetName??"Feedback"}),[e.adapter,e.googleClientId,e.sheetName,e.spreadsheetId]),o=e.currentUrl??window.location.href,s=(e.normalizeUrl??B)(o),[a,y]=p.useState(),[S,c]=p.useState([]),[l,i]=p.useState([]),d=p.useCallback(async()=>{const f=await t.listFeedback({projectKey:e.projectKey,contentId:e.contentId,normalizedPath:s});i(f)},[t,e.contentId,e.projectKey,s]);p.useEffect(()=>{let f=!0;async function v(){const[m,b]=await Promise.all([t.getCurrentUser(),t.getPermissions(e.projectKey)]);f&&(y(m),c(b),await d())}return v(),()=>{f=!1}},[t,e.projectKey,d]);const k=p.useCallback(async f=>{const v=await t.createFeedback(f);return i(m=>[v,...m]),v},[t]),u=p.useCallback(async f=>{const v=await t.resolveFeedback(f,(a==null?void 0:a.email)??"");return i(m=>m.map(b=>b.id===f?v:b)),v},[t,a==null?void 0:a.email]),g=p.useMemo(()=>({config:e,adapter:t,currentUser:a,permissions:S,feedback:l,normalizedPath:s,refreshFeedback:d,createFeedback:k,resolveFeedback:u}),[t,e,k,a,l,s,S,d,u]);return r.jsx(K.Provider,{value:g,children:n})}function M(){const e=p.useContext(K);if(!e)throw new Error("useReviewLens must be used inside ReviewLensProvider");return e}function q(e,n){if(!e)throw new Error(`review-lens-react requires config.${n} when no adapter is provided`);return e}const V=["data-review-id","data-testid","data-test-id","aria-label","name"];function L(e){const n=e.getBoundingClientRect(),t=Z(e);return{selector:t.selector,selectorStrategy:t.strategy,fingerprint:ee(e,n),cssSnapshot:te(e,n),rect:n}}function Z(e){for(const n of V){const t=e.getAttribute(n);if(t)return{selector:`[${n}="${G(t)}"]`,strategy:"stable-attribute"}}return e.id?{selector:`#${G(e.id)}`,strategy:"stable-attribute"}:{selector:R(e),strategy:"css-path"}}function R(e){const n=[];let t=e;for(;t&&t.nodeType===Node.ELEMENT_NODE&&t!==document.body;){const o=t.parentElement,s=t.tagName.toLowerCase();if(!o){n.unshift(s);break}const a=t.tagName,y=Array.from(o.children).filter(c=>c.tagName===a),S=y.indexOf(t)+1;n.unshift(y.length>1?`${s}:nth-of-type(${S})`:s),t=o}return n.join(" > ")}function ee(e,n){var t;return{tagName:e.tagName.toLowerCase(),id:e.id||void 0,className:e.getAttribute("class")||void 0,textSnippet:((t=e.textContent)==null?void 0:t.trim().slice(0,80))||void 0,ariaLabel:e.getAttribute("aria-label")||void 0,width:Math.round(n.width),height:Math.round(n.height)}}function te(e,n){const t=window.getComputedStyle(e);return{margin:j(t.marginTop,t.marginRight,t.marginBottom,t.marginLeft),padding:j(t.paddingTop,t.paddingRight,t.paddingBottom,t.paddingLeft),border:j(t.borderTopWidth,t.borderRightWidth,t.borderBottomWidth,t.borderLeftWidth),fontFamily:t.fontFamily,fontSize:t.fontSize,lineHeight:t.lineHeight,color:t.color,backgroundColor:t.backgroundColor,width:Math.round(n.width),height:Math.round(n.height)}}function j(e,n,t,o){return e===n&&n===t&&t===o?e:`${e} ${n} ${t} ${o}`}function G(e){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(e):e.replace(/["\\]/g,"\\$&")}function ne({open:e,onOpenChange:n,placement:t="top-right",showResolved:o=!1}){const{config:s,currentUser:a,feedback:y,normalizedPath:S,permissions:c,createFeedback:l,resolveFeedback:i}=M(),[d,k]=p.useState(),[u,g]=p.useState(),[f,v]=p.useState(""),[m,b]=p.useState(),E=c.includes("create"),P=c.includes("resolve"),A=p.useMemo(()=>y.filter(h=>o||h.status!=="resolved"),[y,o]);p.useEffect(()=>{e||(k(void 0),g(void 0),v(""))},[e]);const N=p.useCallback(h=>{const I=h.target instanceof Element?h.target:null;if(I)return I.closest("[data-review-lens-ui]")?null:I;const C=document.elementFromPoint(h.clientX,h.clientY);return!C||C.closest("[data-review-lens-ui]")?null:C},[]);if(p.useEffect(()=>{if(!e||u)return;function h(C){const F=N(C);F&&k(L(F))}function I(C){const F=N(C);F&&(C.preventDefault(),C.stopPropagation(),g(L(F)))}return window.addEventListener("mousemove",h,!0),window.addEventListener("click",I,!0),()=>{window.removeEventListener("mousemove",h,!0),window.removeEventListener("click",I,!0)}},[N,u,e]),!e)return null;const $=u??d;async function ie(){!u||!f.trim()||!a||!E||(await l({projectKey:s.projectKey,contentId:s.contentId,normalizedPath:S,originalUrl:s.currentUrl??window.location.href,selector:u.selector,selectorStrategy:u.selectorStrategy,elementFingerprint:u.fingerprint,cssSnapshot:u.cssSnapshot,comment:f.trim(),authorEmail:a.email}),v(""),g(void 0))}return r.jsxs("div",{className:"review-lens-root","data-review-lens-ui":!0,children:[$?r.jsx(re,{target:$,locked:!!u}):null,r.jsx(oe,{feedback:A,selectedFeedback:m,onSelect:b}),r.jsxs("aside",{className:`review-lens-panel review-lens-panel--${t}`,"data-review-lens-ui":!0,children:[r.jsxs("header",{className:"review-lens-panel__header",children:[r.jsxs("div",{children:[r.jsx("p",{className:"review-lens-kicker",children:"Review Lens"}),r.jsx("h2",{children:u?"Element locked":"Inspecting"})]}),r.jsx("button",{type:"button",onClick:()=>n==null?void 0:n(!1),children:"Close"})]}),$?r.jsx(se,{target:$}):r.jsx("p",{children:"Move over the app to inspect."}),u?r.jsxs("form",{className:"review-lens-feedback-form",onSubmit:h=>{h.preventDefault(),ie()},children:[r.jsx("label",{htmlFor:"review-lens-comment",children:"Feedback"}),r.jsx("textarea",{id:"review-lens-comment",value:f,disabled:!E,onChange:h=>v(h.target.value),placeholder:E?"Describe the UX issue...":"You do not have permission to comment."}),r.jsxs("div",{className:"review-lens-actions",children:[r.jsx("button",{type:"button",onClick:()=>g(void 0),children:"Unlock"}),r.jsx("button",{type:"submit",disabled:!f.trim()||!E,children:"Save feedback"})]})]}):null,r.jsxs("section",{className:"review-lens-comments",children:[r.jsx("h3",{children:"Page feedback"}),A.length===0?r.jsx("p",{children:"No feedback for this view."}):null,A.map(h=>r.jsxs("article",{className:(m==null?void 0:m.id)===h.id?"review-lens-comment review-lens-comment--selected":"review-lens-comment",children:[r.jsx("p",{children:h.comment}),r.jsx("span",{children:h.authorEmail}),h.status==="open"&&P?r.jsx("button",{type:"button",onClick:()=>void i(h.id),children:"Resolve"}):null]},h.id))]})]})]})}function re({target:e,locked:n}){return r.jsx("div",{className:n?"review-lens-highlight review-lens-highlight--locked":"review-lens-highlight",style:{top:e.rect.top+window.scrollY,left:e.rect.left+window.scrollX,width:e.rect.width,height:e.rect.height}})}function oe({feedback:e,selectedFeedback:n,onSelect:t}){return r.jsx(r.Fragment,{children:e.map(o=>{const s=ae(o.selector),a=s==null?void 0:s.getBoundingClientRect();return a?r.jsx("button",{type:"button",className:(n==null?void 0:n.id)===o.id?"review-lens-marker review-lens-marker--selected":"review-lens-marker",style:{top:a.top+window.scrollY,left:a.left+window.scrollX+a.width},onClick:()=>t(o),"aria-label":`Open feedback from ${o.authorEmail}`},o.id):null})})}function se({target:e}){const n=[["Selector",e.selector],["Size",`${e.cssSnapshot.width} x ${e.cssSnapshot.height}`],["Margin",e.cssSnapshot.margin],["Padding",e.cssSnapshot.padding],["Border",e.cssSnapshot.border],["Font",`${e.cssSnapshot.fontSize} / ${e.cssSnapshot.lineHeight}`],["Family",e.cssSnapshot.fontFamily],["Color",e.cssSnapshot.color],["Background",e.cssSnapshot.backgroundColor]];return r.jsx("dl",{className:"review-lens-metrics",children:n.map(([t,o])=>r.jsxs("div",{children:[r.jsx("dt",{children:t}),r.jsx("dd",{children:o})]},t))})}function ae(e){try{return document.querySelector(e)}catch{return null}}w.ReviewLensOverlay=ne,w.ReviewLensProvider=Q,w.buildElementTarget=L,w.createGoogleSheetsAdapter=T,w.normalizeReviewUrl=B,w.useReviewLens=M,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"})}));
|
|
1
|
+
(function(y,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],n):(y=typeof globalThis<"u"?globalThis:y||self,n(y.ReviewLensReact={},y.jsxRuntime,y.React))})(this,(function(y,n,h){"use strict";const X=["https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email"].join(" "),Y="https://www.googleapis.com/oauth2/v3/userinfo";function W(e){const o=e.feedbackSheetName??"Feedback",t=e.usersSheetName??"Users";let s,r;async function c(){return s??(s=te(e.googleClientId)),s}async function u(a,d){const l=await c(),p=await fetch(`https://sheets.googleapis.com/v4/spreadsheets/${e.spreadsheetId}${a}`,{...d,headers:{Authorization:`Bearer ${l}`,"Content-Type":"application/json",...d==null?void 0:d.headers}});if(!p.ok)throw new Error(`Google Sheets request failed with ${p.status}`);return p.json()}async function w(a){return(await u(`/values/${encodeURIComponent(a)}`)).values??[]}return{async getCurrentUser(){if(!r){const a=await c(),d=await fetch(Y,{headers:{Authorization:`Bearer ${a}`}});if(!d.ok)throw new Error(`Google userinfo request failed with ${d.status}`);r=(await d.json()).email}if(!r)throw new Error("Google account did not return an email address");return{email:r}},async getPermissions(a){const[{email:d},l]=await Promise.all([this.getCurrentUser(),w(t)]),p=_(l),k=d.toLowerCase(),f=p.find(b=>{var g;return((g=b.email)==null?void 0:g.toLowerCase())===k&&b.active!=="false"&&(!b.projectKey||b.projectKey===a)});return ee((f==null?void 0:f.role)??"designer")},async listFeedback(a){return _(await w(o)).map(z).filter(l=>l!==null).filter(l=>l.projectKey===a.projectKey&&l.contentId===a.contentId&&l.normalizedPath===a.normalizedPath).sort((l,p)=>p.createdAt.localeCompare(l.createdAt))},async createFeedback(a){const d=new Date().toISOString(),l={...a,id:crypto.randomUUID(),status:"open",createdAt:d,updatedAt:d};return await u(`/values/${encodeURIComponent(o)}:append?valueInputOption=RAW`,{method:"POST",body:JSON.stringify({values:[Z(l)]})}),l},async resolveFeedback(a,d){const l=await w(o),p=l[0]??V,k=p.indexOf("id"),f=p.indexOf("status"),b=p.indexOf("updatedAt"),g=p.indexOf("resolvedAt"),S=p.indexOf("resolvedBy"),v=l.findIndex((C,B)=>B>0&&C[k]===a);if(v<1)throw new Error(`Feedback ${a} was not found`);const E=[...l[v]],T=new Date().toISOString();E[f]="resolved",E[b]=T,E[g]=T,E[S]=d,await u(`/values/${encodeURIComponent(o)}!A${v+1}:Q${v+1}?valueInputOption=RAW`,{method:"PUT",body:JSON.stringify({values:[E]})});const N=z(U(p,E));if(!N)throw new Error(`Feedback ${a} could not be parsed after resolving`);return N}}}const V=["id","projectKey","contentId","normalizedPath","originalUrl","selector","selectorStrategy","elementFingerprintJson","cssSnapshotJson","comment","status","authorEmail","createdAt","updatedAt","resolvedAt","resolvedBy"];function Z(e){return[e.id,e.projectKey,e.contentId,e.normalizedPath,e.originalUrl,e.selector,e.selectorStrategy,JSON.stringify(e.elementFingerprint),JSON.stringify(e.cssSnapshot),e.comment,e.status,e.authorEmail,e.createdAt,e.updatedAt,e.resolvedAt??"",e.resolvedBy??""]}function _(e){const[o,...t]=e;return o?t.map(s=>U(o,s)):[]}function U(e,o){return Object.fromEntries(e.map((t,s)=>[t,o[s]??""]))}function z(e){return e.id?{id:e.id,projectKey:e.projectKey,contentId:e.contentId,normalizedPath:e.normalizedPath,originalUrl:e.originalUrl,selector:e.selector,selectorStrategy:e.selectorStrategy==="stable-attribute"?"stable-attribute":"css-path",elementFingerprint:K(e.elementFingerprintJson,{tagName:"",width:0,height:0}),cssSnapshot:R(e.cssSnapshotJson),comment:e.comment,status:e.status==="resolved"?"resolved":"open",authorEmail:e.authorEmail,createdAt:e.createdAt,updatedAt:e.updatedAt,resolvedAt:e.resolvedAt||void 0,resolvedBy:e.resolvedBy||void 0}:null}function K(e,o){try{return e?JSON.parse(e):o}catch{return o}}function R(e){const o=K(e,{});return{margin:o.margin??"",marginTop:o.marginTop??"",marginRight:o.marginRight??"",marginBottom:o.marginBottom??"",marginLeft:o.marginLeft??"",padding:o.padding??"",paddingTop:o.paddingTop??"",paddingRight:o.paddingRight??"",paddingBottom:o.paddingBottom??"",paddingLeft:o.paddingLeft??"",border:o.border??"",borderTopWidth:o.borderTopWidth??"",borderRightWidth:o.borderRightWidth??"",borderBottomWidth:o.borderBottomWidth??"",borderLeftWidth:o.borderLeftWidth??"",fontFamily:o.fontFamily??"",fontSize:o.fontSize??"",lineHeight:o.lineHeight??"",color:o.color??"",backgroundColor:o.backgroundColor??"",width:o.width??0,height:o.height??0}}function ee(e){return e==="admin"?["create","read","resolve"]:e==="developer"?["read","resolve"]:["create","read"]}async function te(e){return await oe(),new Promise((o,t)=>{var r;const s=(r=window.google)==null?void 0:r.accounts.oauth2.initTokenClient({client_id:e,scope:X,callback:c=>{if(c.error||!c.access_token){t(new Error(c.error??"Google OAuth did not return an access token"));return}o(c.access_token)}});s==null||s.requestAccessToken({prompt:""})})}function oe(){var e;return(e=window.google)!=null&&e.accounts.oauth2?Promise.resolve():new Promise((o,t)=>{const s=document.querySelector('script[src="https://accounts.google.com/gsi/client"]');if(s){s.addEventListener("load",()=>o(),{once:!0}),s.addEventListener("error",()=>t(new Error("Google Identity failed to load")),{once:!0});return}const r=document.createElement("script");r.src="https://accounts.google.com/gsi/client",r.async=!0,r.defer=!0,r.onload=()=>o(),r.onerror=()=>t(new Error("Google Identity failed to load")),document.head.append(r)})}function O(e){return new URL(e,window.location.href).pathname.replace(/\/+$/,"")||"/"}const D=h.createContext(null);function ne({config:e,children:o}){const t=h.useMemo(()=>e.adapter?e.adapter:W({googleClientId:G(e.googleClientId,"googleClientId"),spreadsheetId:G(e.spreadsheetId,"spreadsheetId"),feedbackSheetName:e.sheetName??"Feedback"}),[e.adapter,e.googleClientId,e.sheetName,e.spreadsheetId]),s=e.currentUrl??window.location.href,r=(e.normalizeUrl??O)(s),[c,u]=h.useState(),[w,a]=h.useState([]),[d,l]=h.useState([]),p=h.useCallback(async()=>{const g=await t.listFeedback({projectKey:e.projectKey,contentId:e.contentId,normalizedPath:r});l(g)},[t,e.contentId,e.projectKey,r]);h.useEffect(()=>{let g=!0;async function S(){const[v,E]=await Promise.all([t.getCurrentUser(),t.getPermissions(e.projectKey)]);g&&(u(v),a(E),await p())}return S(),()=>{g=!1}},[t,e.projectKey,p]);const k=h.useCallback(async g=>{const S=await t.createFeedback(g);return l(v=>[S,...v]),S},[t]),f=h.useCallback(async g=>{const S=await t.resolveFeedback(g,(c==null?void 0:c.email)??"");return l(v=>v.map(E=>E.id===g?S:E)),S},[t,c==null?void 0:c.email]),b=h.useMemo(()=>({config:e,adapter:t,currentUser:c,permissions:w,feedback:d,normalizedPath:r,refreshFeedback:p,createFeedback:k,resolveFeedback:f}),[t,e,k,c,d,r,w,p,f]);return n.jsx(D.Provider,{value:b,children:o})}function q(){const e=h.useContext(D);if(!e)throw new Error("useReviewLens must be used inside ReviewLensProvider");return e}function G(e,o){if(!e)throw new Error(`review-lens-react requires config.${o} when no adapter is provided`);return e}const re=["data-review-id","data-testid","data-test-id","aria-label","name"];function P(e){const o=e.getBoundingClientRect(),t=se(e);return{selector:t.selector,selectorStrategy:t.strategy,fingerprint:ae(e,o),cssSnapshot:de(e,o),rect:o}}function se(e){for(const o of re){const t=e.getAttribute(o);if(t)return{selector:`[${o}="${J(t)}"]`,strategy:"stable-attribute"}}return e.id?{selector:`#${J(e.id)}`,strategy:"stable-attribute"}:{selector:ie(e),strategy:"css-path"}}function ie(e){const o=[];let t=e;for(;t&&t.nodeType===Node.ELEMENT_NODE&&t!==document.body;){const s=t.parentElement,r=t.tagName.toLowerCase();if(!s){o.unshift(r);break}const c=t.tagName,u=Array.from(s.children).filter(a=>a.tagName===c),w=u.indexOf(t)+1;o.unshift(u.length>1?`${r}:nth-of-type(${w})`:r),t=s}return o.join(" > ")}function ae(e,o){var t;return{tagName:e.tagName.toLowerCase(),id:e.id||void 0,className:e.getAttribute("class")||void 0,textSnippet:((t=e.textContent)==null?void 0:t.trim().slice(0,80))||void 0,ariaLabel:e.getAttribute("aria-label")||void 0,width:Math.round(o.width),height:Math.round(o.height)}}function de(e,o){const t=window.getComputedStyle(e);return{margin:$(t.marginTop,t.marginRight,t.marginBottom,t.marginLeft),marginTop:t.marginTop,marginRight:t.marginRight,marginBottom:t.marginBottom,marginLeft:t.marginLeft,padding:$(t.paddingTop,t.paddingRight,t.paddingBottom,t.paddingLeft),paddingTop:t.paddingTop,paddingRight:t.paddingRight,paddingBottom:t.paddingBottom,paddingLeft:t.paddingLeft,border:$(t.borderTopWidth,t.borderRightWidth,t.borderBottomWidth,t.borderLeftWidth),borderTopWidth:t.borderTopWidth,borderRightWidth:t.borderRightWidth,borderBottomWidth:t.borderBottomWidth,borderLeftWidth:t.borderLeftWidth,fontFamily:t.fontFamily,fontSize:t.fontSize,lineHeight:t.lineHeight,color:t.color,backgroundColor:t.backgroundColor,width:Math.round(o.width),height:Math.round(o.height)}}function $(e,o,t,s){return e===o&&o===t&&t===s?e:`${e} ${o} ${t} ${s}`}function J(e){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(e):e.replace(/["\\]/g,"\\$&")}function ce({open:e,onOpenChange:o,placement:t="top-right",showResolved:s=!1}){const{config:r,currentUser:c,feedback:u,normalizedPath:w,permissions:a,createFeedback:d,resolveFeedback:l}=q(),[p,k]=h.useState(),[f,b]=h.useState(),[g,S]=h.useState(""),[v,E]=h.useState(),[T,N]=h.useState("review"),C=!!c,B=a.includes("create"),ge=a.includes("resolve"),I=h.useMemo(()=>u.filter(i=>s||i.status!=="resolved"),[u,s]);h.useEffect(()=>{e||(k(void 0),b(void 0),S(""),N("review"))},[e]),h.useEffect(()=>{C||(k(void 0),b(void 0))},[C]),h.useEffect(()=>{if(!e)return;function i(m){m.key==="Escape"&&(m.preventDefault(),o==null||o(!1))}return window.addEventListener("keydown",i),()=>{window.removeEventListener("keydown",i)}},[o,e]);const j=h.useCallback(i=>{const m=i.target instanceof Element?i.target:null;if(m)return m.closest("[data-review-lens-ui]")?null:m;const F=document.elementFromPoint(i.clientX,i.clientY);return!F||F.closest("[data-review-lens-ui]")?null:F},[]);if(h.useEffect(()=>{if(!e||!C)return;function i(F){const x=j(F);k(x?P(x):void 0)}function m(F){const x=j(F);x&&(F.preventDefault(),F.stopPropagation(),b(P(x)),N("review"))}return window.addEventListener("mousemove",i,!0),window.addEventListener("click",m,!0),()=>{window.removeEventListener("mousemove",i,!0),window.removeEventListener("click",m,!0)}},[C,j,f,e]),!e)return null;const A=p??f,me=!!f;function M(i){E(i),b(void 0),N("feedback");const m=H(i.selector);m&&(m.scrollIntoView({behavior:"smooth",block:"center",inline:"center"}),window.requestAnimationFrame(()=>{k(P(m))}))}async function Q(){!f||!g.trim()||!c||!B||(await d({projectKey:r.projectKey,contentId:r.contentId,normalizedPath:w,originalUrl:r.currentUrl??window.location.href,selector:f.selector,selectorStrategy:f.selectorStrategy,elementFingerprint:f.fingerprint,cssSnapshot:f.cssSnapshot,comment:g.trim(),authorEmail:c.email}),S(""),b(void 0),k(void 0),N("feedback"))}return n.jsxs("div",{className:"review-lens-root","data-review-lens-ui":!0,children:[C&&A?n.jsx(le,{target:A,locked:!!f}):null,C?n.jsx(he,{feedback:I,selectedFeedback:v,onSelect:M}):null,n.jsxs("aside",{className:`review-lens-panel review-lens-panel--${t}`,"data-review-lens-ui":!0,children:[n.jsxs("header",{className:"review-lens-panel__header",children:[n.jsxs("div",{children:[n.jsx("p",{className:"review-lens-kicker",children:"Review Lens"}),n.jsx("h2",{children:T==="feedback"?"Feedback":f?"Element locked":"Inspecting"})]}),n.jsx("button",{type:"button",onClick:()=>o==null?void 0:o(!1),children:"Close"})]}),n.jsxs("div",{className:"review-lens-panel__body",children:[n.jsxs("div",{className:"review-lens-mode-switch",role:"tablist","aria-label":"Review Lens mode",children:[n.jsx("button",{type:"button",role:"tab","aria-selected":T==="review",onClick:()=>N("review"),children:"Review"}),n.jsxs("button",{type:"button",role:"tab","aria-selected":T==="feedback",onClick:()=>N("feedback"),children:["Feedback ",n.jsx("span",{children:I.length})]})]}),T==="review"?n.jsxs("div",{className:"review-lens-review-pane",role:"tabpanel",children:[n.jsxs("div",{className:"review-lens-inspection",children:[C?null:n.jsx("p",{children:"Authenticate with Google to inspect this page."}),C&&A?n.jsx(pe,{target:A}):null,C&&!A?n.jsx("p",{children:"Move over the app to inspect."}):null]}),me?n.jsxs("form",{className:"review-lens-feedback-form",onSubmit:i=>{i.preventDefault(),Q()},children:[n.jsx("label",{htmlFor:"review-lens-comment",children:"New feedback"}),n.jsx("textarea",{id:"review-lens-comment",value:g,disabled:!B,onChange:i=>S(i.target.value),onKeyDown:i=>{i.key==="Enter"&&i.metaKey&&(i.preventDefault(),Q())},placeholder:B?"Describe the UX issue...":"You do not have permission to comment."}),B?n.jsxs("p",{className:"review-lens-feedback-form__hint",children:["Press ",n.jsx("kbd",{children:"Command"})," + ",n.jsx("kbd",{children:"Enter"})," to submit."]}):null,n.jsx("div",{className:"review-lens-actions",children:n.jsx("button",{type:"submit",disabled:!g.trim()||!B,children:"Save feedback"})})]}):null]}):n.jsxs("div",{className:"review-lens-comments",children:[n.jsxs("div",{className:"review-lens-comments__header",children:[n.jsx("h3",{children:"Page feedback"}),n.jsx("span",{children:I.length})]}),n.jsxs("div",{className:"review-lens-comments__list",children:[I.length===0?n.jsx("p",{children:"No feedback for this view."}):null,I.map(i=>n.jsxs("article",{tabIndex:0,className:(v==null?void 0:v.id)===i.id?"review-lens-comment review-lens-comment--selected":"review-lens-comment",onClick:()=>M(i),onKeyDown:m=>{(m.key==="Enter"||m.key===" ")&&(m.preventDefault(),M(i))},children:[n.jsxs("div",{className:"review-lens-comment__content",children:[n.jsx("p",{children:i.comment}),n.jsx("span",{children:i.authorEmail})]}),i.status==="open"&&ge?n.jsx("div",{className:"review-lens-comment__actions",children:n.jsx("button",{type:"button",onClick:m=>{m.stopPropagation(),l(i.id)},children:"Resolve"})}):null]},i.id))]})]})]})]})]})}function le({target:e,locked:o}){const t=fe(e);return n.jsxs("div",{className:o?"review-lens-highlight review-lens-highlight--locked":"review-lens-highlight",style:{top:t.margin.top,left:t.margin.left,width:t.margin.width,height:t.margin.height},children:[n.jsx("div",{className:"review-lens-highlight__border",style:{top:t.border.top-t.margin.top,left:t.border.left-t.margin.left,width:t.border.width,height:t.border.height}}),n.jsx("div",{className:"review-lens-highlight__padding",style:{top:t.padding.top-t.margin.top,left:t.padding.left-t.margin.left,width:t.padding.width,height:t.padding.height}}),n.jsx("div",{className:"review-lens-highlight__content",style:{top:t.content.top-t.margin.top,left:t.content.left-t.margin.left,width:t.content.width,height:t.content.height}}),n.jsxs("div",{className:"review-lens-highlight__label",children:[Math.round(e.rect.width)," x ",Math.round(e.rect.height)]})]})}function he({feedback:e,selectedFeedback:o,onSelect:t}){return n.jsx(n.Fragment,{children:e.map(s=>n.jsx(ue,{feedback:s,selected:(o==null?void 0:o.id)===s.id,onSelect:t},s.id))})}function ue({feedback:e,selected:o,onSelect:t}){const s=h.useRef(null);return h.useLayoutEffect(()=>{let r=0;const c=()=>{r=0;const w=s.current,a=H(e.selector),d=a==null?void 0:a.getBoundingClientRect();!w||!d||(w.style.top=`${d.top}px`,w.style.left=`${d.right}px`,w.hidden=d.bottom<0||d.top>window.innerHeight)},u=()=>{r||(r=window.requestAnimationFrame(c))};return c(),window.addEventListener("scroll",u,!0),window.addEventListener("resize",u),()=>{r&&window.cancelAnimationFrame(r),window.removeEventListener("scroll",u,!0),window.removeEventListener("resize",u)}},[e.selector]),n.jsx("button",{ref:s,type:"button",className:o?"review-lens-marker review-lens-marker--selected":"review-lens-marker",onClick:()=>t(e),"aria-label":`Open feedback from ${e.authorEmail}`})}function pe({target:e}){const o=[["Selector",e.selector],["Size",`${e.cssSnapshot.width} x ${e.cssSnapshot.height}`],["Margin",e.cssSnapshot.margin],["Padding",e.cssSnapshot.padding],["Border",e.cssSnapshot.border],["Font",`${e.cssSnapshot.fontSize} / ${e.cssSnapshot.lineHeight}`],["Family",e.cssSnapshot.fontFamily],["Color",e.cssSnapshot.color],["Background",e.cssSnapshot.backgroundColor]];return n.jsx("dl",{className:"review-lens-metrics",children:o.map(([t,s])=>n.jsxs("div",{children:[n.jsx("dt",{children:t}),n.jsx("dd",{children:s})]},t))})}function H(e){try{return document.querySelector(e)}catch{return null}}function fe(e){const o={top:L(e.cssSnapshot.marginTop),right:L(e.cssSnapshot.marginRight),bottom:L(e.cssSnapshot.marginBottom),left:L(e.cssSnapshot.marginLeft)},t={top:L(e.cssSnapshot.borderTopWidth),right:L(e.cssSnapshot.borderRightWidth),bottom:L(e.cssSnapshot.borderBottomWidth),left:L(e.cssSnapshot.borderLeftWidth)},s={top:L(e.cssSnapshot.paddingTop),right:L(e.cssSnapshot.paddingRight),bottom:L(e.cssSnapshot.paddingBottom),left:L(e.cssSnapshot.paddingLeft)},r={top:e.rect.top,left:e.rect.left,width:Math.max(e.rect.width,0),height:Math.max(e.rect.height,0)},c={top:r.top-o.top,left:r.left-o.left,width:r.width+o.left+o.right,height:r.height+o.top+o.bottom},u={top:r.top+t.top,left:r.left+t.left,width:Math.max(r.width-t.left-t.right,0),height:Math.max(r.height-t.top-t.bottom,0)},w={top:u.top+s.top,left:u.left+s.left,width:Math.max(u.width-s.left-s.right,0),height:Math.max(u.height-s.top-s.bottom,0)};return{margin:c,border:r,padding:u,content:w}}function L(e){const o=Number.parseFloat(e||"0");return Number.isFinite(o)?o:0}y.ReviewLensOverlay=ce,y.ReviewLensProvider=ne,y.buildElementTarget=P,y.createGoogleSheetsAdapter=W,y.normalizeReviewUrl=O,y.useReviewLens=q,Object.defineProperty(y,Symbol.toStringTag,{value:"Module"})}));
|
package/dist/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.review-lens-root{color:#171717;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;position:fixed;z-index:2147483647}.review-lens-highlight{
|
|
1
|
+
.review-lens-root{color:#171717;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;top:0;right:0;bottom:0;left:0;pointer-events:none;position:fixed;z-index:2147483647}.review-lens-highlight{background:#f9731633;box-shadow:0 0 0 9999px #0f172a14;box-sizing:border-box;pointer-events:none;position:fixed}.review-lens-highlight--locked{box-shadow:0 0 0 9999px #0f172a1f}.review-lens-highlight__border,.review-lens-highlight__padding,.review-lens-highlight__content{box-sizing:border-box;position:absolute}.review-lens-highlight__border{border:2px solid #facc15;background:#facc1538}.review-lens-highlight__padding{border:2px solid #22c55e;background:#22c55e38}.review-lens-highlight__content{border:2px solid #2563eb;background:#2563eb29}.review-lens-highlight--locked .review-lens-highlight__content{border-color:#f97316}.review-lens-highlight__label{background:#171717;border-radius:4px;color:#fff;font-size:11px;font-weight:700;left:0;line-height:1;padding:4px 6px;position:absolute;top:-24px;white-space:nowrap}.review-lens-panel{background:#fafafa;border:1px solid #d4d4d4;border-radius:8px;box-shadow:0 24px 70px #0f172a38;box-sizing:border-box;display:flex;flex-direction:column;height:min(680px,calc(100vh - 32px));min-height:min(520px,calc(100vh - 32px));overflow:hidden;padding:16px;pointer-events:auto;position:fixed;width:min(380px,calc(100vw - 32px))}.review-lens-panel--top-left{left:16px;top:16px}.review-lens-panel--top-right{right:16px;top:16px}.review-lens-panel--bottom-left{bottom:16px;left:16px}.review-lens-panel--bottom-right{bottom:16px;right:16px}.review-lens-panel__header{flex:0 0 auto;align-items:flex-start;display:flex;gap:16px;justify-content:space-between;margin-bottom:12px}.review-lens-panel__body{display:flex;flex:1 1 auto;flex-direction:column;gap:16px;min-height:0;overflow:hidden}.review-lens-panel h2,.review-lens-panel h3,.review-lens-panel p{margin:0}.review-lens-panel h2{font-size:18px;line-height:1.25}.review-lens-panel h3{font-size:14px;margin-top:18px}.review-lens-kicker{color:#525252;font-size:11px;font-weight:700;letter-spacing:0;text-transform:uppercase}.review-lens-panel button{background:#171717;border:1px solid #171717;border-radius:6px;color:#fff;cursor:pointer;font:inherit;font-size:13px;min-height:32px;padding:6px 10px;transition:transform .14s cubic-bezier(.23,1,.32,1)}.review-lens-panel button:active{transform:scale(.97)}.review-lens-panel button:disabled{cursor:not-allowed;opacity:.45}.review-lens-mode-switch{background:#eee;border:1px solid #d4d4d4;border-radius:7px;display:grid;flex:0 0 auto;gap:2px;grid-template-columns:repeat(2,minmax(0,1fr));padding:2px}.review-lens-mode-switch button{background:transparent;border:0;color:#525252;min-height:30px}.review-lens-mode-switch button[aria-selected=true]{background:#fff;box-shadow:0 1px 4px #0f172a1f;color:#171717}.review-lens-mode-switch span{color:#737373;font-size:11px}.review-lens-metrics{border:1px solid #e5e5e5;border-radius:8px;display:grid;gap:0;margin:0;overflow:hidden}.review-lens-metrics div{display:grid;grid-template-columns:96px minmax(0,1fr)}.review-lens-metrics dt,.review-lens-metrics dd{border-bottom:1px solid #e5e5e5;font-size:11px;margin:0;min-width:0;padding:6px 8px}.review-lens-metrics dt{background:#f5f5f5;color:#525252;font-weight:700}.review-lens-metrics dd{overflow-wrap:anywhere}.review-lens-inspection{display:grid;flex:0 0 auto;gap:16px}.review-lens-review-pane{display:flex;flex:1 1 auto;flex-direction:column;gap:16px;min-height:0}.review-lens-feedback-form{display:grid;flex:1 1 auto;gap:8px;grid-template-rows:auto minmax(96px,1fr) auto auto;margin-top:0;min-height:0}.review-lens-feedback-form label{font-size:13px;font-weight:700}.review-lens-feedback-form textarea{border:1px solid #d4d4d4;border-radius:8px;box-sizing:border-box;flex:1 1 auto;font:inherit;min-height:96px;padding:10px;resize:vertical;width:100%}.review-lens-feedback-form__hint{color:#737373;font-size:12px;line-height:1.4}.review-lens-feedback-form__hint kbd{background:#f5f5f5;border:1px solid #d4d4d4;border-radius:4px;color:#404040;font-family:inherit;font-size:11px;padding:1px 4px}.review-lens-actions{display:flex;gap:8px;justify-content:flex-end}.review-lens-comments{border-top:1px solid #e5e5e5;display:flex;flex:1 1 auto;flex-direction:column;gap:8px;min-height:0;padding-top:12px}.review-lens-comments__header{align-items:center;color:#171717;display:flex;gap:8px;justify-content:space-between}.review-lens-comments__header h3{font-size:13px;margin:0}.review-lens-comments__header span{align-items:center;background:#e5e5e5;border-radius:999px;color:#404040;display:inline-flex;font-size:11px;justify-content:center;min-width:22px;padding:2px 7px}.review-lens-comments__list{align-content:start;display:grid;gap:10px;min-height:0;overflow:auto;padding-right:4px}.review-lens-comment{background:linear-gradient(180deg,#fffffffa,#fafafafa);border:1px solid #e5e5e5;border-radius:8px;box-shadow:0 1px 2px #0f172a0a;cursor:pointer;display:grid;gap:10px;padding:12px;position:relative;text-align:left}.review-lens-comment:focus-visible{outline:2px solid #2563eb;outline-offset:2px}.review-lens-comment--selected{background:#eff6ff;border-color:#2563eb;box-shadow:inset 3px 0 #2563eb,0 8px 18px #2563eb1f}.review-lens-comment__content{display:grid;gap:6px}.review-lens-comment__content p{color:#171717;font-size:14px;line-height:1.35}.review-lens-comment__content span{color:#525252;font-size:11px;line-height:1}.review-lens-comment__actions{display:flex;justify-content:flex-end}.review-lens-comment__actions button{background:transparent;border-color:#d4d4d4;color:#404040;min-height:28px;padding:4px 10px}.review-lens-comment__actions button:hover{background:#171717;border-color:#171717;color:#fff}.review-lens-marker{background:#f97316;border:2px solid #ffffff;border-radius:999px;box-shadow:0 8px 20px #0f172a3d;cursor:pointer;height:18px;pointer-events:auto;position:fixed;transform:translate(-50%,-50%);width:18px}.review-lens-marker--selected{background:#2563eb}
|
package/dist/types.d.ts
CHANGED
|
@@ -4,8 +4,20 @@ export type ReviewLensRole = "designer" | "developer" | "admin";
|
|
|
4
4
|
export type ReviewLensPermission = "create" | "read" | "resolve";
|
|
5
5
|
export type CssSnapshot = {
|
|
6
6
|
margin: string;
|
|
7
|
+
marginTop: string;
|
|
8
|
+
marginRight: string;
|
|
9
|
+
marginBottom: string;
|
|
10
|
+
marginLeft: string;
|
|
7
11
|
padding: string;
|
|
12
|
+
paddingTop: string;
|
|
13
|
+
paddingRight: string;
|
|
14
|
+
paddingBottom: string;
|
|
15
|
+
paddingLeft: string;
|
|
8
16
|
border: string;
|
|
17
|
+
borderTopWidth: string;
|
|
18
|
+
borderRightWidth: string;
|
|
19
|
+
borderBottomWidth: string;
|
|
20
|
+
borderLeftWidth: string;
|
|
9
21
|
fontFamily: string;
|
|
10
22
|
fontSize: string;
|
|
11
23
|
lineHeight: string;
|