@alpaca-editor/core 1.0.4041 → 1.0.4042
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/components/ui/textarea.d.ts +1 -1
- package/dist/components/ui/textarea.js +5 -3
- package/dist/components/ui/textarea.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +18 -5
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/page-editor-chrome/CommentHighlighting.js +30 -10
- package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
- package/dist/editor/page-editor-chrome/SuggestionHighlighting.js +17 -13
- package/dist/editor/page-editor-chrome/SuggestionHighlighting.js.map +1 -1
- package/dist/editor/reviews/CommentDisplayPopover.d.ts +9 -0
- package/dist/editor/reviews/CommentDisplayPopover.js +101 -0
- package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -0
- package/dist/editor/reviews/CommentPopover.d.ts +15 -0
- package/dist/editor/reviews/CommentPopover.js +151 -0
- package/dist/editor/reviews/CommentPopover.js.map +1 -0
- package/dist/editor/reviews/SuggestionDisplayPopover.d.ts +9 -0
- package/dist/editor/reviews/SuggestionDisplayPopover.js +186 -0
- package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -0
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +3 -0
- package/package.json +1 -1
- package/src/components/ui/textarea.tsx +7 -2
- package/src/editor/commands/componentCommands.tsx +16 -4
- package/src/editor/page-editor-chrome/CommentHighlighting.tsx +49 -18
- package/src/editor/page-editor-chrome/SuggestionHighlighting.tsx +36 -26
- package/src/editor/reviews/CommentDisplayPopover.tsx +326 -0
- package/src/editor/reviews/CommentPopover.tsx +249 -0
- package/src/editor/reviews/SuggestionDisplayPopover.tsx +410 -0
- package/src/revision.ts +2 -2
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useEffect, useLayoutEffect, useState } from "react";
|
|
5
|
+
import uuid from "react-uuid";
|
|
6
|
+
import { Send, MessageCirclePlus } from "lucide-react";
|
|
7
|
+
import { useEditContext } from "../client/editContext";
|
|
8
|
+
import { createOrUpdateComment } from "../services/reviewsService";
|
|
9
|
+
import { Popover, PopoverContent, PopoverTrigger, PopoverAnchor, } from "../../components/ui/popover";
|
|
10
|
+
import { Button } from "../../components/ui/button";
|
|
11
|
+
import { Textarea } from "../../components/ui/textarea";
|
|
12
|
+
import * as ReactDOM from "react-dom/client";
|
|
13
|
+
export function CommentPopover({ children, editContext: externalEditContext, position, onClose, }) {
|
|
14
|
+
const [isOpen, setIsOpen] = useState(!!position);
|
|
15
|
+
const [text, setText] = useState("");
|
|
16
|
+
const textareaRef = React.useRef(null);
|
|
17
|
+
const [saving, setSaving] = useState(false);
|
|
18
|
+
const contextFromHook = useEditContext();
|
|
19
|
+
const editContext = externalEditContext || contextFromHook;
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (position)
|
|
22
|
+
setIsOpen(true);
|
|
23
|
+
}, [position?.x, position?.y]);
|
|
24
|
+
const handleSubmit = async () => {
|
|
25
|
+
if (!editContext || !text.trim() || saving)
|
|
26
|
+
return;
|
|
27
|
+
const descriptor = editContext.contentEditorItem?.descriptor;
|
|
28
|
+
if (!descriptor)
|
|
29
|
+
return;
|
|
30
|
+
const itemId = editContext.focusedField?.item.id ||
|
|
31
|
+
(editContext.selection.length > 0
|
|
32
|
+
? editContext.selection[0]
|
|
33
|
+
: undefined) ||
|
|
34
|
+
descriptor.id;
|
|
35
|
+
if (!itemId)
|
|
36
|
+
return;
|
|
37
|
+
const language = descriptor.language;
|
|
38
|
+
const version = descriptor.version;
|
|
39
|
+
const getFieldName = async () => {
|
|
40
|
+
if (!editContext.focusedField)
|
|
41
|
+
return undefined;
|
|
42
|
+
const field = await editContext.itemsRepository.getField(editContext.focusedField);
|
|
43
|
+
return field?.name;
|
|
44
|
+
};
|
|
45
|
+
const getItemName = async () => {
|
|
46
|
+
const item = await editContext.itemsRepository.getItem({
|
|
47
|
+
id: itemId,
|
|
48
|
+
language,
|
|
49
|
+
version,
|
|
50
|
+
});
|
|
51
|
+
return item?.name;
|
|
52
|
+
};
|
|
53
|
+
setSaving(true);
|
|
54
|
+
try {
|
|
55
|
+
const newComment = {
|
|
56
|
+
id: uuid(),
|
|
57
|
+
isNew: false,
|
|
58
|
+
itemId,
|
|
59
|
+
itemName: await getItemName(),
|
|
60
|
+
fieldId: editContext.focusedField?.fieldId,
|
|
61
|
+
fieldName: await getFieldName(),
|
|
62
|
+
mainItemId: descriptor.id,
|
|
63
|
+
language,
|
|
64
|
+
version,
|
|
65
|
+
position: 0,
|
|
66
|
+
rangeStart: editContext.selectedRange?.startOffset || 0,
|
|
67
|
+
rangeEnd: editContext.selectedRange?.endOffset || 0,
|
|
68
|
+
author: editContext.user?.name,
|
|
69
|
+
authorDisplayName: editContext.user?.displayName,
|
|
70
|
+
date: new Date().toISOString(),
|
|
71
|
+
text: text.trim(),
|
|
72
|
+
};
|
|
73
|
+
editContext.setComments([newComment, ...editContext.comments]);
|
|
74
|
+
editContext.setSelectedComment(newComment);
|
|
75
|
+
try {
|
|
76
|
+
const item = await editContext.itemsRepository.getItem({
|
|
77
|
+
id: itemId,
|
|
78
|
+
language,
|
|
79
|
+
version,
|
|
80
|
+
});
|
|
81
|
+
if (item && newComment.fieldId) {
|
|
82
|
+
newComment.fieldValue = item.fields.find((f) => f.id === newComment.fieldId)?.rawValue;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch { }
|
|
86
|
+
await createOrUpdateComment(newComment);
|
|
87
|
+
editContext.loadComments();
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
setSaving(false);
|
|
91
|
+
setIsOpen(false);
|
|
92
|
+
setText("");
|
|
93
|
+
onClose?.();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const handleKeyDown = (e) => {
|
|
97
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
handleSubmit();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
useLayoutEffect(() => {
|
|
103
|
+
if (isOpen) {
|
|
104
|
+
// Single focus attempt after the popover is fully mounted
|
|
105
|
+
const focusTextarea = () => {
|
|
106
|
+
const el = textareaRef.current;
|
|
107
|
+
if (el) {
|
|
108
|
+
el.focus();
|
|
109
|
+
try {
|
|
110
|
+
const len = el.value.length;
|
|
111
|
+
el.setSelectionRange(len, len);
|
|
112
|
+
}
|
|
113
|
+
catch { }
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
// Use a longer delay to ensure popover is fully rendered, especially for dynamically created popovers
|
|
117
|
+
const timeoutId = setTimeout(focusTextarea, 300);
|
|
118
|
+
return () => clearTimeout(timeoutId);
|
|
119
|
+
}
|
|
120
|
+
}, [isOpen]);
|
|
121
|
+
const assignTextareaRef = (el) => {
|
|
122
|
+
textareaRef.current = el;
|
|
123
|
+
};
|
|
124
|
+
return (_jsxs(Popover, { open: isOpen, onOpenChange: (open) => {
|
|
125
|
+
setIsOpen(open);
|
|
126
|
+
if (!open)
|
|
127
|
+
onClose?.();
|
|
128
|
+
}, enableIframeClickDetection: false, modal: true, children: [position && (_jsx("div", { style: {
|
|
129
|
+
position: "fixed",
|
|
130
|
+
left: position.x,
|
|
131
|
+
top: position.y,
|
|
132
|
+
width: 1,
|
|
133
|
+
height: 1,
|
|
134
|
+
pointerEvents: "none",
|
|
135
|
+
}, children: _jsx(PopoverAnchor, {}) })), !position && (_jsx(PopoverTrigger, { asChild: true, children: children ?? _jsx(MessageCirclePlus, { size: 16, strokeWidth: 1 }) })), _jsx(PopoverContent, { className: "w-96 p-4", side: "bottom", align: "start", onPointerDownOutside: (e) => e.preventDefault(), onInteractOutside: (e) => e.preventDefault(), onFocusOutside: (e) => e.preventDefault(), onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), children: _jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "font-medium", children: "Add Comment" }), _jsx(Textarea, { ref: assignTextareaRef, value: text, onChange: (e) => setText(e.target.value), onKeyDown: handleKeyDown, placeholder: "Write your comment...", className: "mt-2 resize-none", rows: 3, autoFocus: true }), _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
136
|
+
setIsOpen(false);
|
|
137
|
+
onClose?.();
|
|
138
|
+
}, disabled: saving, children: "Cancel" }), _jsxs(Button, { size: "sm", onClick: handleSubmit, disabled: !text.trim() || saving, className: "flex items-center gap-1", children: [_jsx(Send, { size: 14, strokeWidth: 1 }), saving ? "Saving..." : "Add Comment"] })] })] }) })] }));
|
|
139
|
+
}
|
|
140
|
+
export function showCommentPopoverAt(position, editContext) {
|
|
141
|
+
const container = document.createElement("div");
|
|
142
|
+
document.body.appendChild(container);
|
|
143
|
+
const root = ReactDOM.createRoot(container);
|
|
144
|
+
const handleClose = () => {
|
|
145
|
+
root.unmount();
|
|
146
|
+
if (container.parentNode)
|
|
147
|
+
container.parentNode.removeChild(container);
|
|
148
|
+
};
|
|
149
|
+
root.render(_jsx(CommentPopover, { editContext: editContext, position: position, onClose: handleClose }));
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=CommentPopover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommentPopover.js","sourceRoot":"","sources":["../../../src/editor/reviews/CommentPopover.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { SuggestedEdit } from "../../types";
|
|
3
|
+
interface SuggestionDisplayPopoverProps {
|
|
4
|
+
suggestion: SuggestedEdit;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
onSuggestionUpdated?: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function SuggestionDisplayPopover({ suggestion, children, onSuggestionUpdated, }: SuggestionDisplayPopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { useEditContext } from "../client/editContext";
|
|
6
|
+
import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
|
|
7
|
+
import { formatDate } from "../utils";
|
|
8
|
+
import { Button } from "../../components/ui/button";
|
|
9
|
+
import { deleteSuggestedEdit, createOrUpdateSuggestedEdit, } from "../services/suggestedEditsService";
|
|
10
|
+
import { Check, Trash2, Brush, GalleryVertical, } from "lucide-react";
|
|
11
|
+
import { DiffView } from "./DiffView";
|
|
12
|
+
import { SimpleIconButton } from "../ui/SimpleIconButton";
|
|
13
|
+
import { createPatch, applyPatch } from "diff";
|
|
14
|
+
import { cn } from "../../lib/utils";
|
|
15
|
+
export function SuggestionDisplayPopover({ suggestion, children, onSuggestionUpdated, }) {
|
|
16
|
+
const editContext = useEditContext();
|
|
17
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
18
|
+
const [deleteConfirm, setDeleteConfirm] = useState(false);
|
|
19
|
+
const [isApplying, setIsApplying] = useState(false);
|
|
20
|
+
const [item, setItem] = useState(null);
|
|
21
|
+
const [patchPossible, setPatchPossible] = useState(true);
|
|
22
|
+
const [patchWarning, setPatchWarning] = useState("");
|
|
23
|
+
const [ignoreFormatting, setIgnoreFormatting] = useState(true);
|
|
24
|
+
const [clipUnchanged, setClipUnchanged] = useState(true);
|
|
25
|
+
const canDelete = suggestion.author === editContext?.user?.name &&
|
|
26
|
+
suggestion.status !== "applied";
|
|
27
|
+
const canApply = editContext?.mode === "edit" &&
|
|
28
|
+
suggestion.status !== "applied" &&
|
|
29
|
+
!editContext?.readonly;
|
|
30
|
+
// Load the full item when popover opens
|
|
31
|
+
React.useEffect(() => {
|
|
32
|
+
if (isOpen && editContext?.itemsRepository && suggestion.itemId) {
|
|
33
|
+
editContext.itemsRepository
|
|
34
|
+
.getItem({
|
|
35
|
+
id: suggestion.itemId,
|
|
36
|
+
language: suggestion.mainItemLanguage,
|
|
37
|
+
version: suggestion.mainItemVersion,
|
|
38
|
+
})
|
|
39
|
+
.then((loadedItem) => {
|
|
40
|
+
setItem(loadedItem);
|
|
41
|
+
checkAndComputePatch(loadedItem);
|
|
42
|
+
})
|
|
43
|
+
.catch((err) => {
|
|
44
|
+
console.error("Error loading item:", err);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}, [isOpen, suggestion, editContext?.itemsRepository]);
|
|
48
|
+
// Check if the patch can be applied cleanly
|
|
49
|
+
const checkAndComputePatch = async (loadedItem) => {
|
|
50
|
+
const field = loadedItem?.fields?.find((f) => f.id === suggestion.fieldId);
|
|
51
|
+
if (!field)
|
|
52
|
+
return;
|
|
53
|
+
const currentValue = field.rawValue || "";
|
|
54
|
+
const patch = createPatch("field", suggestion.oldValue, suggestion.newValue);
|
|
55
|
+
const patchedCandidate = applyPatch(currentValue, patch);
|
|
56
|
+
if (patchedCandidate === false || typeof patchedCandidate !== "string") {
|
|
57
|
+
setPatchPossible(false);
|
|
58
|
+
setPatchWarning("Patch cannot be applied cleanly to current field value.");
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
setPatchPossible(true);
|
|
62
|
+
setPatchWarning("");
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const handleDelete = async () => {
|
|
66
|
+
if (!deleteConfirm) {
|
|
67
|
+
setDeleteConfirm(true);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
await deleteSuggestedEdit(suggestion);
|
|
71
|
+
setIsOpen(false);
|
|
72
|
+
onSuggestionUpdated?.();
|
|
73
|
+
};
|
|
74
|
+
const handleApplyPatch = async () => {
|
|
75
|
+
if (!patchPossible || !editContext || isApplying)
|
|
76
|
+
return;
|
|
77
|
+
setIsApplying(true);
|
|
78
|
+
try {
|
|
79
|
+
// Recalculate the patch immediately before applying
|
|
80
|
+
const field = item?.fields?.find((f) => f.id === suggestion.fieldId);
|
|
81
|
+
if (!field)
|
|
82
|
+
return;
|
|
83
|
+
const currentValue = field.rawValue || "";
|
|
84
|
+
const patch = createPatch("field", suggestion.oldValue, suggestion.newValue);
|
|
85
|
+
const patchedCandidate = applyPatch(currentValue, patch);
|
|
86
|
+
if (patchedCandidate === false || typeof patchedCandidate !== "string") {
|
|
87
|
+
setPatchWarning("Patch cannot be applied cleanly to current field value.");
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
await editContext.operations.editField({
|
|
91
|
+
field: {
|
|
92
|
+
fieldId: suggestion.fieldId,
|
|
93
|
+
item: {
|
|
94
|
+
id: suggestion.itemId,
|
|
95
|
+
language: suggestion.mainItemLanguage,
|
|
96
|
+
version: suggestion.mainItemVersion,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
value: patchedCandidate,
|
|
100
|
+
rawValue: patchedCandidate,
|
|
101
|
+
refresh: "immediate",
|
|
102
|
+
});
|
|
103
|
+
// Update the suggestion status to "applied"
|
|
104
|
+
const updatedSuggestion = { ...suggestion, status: "applied" };
|
|
105
|
+
await createOrUpdateSuggestedEdit(updatedSuggestion);
|
|
106
|
+
onSuggestionUpdated?.();
|
|
107
|
+
setIsOpen(false);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
setIsApplying(false);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const handleReplaceCompletely = async () => {
|
|
114
|
+
if (!editContext || isApplying)
|
|
115
|
+
return;
|
|
116
|
+
setIsApplying(true);
|
|
117
|
+
try {
|
|
118
|
+
await editContext.operations.editField({
|
|
119
|
+
field: {
|
|
120
|
+
fieldId: suggestion.fieldId,
|
|
121
|
+
item: {
|
|
122
|
+
id: suggestion.itemId,
|
|
123
|
+
language: suggestion.mainItemLanguage,
|
|
124
|
+
version: suggestion.mainItemVersion,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
value: suggestion.newValue,
|
|
128
|
+
rawValue: suggestion.newValue,
|
|
129
|
+
refresh: "immediate",
|
|
130
|
+
});
|
|
131
|
+
const updatedSuggestion = { ...suggestion, status: "applied" };
|
|
132
|
+
await createOrUpdateSuggestedEdit(updatedSuggestion);
|
|
133
|
+
onSuggestionUpdated?.();
|
|
134
|
+
setIsOpen(false);
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
setIsApplying(false);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const renderContextInfo = () => {
|
|
141
|
+
const itemName = item ? item.name : null;
|
|
142
|
+
const fieldName = item && item.fields
|
|
143
|
+
? item.fields.find((f) => f.id === suggestion.fieldId)?.name
|
|
144
|
+
: null;
|
|
145
|
+
if (!itemName && !fieldName)
|
|
146
|
+
return null;
|
|
147
|
+
return (_jsxs("div", { className: "mt-3 flex items-center border-t pt-3 text-xs", children: [itemName && _jsx("div", { className: "text-xs text-gray-500", children: itemName }), fieldName && itemName && (_jsx("div", { className: "mx-2 text-xs text-gray-500", children: ">" })), fieldName && _jsx("div", { className: "text-xs text-gray-500", children: fieldName })] }));
|
|
148
|
+
};
|
|
149
|
+
const renderDiffToggleButtons = () => {
|
|
150
|
+
return (_jsxs("div", { className: "mb-2 flex gap-2", children: [_jsx(SimpleIconButton, { icon: _jsx(Brush, { size: 14, className: "p-0.5", strokeWidth: 1 }), label: "Ignore Formatting", onClick: () => setIgnoreFormatting((prev) => !prev), className: cn("text-gray-500", ignoreFormatting ? "bg-gray-200" : "") }), _jsx(SimpleIconButton, { icon: _jsx(GalleryVertical, { size: 14, className: "p-0.5", strokeWidth: 1 }), label: "Clip", onClick: () => setClipUnchanged((prev) => !prev), className: cn("text-gray-500", clipUnchanged ? "bg-gray-200" : "") })] }));
|
|
151
|
+
};
|
|
152
|
+
return (_jsxs(Popover, { open: isOpen, onOpenChange: (open) => {
|
|
153
|
+
setIsOpen(open);
|
|
154
|
+
if (!open) {
|
|
155
|
+
setDeleteConfirm(false);
|
|
156
|
+
setPatchWarning("");
|
|
157
|
+
}
|
|
158
|
+
}, enableIframeClickDetection: true, children: [_jsx(PopoverTrigger, { asChild: true, children: children }), _jsx(PopoverContent, { className: "w-96 p-4", side: "bottom", align: "start", children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-semibold text-gray-900", children: suggestion.authorDisplayName || suggestion.author }), _jsx("div", { className: "text-xs text-gray-500", children: suggestion.created
|
|
159
|
+
? formatDate(new Date(suggestion.created))
|
|
160
|
+
: "" })] }), _jsxs("div", { className: "flex items-center gap-1", children: [canApply && patchPossible && suggestion.status !== "applied" && (_jsx(Button, { variant: "ghost", size: "sm", onClick: handleApplyPatch, disabled: isApplying, className: "h-8 w-8 p-0 text-green-600", children: _jsx(Check, { size: 14, strokeWidth: 1 }) })), suggestion.status === "applied" && (_jsx("div", { className: "flex h-8 w-8 items-center justify-center", children: _jsx(Check, { size: 14, strokeWidth: 1, className: "text-green-500" }) })), canDelete && (_jsx(Button, { variant: "ghost", size: "sm", onClick: handleDelete, className: `h-8 w-8 p-0 ${deleteConfirm ? "text-red-500" : "text-gray-400"}`, children: _jsx(Trash2, { size: 14, strokeWidth: 1 }) }))] })] }), suggestion.status === "applied" && (_jsxs("div", { className: "text-xs font-medium text-green-600", children: ["\u2713 Applied", " ", suggestion.updatedBy ? `by ${suggestion.updatedBy}` : "", suggestion.updated
|
|
161
|
+
? ` on ${formatDate(new Date(suggestion.updated))}`
|
|
162
|
+
: ""] })), renderDiffToggleButtons(), _jsxs("div", { className: "text-sm", children: [_jsx(DiffView, { oldText: suggestion.oldValue, newText: suggestion.newValue, ignoreFormatting: ignoreFormatting, clipUnchanged: clipUnchanged, clipThreshold: 50, clipContext: 10 }), canApply && patchWarning && (_jsxs("div", { className: "mt-2 text-xs text-red-500", children: [patchWarning, _jsx("button", { className: "ml-2 cursor-pointer underline hover:text-red-700", onClick: handleReplaceCompletely, disabled: isApplying, children: "Click here to replace the field content completely." })] }))] }), renderContextInfo(), deleteConfirm && (_jsxs("div", { className: "border-t pt-3", children: [_jsx("div", { className: "mb-2 text-sm text-red-600", children: "Are you sure you want to delete this suggestion?" }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => setDeleteConfirm(false), children: "Cancel" }), _jsx(Button, { variant: "destructive", size: "sm", onClick: handleDelete, children: "Delete" })] })] })), canApply && !patchPossible && suggestion.status !== "applied" && (_jsx("div", { className: "border-t pt-3", children: _jsx(Button, { size: "sm", onClick: handleReplaceCompletely, disabled: isApplying, className: "w-full", children: isApplying ? "Applying..." : "Replace Field Content" }) })), !deleteConfirm && (_jsx("div", { className: "border-t pt-3", children: _jsx(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
163
|
+
setIsOpen(false);
|
|
164
|
+
// Exit fullscreen mode if active
|
|
165
|
+
if (editContext?.pageView?.fullscreen) {
|
|
166
|
+
editContext.pageView.setFullscreen(false);
|
|
167
|
+
}
|
|
168
|
+
// Focus on the field and select the item
|
|
169
|
+
if (suggestion.fieldId) {
|
|
170
|
+
editContext?.setFocusedField({
|
|
171
|
+
fieldId: suggestion.fieldId,
|
|
172
|
+
item: {
|
|
173
|
+
id: suggestion.itemId,
|
|
174
|
+
language: suggestion.mainItemLanguage,
|
|
175
|
+
version: suggestion.mainItemVersion,
|
|
176
|
+
},
|
|
177
|
+
}, false);
|
|
178
|
+
editContext?.select?.([suggestion.itemId]);
|
|
179
|
+
}
|
|
180
|
+
// Switch to comments view
|
|
181
|
+
if (editContext?.switchView) {
|
|
182
|
+
editContext.switchView("comments");
|
|
183
|
+
}
|
|
184
|
+
}, className: "w-full", children: "View in Comments Panel" }) }))] }) })] }));
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=SuggestionDisplayPopover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SuggestionDisplayPopover.js","sourceRoot":"","sources":["../../../src/editor/reviews/SuggestionDisplayPopover.tsx"],"names":[],"mappings":"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"}
|
package/dist/revision.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "1.0.
|
|
2
|
-
export declare const buildDate = "2025-08-13
|
|
1
|
+
export declare const version = "1.0.4042";
|
|
2
|
+
export declare const buildDate = "2025-08-13 09:49:23";
|
package/dist/revision.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export const version = "1.0.
|
|
2
|
-
export const buildDate = "2025-08-13
|
|
1
|
+
export const version = "1.0.4042";
|
|
2
|
+
export const buildDate = "2025-08-13 09:49:23";
|
|
3
3
|
//# sourceMappingURL=revision.js.map
|
package/dist/styles.css
CHANGED
package/package.json
CHANGED
|
@@ -2,9 +2,13 @@ import * as React from "react";
|
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../lib/utils";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const Textarea = React.forwardRef<
|
|
6
|
+
HTMLTextAreaElement,
|
|
7
|
+
React.ComponentProps<"textarea">
|
|
8
|
+
>(({ className, ...props }, ref) => {
|
|
6
9
|
return (
|
|
7
10
|
<textarea
|
|
11
|
+
ref={ref}
|
|
8
12
|
data-slot="textarea"
|
|
9
13
|
className={cn(
|
|
10
14
|
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
@@ -13,6 +17,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
|
13
17
|
{...props}
|
|
14
18
|
/>
|
|
15
19
|
);
|
|
16
|
-
}
|
|
20
|
+
});
|
|
21
|
+
Textarea.displayName = "Textarea";
|
|
17
22
|
|
|
18
23
|
export { Textarea };
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
TriangleAlert,
|
|
26
26
|
} from "lucide-react";
|
|
27
27
|
import { AiPromptPopover } from "../ai/AiPromptPopover";
|
|
28
|
+
import { showCommentPopoverAt } from "../reviews/CommentPopover";
|
|
28
29
|
|
|
29
30
|
export type ComponentCommandData = CommandData & {
|
|
30
31
|
components: Component[];
|
|
@@ -72,7 +73,7 @@ export async function getComponentCommands(
|
|
|
72
73
|
) as Component[];
|
|
73
74
|
|
|
74
75
|
const commands = [
|
|
75
|
-
await getCreateCommentCommand(components),
|
|
76
|
+
await getCreateCommentCommand(components, editContext),
|
|
76
77
|
await getInsertCommand(components, editContext),
|
|
77
78
|
await getDeleteCommand(components, editContext),
|
|
78
79
|
await getDuplicateCommand(components, editContext),
|
|
@@ -413,18 +414,29 @@ function deleteComponents(
|
|
|
413
414
|
|
|
414
415
|
function getCreateCommentCommand(
|
|
415
416
|
components: Component[],
|
|
417
|
+
editContext: EditContextType,
|
|
416
418
|
): ComponentCommand | null {
|
|
417
419
|
if (components.length !== 1 || isPlaceholder(components[0])) return null;
|
|
418
420
|
|
|
419
421
|
return {
|
|
420
422
|
id: "addComment",
|
|
421
423
|
label: "Add Comment",
|
|
422
|
-
icon: <MessageCirclePlus size={14} />,
|
|
424
|
+
icon: <MessageCirclePlus size={14} strokeWidth={1} />,
|
|
423
425
|
disabled: () => false,
|
|
424
426
|
visibilityScopes: ["contextMenu"],
|
|
425
427
|
execute: async (context: CommandContext<any>) => {
|
|
426
|
-
context.
|
|
427
|
-
|
|
428
|
+
const ev = context.event as any;
|
|
429
|
+
if (ev?.preventDefault) ev.preventDefault();
|
|
430
|
+
if (ev?.stopPropagation) ev.stopPropagation();
|
|
431
|
+
if (ev?.nativeEvent?.stopImmediatePropagation)
|
|
432
|
+
ev.nativeEvent.stopImmediatePropagation();
|
|
433
|
+
const x = ev?.clientX ?? ev?.pageX ?? window.innerWidth / 2;
|
|
434
|
+
const y = ev?.clientY ?? ev?.pageY ?? window.innerHeight / 2;
|
|
435
|
+
setTimeout(() => {
|
|
436
|
+
requestAnimationFrame(() => {
|
|
437
|
+
showCommentPopoverAt({ x, y }, context.editContext);
|
|
438
|
+
});
|
|
439
|
+
}, 0);
|
|
428
440
|
},
|
|
429
441
|
};
|
|
430
442
|
}
|
|
@@ -8,7 +8,7 @@ import { useState } from "react";
|
|
|
8
8
|
import { useEffect } from "react";
|
|
9
9
|
import { classNames } from "primereact/utils";
|
|
10
10
|
import { CommentIcon } from "../ui/Icons";
|
|
11
|
-
import {
|
|
11
|
+
import { CommentDisplayPopover } from "../reviews/CommentDisplayPopover";
|
|
12
12
|
|
|
13
13
|
export function CommentHighlighting({
|
|
14
14
|
comment,
|
|
@@ -20,6 +20,7 @@ export function CommentHighlighting({
|
|
|
20
20
|
iframe: HTMLIFrameElement;
|
|
21
21
|
}) {
|
|
22
22
|
const editContext = useEditContext();
|
|
23
|
+
const isSelected = comment.id === editContext?.selectedComment?.id;
|
|
23
24
|
const modifiedFields = useModifiedFieldsContext();
|
|
24
25
|
|
|
25
26
|
const [range, setRange] = useState<number[]>([
|
|
@@ -176,22 +177,50 @@ export function CommentHighlighting({
|
|
|
176
177
|
}}
|
|
177
178
|
>
|
|
178
179
|
{index === 0 && (
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
(
|
|
184
|
-
? "right-0"
|
|
185
|
-
: "right-[-18px]",
|
|
186
|
-
)}
|
|
187
|
-
onClick={() => {
|
|
188
|
-
editContext.switchView("comments");
|
|
189
|
-
editContext?.select([comment.itemId]);
|
|
190
|
-
editContext?.setSelectedComment(comment);
|
|
180
|
+
<CommentDisplayPopover
|
|
181
|
+
comment={comment}
|
|
182
|
+
onCommentUpdated={() => {
|
|
183
|
+
// Reload comments to reflect any changes
|
|
184
|
+
editContext?.loadComments?.();
|
|
191
185
|
}}
|
|
192
186
|
>
|
|
193
|
-
<
|
|
194
|
-
|
|
187
|
+
<div
|
|
188
|
+
className={classNames(
|
|
189
|
+
"pointer-events-auto absolute h-5 w-5 cursor-pointer",
|
|
190
|
+
rect.top * scale < 18 ? "top-0" : "top-[-18px]",
|
|
191
|
+
(rect.left + rect.width) * scale > iframeRect.width - 18
|
|
192
|
+
? "right-0"
|
|
193
|
+
: "right-[-18px]",
|
|
194
|
+
)}
|
|
195
|
+
onClick={() => {
|
|
196
|
+
// Set this comment as selected
|
|
197
|
+
editContext?.setSelectedComment(comment);
|
|
198
|
+
editContext?.setScrollIntoView(comment.itemId);
|
|
199
|
+
editContext?.select([comment.itemId]);
|
|
200
|
+
if (comment.fieldId) {
|
|
201
|
+
editContext?.setFocusedField(
|
|
202
|
+
{
|
|
203
|
+
fieldId: comment.fieldId,
|
|
204
|
+
item: {
|
|
205
|
+
id: comment.itemId,
|
|
206
|
+
language: comment.language,
|
|
207
|
+
version: comment.version,
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
false,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}}
|
|
214
|
+
>
|
|
215
|
+
<CommentIcon
|
|
216
|
+
className={
|
|
217
|
+
isSelected
|
|
218
|
+
? "text-red-700 hover:text-red-800"
|
|
219
|
+
: "text-blue-500 hover:text-blue-600"
|
|
220
|
+
}
|
|
221
|
+
/>
|
|
222
|
+
</div>
|
|
223
|
+
</CommentDisplayPopover>
|
|
195
224
|
)}
|
|
196
225
|
{isTextRange && (
|
|
197
226
|
<div
|
|
@@ -199,9 +228,11 @@ export function CommentHighlighting({
|
|
|
199
228
|
style={{
|
|
200
229
|
width: "100%",
|
|
201
230
|
height: "100%",
|
|
202
|
-
backgroundColor:
|
|
203
|
-
? "rgba(
|
|
204
|
-
:
|
|
231
|
+
backgroundColor: isSelected
|
|
232
|
+
? "rgba(255, 0, 0, 1)" // Darker red for selected
|
|
233
|
+
: comment.isResolved
|
|
234
|
+
? "rgba(0, 255, 0, 0.45)" // Green for resolved
|
|
235
|
+
: "rgba(255, 0, 0, 0.45)", // Red for unresolved
|
|
205
236
|
}}
|
|
206
237
|
></div>
|
|
207
238
|
)}
|