@llumi/design-system 1.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +51 -0
  2. package/NOTICE +66 -0
  3. package/README.md +15 -205
  4. package/adopt-global-styles-D9108lqB.js +15 -0
  5. package/base.css +2 -0
  6. package/base.md +59 -0
  7. package/bpmn.md +113 -0
  8. package/bpmn.mjs +5076 -0
  9. package/copy-button.md +128 -0
  10. package/copy-button.mjs +161 -0
  11. package/custom-elements.json +1135 -18
  12. package/download-button.md +106 -0
  13. package/download-button.mjs +177 -0
  14. package/highlighter.md +45 -0
  15. package/highlighter.mjs +403 -0
  16. package/icon-button-BwB11RGC.js +5 -0
  17. package/icons-BaUbjt-v.js +42 -0
  18. package/index-BEhA78nX.js +7733 -0
  19. package/llumi-element-BWRwgzW5.js +22 -0
  20. package/mermaid.md +58 -0
  21. package/mermaid.mjs +254 -0
  22. package/package.json +16 -50
  23. package/review.md +141 -0
  24. package/review.mjs +2044 -0
  25. package/slot-text-mSWBdWBc.js +51 -0
  26. package/theme.css +2 -0
  27. package/dist/review.cjs +0 -172
  28. package/dist/review.css +0 -98
  29. package/dist/review.js +0 -172
  30. package/dist/review.mjs +0 -1710
  31. package/dist/types/components/review/comment-dialog.element.d.ts +0 -29
  32. package/dist/types/components/review/custom-target.utils.d.ts +0 -16
  33. package/dist/types/components/review/default-editor.element.d.ts +0 -19
  34. package/dist/types/components/review/highlight-manager.d.ts +0 -21
  35. package/dist/types/components/review/index.d.ts +0 -8
  36. package/dist/types/components/review/overall-comment-dialog.element.d.ts +0 -22
  37. package/dist/types/components/review/review-bar.element.d.ts +0 -26
  38. package/dist/types/components/review/review.element.d.ts +0 -60
  39. package/dist/types/components/review/review.machine.d.ts +0 -234
  40. package/dist/types/components/review/review.persistence.d.ts +0 -16
  41. package/dist/types/components/review/review.type.d.ts +0 -37
  42. package/dist/types/components/review/selection-comment-icons.element.d.ts +0 -17
  43. package/dist/types/components/review/selection-range.utils.d.ts +0 -6
  44. package/dist/types/components/review/sort-comments.utils.d.ts +0 -6
  45. package/dist/types/index.d.ts +0 -1
  46. package/dist/types/shared/cn.d.ts +0 -2
  47. package/dist/types/shared/icons.d.ts +0 -7
  48. package/dist/types/shared/tailwind-element.d.ts +0 -4
package/review.mjs ADDED
@@ -0,0 +1,2044 @@
1
+ import { fromCallback as rt, setup as xt, emit as st, assign as E, stateIn as yt, enqueueActions as It, createActor as St } from "https://cdn.jsdelivr.net/npm/xstate@5.32.2";
2
+ import { a as Tt } from "./adopt-global-styles-D9108lqB.js";
3
+ import { tinykeys as Lt } from "https://cdn.jsdelivr.net/npm/tinykeys@3.1.0";
4
+ import { html as w, css as F } from "https://cdn.jsdelivr.net/npm/lit@3.3.3";
5
+ import { property as v, query as U, state as Ot, customElement as k } from "https://cdn.jsdelivr.net/npm/lit@3.3.3/decorators.js";
6
+ import { classMap as A } from "https://cdn.jsdelivr.net/npm/lit@3.3.3/directives/class-map.js";
7
+ import { i as M } from "./icons-BaUbjt-v.js";
8
+ import { L as C } from "./llumi-element-BWRwgzW5.js";
9
+ import { autoUpdate as gt, computePosition as ut, offset as pt, flip as ft, shift as vt, size as bt } from "https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.7.6";
10
+ import { repeat as At } from "https://cdn.jsdelivr.net/npm/lit@3.3.3/directives/repeat.js";
11
+ import { styleMap as Dt } from "https://cdn.jsdelivr.net/npm/lit@3.3.3/directives/style-map.js";
12
+ /*! @llumi/design-system v2.1.0 | (c) 2026 pAIrprog SAS | license: https://cdn.jsdelivr.net/npm/@llumi/design-system@2.1.0/LICENSE | bundled third-party components under MIT, see NOTICE | @license */
13
+ function at(o, e) {
14
+ const t = o.getAttribute("data-review-id");
15
+ if (t) return t;
16
+ for (const n of e ?? [])
17
+ if (o.matches(n.selector)) {
18
+ const i = n.toId(o);
19
+ if (i) return i;
20
+ }
21
+ return null;
22
+ }
23
+ function _(o, e) {
24
+ const t = o.closest("[data-review-id]");
25
+ if (t) {
26
+ const n = t.getAttribute("data-review-id");
27
+ if (n) return { element: t, targetId: n };
28
+ }
29
+ for (const n of e ?? []) {
30
+ const i = o.closest(n.selector);
31
+ if (i) {
32
+ const r = n.toId(i);
33
+ if (r) return { element: i, targetId: r };
34
+ }
35
+ }
36
+ return null;
37
+ }
38
+ function D(o, e) {
39
+ const t = /* @__PURE__ */ new Set(), n = [];
40
+ for (const i of Array.from(
41
+ o.querySelectorAll("[data-review-id]")
42
+ )) {
43
+ const r = i.getAttribute("data-review-id");
44
+ if (!r) continue;
45
+ const s = i.hasAttribute("data-review-selectable");
46
+ n.push({
47
+ element: i,
48
+ targetId: r,
49
+ kind: s ? "both" : "element"
50
+ }), t.add(i);
51
+ }
52
+ for (const i of e ?? [])
53
+ for (const r of Array.from(
54
+ o.querySelectorAll(i.selector)
55
+ )) {
56
+ if (t.has(r)) continue;
57
+ const s = i.toId(r);
58
+ if (!s) continue;
59
+ const a = r.hasAttribute("data-review-selectable");
60
+ n.push({
61
+ element: r,
62
+ targetId: s,
63
+ kind: a ? "both" : "element"
64
+ }), t.add(r);
65
+ }
66
+ for (const i of Array.from(
67
+ o.querySelectorAll("[data-review-selectable]")
68
+ )) {
69
+ if (t.has(i)) continue;
70
+ const r = i.getAttribute("data-review-selectable");
71
+ r && (n.push({ element: i, targetId: r, kind: "selectable" }), t.add(i));
72
+ }
73
+ return n;
74
+ }
75
+ const J = "review-highlight-hover", y = "review-highlight-commented", $ = "review-highlight-editing", H = "review-highlight-uncommented", j = "review-target", lt = "review-active";
76
+ function q(o) {
77
+ o.classList.remove(
78
+ J,
79
+ y,
80
+ $,
81
+ H
82
+ );
83
+ }
84
+ function kt(o, e) {
85
+ let t = null, n = null, i = null;
86
+ function r(c) {
87
+ o.classList.add(lt);
88
+ const m = D(o, e);
89
+ for (const { element: f, targetId: d, kind: O } of m)
90
+ (O === "element" || O === "both") && (f.hasAttribute("data-review-id") || f.classList.add(j), c.has(d) && f.classList.add(y));
91
+ }
92
+ function s() {
93
+ o.classList.remove(lt), t && (clearTimeout(t), t = null);
94
+ const c = D(o, e);
95
+ for (const { element: m } of c)
96
+ q(m), m.classList.remove(j);
97
+ }
98
+ function a(c) {
99
+ const m = D(o, e), f = [];
100
+ for (const { element: d } of m)
101
+ !d.classList.contains(y) && !d.classList.contains($) && (d.classList.add(H), f.push(d));
102
+ c && (t && clearTimeout(t), t = setTimeout(() => {
103
+ t = null;
104
+ for (const d of f)
105
+ d.classList.contains($) || d.classList.remove(H);
106
+ }, 500));
107
+ }
108
+ function l() {
109
+ t && (clearTimeout(t), t = null);
110
+ const c = D(o, e);
111
+ for (const { element: m } of c)
112
+ m.classList.remove(H);
113
+ }
114
+ function h(c, m) {
115
+ m || (q(c), c.classList.add($));
116
+ }
117
+ function u(c, m) {
118
+ q(c), m && c.classList.add(y);
119
+ }
120
+ function p(c, m) {
121
+ (at(c, e) ?? c.getAttribute("data-review-selectable")) !== m && c.classList.add(J);
122
+ }
123
+ function g(c, m, f) {
124
+ const d = at(c, e) ?? c.getAttribute("data-review-selectable");
125
+ d !== m && (c.classList.remove(J), d && (f != null && f.has(d)) && c.classList.add(y));
126
+ }
127
+ function Et(c) {
128
+ W(), i = c.editingTarget ?? null, n = new MutationObserver((m) => {
129
+ for (const f of m) {
130
+ for (const d of Array.from(f.removedNodes)) {
131
+ if (!(d instanceof HTMLElement)) continue;
132
+ i && (d === i || d.contains(i)) && (i = null, c.onTargetDisconnected()), (d.hasAttribute("data-review-selectable") || d.querySelector("[data-review-selectable]") !== null) && c.onSelectableReconnected();
133
+ }
134
+ for (const d of Array.from(f.addedNodes)) {
135
+ if (!(d instanceof HTMLElement)) continue;
136
+ const O = [
137
+ ...d.matches("[data-review-id]") ? [d] : [],
138
+ ...Array.from(
139
+ d.querySelectorAll("[data-review-id]")
140
+ )
141
+ ];
142
+ for (const T of O) {
143
+ const R = T.getAttribute("data-review-id");
144
+ R && c.commentedIds.has(R) && T.classList.add(y);
145
+ }
146
+ for (const T of e ?? []) {
147
+ const R = [
148
+ ...d.matches(T.selector) ? [d] : [],
149
+ ...Array.from(d.querySelectorAll(T.selector))
150
+ ];
151
+ for (const X of R) {
152
+ const ot = T.toId(X);
153
+ X.classList.add(j), ot && c.commentedIds.has(ot) && X.classList.add(y);
154
+ }
155
+ }
156
+ (d.hasAttribute("data-review-selectable") || d.querySelector("[data-review-selectable]") !== null) && c.onSelectableReconnected();
157
+ }
158
+ }
159
+ }), n.observe(o, { childList: !0, subtree: !0 });
160
+ }
161
+ function W() {
162
+ n && (n.disconnect(), n = null), i = null;
163
+ }
164
+ function wt() {
165
+ s(), W();
166
+ }
167
+ return {
168
+ activate: r,
169
+ deactivate: s,
170
+ reveal: a,
171
+ unreveal: l,
172
+ setEditing: h,
173
+ clearEditing: u,
174
+ applyHover: p,
175
+ clearHover: g,
176
+ startObserving: Et,
177
+ stopObserving: W,
178
+ destroy: wt
179
+ };
180
+ }
181
+ const Nt = `:root{--review-highlight-uncommented-color: oklch(.7 0 0 / .15);--review-highlight-commented-color: oklch(.7 0 0 / .3);--review-highlight-color: oklch(.7 0 0 / .5);--review-highlight-editing-color: oklch(.6 0 0 / .7);--review-badge-icon-color: oklch(.35 0 0);--review-z-index: 9998;--review-selection-commented-color: oklch(.85 .08 250 / .4);--review-selection-editing-color: oklch(.75 .12 250 / .6);--review-selection-hover-color: oklch(.8 .1 250 / .5)}[data-review-id],[data-review-selectable],.review-target{outline:2px solid transparent;outline-offset:2px;transition:outline-color .15s ease}.review-highlight-uncommented{outline-color:var(--review-highlight-uncommented-color)}.review-highlight-commented{outline-color:var(--review-highlight-commented-color);position:relative}.review-highlight-hover{outline-color:var(--review-highlight-color)}.review-highlight-commented:after{content:"";position:absolute;top:-12px;right:-14px;width:20px;height:20px;border-radius:50%;background-color:#fff;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23404040' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z'/%3E%3C/svg%3E");background-size:12px 12px;background-repeat:no-repeat;background-position:center;box-shadow:0 1px 3px #0000001a;pointer-events:none}.review-highlight-editing:after{display:none}[data-review-selectable]:not([data-review-id]).review-highlight-commented:after{display:none}.review-highlight-editing{outline-color:var(--review-highlight-editing-color)}::highlight(review-selection-commented){background-color:var(--review-selection-commented-color)}::highlight(review-selection-editing){background-color:var(--review-selection-editing-color)}::highlight(review-selection-hover){background-color:var(--review-selection-hover-color)}.review-active [data-review-id],.review-active .review-target{cursor:pointer}.review-active [data-review-selectable]{cursor:text}`;
182
+ function Pt(o, e) {
183
+ const t = o.find(
184
+ (i) => i.targetId === e && !i.selection
185
+ );
186
+ return t ? { comment: t, isNew: !1 } : { comment: {
187
+ commentId: crypto.randomUUID(),
188
+ targetId: e,
189
+ content: "",
190
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
191
+ }, isNew: !0 };
192
+ }
193
+ function Rt(o) {
194
+ let e = o.comments;
195
+ if (o.editingCommentId !== null) {
196
+ const t = e.find(
197
+ (n) => n.commentId === o.editingCommentId
198
+ );
199
+ t && t.content === "" && (e = e.filter(
200
+ (n) => n.commentId !== o.editingCommentId
201
+ ));
202
+ }
203
+ return {
204
+ comments: e,
205
+ editingCommentId: null,
206
+ targetElement: null,
207
+ selectionRange: null
208
+ };
209
+ }
210
+ function B(o) {
211
+ const e = o.comments.filter((i) => i.content.trim()), t = e.length > 0, n = o.overallComment.trim().length > 0;
212
+ return !t && !n ? { status: "approved" } : {
213
+ status: "commented",
214
+ comments: e,
215
+ overallComment: n ? o.overallComment.trim() : void 0
216
+ };
217
+ }
218
+ function _t(o) {
219
+ const e = /* @__PURE__ */ new Set();
220
+ for (const t of o.comments)
221
+ !t.selection && t.content.trim() && e.add(t.targetId);
222
+ return e;
223
+ }
224
+ function Mt() {
225
+ const o = rt(
226
+ ({ sendBack: t, input: n }) => {
227
+ const i = () => t({ type: "RELEASE_ANNOTATE" }), r = (l) => {
228
+ l.key === "Alt" && (l.preventDefault(), t({ type: "HOLD_ANNOTATE" }));
229
+ }, s = (l) => {
230
+ l.key === "Alt" && t({ type: "RELEASE_ANNOTATE" });
231
+ }, a = Lt(window, {
232
+ [n.shortcut]: (l) => {
233
+ l.preventDefault(), t({ type: "TOGGLE" });
234
+ },
235
+ "$mod+Enter": (l) => {
236
+ l.preventDefault(), t({ type: "CLOSE" });
237
+ },
238
+ "$mod+Shift+Backspace": (l) => {
239
+ l.preventDefault(), t({ type: "DELETE" });
240
+ },
241
+ Escape: (l) => {
242
+ l.preventDefault(), t({ type: "CLOSE" });
243
+ }
244
+ });
245
+ return window.addEventListener("keydown", r), window.addEventListener("keyup", s), window.addEventListener("blur", i), () => {
246
+ a(), window.removeEventListener("keydown", r), window.removeEventListener("keyup", s), window.removeEventListener("blur", i);
247
+ };
248
+ }
249
+ ), e = rt(({ sendBack: t, input: n }) => {
250
+ const i = new MutationObserver((r) => {
251
+ for (const s of r)
252
+ for (const a of Array.from(s.removedNodes))
253
+ if (a instanceof HTMLElement && (a === n.targetElement || a.contains(n.targetElement))) {
254
+ t({ type: "TARGET_DISCONNECTED" });
255
+ return;
256
+ }
257
+ });
258
+ return i.observe(n.wrapperElement, { childList: !0, subtree: !0 }), () => i.disconnect();
259
+ });
260
+ return xt({
261
+ types: {
262
+ context: {},
263
+ events: {},
264
+ input: {},
265
+ emitted: {}
266
+ },
267
+ actors: {
268
+ keyboardActor: o,
269
+ mutationObserverActor: e
270
+ },
271
+ guards: {
272
+ isCommentingEditing: yt({ commenting: "editing" }),
273
+ hasSelectionCommentId: ({ event: t }) => t.type !== "CLICK" ? !1 : !!t.selectionCommentId,
274
+ hasTargetId: ({ event: t }) => t.type !== "CLICK" ? !1 : !!t.targetId && !t.selectionCommentId,
275
+ hasNoTarget: ({ event: t }) => t.type !== "CLICK" ? !1 : !t.targetId && !t.selectionCommentId,
276
+ isSameComment: ({ context: t, event: n }) => {
277
+ if (n.type !== "CLICK") return !1;
278
+ if (n.selectionCommentId)
279
+ return t.editingCommentId === n.selectionCommentId;
280
+ if (n.targetId) {
281
+ const i = t.comments.find(
282
+ (r) => r.commentId === t.editingCommentId
283
+ );
284
+ return !!i && i.targetId === n.targetId && !i.selection;
285
+ }
286
+ return !1;
287
+ }
288
+ },
289
+ delays: {
290
+ flashDuration: 500
291
+ },
292
+ actions: {
293
+ openElementComment: E(({ context: t, event: n }) => {
294
+ if (n.type !== "CLICK" || !n.targetId) return {};
295
+ const { comment: i, isNew: r } = Pt(
296
+ t.comments,
297
+ n.targetId
298
+ );
299
+ return {
300
+ comments: r ? [...t.comments, i] : t.comments,
301
+ editingCommentId: i.commentId,
302
+ targetElement: n.element ?? null,
303
+ selectionRange: null
304
+ };
305
+ }),
306
+ openSelectionComment: E(({ event: t }) => t.type !== "CLICK" || !t.selectionCommentId ? {} : {
307
+ editingCommentId: t.selectionCommentId,
308
+ targetElement: t.element ?? null,
309
+ selectionRange: null
310
+ }),
311
+ createSelectionComment: E(({ context: t, event: n }) => {
312
+ if (n.type !== "SELECT_TEXT") return {};
313
+ const i = {
314
+ commentId: crypto.randomUUID(),
315
+ targetId: n.targetId,
316
+ content: "",
317
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
318
+ selection: n.selectionRange
319
+ };
320
+ return {
321
+ comments: [...t.comments, i],
322
+ editingCommentId: i.commentId,
323
+ targetElement: n.targetElement,
324
+ selectionRange: n.selectionRange
325
+ };
326
+ }),
327
+ updateContent: E(({ context: t, event: n }) => n.type !== "COMMENT_CHANGE" ? {} : t.editingCommentId === null ? { overallComment: n.content } : {
328
+ comments: t.comments.map(
329
+ (i) => i.commentId === t.editingCommentId ? { ...i, content: n.content } : i
330
+ )
331
+ }),
332
+ deleteComment: E(({ context: t }) => ({
333
+ comments: t.comments.filter(
334
+ (n) => n.commentId !== t.editingCommentId
335
+ ),
336
+ editingCommentId: null,
337
+ targetElement: null,
338
+ selectionRange: null
339
+ })),
340
+ cleanup: E(({ context: t }) => Rt(t)),
341
+ emitChanged: st(({ context: t }) => ({
342
+ type: "REVIEW_CHANGED",
343
+ result: B(t)
344
+ })),
345
+ persistSave: ({ context: t }) => {
346
+ t.persistence.save(B(t));
347
+ },
348
+ emitSubmitted: st(({ context: t }) => ({
349
+ type: "REVIEW_SUBMITTED",
350
+ result: B(t)
351
+ })),
352
+ // Highlight lifecycle actions — call manager methods directly via
353
+ // callbacks passed through input. The machine owns WHEN highlights
354
+ // change; the manager owns HOW (DOM manipulation).
355
+ // Actions run synchronously during transitions — no timing gap.
356
+ // Never add useEffects that react to derived machine state.
357
+ highlightsActivate: ({ context: t }) => {
358
+ t.highlights.activate(_t(t));
359
+ },
360
+ highlightsDeactivate: ({ context: t }) => {
361
+ t.highlights.deactivate();
362
+ },
363
+ highlightsRevealFlash: ({ context: t }) => {
364
+ t.highlights.reveal(!0);
365
+ },
366
+ highlightsReveal: ({ context: t }) => {
367
+ t.highlights.reveal(!1);
368
+ },
369
+ highlightsUnreveal: ({ context: t }) => {
370
+ t.highlights.unreveal();
371
+ },
372
+ editingTargetSet: ({ context: t }) => {
373
+ var i;
374
+ if (!t.targetElement) return;
375
+ const n = !!((i = t.comments.find(
376
+ (r) => r.commentId === t.editingCommentId
377
+ )) != null && i.selection);
378
+ t.highlights.setEditing(t.targetElement, n);
379
+ },
380
+ editingTargetCleared: ({ context: t }) => {
381
+ if (!t.targetElement) return;
382
+ const n = t.comments.find(
383
+ (i) => i.commentId === t.editingCommentId
384
+ );
385
+ t.highlights.clearEditing(
386
+ t.targetElement,
387
+ !!(n != null && n.content.trim())
388
+ );
389
+ }
390
+ }
391
+ }).createMachine({
392
+ id: "review",
393
+ type: "parallel",
394
+ context: ({ input: t }) => {
395
+ const n = t.persistence.load() ?? t.initialData, i = (n == null ? void 0 : n.status) === "commented" ? n.comments ?? [] : [], r = (n == null ? void 0 : n.status) === "commented" ? n.overallComment ?? "" : "";
396
+ return {
397
+ comments: i,
398
+ overallComment: r,
399
+ editingCommentId: null,
400
+ targetElement: null,
401
+ selectionRange: null,
402
+ shortcut: t.shortcut,
403
+ defaultMode: t.defaultMode,
404
+ highlights: t.highlights,
405
+ persistence: t.persistence
406
+ };
407
+ },
408
+ invoke: {
409
+ id: "keyboard",
410
+ src: "keyboardActor",
411
+ input: ({ context: t }) => ({ shortcut: t.shortcut })
412
+ },
413
+ states: {
414
+ annotating: {
415
+ initial: "waitingForMount",
416
+ on: {
417
+ SUBMIT: ".inactive"
418
+ },
419
+ states: {
420
+ waitingForMount: {
421
+ on: {
422
+ MOUNTED: [
423
+ {
424
+ guard: ({ context: t }) => t.defaultMode === "annotating",
425
+ target: "toggled"
426
+ },
427
+ { target: "inactive" }
428
+ ]
429
+ }
430
+ },
431
+ inactive: {
432
+ on: {
433
+ TOGGLE: "toggled",
434
+ HOLD_ANNOTATE: "held"
435
+ }
436
+ },
437
+ toggled: {
438
+ initial: "flashing",
439
+ entry: "highlightsActivate",
440
+ exit: "highlightsDeactivate",
441
+ on: {
442
+ TOGGLE: {
443
+ target: "inactive",
444
+ actions: It(({ enqueue: t, check: n }) => {
445
+ n("isCommentingEditing") && t.raise({ type: "CLOSE" });
446
+ })
447
+ }
448
+ },
449
+ states: {
450
+ flashing: {
451
+ entry: "highlightsRevealFlash",
452
+ exit: "highlightsUnreveal",
453
+ after: {
454
+ flashDuration: "ready"
455
+ },
456
+ on: {
457
+ HOLD_ANNOTATE: "revealing"
458
+ }
459
+ },
460
+ ready: {
461
+ on: {
462
+ HOLD_ANNOTATE: "revealing"
463
+ }
464
+ },
465
+ revealing: {
466
+ entry: "highlightsReveal",
467
+ exit: "highlightsUnreveal",
468
+ on: {
469
+ RELEASE_ANNOTATE: "ready"
470
+ }
471
+ }
472
+ }
473
+ },
474
+ held: {
475
+ initial: "revealing",
476
+ entry: "highlightsActivate",
477
+ exit: "highlightsDeactivate",
478
+ states: {
479
+ revealing: {
480
+ entry: "highlightsReveal",
481
+ exit: "highlightsUnreveal",
482
+ on: {
483
+ RELEASE_ANNOTATE: [
484
+ { guard: "isCommentingEditing", target: "lingering" },
485
+ { target: "#review.annotating.inactive" }
486
+ ]
487
+ }
488
+ },
489
+ lingering: {
490
+ on: {
491
+ CLOSE: "#review.annotating.inactive",
492
+ DELETE: "#review.annotating.inactive"
493
+ }
494
+ }
495
+ }
496
+ }
497
+ }
498
+ },
499
+ commenting: {
500
+ initial: "idle",
501
+ states: {
502
+ idle: {
503
+ on: {
504
+ CLICK: [
505
+ {
506
+ guard: "hasSelectionCommentId",
507
+ target: "editing.selection",
508
+ actions: ["openSelectionComment", "editingTargetSet"]
509
+ },
510
+ {
511
+ guard: "hasTargetId",
512
+ target: "editing.element",
513
+ actions: ["openElementComment", "editingTargetSet"]
514
+ }
515
+ ],
516
+ SELECT_TEXT: {
517
+ target: "editing.selection",
518
+ actions: ["createSelectionComment", "editingTargetSet"]
519
+ },
520
+ OPEN_OVERALL: {
521
+ target: "editing.element",
522
+ actions: E({
523
+ editingCommentId: null,
524
+ targetElement: null,
525
+ selectionRange: null
526
+ })
527
+ },
528
+ SUBMIT: {
529
+ actions: ["emitSubmitted"]
530
+ }
531
+ }
532
+ },
533
+ editing: {
534
+ initial: "element",
535
+ on: {
536
+ CLICK: [
537
+ { guard: "isSameComment" },
538
+ {
539
+ guard: "hasSelectionCommentId",
540
+ target: ".selection",
541
+ reenter: !0,
542
+ actions: [
543
+ "editingTargetCleared",
544
+ "cleanup",
545
+ "openSelectionComment",
546
+ "editingTargetSet"
547
+ ]
548
+ },
549
+ {
550
+ guard: "hasTargetId",
551
+ target: ".element",
552
+ reenter: !0,
553
+ actions: [
554
+ "editingTargetCleared",
555
+ "cleanup",
556
+ "openElementComment",
557
+ "editingTargetSet"
558
+ ]
559
+ },
560
+ {
561
+ guard: "hasNoTarget",
562
+ target: "idle",
563
+ actions: [
564
+ "editingTargetCleared",
565
+ "cleanup",
566
+ "emitChanged",
567
+ "persistSave"
568
+ ]
569
+ }
570
+ ],
571
+ SELECT_TEXT: {
572
+ target: ".selection",
573
+ reenter: !0,
574
+ actions: [
575
+ "editingTargetCleared",
576
+ "cleanup",
577
+ "createSelectionComment",
578
+ "editingTargetSet"
579
+ ]
580
+ },
581
+ COMMENT_CHANGE: {
582
+ actions: ["updateContent", "emitChanged", "persistSave"]
583
+ },
584
+ DELETE: {
585
+ target: "idle",
586
+ actions: [
587
+ "editingTargetCleared",
588
+ "deleteComment",
589
+ "emitChanged",
590
+ "persistSave"
591
+ ]
592
+ },
593
+ CLOSE: {
594
+ target: "idle",
595
+ actions: [
596
+ "editingTargetCleared",
597
+ "cleanup",
598
+ "emitChanged",
599
+ "persistSave"
600
+ ]
601
+ },
602
+ TARGET_DISCONNECTED: {
603
+ target: "idle",
604
+ actions: [
605
+ "editingTargetCleared",
606
+ "cleanup",
607
+ "emitChanged",
608
+ "persistSave"
609
+ ]
610
+ },
611
+ SUBMIT: {
612
+ target: "idle",
613
+ actions: ["editingTargetCleared", "cleanup", "emitSubmitted"]
614
+ },
615
+ OPEN_OVERALL: {
616
+ target: ".element",
617
+ reenter: !0,
618
+ actions: [
619
+ "editingTargetCleared",
620
+ "cleanup",
621
+ E({
622
+ editingCommentId: null,
623
+ targetElement: null,
624
+ selectionRange: null
625
+ })
626
+ ]
627
+ }
628
+ },
629
+ states: {
630
+ element: {},
631
+ selection: {}
632
+ }
633
+ }
634
+ }
635
+ }
636
+ }
637
+ });
638
+ }
639
+ const ct = {
640
+ load: () => {
641
+ },
642
+ save: () => {
643
+ },
644
+ clear: () => {
645
+ }
646
+ };
647
+ function V() {
648
+ try {
649
+ return typeof localStorage > "u" ? void 0 : localStorage;
650
+ } catch {
651
+ return;
652
+ }
653
+ }
654
+ function $t(o) {
655
+ if (typeof o != "object" || o === null) return !1;
656
+ const e = o.status;
657
+ return e === "approved" || e === "commented";
658
+ }
659
+ function Ht(o) {
660
+ return {
661
+ load() {
662
+ const e = V();
663
+ if (e)
664
+ try {
665
+ const t = e.getItem(o);
666
+ if (t === null) return;
667
+ const n = JSON.parse(t);
668
+ return $t(n) ? n : void 0;
669
+ } catch {
670
+ return;
671
+ }
672
+ },
673
+ save(e) {
674
+ const t = V();
675
+ if (t)
676
+ try {
677
+ if (e.status === "approved") {
678
+ t.removeItem(o);
679
+ return;
680
+ }
681
+ t.setItem(o, JSON.stringify(e));
682
+ } catch {
683
+ }
684
+ },
685
+ clear() {
686
+ const e = V();
687
+ if (e)
688
+ try {
689
+ e.removeItem(o);
690
+ } catch {
691
+ }
692
+ }
693
+ };
694
+ }
695
+ const Gt = 3;
696
+ function zt(o) {
697
+ const e = window.getSelection();
698
+ if (!e || e.isCollapsed || e.rangeCount === 0)
699
+ return null;
700
+ const t = e.getRangeAt(0), n = t.toString();
701
+ if (n.length < Gt) return null;
702
+ const i = Kt(
703
+ o,
704
+ t.startContainer,
705
+ t.startOffset
706
+ ), r = i + n.length;
707
+ if (i < 0) return null;
708
+ const s = Wt(
709
+ o.textContent ?? "",
710
+ n,
711
+ i
712
+ );
713
+ return { startOffset: i, endOffset: r, selectedText: n, matchIndex: s };
714
+ }
715
+ function Q(o, e) {
716
+ const t = o.textContent ?? "";
717
+ if (t.slice(
718
+ e.startOffset,
719
+ e.endOffset
720
+ ) === e.selectedText)
721
+ return dt(
722
+ o,
723
+ e.startOffset,
724
+ e.endOffset
725
+ );
726
+ const i = Xt(
727
+ t,
728
+ e.selectedText,
729
+ e.matchIndex
730
+ );
731
+ return i < 0 ? null : dt(
732
+ o,
733
+ i,
734
+ i + e.selectedText.length
735
+ );
736
+ }
737
+ function Ft(o, e) {
738
+ if (o.isCollapsed || o.rangeCount === 0) return !1;
739
+ const t = o.getRangeAt(0);
740
+ return e.contains(t.startContainer) && e.contains(t.endContainer);
741
+ }
742
+ function Y(o) {
743
+ const e = o instanceof HTMLElement ? o : o.parentElement;
744
+ return (e == null ? void 0 : e.closest("[data-review-selectable]")) ?? null;
745
+ }
746
+ function Ut(o, e) {
747
+ var s;
748
+ if (o.isCollapsed || o.rangeCount === 0) return null;
749
+ const t = o.getRangeAt(0), n = t.cloneRange(), i = e.contains(t.startContainer), r = e.contains(t.endContainer);
750
+ if (i && r) return n;
751
+ if (i && !r) {
752
+ const a = jt(e);
753
+ return a && n.setEnd(a, ((s = a.textContent) == null ? void 0 : s.length) ?? 0), n;
754
+ }
755
+ return null;
756
+ }
757
+ function Kt(o, e, t) {
758
+ var r;
759
+ const n = document.createTreeWalker(o, NodeFilter.SHOW_TEXT);
760
+ let i = 0;
761
+ for (; n.nextNode(); ) {
762
+ if (n.currentNode === e) return i + t;
763
+ i += ((r = n.currentNode.textContent) == null ? void 0 : r.length) ?? 0;
764
+ }
765
+ return -1;
766
+ }
767
+ function dt(o, e, t) {
768
+ var a;
769
+ const n = document.createTreeWalker(o, NodeFilter.SHOW_TEXT), i = document.createRange();
770
+ let r = 0, s = !1;
771
+ for (; n.nextNode(); ) {
772
+ const l = ((a = n.currentNode.textContent) == null ? void 0 : a.length) ?? 0;
773
+ if (!s && r + l > e && (i.setStart(n.currentNode, e - r), s = !0), s && r + l >= t)
774
+ return i.setEnd(n.currentNode, t - r), i;
775
+ r += l;
776
+ }
777
+ return null;
778
+ }
779
+ function Wt(o, e, t) {
780
+ let n = 0, i = 0;
781
+ for (; ; ) {
782
+ const r = o.indexOf(e, i);
783
+ if (r < 0 || r === t) return n;
784
+ i = r + 1, n++;
785
+ }
786
+ }
787
+ function Xt(o, e, t) {
788
+ let n = 0, i = 0;
789
+ for (; ; ) {
790
+ const r = o.indexOf(e, i);
791
+ if (r < 0) return -1;
792
+ if (n === t) return r;
793
+ i = r + 1, n++;
794
+ }
795
+ }
796
+ function jt(o) {
797
+ const e = document.createTreeWalker(o, NodeFilter.SHOW_TEXT);
798
+ let t = null;
799
+ for (; e.nextNode(); )
800
+ t = e.currentNode;
801
+ return t;
802
+ }
803
+ function qt(o, e, t) {
804
+ const n = /* @__PURE__ */ new Map(), i = D(e, t).sort((r, s) => {
805
+ const a = r.element.compareDocumentPosition(s.element);
806
+ return a & Node.DOCUMENT_POSITION_PRECEDING ? 1 : a & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 0;
807
+ });
808
+ for (const [r, s] of i.entries())
809
+ n.set(s.targetId, r);
810
+ return [...o].sort((r, s) => {
811
+ const a = n.get(r.targetId) ?? Number.MAX_SAFE_INTEGER, l = n.get(s.targetId) ?? Number.MAX_SAFE_INTEGER;
812
+ return a - l;
813
+ });
814
+ }
815
+ var Bt = Object.defineProperty, Vt = Object.getOwnPropertyDescriptor, x = (o, e, t, n) => {
816
+ for (var i = n > 1 ? void 0 : n ? Vt(e, t) : e, r = o.length - 1, s; r >= 0; r--)
817
+ (s = o[r]) && (i = (n ? s(e, t, i) : s(i)) || i);
818
+ return n && i && Bt(e, t, i), i;
819
+ };
820
+ const Yt = {
821
+ "top-left": { top: "16px", left: "16px" },
822
+ "top-center": { top: "16px", left: "50%", translateX: "-50%" },
823
+ "top-right": { top: "16px", right: "16px" },
824
+ "bottom-left": { bottom: "16px", left: "16px" },
825
+ "bottom-center": { bottom: "16px", left: "50%", translateX: "-50%" },
826
+ "bottom-right": { bottom: "16px", right: "16px" }
827
+ };
828
+ let b = class extends C {
829
+ constructor() {
830
+ super(...arguments), this.mode = "idle", this.commentCount = 0, this.hasOverallComment = !1, this.overallCommentOpen = !1, this.barPosition = "bottom-center", this.dragOffset = null, this.dragStart = null, this.onDragStart = (o) => {
831
+ const e = this.bar.getBoundingClientRect();
832
+ this.dragStart = {
833
+ px: o.clientX,
834
+ py: o.clientY,
835
+ ox: e.left,
836
+ oy: e.top
837
+ }, window.addEventListener("pointermove", this.onDragMove), window.addEventListener("pointerup", this.onDragEnd);
838
+ }, this.onDragMove = (o) => {
839
+ if (!this.dragStart) return;
840
+ const e = this.dragStart.ox + (o.clientX - this.dragStart.px), t = this.dragStart.oy + (o.clientY - this.dragStart.py), n = 16, i = window.innerWidth - this.bar.offsetWidth - n, r = window.innerHeight - this.bar.offsetHeight - n;
841
+ this.dragOffset = {
842
+ x: Math.max(n, Math.min(e, i)),
843
+ y: Math.max(n, Math.min(t, r))
844
+ };
845
+ }, this.onDragEnd = () => {
846
+ this.dragStart = null, window.removeEventListener("pointermove", this.onDragMove), window.removeEventListener("pointerup", this.onDragEnd);
847
+ };
848
+ }
849
+ get barRoot() {
850
+ return this.bar ?? null;
851
+ }
852
+ render() {
853
+ const o = this.mode !== "idle", e = this.commentCount + (this.hasOverallComment ? 1 : 0), t = e > 0, n = Yt[this.barPosition], i = this.dragOffset ? `position:fixed;left:${this.dragOffset.x}px;top:${this.dragOffset.y}px;z-index:var(--review-z-index,9998);` : `position:fixed;${n.top ? `top:${n.top};` : ""}${n.bottom ? `bottom:${n.bottom};` : ""}${n.left ? `left:${n.left};` : ""}${n.right ? `right:${n.right};` : ""}${n.translateX ? `transform:translateX(${n.translateX});` : ""}z-index:var(--review-z-index,9998);`;
854
+ return w`<div
855
+ data-bar
856
+ class=${A({ bar: !0, "bar--active": o })}
857
+ style=${i}
858
+ >
859
+ <div
860
+ class="grip"
861
+ @pointerdown=${this.onDragStart}
862
+ >
863
+ <span class="icon icon-12">${M.gripVertical}</span>
864
+ </div>
865
+
866
+ <label class="label">
867
+ <span class=${A({
868
+ "label-text": !0,
869
+ "label-text--active": o,
870
+ "label-text--idle": !o
871
+ })}>Annotate</span>
872
+ <button
873
+ type="button"
874
+ role="switch"
875
+ aria-checked=${o ? "true" : "false"}
876
+ data-toggle
877
+ @click=${this.onToggle}
878
+ class=${A({
879
+ toggle: !0,
880
+ "toggle--active": o,
881
+ "toggle--idle": !o
882
+ })}
883
+ >
884
+ <span class=${A({
885
+ knob: !0,
886
+ "knob--active": o,
887
+ "knob--idle": !o
888
+ })}></span>
889
+ </button>
890
+ </label>
891
+
892
+ <div class="divider"></div>
893
+
894
+ <button
895
+ type="button"
896
+ data-overall
897
+ @click=${this.onOverallToggle}
898
+ class=${A({
899
+ overall: !0,
900
+ "overall--has": this.hasOverallComment,
901
+ "overall--open": !this.hasOverallComment && this.overallCommentOpen,
902
+ "overall--idle": !this.hasOverallComment && !this.overallCommentOpen
903
+ })}
904
+ >
905
+ Comment
906
+ <span class="icon icon-14">${M.messageSquare}</span>
907
+ </button>
908
+
909
+ <div class="divider"></div>
910
+
911
+ <button
912
+ type="button"
913
+ data-submit
914
+ @click=${this.onSubmit}
915
+ class="submit"
916
+ >
917
+ ${t ? "Submit" : "Approve"}
918
+ <span class="badge">
919
+ ${t ? e : w`<span class="icon icon-12">${M.check}</span>`}
920
+ </span>
921
+ </button>
922
+ </div>`;
923
+ }
924
+ onToggle() {
925
+ this.dispatchEvent(
926
+ new CustomEvent("toggle", { bubbles: !0, composed: !0 })
927
+ );
928
+ }
929
+ onOverallToggle() {
930
+ this.dispatchEvent(
931
+ new CustomEvent("overall-toggle", { bubbles: !0, composed: !0 })
932
+ );
933
+ }
934
+ onSubmit() {
935
+ this.dispatchEvent(
936
+ new CustomEvent("submit", { bubbles: !0, composed: !0 })
937
+ );
938
+ }
939
+ disconnectedCallback() {
940
+ super.disconnectedCallback(), window.removeEventListener("pointermove", this.onDragMove), window.removeEventListener("pointerup", this.onDragEnd);
941
+ }
942
+ };
943
+ b.styles = [
944
+ C.styles,
945
+ F`
946
+ :host {
947
+ color-scheme: light;
948
+ color: #18181b;
949
+ }
950
+ .bar {
951
+ display: flex;
952
+ align-items: center;
953
+ gap: 8px;
954
+ border-radius: 9999px;
955
+ border: 1px solid #e4e4e7;
956
+ background-color: #fff;
957
+ padding: 4px;
958
+ box-shadow:
959
+ 0 10px 15px -3px rgb(0 0 0 / 0.1),
960
+ 0 4px 6px -4px rgb(0 0 0 / 0.1);
961
+ }
962
+ .bar--active {
963
+ box-shadow:
964
+ 0 0 0 1px rgb(161 161 170 / 0.2),
965
+ 0 10px 15px -3px rgb(0 0 0 / 0.1),
966
+ 0 4px 6px -4px rgb(0 0 0 / 0.1);
967
+ }
968
+ .grip {
969
+ display: flex;
970
+ height: 28px;
971
+ width: 28px;
972
+ align-items: center;
973
+ justify-content: center;
974
+ color: #a1a1aa;
975
+ cursor: grab;
976
+ }
977
+ .grip:active {
978
+ cursor: grabbing;
979
+ }
980
+ .icon {
981
+ display: block;
982
+ }
983
+ .icon svg {
984
+ display: block;
985
+ width: 100%;
986
+ height: 100%;
987
+ }
988
+ .icon-12 {
989
+ width: 12px;
990
+ height: 12px;
991
+ }
992
+ .icon-14 {
993
+ width: 14px;
994
+ height: 14px;
995
+ }
996
+ .label {
997
+ display: flex;
998
+ cursor: pointer;
999
+ align-items: center;
1000
+ gap: 8px;
1001
+ padding: 0 4px;
1002
+ }
1003
+ .label-text {
1004
+ user-select: none;
1005
+ font-size: 12px;
1006
+ line-height: 16px;
1007
+ font-weight: 500;
1008
+ transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1);
1009
+ }
1010
+ .label-text--active {
1011
+ color: #18181b;
1012
+ }
1013
+ .label-text--idle {
1014
+ color: #71717a;
1015
+ }
1016
+ .toggle {
1017
+ position: relative;
1018
+ display: inline-flex;
1019
+ height: 16px;
1020
+ width: 28px;
1021
+ align-items: center;
1022
+ border-radius: 9999px;
1023
+ border: 0;
1024
+ margin: 0;
1025
+ padding: 0;
1026
+ font-family: inherit;
1027
+ color: inherit;
1028
+ cursor: pointer;
1029
+ transition: background-color 150ms cubic-bezier(0.4, 0, 0.2, 1);
1030
+ }
1031
+ .toggle--active {
1032
+ background-color: #18181b;
1033
+ }
1034
+ .toggle--idle {
1035
+ background-color: #d4d4d8;
1036
+ }
1037
+ .knob {
1038
+ display: inline-block;
1039
+ width: 12px;
1040
+ height: 12px;
1041
+ border-radius: 9999px;
1042
+ background-color: #fff;
1043
+ transition: translate 150ms cubic-bezier(0.4, 0, 0.2, 1);
1044
+ }
1045
+ .knob--active {
1046
+ translate: 14px 0;
1047
+ }
1048
+ .knob--idle {
1049
+ translate: 2px 0;
1050
+ }
1051
+ .divider {
1052
+ height: 16px;
1053
+ width: 1px;
1054
+ background-color: #e4e4e7;
1055
+ }
1056
+ .overall {
1057
+ position: relative;
1058
+ display: flex;
1059
+ height: 28px;
1060
+ align-items: center;
1061
+ gap: 6px;
1062
+ border-radius: 9999px;
1063
+ padding: 0 12px;
1064
+ font-family: inherit;
1065
+ font-size: 12px;
1066
+ line-height: 16px;
1067
+ font-weight: 500;
1068
+ color: inherit;
1069
+ background-color: transparent;
1070
+ border: 0;
1071
+ margin: 0;
1072
+ cursor: pointer;
1073
+ }
1074
+ .overall--has {
1075
+ background-color: #18181b;
1076
+ color: #fff;
1077
+ }
1078
+ .overall--has:hover {
1079
+ background-color: #27272a;
1080
+ }
1081
+ .overall--has:active {
1082
+ background-color: #09090b;
1083
+ }
1084
+ .overall--open {
1085
+ background-color: #f4f4f5;
1086
+ }
1087
+ .overall--open:hover {
1088
+ background-color: #e4e4e7;
1089
+ }
1090
+ .overall--idle {
1091
+ border: 1px solid #e4e4e7;
1092
+ }
1093
+ .overall--idle:hover {
1094
+ background-color: #fafafa;
1095
+ }
1096
+ .submit {
1097
+ display: flex;
1098
+ height: 28px;
1099
+ align-items: center;
1100
+ gap: 6px;
1101
+ border-radius: 9999px;
1102
+ padding: 0 8px 0 12px;
1103
+ background-color: #18181b;
1104
+ color: #fff;
1105
+ font-family: inherit;
1106
+ font-size: 12px;
1107
+ line-height: 16px;
1108
+ font-weight: 500;
1109
+ border: 0;
1110
+ margin: 0;
1111
+ cursor: pointer;
1112
+ }
1113
+ .submit:hover {
1114
+ background-color: #27272a;
1115
+ }
1116
+ .submit:active {
1117
+ background-color: #09090b;
1118
+ }
1119
+ .badge {
1120
+ display: flex;
1121
+ height: 18px;
1122
+ min-width: 18px;
1123
+ align-items: center;
1124
+ justify-content: center;
1125
+ border-radius: 9999px;
1126
+ background-color: rgb(255 255 255 / 0.25);
1127
+ padding: 0 4px;
1128
+ font-size: 11px;
1129
+ line-height: 16px;
1130
+ font-weight: 600;
1131
+ }
1132
+ `
1133
+ ];
1134
+ x([
1135
+ v()
1136
+ ], b.prototype, "mode", 2);
1137
+ x([
1138
+ v({ type: Number })
1139
+ ], b.prototype, "commentCount", 2);
1140
+ x([
1141
+ v({ type: Boolean })
1142
+ ], b.prototype, "hasOverallComment", 2);
1143
+ x([
1144
+ v({ type: Boolean })
1145
+ ], b.prototype, "overallCommentOpen", 2);
1146
+ x([
1147
+ v()
1148
+ ], b.prototype, "barPosition", 2);
1149
+ x([
1150
+ U("[data-bar]")
1151
+ ], b.prototype, "bar", 2);
1152
+ x([
1153
+ Ot()
1154
+ ], b.prototype, "dragOffset", 2);
1155
+ b = x([
1156
+ k("llumi-review-bar")
1157
+ ], b);
1158
+ var Jt = Object.defineProperty, Qt = Object.getOwnPropertyDescriptor, N = (o, e, t, n) => {
1159
+ for (var i = n > 1 ? void 0 : n ? Qt(e, t) : e, r = o.length - 1, s; r >= 0; r--)
1160
+ (s = o[r]) && (i = (n ? s(e, t, i) : s(i)) || i);
1161
+ return n && i && Jt(e, t, i), i;
1162
+ };
1163
+ let I = class extends C {
1164
+ constructor() {
1165
+ super(...arguments), this.value = "", this.autoFocus = !1, this.placeholder = "Write a comment...";
1166
+ }
1167
+ /** Focus the inner textarea (the element itself isn't focusable). */
1168
+ focus() {
1169
+ var o;
1170
+ (o = this.textarea) == null || o.focus();
1171
+ }
1172
+ render() {
1173
+ return w`<textarea
1174
+ rows="1"
1175
+ placeholder=${this.placeholder}
1176
+ .value=${this.value}
1177
+ @input=${this.onInput}
1178
+ ></textarea>`;
1179
+ }
1180
+ onInput(o) {
1181
+ const e = o.target.value;
1182
+ this.autoGrow(), this.dispatchEvent(
1183
+ new CustomEvent("change", {
1184
+ detail: e,
1185
+ bubbles: !0,
1186
+ composed: !0
1187
+ })
1188
+ );
1189
+ }
1190
+ autoGrow() {
1191
+ const o = this.textarea;
1192
+ o && (o.style.height = "auto", o.style.height = `${o.scrollHeight}px`);
1193
+ }
1194
+ firstUpdated() {
1195
+ this.autoFocus && this.textarea.focus(), this.autoGrow();
1196
+ }
1197
+ updated() {
1198
+ this.autoGrow();
1199
+ }
1200
+ };
1201
+ I.styles = [
1202
+ C.styles,
1203
+ F`
1204
+ textarea {
1205
+ width: 100%;
1206
+ resize: none;
1207
+ background-color: transparent;
1208
+ color: #18181b;
1209
+ font-family: inherit;
1210
+ font-size: 0.875rem;
1211
+ line-height: 1.25rem;
1212
+ max-height: 200px;
1213
+ overflow-y: auto;
1214
+ margin: 0;
1215
+ padding: 0;
1216
+ border: 0;
1217
+ }
1218
+ textarea::placeholder {
1219
+ color: #a1a1aa;
1220
+ }
1221
+ textarea:focus {
1222
+ outline: none;
1223
+ }
1224
+ `
1225
+ ];
1226
+ N([
1227
+ v()
1228
+ ], I.prototype, "value", 2);
1229
+ N([
1230
+ v({ type: Boolean })
1231
+ ], I.prototype, "autoFocus", 2);
1232
+ N([
1233
+ v()
1234
+ ], I.prototype, "placeholder", 2);
1235
+ N([
1236
+ U("textarea")
1237
+ ], I.prototype, "textarea", 2);
1238
+ I = N([
1239
+ k("llumi-default-editor")
1240
+ ], I);
1241
+ var Zt = Object.defineProperty, te = Object.getOwnPropertyDescriptor, P = (o, e, t, n) => {
1242
+ for (var i = n > 1 ? void 0 : n ? te(e, t) : e, r = o.length - 1, s; r >= 0; r--)
1243
+ (s = o[r]) && (i = (n ? s(e, t, i) : s(i)) || i);
1244
+ return n && i && Zt(e, t, i), i;
1245
+ };
1246
+ let S = class extends C {
1247
+ constructor() {
1248
+ super(...arguments), this.targetElement = null, this.anchor = null, this.value = "";
1249
+ }
1250
+ render() {
1251
+ const o = this.value.trim().length > 0;
1252
+ return w`<div
1253
+ data-floating
1254
+ class="floating"
1255
+ style="position:absolute;top:0;left:0;"
1256
+ >
1257
+ <div class="panel">
1258
+ ${o ? w`<button
1259
+ type="button"
1260
+ data-delete
1261
+ class="delete-btn"
1262
+ @click=${this.onDelete}
1263
+ >
1264
+ <span class="icon icon-14">${M.trash}</span>
1265
+ <span class="delete-label">Delete</span>
1266
+ </button>` : null}
1267
+ <div class="editor-wrap" @change=${this.onEditorChange} @cancel=${this.onCancel} @delete=${this.onDelete}>
1268
+ <slot name="editor">
1269
+ <llumi-default-editor .value=${this.value} autoFocus></llumi-default-editor>
1270
+ </slot>
1271
+ </div>
1272
+ </div>
1273
+ </div>`;
1274
+ }
1275
+ onEditorChange(o) {
1276
+ if (typeof o.detail != "string") return;
1277
+ const e = o.detail;
1278
+ o.stopPropagation(), this.dispatchEvent(
1279
+ new CustomEvent("change", { detail: e, bubbles: !0, composed: !0 })
1280
+ );
1281
+ }
1282
+ onCancel(o) {
1283
+ o.stopPropagation(), this.dispatchEvent(
1284
+ new CustomEvent("close", { bubbles: !0, composed: !0 })
1285
+ );
1286
+ }
1287
+ onDelete(o) {
1288
+ o.stopPropagation(), this.dispatchEvent(
1289
+ new CustomEvent("delete", { bubbles: !0, composed: !0 })
1290
+ );
1291
+ }
1292
+ startPositioning() {
1293
+ var t;
1294
+ const o = this.anchor ?? this.targetElement, e = this.floating;
1295
+ !o || !e || ((t = this.cleanup) == null || t.call(this), this.cleanup = gt(o, e, () => {
1296
+ ut(o, e, {
1297
+ placement: "right",
1298
+ middleware: [
1299
+ pt(12),
1300
+ ft({ padding: 16 }),
1301
+ vt({ padding: 16, crossAxis: !0 }),
1302
+ bt({
1303
+ padding: 16,
1304
+ apply({ availableWidth: n, elements: i }) {
1305
+ Object.assign(i.floating.style, {
1306
+ maxWidth: `${Math.min(400, n)}px`
1307
+ });
1308
+ }
1309
+ })
1310
+ ]
1311
+ }).then(({ x: n, y: i }) => {
1312
+ Object.assign(e.style, { left: `${n}px`, top: `${i}px` });
1313
+ });
1314
+ }));
1315
+ }
1316
+ updated(o) {
1317
+ (o.has("targetElement") || o.has("anchor")) && (this.startPositioning(), this.focusEditor());
1318
+ }
1319
+ focusEditor() {
1320
+ const o = this.renderRoot.querySelector(
1321
+ 'slot[name="editor"]'
1322
+ ), t = ((o == null ? void 0 : o.assignedElements()) ?? [])[0] ?? this.renderRoot.querySelector("llumi-default-editor");
1323
+ t == null || t.focus();
1324
+ }
1325
+ disconnectedCallback() {
1326
+ var o;
1327
+ super.disconnectedCallback(), (o = this.cleanup) == null || o.call(this), this.cleanup = void 0;
1328
+ }
1329
+ };
1330
+ S.styles = [
1331
+ C.styles,
1332
+ F`
1333
+ .floating {
1334
+ z-index: calc(var(--review-z-index, 9998) + 1);
1335
+ }
1336
+ .panel {
1337
+ position: relative;
1338
+ width: 400px;
1339
+ border-radius: 8px;
1340
+ border: 1px solid #e4e4e7;
1341
+ background-color: #fff;
1342
+ box-shadow:
1343
+ 0 20px 25px -5px rgb(0 0 0 / 0.1),
1344
+ 0 8px 10px -6px rgb(0 0 0 / 0.1);
1345
+ animation: llumi-fade-in 0.15s ease-out;
1346
+ }
1347
+ .delete-btn {
1348
+ position: absolute;
1349
+ top: 8px;
1350
+ right: 8px;
1351
+ z-index: 10;
1352
+ display: flex;
1353
+ align-items: center;
1354
+ gap: 4px;
1355
+ border-radius: 6px;
1356
+ padding: 4px 6px;
1357
+ color: #a1a1aa;
1358
+ background-color: transparent;
1359
+ border: 0;
1360
+ margin: 0;
1361
+ font-family: inherit;
1362
+ cursor: pointer;
1363
+ transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1);
1364
+ }
1365
+ .delete-btn:hover {
1366
+ background-color: #18181b;
1367
+ color: #fff;
1368
+ }
1369
+ .icon {
1370
+ display: block;
1371
+ }
1372
+ .icon svg {
1373
+ display: block;
1374
+ width: 100%;
1375
+ height: 100%;
1376
+ }
1377
+ .icon-14 {
1378
+ width: 14px;
1379
+ height: 14px;
1380
+ }
1381
+ .delete-label {
1382
+ font-size: 0.75rem;
1383
+ line-height: 1rem;
1384
+ max-width: 0;
1385
+ overflow: hidden;
1386
+ transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1);
1387
+ }
1388
+ .delete-btn:hover .delete-label {
1389
+ max-width: 60px;
1390
+ }
1391
+ .editor-wrap {
1392
+ padding: 12px;
1393
+ }
1394
+ @keyframes llumi-fade-in {
1395
+ from {
1396
+ opacity: 0;
1397
+ transform: translateY(4px);
1398
+ }
1399
+ to {
1400
+ opacity: 1;
1401
+ transform: translateY(0);
1402
+ }
1403
+ }
1404
+ `
1405
+ ];
1406
+ P([
1407
+ v({ attribute: !1 })
1408
+ ], S.prototype, "targetElement", 2);
1409
+ P([
1410
+ v({ attribute: !1 })
1411
+ ], S.prototype, "anchor", 2);
1412
+ P([
1413
+ v()
1414
+ ], S.prototype, "value", 2);
1415
+ P([
1416
+ U("[data-floating]")
1417
+ ], S.prototype, "floating", 2);
1418
+ S = P([
1419
+ k("llumi-comment-dialog")
1420
+ ], S);
1421
+ var ee = Object.defineProperty, ne = Object.getOwnPropertyDescriptor, K = (o, e, t, n) => {
1422
+ for (var i = n > 1 ? void 0 : n ? ne(e, t) : e, r = o.length - 1, s; r >= 0; r--)
1423
+ (s = o[r]) && (i = (n ? s(e, t, i) : s(i)) || i);
1424
+ return n && i && ee(e, t, i), i;
1425
+ };
1426
+ let L = class extends C {
1427
+ constructor() {
1428
+ super(...arguments), this.barElement = null, this.value = "", this.onDocKeydown = (o) => {
1429
+ o.key === "Escape" && (o.preventDefault(), this.emitClose());
1430
+ }, this.onDocPointerdown = (o) => {
1431
+ const e = o.composedPath();
1432
+ this.floating && !e.includes(this.floating) && !e.includes(this) && this.emitClose();
1433
+ };
1434
+ }
1435
+ render() {
1436
+ return w`<div
1437
+ data-floating
1438
+ class="floating"
1439
+ style="position:absolute;top:0;left:0;"
1440
+ >
1441
+ <div class="panel">
1442
+ <div class="editor-wrap" @change=${this.onEditorChange}>
1443
+ <slot name="editor">
1444
+ <llumi-default-editor
1445
+ .value=${this.value}
1446
+ autoFocus
1447
+ placeholder="Overall comment..."
1448
+ ></llumi-default-editor>
1449
+ </slot>
1450
+ </div>
1451
+ </div>
1452
+ </div>`;
1453
+ }
1454
+ onEditorChange(o) {
1455
+ if (typeof o.detail != "string") return;
1456
+ const e = o.detail;
1457
+ o.stopPropagation(), this.dispatchEvent(
1458
+ new CustomEvent("change", { detail: e, bubbles: !0, composed: !0 })
1459
+ );
1460
+ }
1461
+ emitClose() {
1462
+ this.dispatchEvent(
1463
+ new CustomEvent("close", { bubbles: !0, composed: !0 })
1464
+ );
1465
+ }
1466
+ startPositioning() {
1467
+ var t;
1468
+ const o = this.barElement, e = this.floating;
1469
+ !o || !e || ((t = this.cleanup) == null || t.call(this), this.cleanup = gt(o, e, () => {
1470
+ ut(o, e, {
1471
+ placement: "top",
1472
+ middleware: [
1473
+ pt(12),
1474
+ ft({ padding: 16 }),
1475
+ vt({ padding: 16, crossAxis: !0 }),
1476
+ bt({
1477
+ padding: 16,
1478
+ apply({ availableWidth: n, elements: i }) {
1479
+ Object.assign(i.floating.style, {
1480
+ maxWidth: `${Math.min(400, n)}px`
1481
+ });
1482
+ }
1483
+ })
1484
+ ]
1485
+ }).then(({ x: n, y: i }) => {
1486
+ Object.assign(e.style, { left: `${n}px`, top: `${i}px` });
1487
+ });
1488
+ }));
1489
+ }
1490
+ connectedCallback() {
1491
+ super.connectedCallback(), document.addEventListener("keydown", this.onDocKeydown), document.addEventListener("pointerdown", this.onDocPointerdown, !0);
1492
+ }
1493
+ updated(o) {
1494
+ o.has("barElement") && this.startPositioning();
1495
+ }
1496
+ disconnectedCallback() {
1497
+ var o;
1498
+ super.disconnectedCallback(), (o = this.cleanup) == null || o.call(this), this.cleanup = void 0, document.removeEventListener("keydown", this.onDocKeydown), document.removeEventListener("pointerdown", this.onDocPointerdown, !0);
1499
+ }
1500
+ };
1501
+ L.styles = [
1502
+ C.styles,
1503
+ F`
1504
+ .floating {
1505
+ z-index: calc(var(--review-z-index, 9998) + 1);
1506
+ }
1507
+ .panel {
1508
+ width: 400px;
1509
+ border-radius: 8px;
1510
+ border: 1px solid #e4e4e7;
1511
+ background-color: #fff;
1512
+ box-shadow:
1513
+ 0 20px 25px -5px rgb(0 0 0 / 0.1),
1514
+ 0 8px 10px -6px rgb(0 0 0 / 0.1);
1515
+ animation: llumi-fade-in 0.15s ease-out;
1516
+ }
1517
+ .editor-wrap {
1518
+ padding: 12px;
1519
+ }
1520
+ @keyframes llumi-fade-in {
1521
+ from {
1522
+ opacity: 0;
1523
+ transform: translateY(4px);
1524
+ }
1525
+ to {
1526
+ opacity: 1;
1527
+ transform: translateY(0);
1528
+ }
1529
+ }
1530
+ `
1531
+ ];
1532
+ K([
1533
+ v({ attribute: !1 })
1534
+ ], L.prototype, "barElement", 2);
1535
+ K([
1536
+ v()
1537
+ ], L.prototype, "value", 2);
1538
+ K([
1539
+ U("[data-floating]")
1540
+ ], L.prototype, "floating", 2);
1541
+ L = K([
1542
+ k("llumi-overall-comment-dialog")
1543
+ ], L);
1544
+ var ie = Object.defineProperty, oe = Object.getOwnPropertyDescriptor, Ct = (o, e, t, n) => {
1545
+ for (var i = n > 1 ? void 0 : n ? oe(e, t) : e, r = o.length - 1, s; r >= 0; r--)
1546
+ (s = o[r]) && (i = (n ? s(e, t, i) : s(i)) || i);
1547
+ return n && i && ie(e, t, i), i;
1548
+ };
1549
+ const re = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23404040' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z'/%3E%3C/svg%3E";
1550
+ let Z = class extends C {
1551
+ constructor() {
1552
+ super(...arguments), this.positions = [];
1553
+ }
1554
+ render() {
1555
+ return w`${At(
1556
+ this.positions,
1557
+ (o) => o.commentId,
1558
+ (o) => w`<button
1559
+ type="button"
1560
+ @click=${(e) => this.onClick(e, o.commentId)}
1561
+ style=${Dt({
1562
+ position: "absolute",
1563
+ top: `${o.top - 10}px`,
1564
+ left: `${o.left + 2}px`,
1565
+ width: "20px",
1566
+ height: "20px",
1567
+ borderRadius: "50%",
1568
+ backgroundColor: "white",
1569
+ backgroundImage: `url("${re}")`,
1570
+ backgroundSize: "12px 12px",
1571
+ backgroundRepeat: "no-repeat",
1572
+ backgroundPosition: "center",
1573
+ boxShadow: "0 1px 3px oklch(0 0 0 / 0.1)",
1574
+ zIndex: "calc(var(--review-z-index, 9998) + 1)",
1575
+ border: "none",
1576
+ padding: "0",
1577
+ cursor: "pointer"
1578
+ })}
1579
+ ></button>`
1580
+ )}`;
1581
+ }
1582
+ onClick(o, e) {
1583
+ o.stopPropagation(), this.dispatchEvent(
1584
+ new CustomEvent("icon-click", {
1585
+ detail: e,
1586
+ bubbles: !0,
1587
+ composed: !0
1588
+ })
1589
+ );
1590
+ }
1591
+ };
1592
+ Ct([
1593
+ v({ attribute: !1 })
1594
+ ], Z.prototype, "positions", 2);
1595
+ Z = Ct([
1596
+ k("llumi-selection-comment-icons")
1597
+ ], Z);
1598
+ const z = "data-review-selectable", ht = "review-selection-commented", mt = "review-selection-editing", G = "review-selection-hover";
1599
+ function tt() {
1600
+ if (!(typeof CSS > "u"))
1601
+ return CSS.highlights;
1602
+ }
1603
+ function et(...o) {
1604
+ return new Highlight(
1605
+ ...o
1606
+ );
1607
+ }
1608
+ class se {
1609
+ constructor(e) {
1610
+ this.ranges = /* @__PURE__ */ new Map(), this.repositionRaf = 0, this.reposition = () => {
1611
+ this.repositionRaf || (this.repositionRaf = requestAnimationFrame(() => {
1612
+ if (this.repositionRaf = 0, !this.ctx.isAnnotating() || this.ranges.size === 0) return;
1613
+ const t = [];
1614
+ for (const [n, i] of this.ranges) {
1615
+ const r = this.iconPositionForRange(n, i);
1616
+ r && t.push(r);
1617
+ }
1618
+ this.ctx.icons.positions = t;
1619
+ }));
1620
+ }, this.ctx = e;
1621
+ }
1622
+ /** Read accessor: the element's pointer hit-testing iterates this. */
1623
+ get rangeMap() {
1624
+ return this.ranges;
1625
+ }
1626
+ /**
1627
+ * Rebuild the commented/editing highlight registries, the `rangeMap`, and
1628
+ * the icon positions from the given selection comments + the machine
1629
+ * snapshot's `editingCommentId` / `comments` (the editing range may belong
1630
+ * to a comment whose content is not yet committed, hence the fallback).
1631
+ */
1632
+ update(e) {
1633
+ const t = tt();
1634
+ if (!t) return;
1635
+ const n = et(), i = et(), r = /* @__PURE__ */ new Map(), s = [], a = this.ctx.getSnapshot();
1636
+ for (const h of e) {
1637
+ if (!h.selection) continue;
1638
+ const u = this.ctx.host.querySelector(
1639
+ `[${z}="${h.targetId}"]`
1640
+ );
1641
+ if (!u) continue;
1642
+ const p = Q(u, h.selection);
1643
+ if (!p) continue;
1644
+ r.set(h.commentId, p), h.commentId === a.editingCommentId ? i.add(p) : n.add(p);
1645
+ const g = this.iconPositionForRange(h.commentId, p);
1646
+ g && s.push(g);
1647
+ }
1648
+ const l = a.editingCommentId;
1649
+ if (l && !r.has(l)) {
1650
+ const h = a.comments.find(
1651
+ (u) => u.commentId === l
1652
+ );
1653
+ if (h != null && h.selection) {
1654
+ const u = this.ctx.host.querySelector(
1655
+ `[${z}="${h.targetId}"]`
1656
+ );
1657
+ if (u) {
1658
+ const p = Q(u, h.selection);
1659
+ p && i.add(p);
1660
+ }
1661
+ }
1662
+ }
1663
+ this.ranges = r, t.set(
1664
+ ht,
1665
+ n
1666
+ ), t.set(mt, i), this.ctx.icons.positions = s;
1667
+ }
1668
+ // Page-coordinate position of a selection comment's icon, anchored to the
1669
+ // end of its range (so it sits just past the selected text).
1670
+ iconPositionForRange(e, t) {
1671
+ const n = t.getClientRects(), i = n[n.length - 1];
1672
+ return i ? {
1673
+ commentId: e,
1674
+ top: i.top + window.scrollY,
1675
+ left: i.right + window.scrollX
1676
+ } : null;
1677
+ }
1678
+ /** Clear all three highlight registries, the `rangeMap`, and icon positions. */
1679
+ clear() {
1680
+ const e = tt();
1681
+ e && (e.delete(ht), e.delete(mt), e.delete(G)), this.ranges.clear(), this.ctx.icons.positions = [];
1682
+ }
1683
+ /** Capture-phase scroll + resize listeners, so icons recompute on any scroll. */
1684
+ attachListeners() {
1685
+ window.addEventListener("scroll", this.reposition, !0), window.addEventListener("resize", this.reposition);
1686
+ }
1687
+ /** Remove listeners and cancel any pending rAF. */
1688
+ detachListeners() {
1689
+ window.removeEventListener("scroll", this.reposition, !0), window.removeEventListener("resize", this.reposition), this.repositionRaf && cancelAnimationFrame(this.repositionRaf);
1690
+ }
1691
+ }
1692
+ const ae = "$mod+Shift+M", it = class it extends HTMLElement {
1693
+ constructor() {
1694
+ super(...arguments), this.persistence = ct, this.manager = null, this.hoveredComment = null, this.selectionJustHandled = !1, this.selectionComments = [], this.commentDialog = null, this.commentDialogAnchorId = null, this.overallDialog = null, this.onPointerUp = () => {
1695
+ if (!this.isAnnotating()) return;
1696
+ const e = window.getSelection();
1697
+ if (!e || e.isCollapsed || e.rangeCount === 0)
1698
+ return;
1699
+ const t = e.getRangeAt(0), n = Y(t.startContainer);
1700
+ if (!n) return;
1701
+ const i = Y(t.endContainer);
1702
+ if (i && i !== n) {
1703
+ e.removeAllRanges();
1704
+ return;
1705
+ }
1706
+ if (!i || !Ft(e, n)) {
1707
+ const a = Ut(e, n);
1708
+ if (!a) return;
1709
+ e.removeAllRanges(), e.addRange(a);
1710
+ }
1711
+ const r = n.getAttribute(z);
1712
+ if (!r) return;
1713
+ const s = zt(n);
1714
+ s && (e.removeAllRanges(), this.selectionJustHandled = !0, this.actor.send({
1715
+ type: "SELECT_TEXT",
1716
+ targetId: r,
1717
+ targetElement: n,
1718
+ selectionRange: s
1719
+ }));
1720
+ }, this.onPointerMove = (e) => {
1721
+ if (!this.isAnnotating()) return;
1722
+ const t = tt();
1723
+ if (!t) return;
1724
+ const n = this.caretPosition(e.clientX, e.clientY);
1725
+ if (!n) {
1726
+ this.hoveredComment && (t.delete(G), this.hoveredComment = null);
1727
+ return;
1728
+ }
1729
+ let i = null;
1730
+ for (const [r, s] of this.painter.rangeMap)
1731
+ if (s.isPointInRange(n.offsetNode, n.offset)) {
1732
+ i = r;
1733
+ break;
1734
+ }
1735
+ if (i !== this.hoveredComment)
1736
+ if (this.hoveredComment = i, i) {
1737
+ const r = this.painter.rangeMap.get(i);
1738
+ r && t.set(
1739
+ G,
1740
+ et(r)
1741
+ );
1742
+ } else
1743
+ t.delete(G);
1744
+ }, this.onClickCapture = (e) => {
1745
+ if (!this.isAnnotating() || e.defaultPrevented) return;
1746
+ if (this.selectionJustHandled) {
1747
+ this.selectionJustHandled = !1, e.stopPropagation();
1748
+ return;
1749
+ }
1750
+ const t = window.getSelection();
1751
+ if (t && !t.isCollapsed) return;
1752
+ const n = this.caretPosition(e.clientX, e.clientY);
1753
+ if (n) {
1754
+ for (const [a, l] of this.painter.rangeMap)
1755
+ if (l.isPointInRange(n.offsetNode, n.offset)) {
1756
+ const h = this.selectionComments.find(
1757
+ (p) => p.commentId === a
1758
+ );
1759
+ if (!h) continue;
1760
+ const u = Y(n.offsetNode);
1761
+ if (!u) continue;
1762
+ e.stopPropagation(), e.preventDefault(), this.actor.send({
1763
+ type: "CLICK",
1764
+ targetId: h.targetId,
1765
+ element: u,
1766
+ selectionCommentId: a
1767
+ });
1768
+ return;
1769
+ }
1770
+ }
1771
+ const i = e.target, s = i.closest(
1772
+ ".review-highlight-hover, .review-highlight-commented, .review-highlight-editing"
1773
+ );
1774
+ if (s && this.contains(s)) {
1775
+ e.stopPropagation(), e.preventDefault();
1776
+ const a = _(i, this.customTargets);
1777
+ a ? this.actor.send({
1778
+ type: "CLICK",
1779
+ targetId: a.targetId,
1780
+ element: a.element
1781
+ }) : this.actor.send({ type: "CLICK" });
1782
+ }
1783
+ }, this.onWrapperClick = (e) => {
1784
+ if (!this.contains(e.target) || !this.isAnnotating()) return;
1785
+ const t = _(e.target, this.customTargets);
1786
+ t ? (e.stopPropagation(), e.preventDefault(), this.actor.send({
1787
+ type: "CLICK",
1788
+ targetId: t.targetId,
1789
+ element: t.element
1790
+ })) : this.actor.send({ type: "CLICK" });
1791
+ }, this.onMouseOver = (e) => {
1792
+ const t = this.manager;
1793
+ if (!t || !this.isAnnotating()) return;
1794
+ const n = this.currentEditingTargetId(), i = _(
1795
+ e.target,
1796
+ this.customTargets
1797
+ );
1798
+ if (i) {
1799
+ t.applyHover(i.element, n);
1800
+ return;
1801
+ }
1802
+ const r = e.target.closest(
1803
+ "[data-review-selectable]"
1804
+ );
1805
+ r && t.applyHover(r, n);
1806
+ }, this.onMouseOut = (e) => {
1807
+ const t = this.manager;
1808
+ if (!t || !this.isAnnotating()) return;
1809
+ const n = this.currentEditingTargetId(), i = /* @__PURE__ */ new Set();
1810
+ for (const a of this.actor.getSnapshot().context.comments)
1811
+ !a.selection && a.content.trim() && i.add(a.targetId);
1812
+ const r = _(
1813
+ e.target,
1814
+ this.customTargets
1815
+ );
1816
+ if (r) {
1817
+ t.clearHover(r.element, n, i);
1818
+ return;
1819
+ }
1820
+ const s = e.target.closest(
1821
+ "[data-review-selectable]"
1822
+ );
1823
+ s && t.clearHover(s, n, i);
1824
+ };
1825
+ }
1826
+ get shortcut() {
1827
+ return this.getAttribute("shortcut") ?? ae;
1828
+ }
1829
+ get barPosition() {
1830
+ return this.getAttribute("bar-position") ?? "bottom-center";
1831
+ }
1832
+ get defaultMode() {
1833
+ return this.getAttribute("default-mode") === "annotating" ? "annotating" : "idle";
1834
+ }
1835
+ get persistKey() {
1836
+ const e = this.getAttribute("persist");
1837
+ return e != null && e.trim() ? e : null;
1838
+ }
1839
+ connectedCallback() {
1840
+ Tt("review", Nt), this.style.position === "" && (this.style.position = "relative"), this.style.display === "" && (this.style.display = "block");
1841
+ const e = this.buildHighlightCallbacks();
1842
+ this.persistence = this.persistKey ? Ht(this.persistKey) : ct;
1843
+ const t = Mt();
1844
+ this.actor = St(t, {
1845
+ input: {
1846
+ shortcut: this.shortcut,
1847
+ initialData: this.initialData,
1848
+ defaultMode: this.defaultMode,
1849
+ highlights: e,
1850
+ persistence: this.persistence
1851
+ }
1852
+ }), this.actor.on("REVIEW_CHANGED", (n) => this.emitChange(n.result)), this.actor.on("REVIEW_SUBMITTED", (n) => this.emitSubmit(n.result)), this.mountChrome(), this.painter = new se({
1853
+ host: this,
1854
+ icons: this.icons,
1855
+ getSnapshot: () => this.actor.getSnapshot().context,
1856
+ isAnnotating: () => this.isAnnotating()
1857
+ }), this.actor.subscribe(() => this.syncFromSnapshot()), this.actor.start(), this.manager = kt(this, this.customTargets), this.actor.send({ type: "MOUNTED" }), this.addEventListener("pointerup", this.onPointerUp), this.addEventListener("pointermove", this.onPointerMove), this.addEventListener("click", this.onClickCapture, !0), this.addEventListener("click", this.onWrapperClick), this.addEventListener("mouseover", this.onMouseOver), this.addEventListener("mouseout", this.onMouseOut), this.painter.attachListeners(), this.syncFromSnapshot();
1858
+ }
1859
+ disconnectedCallback() {
1860
+ var e, t, n, i, r, s, a, l;
1861
+ this.removeEventListener("pointerup", this.onPointerUp), this.removeEventListener("pointermove", this.onPointerMove), this.removeEventListener("click", this.onClickCapture, !0), this.removeEventListener("click", this.onWrapperClick), this.removeEventListener("mouseover", this.onMouseOver), this.removeEventListener("mouseout", this.onMouseOut), (e = this.painter) == null || e.detachListeners(), (t = this.painter) == null || t.clear(), (n = this.manager) == null || n.destroy(), this.manager = null, (i = this.actor) == null || i.stop(), (r = this.bar) == null || r.remove(), (s = this.commentDialog) == null || s.remove(), (a = this.overallDialog) == null || a.remove(), (l = this.icons) == null || l.remove();
1862
+ }
1863
+ attributeChangedCallback() {
1864
+ this.bar && (this.bar.barPosition = this.barPosition);
1865
+ }
1866
+ buildDetailResult(e) {
1867
+ return e.status === "commented" ? {
1868
+ ...e,
1869
+ comments: qt(
1870
+ e.comments,
1871
+ this,
1872
+ this.customTargets
1873
+ )
1874
+ } : e;
1875
+ }
1876
+ emitChange(e) {
1877
+ this.dispatchEvent(
1878
+ new CustomEvent("llumi-review-change", {
1879
+ detail: this.buildDetailResult(e),
1880
+ bubbles: !0,
1881
+ composed: !0
1882
+ })
1883
+ );
1884
+ }
1885
+ emitSubmit(e) {
1886
+ this.dispatchEvent(
1887
+ new CustomEvent("llumi-review-submit", {
1888
+ detail: {
1889
+ result: this.buildDetailResult(e),
1890
+ clearPersisted: () => this.clearPersisted()
1891
+ },
1892
+ bubbles: !0,
1893
+ composed: !0
1894
+ })
1895
+ );
1896
+ }
1897
+ /** Clears the persisted draft for this element. No-op when persistence is off. */
1898
+ clearPersisted() {
1899
+ this.persistence.clear();
1900
+ }
1901
+ // Build a floating-ui virtual reference that tracks a selection's live rect.
1902
+ // `contextElement` lets autoUpdate find the right scroll ancestors. Returns
1903
+ // null when the range can't be restored, so the dialog falls back to anchoring
1904
+ // on the whole element.
1905
+ selectionAnchor(e, t) {
1906
+ const n = Q(e, t);
1907
+ return n ? {
1908
+ getBoundingClientRect: () => n.getBoundingClientRect(),
1909
+ getClientRects: () => n.getClientRects(),
1910
+ contextElement: e
1911
+ } : null;
1912
+ }
1913
+ // --- chrome lifecycle ---
1914
+ mountChrome() {
1915
+ this.bar = document.createElement("llumi-review-bar"), this.bar.barPosition = this.barPosition, this.bar.addEventListener(
1916
+ "toggle",
1917
+ () => this.actor.send({ type: "TOGGLE" })
1918
+ ), this.bar.addEventListener("overall-toggle", () => {
1919
+ const e = this.actor.getSnapshot(), t = e.matches({ commenting: "editing" }) && e.context.editingCommentId === null;
1920
+ this.actor.send(
1921
+ t ? { type: "CLOSE" } : { type: "OPEN_OVERALL" }
1922
+ );
1923
+ }), this.bar.addEventListener(
1924
+ "submit",
1925
+ () => this.actor.send({ type: "SUBMIT" })
1926
+ ), document.body.append(this.bar), this.icons = document.createElement(
1927
+ "llumi-selection-comment-icons"
1928
+ ), this.icons.addEventListener(
1929
+ "icon-click",
1930
+ (e) => this.onIconClick(e.detail)
1931
+ ), document.body.append(this.icons);
1932
+ }
1933
+ onIconClick(e) {
1934
+ const t = this.actor.getSnapshot().context.comments.find((i) => i.commentId === e);
1935
+ if (!t) return;
1936
+ const n = this.querySelector(
1937
+ `[${z}="${t.targetId}"]`
1938
+ );
1939
+ n && this.actor.send({
1940
+ type: "CLICK",
1941
+ targetId: t.targetId,
1942
+ element: n,
1943
+ selectionCommentId: e
1944
+ });
1945
+ }
1946
+ // --- snapshot → UI sync ---
1947
+ syncFromSnapshot() {
1948
+ const e = this.actor.getSnapshot(), { comments: t, overallComment: n, editingCommentId: i, targetElement: r } = e.context;
1949
+ this.selectionComments = t.filter(
1950
+ (g) => g.selection && g.content.trim()
1951
+ );
1952
+ const s = !e.matches({ annotating: "inactive" }), a = e.matches({ commenting: "editing" }), l = i ? t.find((g) => g.commentId === i) : null, h = a && i === null, u = t.filter((g) => g.content.trim()).length, p = n.trim().length > 0;
1953
+ this.bar.mode = s ? l ? "editing" : "commenting" : "idle", this.bar.commentCount = u, this.bar.hasOverallComment = p, this.bar.overallCommentOpen = h, this.icons.style.display = s ? "" : "none", a && l && r ? (this.commentDialog || (this.commentDialog = document.createElement(
1954
+ "llumi-comment-dialog"
1955
+ ), this.commentDialog.addEventListener(
1956
+ "change",
1957
+ (g) => this.actor.send({
1958
+ type: "COMMENT_CHANGE",
1959
+ content: g.detail
1960
+ })
1961
+ ), this.commentDialog.addEventListener(
1962
+ "delete",
1963
+ () => this.actor.send({ type: "DELETE" })
1964
+ ), this.commentDialog.addEventListener(
1965
+ "close",
1966
+ () => this.actor.send({ type: "CLOSE" })
1967
+ ), document.body.append(this.commentDialog)), l.commentId !== this.commentDialogAnchorId && (this.commentDialogAnchorId = l.commentId, this.commentDialog.anchor = l.selection ? this.selectionAnchor(r, l.selection) : null, this.commentDialog.targetElement = r), this.commentDialog.value = l.content) : this.commentDialog && (this.commentDialog.remove(), this.commentDialog = null, this.commentDialogAnchorId = null), h ? (this.overallDialog || (this.overallDialog = document.createElement(
1968
+ "llumi-overall-comment-dialog"
1969
+ ), this.overallDialog.addEventListener(
1970
+ "change",
1971
+ (g) => this.actor.send({
1972
+ type: "COMMENT_CHANGE",
1973
+ content: g.detail
1974
+ })
1975
+ ), this.overallDialog.addEventListener(
1976
+ "close",
1977
+ () => this.actor.send({ type: "CLOSE" })
1978
+ ), document.body.append(this.overallDialog)), this.overallDialog.barElement = this.bar.barRoot, this.overallDialog.value = n) : this.overallDialog && (this.overallDialog.remove(), this.overallDialog = null), s && this.painter.update(this.selectionComments);
1979
+ }
1980
+ // --- highlight callbacks ---
1981
+ buildHighlightCallbacks() {
1982
+ return {
1983
+ activate: (e) => {
1984
+ const t = this.manager;
1985
+ t && (t.activate(e), t.startObserving({
1986
+ editingTarget: this.actor.getSnapshot().context.targetElement,
1987
+ onTargetDisconnected: () => this.actor.send({ type: "CLOSE" }),
1988
+ onSelectableReconnected: () => this.painter.update(this.selectionComments),
1989
+ commentedIds: e
1990
+ }));
1991
+ },
1992
+ deactivate: () => {
1993
+ const e = this.manager;
1994
+ e && (e.deactivate(), e.stopObserving(), this.painter.clear());
1995
+ },
1996
+ reveal: (e) => {
1997
+ var t;
1998
+ return (t = this.manager) == null ? void 0 : t.reveal(e);
1999
+ },
2000
+ unreveal: () => {
2001
+ var e;
2002
+ return (e = this.manager) == null ? void 0 : e.unreveal();
2003
+ },
2004
+ setEditing: (e, t) => {
2005
+ var n;
2006
+ (n = this.manager) == null || n.setEditing(e, t), this.painter.update(this.selectionComments);
2007
+ },
2008
+ clearEditing: (e, t) => {
2009
+ var n;
2010
+ (n = this.manager) == null || n.clearEditing(e, t), this.painter.update(this.selectionComments);
2011
+ }
2012
+ };
2013
+ }
2014
+ isAnnotating() {
2015
+ return !this.actor.getSnapshot().matches({ annotating: "inactive" });
2016
+ }
2017
+ caretPosition(e, t) {
2018
+ if ("caretPositionFromPoint" in document) {
2019
+ const n = document.caretPositionFromPoint(e, t);
2020
+ if (n) return n;
2021
+ } else if ("caretRangeFromPoint" in document) {
2022
+ const n = document.caretRangeFromPoint(e, t);
2023
+ if (n) return { offsetNode: n.startContainer, offset: n.startOffset };
2024
+ }
2025
+ return null;
2026
+ }
2027
+ currentEditingTargetId() {
2028
+ var t;
2029
+ const e = this.actor.getSnapshot().context;
2030
+ if (e.editingCommentId)
2031
+ return ((t = e.comments.find((n) => n.commentId === e.editingCommentId)) == null ? void 0 : t.targetId) ?? void 0;
2032
+ }
2033
+ };
2034
+ it.observedAttributes = ["bar-position", "shortcut", "default-mode"];
2035
+ let nt = it;
2036
+ customElements.get("llumi-review") || customElements.define("llumi-review", nt);
2037
+ export {
2038
+ S as LlumiCommentDialog,
2039
+ I as LlumiDefaultEditor,
2040
+ L as LlumiOverallCommentDialog,
2041
+ nt as LlumiReview,
2042
+ b as LlumiReviewBar,
2043
+ Z as LlumiSelectionCommentIcons
2044
+ };