@parhelia/core 0.4.12818 → 0.4.12825
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/config/config.js +3 -0
- package/dist/config/config.js.map +1 -1
- package/dist/editor/ai/AgentStatusBadge.js +11 -9
- package/dist/editor/ai/AgentStatusBadge.js.map +1 -1
- package/dist/editor/ai/Agents.js +2 -2
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/agentDiagnostics.d.ts +1 -1
- package/dist/editor/ai/agentDiagnostics.js +8 -0
- package/dist/editor/ai/agentDiagnostics.js.map +1 -1
- package/dist/editor/ai/terminal/agentSessionSnapshot.d.ts +15 -0
- package/dist/editor/ai/terminal/agentSessionSnapshot.js +103 -3
- package/dist/editor/ai/terminal/agentSessionSnapshot.js.map +1 -1
- package/dist/editor/ai/terminal/agentSessionState.js +5 -1
- package/dist/editor/ai/terminal/agentSessionState.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentActivityOverviewPanel.js +5 -5
- package/dist/editor/ai/terminal/components/AgentActivityOverviewPanel.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentPromptTrayPopovers.js +1 -1
- package/dist/editor/ai/terminal/components/AgentPromptTrayPopovers.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentSkillSettingsSection.js +2 -2
- package/dist/editor/ai/terminal/components/AgentSkillSettingsSection.js.map +1 -1
- package/dist/editor/ai/terminal/components/AiResponseMessage.js +8 -7
- package/dist/editor/ai/terminal/components/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/terminal/components/ContextInfoBar.js +1 -1
- package/dist/editor/ai/terminal/components/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentEditorContext.js +13 -3
- package/dist/editor/ai/terminal/useAgentEditorContext.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentOperationHistoryLoader.js +5 -1
- package/dist/editor/ai/terminal/useAgentOperationHistoryLoader.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentOperationSocketHandler.js +33 -1
- package/dist/editor/ai/terminal/useAgentOperationSocketHandler.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentServerReconciler.js +11 -0
- package/dist/editor/ai/terminal/useAgentServerReconciler.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentSubmitHandlers.d.ts +1 -0
- package/dist/editor/ai/terminal/useAgentSubmitHandlers.js +6 -2
- package/dist/editor/ai/terminal/useAgentSubmitHandlers.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentTerminalController.js +4 -0
- package/dist/editor/ai/terminal/useAgentTerminalController.js.map +1 -1
- package/dist/editor/bridge/protocol.d.ts +5 -0
- package/dist/editor/bridge/protocol.js.map +1 -1
- package/dist/editor/client/EditorShell.js +4 -3
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js +3 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/operations.js +34 -2
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/commands/commands.d.ts +6 -0
- package/dist/editor/commands/commands.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.js +10 -1
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.js +8 -2
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
- package/dist/editor/field-types/useFormFieldCaretPresence.js +1 -0
- package/dist/editor/field-types/useFormFieldCaretPresence.js.map +1 -1
- package/dist/editor/find-replace/FindReplacePanel.d.ts +11 -0
- package/dist/editor/find-replace/FindReplacePanel.js +311 -0
- package/dist/editor/find-replace/FindReplacePanel.js.map +1 -0
- package/dist/editor/find-replace/findReplaceCommand.d.ts +8 -0
- package/dist/editor/find-replace/findReplaceCommand.js +25 -0
- package/dist/editor/find-replace/findReplaceCommand.js.map +1 -0
- package/dist/editor/find-replace/findReplaceMatches.d.ts +42 -0
- package/dist/editor/find-replace/findReplaceMatches.js +66 -0
- package/dist/editor/find-replace/findReplaceMatches.js.map +1 -0
- package/dist/editor/find-replace/findReplaceStore.d.ts +30 -0
- package/dist/editor/find-replace/findReplaceStore.js +61 -0
- package/dist/editor/find-replace/findReplaceStore.js.map +1 -0
- package/dist/editor/find-replace/findReplaceTargets.d.ts +49 -0
- package/dist/editor/find-replace/findReplaceTargets.js +110 -0
- package/dist/editor/find-replace/findReplaceTargets.js.map +1 -0
- package/dist/editor/find-replace/findReplaceText.d.ts +50 -0
- package/dist/editor/find-replace/findReplaceText.js +189 -0
- package/dist/editor/find-replace/findReplaceText.js.map +1 -0
- package/dist/editor/menubar/ActiveUsers.js +1 -1
- package/dist/editor/menubar/ActiveUsers.js.map +1 -1
- package/dist/editor/menubar/ToolbarFactory.js +9 -1
- package/dist/editor/menubar/ToolbarFactory.js.map +1 -1
- package/dist/editor/menubar/VersionSelector.js +2 -2
- package/dist/editor/menubar/VersionSelector.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/FindReplaceControls.d.ts +6 -0
- package/dist/editor/menubar/toolbar-sections/FindReplaceControls.js +31 -0
- package/dist/editor/menubar/toolbar-sections/FindReplaceControls.js.map +1 -0
- package/dist/editor/menubar/toolbar-sections/index.d.ts +1 -0
- package/dist/editor/menubar/toolbar-sections/index.js +1 -0
- package/dist/editor/menubar/toolbar-sections/index.js.map +1 -1
- package/dist/editor/page-editor-chrome/FieldActionIndicator.js +8 -4
- package/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -1
- package/dist/editor/page-editor-chrome/FindReplaceHighlightings.d.ts +11 -0
- package/dist/editor/page-editor-chrome/FindReplaceHighlightings.js +117 -0
- package/dist/editor/page-editor-chrome/FindReplaceHighlightings.js.map +1 -0
- package/dist/editor/page-editor-chrome/PageEditorChrome.js +2 -1
- package/dist/editor/page-editor-chrome/PageEditorChrome.js.map +1 -1
- package/dist/editor/page-editor-chrome/SuggestionHighlightings.js +8 -1
- package/dist/editor/page-editor-chrome/SuggestionHighlightings.js.map +1 -1
- package/dist/editor/page-viewer/MiniMap.d.ts +6 -2
- package/dist/editor/page-viewer/MiniMap.js +139 -21
- package/dist/editor/page-viewer/MiniMap.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +21 -5
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/bridgeKeyboardShortcuts.d.ts +6 -0
- package/dist/editor/page-viewer/bridgeKeyboardShortcuts.js +19 -1
- package/dist/editor/page-viewer/bridgeKeyboardShortcuts.js.map +1 -1
- package/dist/editor/page-viewer/minimapViewport.d.ts +2 -0
- package/dist/editor/page-viewer/minimapViewport.js +31 -0
- package/dist/editor/page-viewer/minimapViewport.js.map +1 -0
- package/dist/editor/reviews/CommentEditor.js +34 -29
- package/dist/editor/reviews/CommentEditor.js.map +1 -1
- package/dist/editor/reviews/CommentImageAttachments.d.ts +12 -0
- package/dist/editor/reviews/CommentImageAttachments.js +19 -0
- package/dist/editor/reviews/CommentImageAttachments.js.map +1 -0
- package/dist/editor/reviews/SuggestionDisplayPopover.d.ts +3 -1
- package/dist/editor/reviews/SuggestionDisplayPopover.js +7 -2
- package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
- package/dist/editor/reviews/commentAgentAttachments.d.ts +5 -0
- package/dist/editor/reviews/commentAgentAttachments.js +51 -0
- package/dist/editor/reviews/commentAgentAttachments.js.map +1 -0
- package/dist/editor/reviews/commentAi.d.ts +4 -2
- package/dist/editor/reviews/commentAi.js +19 -12
- package/dist/editor/reviews/commentAi.js.map +1 -1
- package/dist/editor/reviews/useCommentImagePaste.d.ts +41 -14
- package/dist/editor/reviews/useCommentImagePaste.js +102 -63
- package/dist/editor/reviews/useCommentImagePaste.js.map +1 -1
- package/dist/editor/services/agentStatus.d.ts +1 -0
- package/dist/editor/services/agentStatus.js +14 -0
- package/dist/editor/services/agentStatus.js.map +1 -1
- package/dist/editor/settings/index/RecentBatchesList.js +2 -1
- package/dist/editor/settings/index/RecentBatchesList.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +6 -3
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/OperationItem.js +2 -1
- package/dist/editor/sidebar/OperationItem.js.map +1 -1
- package/dist/editor/sidebar/liveComponentThumbnails.d.ts +6 -2
- package/dist/editor/sidebar/liveComponentThumbnails.js +7 -2
- package/dist/editor/sidebar/liveComponentThumbnails.js.map +1 -1
- package/dist/editor/ui/ParheliaMark.d.ts +15 -0
- package/dist/editor/ui/ParheliaMark.js +12 -0
- package/dist/editor/ui/ParheliaMark.js.map +1 -0
- package/dist/editor/undoEligibility.d.ts +2 -0
- package/dist/editor/undoEligibility.js +8 -0
- package/dist/editor/undoEligibility.js.map +1 -0
- package/dist/editor/utils/keyboardNavigation.js +16 -0
- package/dist/editor/utils/keyboardNavigation.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +7 -0
- package/dist/lib/utils.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/ModernSplashScreen.js +4 -3
- package/dist/splash-screen/ModernSplashScreen.js.map +1 -1
- package/dist/splash-screen/RecentPages.js +3 -3
- package/dist/splash-screen/RecentPages.js.map +1 -1
- package/dist/task-board/TaskBoardWorkspace.js +179 -33
- package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
- package/dist/task-board/components/AttentionPromptDialog.d.ts +13 -0
- package/dist/task-board/components/AttentionPromptDialog.js +45 -0
- package/dist/task-board/components/AttentionPromptDialog.js.map +1 -0
- package/dist/task-board/components/GoalDataView.d.ts +22 -1
- package/dist/task-board/components/GoalDataView.js +63 -17
- package/dist/task-board/components/GoalDataView.js.map +1 -1
- package/dist/task-board/components/GoalFindingsTable.d.ts +43 -0
- package/dist/task-board/components/GoalFindingsTable.js +160 -0
- package/dist/task-board/components/GoalFindingsTable.js.map +1 -0
- package/dist/task-board/components/GoalsMatrix.js +33 -6
- package/dist/task-board/components/GoalsMatrix.js.map +1 -1
- package/dist/task-board/components/IssuePanel.d.ts +31 -0
- package/dist/task-board/components/IssuePanel.js +268 -0
- package/dist/task-board/components/IssuePanel.js.map +1 -0
- package/dist/task-board/components/ProjectGoalsPanel.js +66 -13
- package/dist/task-board/components/ProjectGoalsPanel.js.map +1 -1
- package/dist/task-board/components/SubgoalFindings.d.ts +40 -0
- package/dist/task-board/components/SubgoalFindings.js +88 -0
- package/dist/task-board/components/SubgoalFindings.js.map +1 -0
- package/dist/task-board/components/TaskAgentPanel.d.ts +2 -0
- package/dist/task-board/components/TaskAgentPanel.js +5 -4
- package/dist/task-board/components/TaskAgentPanel.js.map +1 -1
- package/dist/task-board/components/TaskDetailPanel.js +8 -12
- package/dist/task-board/components/TaskDetailPanel.js.map +1 -1
- package/dist/task-board/components/WizardCommunicationCenter.d.ts +2 -0
- package/dist/task-board/components/WizardCommunicationCenter.js +5 -3
- package/dist/task-board/components/WizardCommunicationCenter.js.map +1 -1
- package/dist/task-board/components/WizardCommunicationShared.js +2 -1
- package/dist/task-board/components/WizardCommunicationShared.js.map +1 -1
- package/dist/task-board/components/WizardTask.d.ts +2 -0
- package/dist/task-board/components/WizardTask.js +2 -2
- package/dist/task-board/components/WizardTask.js.map +1 -1
- package/dist/task-board/components/WizardTaskDetailsPanel.d.ts +4 -0
- package/dist/task-board/components/WizardTaskDetailsPanel.js +16 -3
- package/dist/task-board/components/WizardTaskDetailsPanel.js.map +1 -1
- package/dist/task-board/services/issueService.d.ts +193 -0
- package/dist/task-board/services/issueService.js +97 -0
- package/dist/task-board/services/issueService.js.map +1 -0
- package/dist/task-board/types.d.ts +24 -0
- package/dist/task-board/utils/projectDashboardModel.js +8 -0
- package/dist/task-board/utils/projectDashboardModel.js.map +1 -1
- package/package.json +1 -1
- package/styles.css +57 -3
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
3
|
+
import { ChevronDown, ChevronUp, Replace, Share2, X } from "lucide-react";
|
|
4
|
+
import { toast } from "sonner";
|
|
5
|
+
import { Button } from "../../components/ui/button";
|
|
6
|
+
import { Checkbox } from "../../components/ui/checkbox";
|
|
7
|
+
import { Input } from "../../components/ui/input";
|
|
8
|
+
import { cn } from "../../lib/utils";
|
|
9
|
+
import { SimpleIconButton } from "../ui/SimpleIconButton";
|
|
10
|
+
import { collectFindReplaceMatches, toBridgeTextRange, } from "./findReplaceMatches";
|
|
11
|
+
import { findReplaceStore, useFindReplaceState } from "./findReplaceStore";
|
|
12
|
+
import { collectFindReplaceItemSources, planFindReplace, } from "./findReplaceTargets";
|
|
13
|
+
import { buildFindRegExp, replaceInFieldValue } from "./findReplaceText";
|
|
14
|
+
const EMPTY_ITEMS = [];
|
|
15
|
+
function pluralize(count, singular, plural = `${singular}s`) {
|
|
16
|
+
return `${count} ${count === 1 ? singular : plural}`;
|
|
17
|
+
}
|
|
18
|
+
function sourcesSignature(sources) {
|
|
19
|
+
return sources
|
|
20
|
+
.map((s) => `${s.descriptor.id}|${s.descriptor.language}|${s.descriptor.version}`)
|
|
21
|
+
.join(",");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Content of the "Find and replace" popover: searches every text field of the
|
|
25
|
+
* current item (or of every item on the page), highlights the matches on the
|
|
26
|
+
* canvas through the shared store, steps through them, and replaces one or
|
|
27
|
+
* all of them through the regular field-edit path.
|
|
28
|
+
*/
|
|
29
|
+
export function FindReplacePanel({ editContext, onClose, }) {
|
|
30
|
+
const { initialFind, openRequest } = useFindReplaceState();
|
|
31
|
+
const [find, setFind] = useState(initialFind);
|
|
32
|
+
const [replacement, setReplacement] = useState("");
|
|
33
|
+
const [matchCase, setMatchCase] = useState(false);
|
|
34
|
+
const [wholeWord, setWholeWord] = useState(false);
|
|
35
|
+
const hasPageComponents = !!editContext.page?.rootComponent;
|
|
36
|
+
// On by default. Kept as a plain preference and resolved against the page
|
|
37
|
+
// on every render: the page model can arrive after the panel mounted, and
|
|
38
|
+
// freezing the initial value then left components out of the search.
|
|
39
|
+
const [includeComponents, setIncludeComponents] = useState(true);
|
|
40
|
+
const scope = includeComponents && hasPageComponents ? "page" : "item";
|
|
41
|
+
const [items, setItems] = useState(EMPTY_ITEMS);
|
|
42
|
+
const [loaded, setLoaded] = useState(false);
|
|
43
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
44
|
+
const [applying, setApplying] = useState(false);
|
|
45
|
+
const findRef = useRef(null);
|
|
46
|
+
const canEdit = editContext.mode === "edit";
|
|
47
|
+
// The canvas only scrolls on explicit user actions (typing, stepping,
|
|
48
|
+
// clicking a row, a single Replace). Matches also change on their own when
|
|
49
|
+
// values reload after a save, and those changes must not move the page.
|
|
50
|
+
const [scrollRequest, setScrollRequest] = useState(0);
|
|
51
|
+
const requestScroll = useCallback(() => setScrollRequest((request) => request + 1), []);
|
|
52
|
+
const pendingScrollRef = useRef(false);
|
|
53
|
+
// Ctrl+H while the panel is open re-seeds the search text (from the canvas
|
|
54
|
+
// selection) and puts the caret back into the search box.
|
|
55
|
+
useLayoutEffect(() => {
|
|
56
|
+
if (initialFind) {
|
|
57
|
+
setFind(initialFind);
|
|
58
|
+
requestScroll();
|
|
59
|
+
}
|
|
60
|
+
const timer = window.setTimeout(() => {
|
|
61
|
+
findRef.current?.focus({ preventScroll: true });
|
|
62
|
+
findRef.current?.select();
|
|
63
|
+
}, 0);
|
|
64
|
+
return () => window.clearTimeout(timer);
|
|
65
|
+
}, [openRequest, initialFind, requestScroll]);
|
|
66
|
+
const sources = useMemo(() => collectFindReplaceItemSources({
|
|
67
|
+
page: editContext.page,
|
|
68
|
+
item: editContext.item,
|
|
69
|
+
currentItemDescriptor: editContext.currentItemDescriptor,
|
|
70
|
+
scope,
|
|
71
|
+
}), [
|
|
72
|
+
editContext.page,
|
|
73
|
+
editContext.item,
|
|
74
|
+
editContext.currentItemDescriptor,
|
|
75
|
+
scope,
|
|
76
|
+
]);
|
|
77
|
+
// The page object is replaced on every canvas refresh. Reload only when the
|
|
78
|
+
// set of items actually changed, and keep showing the previous result while
|
|
79
|
+
// the reload runs, so the panel never flashes back to a loading state.
|
|
80
|
+
const signature = sourcesSignature(sources);
|
|
81
|
+
const sourcesRef = useRef(sources);
|
|
82
|
+
sourcesRef.current = sources;
|
|
83
|
+
const [reloadTick, setReloadTick] = useState(0);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
let cancelled = false;
|
|
86
|
+
editContext.itemsRepository
|
|
87
|
+
.getItems(sourcesRef.current.map((source) => source.descriptor))
|
|
88
|
+
.then((loadedItems) => {
|
|
89
|
+
if (cancelled)
|
|
90
|
+
return;
|
|
91
|
+
setItems(loadedItems);
|
|
92
|
+
setLoaded(true);
|
|
93
|
+
// A single Replace asked to follow the next match once the new
|
|
94
|
+
// values are in; do that now, with the fresh match list.
|
|
95
|
+
if (pendingScrollRef.current) {
|
|
96
|
+
pendingScrollRef.current = false;
|
|
97
|
+
requestScroll();
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
.catch((error) => {
|
|
101
|
+
console.error("[FindReplacePanel] Could not load items", error);
|
|
102
|
+
if (!cancelled)
|
|
103
|
+
setLoaded(true);
|
|
104
|
+
});
|
|
105
|
+
return () => {
|
|
106
|
+
cancelled = true;
|
|
107
|
+
};
|
|
108
|
+
}, [editContext.itemsRepository, signature, reloadTick, requestScroll]);
|
|
109
|
+
// Field values change underneath the panel (own replacements, other users,
|
|
110
|
+
// canvas edits): re-read the cached items so counts and highlights follow.
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
let timer;
|
|
113
|
+
const unsubscribe = editContext.itemsRepository.subscribeItemsChanged(() => {
|
|
114
|
+
if (timer !== undefined)
|
|
115
|
+
window.clearTimeout(timer);
|
|
116
|
+
timer = window.setTimeout(() => setReloadTick((tick) => tick + 1), 150);
|
|
117
|
+
});
|
|
118
|
+
return () => {
|
|
119
|
+
unsubscribe();
|
|
120
|
+
if (timer !== undefined)
|
|
121
|
+
window.clearTimeout(timer);
|
|
122
|
+
};
|
|
123
|
+
}, [editContext.itemsRepository]);
|
|
124
|
+
const findRegExp = useMemo(() => buildFindRegExp(find, { matchCase, wholeWord }), [find, matchCase, wholeWord]);
|
|
125
|
+
const plan = useMemo(() => planFindReplace(items, sources, findRegExp), [items, sources, findRegExp]);
|
|
126
|
+
const matches = useMemo(() => collectFindReplaceMatches(plan.targets, findRegExp), [plan.targets, findRegExp]);
|
|
127
|
+
const clampedIndex = matches.length === 0 ? 0 : Math.min(activeIndex, matches.length - 1);
|
|
128
|
+
const activeMatch = matches[clampedIndex];
|
|
129
|
+
// Publish the highlights for the canvas overlay; clear them on close.
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
findReplaceStore.setHighlighting(matches.length > 0 ? { matches, activeIndex: clampedIndex } : null);
|
|
132
|
+
}, [matches, clampedIndex]);
|
|
133
|
+
useEffect(() => () => findReplaceStore.setHighlighting(null), []);
|
|
134
|
+
// Scroll the canvas to the current match, but only when a user action
|
|
135
|
+
// asked for it. The match is read through a ref so the effect depends on
|
|
136
|
+
// the request alone and a reloaded match list never scrolls by itself.
|
|
137
|
+
const activeMatchRef = useRef(activeMatch);
|
|
138
|
+
activeMatchRef.current = activeMatch;
|
|
139
|
+
// The edit context object is replaced whenever the shell consumes the
|
|
140
|
+
// scroll target, so it must not be an effect dependency here: that would
|
|
141
|
+
// re-request the scroll on every consumption and loop forever.
|
|
142
|
+
const editContextRef = useRef(editContext);
|
|
143
|
+
editContextRef.current = editContext;
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
const match = activeMatchRef.current;
|
|
146
|
+
if (scrollRequest === 0 || !match)
|
|
147
|
+
return;
|
|
148
|
+
editContextRef.current.setScrollIntoView({
|
|
149
|
+
kind: "textRange",
|
|
150
|
+
key: match.key,
|
|
151
|
+
textRanges: [toBridgeTextRange(match)],
|
|
152
|
+
fallbackField: match.field,
|
|
153
|
+
fallbackComponentId: match.componentId,
|
|
154
|
+
});
|
|
155
|
+
}, [scrollRequest]);
|
|
156
|
+
const goTo = useCallback((delta) => {
|
|
157
|
+
if (matches.length === 0)
|
|
158
|
+
return;
|
|
159
|
+
setActiveIndex((index) => (Math.min(index, matches.length - 1) + delta + matches.length) %
|
|
160
|
+
matches.length);
|
|
161
|
+
requestScroll();
|
|
162
|
+
}, [matches.length, requestScroll]);
|
|
163
|
+
const targetForMatch = (match) => plan.targets.find((target) => target.field.descriptor.fieldId === match.field.fieldId &&
|
|
164
|
+
target.item.id === match.item.id &&
|
|
165
|
+
target.item.language === match.item.language &&
|
|
166
|
+
target.item.version === match.item.version);
|
|
167
|
+
const saveTarget = async (target, onlyOccurrence, refresh) => {
|
|
168
|
+
if (!findRegExp)
|
|
169
|
+
return 0;
|
|
170
|
+
const result = replaceInFieldValue(target.value, target.field.type, findRegExp, replacement, onlyOccurrence);
|
|
171
|
+
if (result.count === 0 || result.value === target.value)
|
|
172
|
+
return 0;
|
|
173
|
+
await editContext.operations.editField({
|
|
174
|
+
field: target.field.descriptor,
|
|
175
|
+
value: result.value,
|
|
176
|
+
refresh,
|
|
177
|
+
saveMode: "immediate",
|
|
178
|
+
});
|
|
179
|
+
return result.count;
|
|
180
|
+
};
|
|
181
|
+
const replaceCurrent = async () => {
|
|
182
|
+
if (!activeMatch || !canEdit || applying)
|
|
183
|
+
return;
|
|
184
|
+
const target = targetForMatch(activeMatch);
|
|
185
|
+
if (!target)
|
|
186
|
+
return;
|
|
187
|
+
setApplying(true);
|
|
188
|
+
try {
|
|
189
|
+
await saveTarget(target, activeMatch.occurrence, "immediate");
|
|
190
|
+
// The next match slides into the same index once the value reloads;
|
|
191
|
+
// follow it then, not now (the current list still holds the old match).
|
|
192
|
+
setActiveIndex(clampedIndex);
|
|
193
|
+
pendingScrollRef.current = true;
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
console.error("[FindReplacePanel] Could not replace match", error);
|
|
197
|
+
toast.error("The field could not be saved.");
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
setApplying(false);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
const replaceAll = async () => {
|
|
204
|
+
if (!findRegExp || plan.totalMatches === 0 || !canEdit || applying)
|
|
205
|
+
return;
|
|
206
|
+
setApplying(true);
|
|
207
|
+
let replacedMatches = 0;
|
|
208
|
+
let changedFields = 0;
|
|
209
|
+
let failedFields = 0;
|
|
210
|
+
try {
|
|
211
|
+
for (let index = 0; index < plan.targets.length; index += 1) {
|
|
212
|
+
const target = plan.targets[index];
|
|
213
|
+
const isLast = index === plan.targets.length - 1;
|
|
214
|
+
try {
|
|
215
|
+
// Every field is its own undoable operation; one canvas refresh
|
|
216
|
+
// after the last one shows the whole result.
|
|
217
|
+
const count = await saveTarget(target, undefined, isLast ? "immediate" : "none");
|
|
218
|
+
if (count > 0) {
|
|
219
|
+
replacedMatches += count;
|
|
220
|
+
changedFields += 1;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
failedFields += 1;
|
|
225
|
+
console.error("[FindReplacePanel] Could not replace in field", target.field.name, error);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const summary = `Replaced ${pluralize(replacedMatches, "occurrence")} in ${pluralize(changedFields, "field")}.`;
|
|
229
|
+
if (failedFields > 0) {
|
|
230
|
+
toast.error(`${summary} ${pluralize(failedFields, "field")} could not be saved.`);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
toast.success(summary);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
setApplying(false);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
const onFindKeyDown = (event) => {
|
|
241
|
+
if (event.key === "Enter") {
|
|
242
|
+
event.preventDefault();
|
|
243
|
+
goTo(event.shiftKey ? -1 : 1);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const onReplacementKeyDown = (event) => {
|
|
247
|
+
if (event.key === "Enter") {
|
|
248
|
+
event.preventDefault();
|
|
249
|
+
if (event.ctrlKey || event.metaKey)
|
|
250
|
+
void replaceAll();
|
|
251
|
+
else
|
|
252
|
+
void replaceCurrent();
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
const counter = !findRegExp || !loaded
|
|
256
|
+
? ""
|
|
257
|
+
: matches.length === 0
|
|
258
|
+
? "No matches"
|
|
259
|
+
: `${clampedIndex + 1} of ${matches.length}`;
|
|
260
|
+
const skipped = [];
|
|
261
|
+
if (plan.skippedInherited > 0)
|
|
262
|
+
skipped.push(`${pluralize(plan.skippedInherited, "match", "matches")} in inherited values`);
|
|
263
|
+
if (plan.skippedReadOnly > 0)
|
|
264
|
+
skipped.push(`${pluralize(plan.skippedReadOnly, "match", "matches")} in read-only fields`);
|
|
265
|
+
return (_jsxs("div", { className: "flex flex-col", "data-testid": "find-replace-panel", children: [_jsxs("div", { className: "border-border-default flex items-center justify-between gap-2 border-b px-3 py-2", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-1.5", children: [_jsx(Replace, { className: "text-neutral-grey-50 h-3.5 w-3.5 shrink-0", strokeWidth: 1 }), _jsx("span", { className: "text-neutral-grey-100 truncate text-xs font-medium", children: "Find and replace" })] }), _jsx(SimpleIconButton, { icon: _jsx(X, { className: "h-3.5 w-3.5", strokeWidth: 1 }), label: "Close", size: "small", showTooltip: false, onClick: onClose, "data-testid": "find-replace-close" })] }), _jsxs("div", { className: "flex flex-col gap-2 px-3 py-3", children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsxs("div", { className: "relative min-w-0 flex-1", children: [_jsx(Input, { ref: findRef, value: find, onChange: (event) => {
|
|
266
|
+
setFind(event.target.value);
|
|
267
|
+
setActiveIndex(0);
|
|
268
|
+
requestScroll();
|
|
269
|
+
}, onKeyDown: onFindKeyDown, placeholder: "Find", autoComplete: "off", className: "h-8 pr-20 text-sm", "data-testid": "find-replace-find" }), counter && (_jsx("span", { className: "text-neutral-grey-50 pointer-events-none absolute inset-y-0 right-2 flex items-center text-[11px] tabular-nums", "data-testid": "find-replace-counter", children: counter }))] }), _jsx(SimpleIconButton, { icon: _jsx(ChevronUp, { className: "h-4 w-4", strokeWidth: 1 }), label: "Previous match (Shift+Enter)", size: "small", disabled: matches.length === 0, onClick: () => goTo(-1), "data-testid": "find-replace-previous" }), _jsx(SimpleIconButton, { icon: _jsx(ChevronDown, { className: "h-4 w-4", strokeWidth: 1 }), label: "Next match (Enter)", size: "small", disabled: matches.length === 0, onClick: () => goTo(1), "data-testid": "find-replace-next" })] }), _jsx(Input, { value: replacement, onChange: (event) => setReplacement(event.target.value), onKeyDown: onReplacementKeyDown, placeholder: "Replace with", autoComplete: "off", className: "h-8 text-sm", "data-testid": "find-replace-replacement" }), _jsxs("div", { className: "flex flex-wrap items-center gap-x-4 gap-y-1 text-xs", children: [_jsxs("label", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Checkbox, { checked: matchCase, onCheckedChange: (checked) => {
|
|
270
|
+
setMatchCase(!!checked);
|
|
271
|
+
setActiveIndex(0);
|
|
272
|
+
requestScroll();
|
|
273
|
+
}, "data-testid": "find-replace-match-case" }), "Match case"] }), _jsxs("label", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Checkbox, { checked: wholeWord, onCheckedChange: (checked) => {
|
|
274
|
+
setWholeWord(!!checked);
|
|
275
|
+
setActiveIndex(0);
|
|
276
|
+
requestScroll();
|
|
277
|
+
}, "data-testid": "find-replace-whole-word" }), "Whole word"] }), hasPageComponents && (_jsxs("label", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Checkbox, { checked: includeComponents, onCheckedChange: (checked) => {
|
|
278
|
+
setIncludeComponents(!!checked);
|
|
279
|
+
setActiveIndex(0);
|
|
280
|
+
requestScroll();
|
|
281
|
+
}, "data-testid": "find-replace-include-components" }), "Include components"] }))] }), _jsxs("div", { className: "text-neutral-grey-50 text-[11px]", "data-testid": "find-replace-summary", children: [!findRegExp
|
|
282
|
+
? "Type to search every text field on this page."
|
|
283
|
+
: !loaded
|
|
284
|
+
? "Loading fields…"
|
|
285
|
+
: plan.totalMatches === 0
|
|
286
|
+
? "No matches."
|
|
287
|
+
: `${pluralize(plan.totalMatches, "match", "matches")} in ${pluralize(plan.targets.length, "field")}`, skipped.length > 0 && _jsxs("span", { children: [" \u00B7 Skipped ", skipped.join(", "), "."] })] }), plan.targets.length > 0 && (_jsx("ul", { className: "divide-border-default border-border-default max-h-40 divide-y overflow-y-auto rounded border text-xs", "data-testid": "find-replace-matches", children: plan.targets.map((target) => {
|
|
288
|
+
const firstIndex = matches.findIndex((match) => match.field.fieldId === target.field.descriptor.fieldId &&
|
|
289
|
+
match.item.id === target.item.id);
|
|
290
|
+
const isActive = activeMatch !== undefined &&
|
|
291
|
+
activeMatch.field.fieldId === target.field.descriptor.fieldId &&
|
|
292
|
+
activeMatch.item.id === target.item.id;
|
|
293
|
+
return (_jsx("li", { children: _jsxs("button", { type: "button", className: cn("hover:bg-neutral-grey-5 flex w-full items-center gap-2 px-2 py-1.5 text-left", isActive && "bg-neutral-grey-5"), onClick: () => {
|
|
294
|
+
if (firstIndex < 0)
|
|
295
|
+
return;
|
|
296
|
+
setActiveIndex(firstIndex);
|
|
297
|
+
requestScroll();
|
|
298
|
+
}, "data-testid": "find-replace-match", "data-field-name": target.field.name, children: [_jsx("span", { className: "truncate font-medium", children: target.field.displayName || target.field.name }), _jsx("span", { className: "text-neutral-grey-50 truncate", children: [
|
|
299
|
+
!target.source.isMainItem &&
|
|
300
|
+
target.source.componentName,
|
|
301
|
+
target.item.displayName || target.item.name,
|
|
302
|
+
]
|
|
303
|
+
.filter((part, index, parts) => !!part && parts.indexOf(part) === index)
|
|
304
|
+
.join(" · ") }), target.source.isShared && (_jsx("span", { className: "text-neutral-grey-50 flex shrink-0 items-center gap-1", title: "Shared content: the change affects every page that renders this component", children: _jsx(Share2, { className: "size-3", strokeWidth: 1.5 }) })), _jsx("span", { className: "text-neutral-grey-50 ml-auto shrink-0 tabular-nums", children: target.count })] }) }, `${target.item.id}|${target.item.language}|${target.item.version}|${target.field.id}`));
|
|
305
|
+
}) }))] }), _jsxs("div", { className: "border-border-default flex items-center justify-end gap-2 border-t px-3 py-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "xs", disabled: !activeMatch || !canEdit || applying, onClick: () => void replaceCurrent(), "data-testid": "find-replace-replace", children: "Replace" }), _jsx(Button, { type: "button", size: "xs", disabled: plan.totalMatches === 0 || !canEdit || applying, onClick: () => void replaceAll(), "data-testid": "find-replace-replace-all", children: applying
|
|
306
|
+
? "Replacing…"
|
|
307
|
+
: plan.totalMatches > 0
|
|
308
|
+
? `Replace all (${plan.totalMatches})`
|
|
309
|
+
: "Replace all" })] })] }));
|
|
310
|
+
}
|
|
311
|
+
//# sourceMappingURL=FindReplacePanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FindReplacePanel.js","sourceRoot":"","sources":["../../../src/editor/find-replace/FindReplacePanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CommandData, KeyboardCommand } from "../commands/commands";
|
|
2
|
+
/**
|
|
3
|
+
* Ctrl+H opens the "Find and replace" popover in the toolbar (see
|
|
4
|
+
* menubar/toolbar-sections/FindReplaceControls). The binding is allowed
|
|
5
|
+
* while typing because that is where the shortcut is usually pressed, and it
|
|
6
|
+
* must cancel the browser's own Ctrl+H (history).
|
|
7
|
+
*/
|
|
8
|
+
export declare const findReplaceCommand: KeyboardCommand<CommandData>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Replace } from "lucide-react";
|
|
3
|
+
import { findReplaceStore } from "./findReplaceStore";
|
|
4
|
+
/**
|
|
5
|
+
* Ctrl+H opens the "Find and replace" popover in the toolbar (see
|
|
6
|
+
* menubar/toolbar-sections/FindReplaceControls). The binding is allowed
|
|
7
|
+
* while typing because that is where the shortcut is usually pressed, and it
|
|
8
|
+
* must cancel the browser's own Ctrl+H (history).
|
|
9
|
+
*/
|
|
10
|
+
export const findReplaceCommand = {
|
|
11
|
+
id: "findReplace",
|
|
12
|
+
label: "Find and replace",
|
|
13
|
+
icon: _jsx(Replace, { strokeWidth: 1 }),
|
|
14
|
+
keyBinding: { key: "h", ctrlOrMeta: true },
|
|
15
|
+
allowWhileTyping: true,
|
|
16
|
+
disabled: (context) => context.editContext.mode !== "edit" ||
|
|
17
|
+
(!context.editContext.page &&
|
|
18
|
+
!context.editContext.item &&
|
|
19
|
+
!context.editContext.currentItemDescriptor),
|
|
20
|
+
execute: async (context) => {
|
|
21
|
+
const selectedText = context.editContext.selectedRange?.text?.trim();
|
|
22
|
+
findReplaceStore.open(selectedText && !selectedText.includes("\n") ? selectedText : undefined);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=findReplaceCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findReplaceCommand.js","sourceRoot":"","sources":["../../../src/editor/find-replace/findReplaceCommand.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAOvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAiC;IAC9D,EAAE,EAAE,aAAa;IACjB,KAAK,EAAE,kBAAkB;IACzB,IAAI,EAAE,KAAC,OAAO,IAAC,WAAW,EAAE,CAAC,GAAI;IACjC,UAAU,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE;IAC1C,gBAAgB,EAAE,IAAI;IACtB,QAAQ,EAAE,CAAC,OAAoC,EAAE,EAAE,CACjD,OAAO,CAAC,WAAW,CAAC,IAAI,KAAK,MAAM;QACnC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI;YACxB,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI;YACzB,CAAC,OAAO,CAAC,WAAW,CAAC,qBAAqB,CAAC;IAC/C,OAAO,EAAE,KAAK,EAAE,OAAoC,EAAE,EAAE;QACtD,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACrE,gBAAgB,CAAC,IAAI,CACnB,YAAY,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CACxE,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { FieldDescriptor, ItemDescriptor } from "../pageModel";
|
|
2
|
+
import type { FindReplaceFieldTarget } from "./findReplaceTargets";
|
|
3
|
+
/**
|
|
4
|
+
* Entry in the bridge geometry union. The editing host keeps the latest text
|
|
5
|
+
* ranges per source, so this name must stay unique among overlay features.
|
|
6
|
+
*/
|
|
7
|
+
export declare const FIND_REPLACE_BRIDGE_SOURCE = "find-replace";
|
|
8
|
+
export declare function getFindReplaceTextRangeKey(targetKey: string, matchIndex: number): string;
|
|
9
|
+
/** One occurrence of the search text, addressed in rendered-text offsets. */
|
|
10
|
+
export type FindReplaceMatch = {
|
|
11
|
+
/** Bridge text-range key; unique per match. */
|
|
12
|
+
key: string;
|
|
13
|
+
/** `fieldKey(field)`: groups matches by field. */
|
|
14
|
+
targetKey: string;
|
|
15
|
+
field: FieldDescriptor;
|
|
16
|
+
item: ItemDescriptor;
|
|
17
|
+
/** Component that renders the field on the canvas, when known. */
|
|
18
|
+
componentId?: string;
|
|
19
|
+
/** Index of this match within its field (0-based). */
|
|
20
|
+
occurrence: number;
|
|
21
|
+
/** Offsets into the rendered plain text of the field (tags stripped). */
|
|
22
|
+
start: number;
|
|
23
|
+
end: number;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Turns an HTML value into the plain text the canvas renders, which is the
|
|
27
|
+
* offset space the bridge measures text ranges in (`element.textContent`).
|
|
28
|
+
* Falls back to a tag strip where DOMParser is unavailable (tests).
|
|
29
|
+
*/
|
|
30
|
+
export declare function toRenderedText(value: string, fieldType: string | undefined): string;
|
|
31
|
+
/**
|
|
32
|
+
* Lists every match of `find` inside the planned targets, in target order,
|
|
33
|
+
* as rendered-text ranges the canvas overlay can highlight and scroll to.
|
|
34
|
+
*/
|
|
35
|
+
export declare function collectFindReplaceMatches(targets: FindReplaceFieldTarget[], find: RegExp | undefined): FindReplaceMatch[];
|
|
36
|
+
export declare function toBridgeTextRange(match: FindReplaceMatch): {
|
|
37
|
+
key: string;
|
|
38
|
+
fieldId: string;
|
|
39
|
+
item: ItemDescriptor;
|
|
40
|
+
start: number;
|
|
41
|
+
end: number;
|
|
42
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { fieldKey } from "../version-diff/versionDiffTargets";
|
|
2
|
+
import { isHtmlFieldType } from "./findReplaceText";
|
|
3
|
+
/**
|
|
4
|
+
* Entry in the bridge geometry union. The editing host keeps the latest text
|
|
5
|
+
* ranges per source, so this name must stay unique among overlay features.
|
|
6
|
+
*/
|
|
7
|
+
export const FIND_REPLACE_BRIDGE_SOURCE = "find-replace";
|
|
8
|
+
export function getFindReplaceTextRangeKey(targetKey, matchIndex) {
|
|
9
|
+
return `find-replace:${targetKey}:m${matchIndex}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Turns an HTML value into the plain text the canvas renders, which is the
|
|
13
|
+
* offset space the bridge measures text ranges in (`element.textContent`).
|
|
14
|
+
* Falls back to a tag strip where DOMParser is unavailable (tests).
|
|
15
|
+
*/
|
|
16
|
+
export function toRenderedText(value, fieldType) {
|
|
17
|
+
if (!isHtmlFieldType(fieldType) || !value.includes("<"))
|
|
18
|
+
return value;
|
|
19
|
+
if (typeof DOMParser === "undefined")
|
|
20
|
+
return value.replace(/<[^>]*>/g, "");
|
|
21
|
+
return (new DOMParser().parseFromString(value, "text/html").body.textContent ?? "");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Lists every match of `find` inside the planned targets, in target order,
|
|
25
|
+
* as rendered-text ranges the canvas overlay can highlight and scroll to.
|
|
26
|
+
*/
|
|
27
|
+
export function collectFindReplaceMatches(targets, find) {
|
|
28
|
+
if (!find)
|
|
29
|
+
return [];
|
|
30
|
+
const matches = [];
|
|
31
|
+
targets.forEach((target) => {
|
|
32
|
+
const text = toRenderedText(target.value, target.field.type);
|
|
33
|
+
const targetKey = fieldKey(target.field.descriptor);
|
|
34
|
+
find.lastIndex = 0;
|
|
35
|
+
let occurrence = 0;
|
|
36
|
+
for (const match of text.matchAll(find)) {
|
|
37
|
+
const start = match.index ?? 0;
|
|
38
|
+
const end = start + match[0].length;
|
|
39
|
+
if (end <= start)
|
|
40
|
+
continue;
|
|
41
|
+
matches.push({
|
|
42
|
+
key: getFindReplaceTextRangeKey(targetKey, occurrence),
|
|
43
|
+
targetKey,
|
|
44
|
+
field: target.field.descriptor,
|
|
45
|
+
item: target.field.descriptor.item,
|
|
46
|
+
componentId: target.source.componentId,
|
|
47
|
+
occurrence,
|
|
48
|
+
start,
|
|
49
|
+
end,
|
|
50
|
+
});
|
|
51
|
+
occurrence += 1;
|
|
52
|
+
}
|
|
53
|
+
find.lastIndex = 0;
|
|
54
|
+
});
|
|
55
|
+
return matches;
|
|
56
|
+
}
|
|
57
|
+
export function toBridgeTextRange(match) {
|
|
58
|
+
return {
|
|
59
|
+
key: match.key,
|
|
60
|
+
fieldId: match.field.fieldId,
|
|
61
|
+
item: match.item,
|
|
62
|
+
start: match.start,
|
|
63
|
+
end: match.end,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=findReplaceMatches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findReplaceMatches.js","sourceRoot":"","sources":["../../../src/editor/find-replace/findReplaceMatches.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,cAAc,CAAC;AAEzD,MAAM,UAAU,0BAA0B,CACxC,SAAiB,EACjB,UAAkB;IAElB,OAAO,gBAAgB,SAAS,KAAK,UAAU,EAAE,CAAC;AACpD,CAAC;AAmBD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,SAA6B;IACzE,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACtE,IAAI,OAAO,SAAS,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3E,OAAO,CACL,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAC3E,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAAiC,EACjC,IAAwB;IAExB,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QACzB,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7D,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACnB,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;YAC/B,MAAM,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACpC,IAAI,GAAG,IAAI,KAAK;gBAAE,SAAS;YAC3B,OAAO,CAAC,IAAI,CAAC;gBACX,GAAG,EAAE,0BAA0B,CAAC,SAAS,EAAE,UAAU,CAAC;gBACtD,SAAS;gBACT,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU;gBAC9B,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI;gBAClC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW;gBACtC,UAAU;gBACV,KAAK;gBACL,GAAG;aACJ,CAAC,CAAC;YACH,UAAU,IAAI,CAAC,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAuB;IACvD,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO;QAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,GAAG,EAAE,KAAK,CAAC,GAAG;KACf,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { FindReplaceMatch } from "./findReplaceMatches";
|
|
2
|
+
/** What the canvas overlay paints: every match, and which one is current. */
|
|
3
|
+
export type FindReplaceHighlighting = {
|
|
4
|
+
matches: FindReplaceMatch[];
|
|
5
|
+
activeIndex: number;
|
|
6
|
+
};
|
|
7
|
+
export type FindReplaceState = {
|
|
8
|
+
open: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Search text to seed the panel with; bumped `openRequest` tells the panel a
|
|
11
|
+
* fresh open happened (so Ctrl+H re-focuses the search box even when the
|
|
12
|
+
* panel was already open).
|
|
13
|
+
*/
|
|
14
|
+
initialFind: string;
|
|
15
|
+
openRequest: number;
|
|
16
|
+
highlighting: FindReplaceHighlighting | null;
|
|
17
|
+
};
|
|
18
|
+
type Listener = () => void;
|
|
19
|
+
export declare const findReplaceStore: {
|
|
20
|
+
getState: () => FindReplaceState;
|
|
21
|
+
subscribe: (listener: Listener) => () => void;
|
|
22
|
+
open: (initialFind?: string) => void;
|
|
23
|
+
close: () => void;
|
|
24
|
+
toggle: (initialFind?: string) => void;
|
|
25
|
+
setHighlighting: (highlighting: FindReplaceHighlighting | null) => void;
|
|
26
|
+
/** Test seam: reset to the initial state. */
|
|
27
|
+
reset: () => void;
|
|
28
|
+
};
|
|
29
|
+
export declare function useFindReplaceState(): FindReplaceState;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Tiny external store shared by the toolbar button (which owns the popover),
|
|
4
|
+
* the Ctrl+H command and the canvas highlight overlay. They sit far apart in
|
|
5
|
+
* the tree, and none of this state belongs in the persisted edit context.
|
|
6
|
+
*/
|
|
7
|
+
function createFindReplaceStore() {
|
|
8
|
+
let state = {
|
|
9
|
+
open: false,
|
|
10
|
+
initialFind: "",
|
|
11
|
+
openRequest: 0,
|
|
12
|
+
highlighting: null,
|
|
13
|
+
};
|
|
14
|
+
const listeners = new Set();
|
|
15
|
+
const setState = (patch) => {
|
|
16
|
+
state = { ...state, ...patch };
|
|
17
|
+
listeners.forEach((listener) => listener());
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
getState: () => state,
|
|
21
|
+
subscribe: (listener) => {
|
|
22
|
+
listeners.add(listener);
|
|
23
|
+
return () => {
|
|
24
|
+
listeners.delete(listener);
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
open: (initialFind) => setState({
|
|
28
|
+
open: true,
|
|
29
|
+
initialFind: initialFind ?? state.initialFind,
|
|
30
|
+
openRequest: state.openRequest + 1,
|
|
31
|
+
}),
|
|
32
|
+
close: () => setState({ open: false, highlighting: null }),
|
|
33
|
+
toggle: (initialFind) => {
|
|
34
|
+
if (state.open)
|
|
35
|
+
setState({ open: false, highlighting: null });
|
|
36
|
+
else
|
|
37
|
+
setState({
|
|
38
|
+
open: true,
|
|
39
|
+
initialFind: initialFind ?? state.initialFind,
|
|
40
|
+
openRequest: state.openRequest + 1,
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
setHighlighting: (highlighting) => {
|
|
44
|
+
if (highlighting === state.highlighting)
|
|
45
|
+
return;
|
|
46
|
+
setState({ highlighting });
|
|
47
|
+
},
|
|
48
|
+
/** Test seam: reset to the initial state. */
|
|
49
|
+
reset: () => setState({
|
|
50
|
+
open: false,
|
|
51
|
+
initialFind: "",
|
|
52
|
+
openRequest: 0,
|
|
53
|
+
highlighting: null,
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export const findReplaceStore = createFindReplaceStore();
|
|
58
|
+
export function useFindReplaceState() {
|
|
59
|
+
return useSyncExternalStore(findReplaceStore.subscribe, findReplaceStore.getState, findReplaceStore.getState);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=findReplaceStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findReplaceStore.js","sourceRoot":"","sources":["../../../src/editor/find-replace/findReplaceStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAwB7C;;;;GAIG;AACH,SAAS,sBAAsB;IAC7B,IAAI,KAAK,GAAqB;QAC5B,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,IAAI;KACnB,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,GAAG,EAAY,CAAC;IAEtC,MAAM,QAAQ,GAAG,CAAC,KAAgC,EAAE,EAAE;QACpD,KAAK,GAAG,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;QAC/B,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK;QACrB,SAAS,EAAE,CAAC,QAAkB,EAAE,EAAE;YAChC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,GAAG,EAAE;gBACV,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC,CAAC;QACJ,CAAC;QACD,IAAI,EAAE,CAAC,WAAoB,EAAE,EAAE,CAC7B,QAAQ,CAAC;YACP,IAAI,EAAE,IAAI;YACV,WAAW,EAAE,WAAW,IAAI,KAAK,CAAC,WAAW;YAC7C,WAAW,EAAE,KAAK,CAAC,WAAW,GAAG,CAAC;SACnC,CAAC;QACJ,KAAK,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QAC1D,MAAM,EAAE,CAAC,WAAoB,EAAE,EAAE;YAC/B,IAAI,KAAK,CAAC,IAAI;gBAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;;gBAE5D,QAAQ,CAAC;oBACP,IAAI,EAAE,IAAI;oBACV,WAAW,EAAE,WAAW,IAAI,KAAK,CAAC,WAAW;oBAC7C,WAAW,EAAE,KAAK,CAAC,WAAW,GAAG,CAAC;iBACnC,CAAC,CAAC;QACP,CAAC;QACD,eAAe,EAAE,CAAC,YAA4C,EAAE,EAAE;YAChE,IAAI,YAAY,KAAK,KAAK,CAAC,YAAY;gBAAE,OAAO;YAChD,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC;QAC7B,CAAC;QACD,6CAA6C;QAC7C,KAAK,EAAE,GAAG,EAAE,CACV,QAAQ,CAAC;YACP,IAAI,EAAE,KAAK;YACX,WAAW,EAAE,EAAE;YACf,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,IAAI;SACnB,CAAC;KACL,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,EAAE,CAAC;AAEzD,MAAM,UAAU,mBAAmB;IACjC,OAAO,oBAAoB,CACzB,gBAAgB,CAAC,SAAS,EAC1B,gBAAgB,CAAC,QAAQ,EACzB,gBAAgB,CAAC,QAAQ,CAC1B,CAAC;AACJ,CAAC"}
|