@parhelia/localization 0.1.12902 → 0.1.12904

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 (73) hide show
  1. package/dist/LocalizeItemCommand.d.ts.map +1 -1
  2. package/dist/LocalizeItemCommand.js +2 -4
  3. package/dist/LocalizeItemDialog.d.ts.map +1 -1
  4. package/dist/LocalizeItemDialog.js +35 -97
  5. package/dist/LocalizeItemUtils.d.ts +2 -1
  6. package/dist/LocalizeItemUtils.d.ts.map +1 -1
  7. package/dist/LocalizeItemUtils.js +36 -78
  8. package/dist/api/discovery.d.ts +0 -25
  9. package/dist/api/discovery.d.ts.map +1 -1
  10. package/dist/api/discovery.js +2 -106
  11. package/dist/constants.d.ts +15 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/constants.js +21 -0
  14. package/dist/hooks/useTranslationWizard.d.ts.map +1 -1
  15. package/dist/hooks/useTranslationWizard.js +3 -3
  16. package/dist/index.d.ts +11 -10
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +32 -36
  19. package/dist/services/translationService.d.ts +10 -41
  20. package/dist/services/translationService.d.ts.map +1 -1
  21. package/dist/services/translationService.js +6 -48
  22. package/dist/settings/TranslationServicesPanel.d.ts.map +1 -1
  23. package/dist/settings/TranslationServicesPanel.js +36 -21
  24. package/dist/setup/LocalizationSetupStep.d.ts.map +1 -1
  25. package/dist/setup/LocalizationSetupStep.js +18 -29
  26. package/dist/sidebar/TranslationSidebar.d.ts.map +1 -1
  27. package/dist/sidebar/TranslationSidebar.js +10 -20
  28. package/dist/steps/MetadataInputStep.d.ts +4 -0
  29. package/dist/steps/MetadataInputStep.d.ts.map +1 -0
  30. package/dist/steps/MetadataInputStep.js +41 -0
  31. package/dist/steps/PromptCustomizationStep.d.ts +1 -1
  32. package/dist/steps/PromptCustomizationStep.d.ts.map +1 -1
  33. package/dist/steps/PromptCustomizationStep.js +56 -159
  34. package/dist/steps/ServiceLanguageSelectionStep.d.ts +1 -6
  35. package/dist/steps/ServiceLanguageSelectionStep.d.ts.map +1 -1
  36. package/dist/steps/ServiceLanguageSelectionStep.js +163 -56
  37. package/dist/steps/SubitemDiscoveryStep.d.ts +3 -0
  38. package/dist/steps/SubitemDiscoveryStep.d.ts.map +1 -0
  39. package/dist/steps/SubitemDiscoveryStep.js +313 -0
  40. package/dist/steps/index.d.ts +5 -0
  41. package/dist/steps/index.d.ts.map +1 -0
  42. package/dist/steps/index.js +4 -0
  43. package/dist/steps/types.d.ts +1 -17
  44. package/dist/steps/types.d.ts.map +1 -1
  45. package/dist/translation-center/BatchTranslationView.d.ts +8 -0
  46. package/dist/translation-center/BatchTranslationView.d.ts.map +1 -0
  47. package/dist/translation-center/BatchTranslationView.js +870 -0
  48. package/dist/translation-center/RecentTranslations.d.ts +2 -0
  49. package/dist/translation-center/RecentTranslations.d.ts.map +1 -0
  50. package/dist/translation-center/RecentTranslations.js +309 -0
  51. package/dist/translation-center/TranslationManagement.d.ts.map +1 -1
  52. package/dist/translation-center/TranslationManagement.js +15 -25
  53. package/dist/types.d.ts +0 -1
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/utils/createVersions.d.ts +14 -0
  56. package/dist/utils/createVersions.d.ts.map +1 -0
  57. package/dist/utils/createVersions.js +26 -0
  58. package/package.json +1 -1
  59. package/dist/steps/ItemSelectionStep.d.ts +0 -3
  60. package/dist/steps/ItemSelectionStep.d.ts.map +0 -1
  61. package/dist/steps/ItemSelectionStep.js +0 -24
  62. package/dist/steps/ItemSelectionTree.d.ts +0 -13
  63. package/dist/steps/ItemSelectionTree.d.ts.map +0 -1
  64. package/dist/steps/ItemSelectionTree.js +0 -327
  65. package/dist/steps/WizardStepShell.d.ts +0 -17
  66. package/dist/steps/WizardStepShell.d.ts.map +0 -1
  67. package/dist/steps/WizardStepShell.js +0 -11
  68. package/dist/translation-center/TranslationBatches.d.ts +0 -2
  69. package/dist/translation-center/TranslationBatches.d.ts.map +0 -1
  70. package/dist/translation-center/TranslationBatches.js +0 -1160
  71. package/dist/translation-center/TranslationsTitlebar.d.ts +0 -6
  72. package/dist/translation-center/TranslationsTitlebar.d.ts.map +0 -1
  73. package/dist/translation-center/TranslationsTitlebar.js +0 -16
@@ -1,77 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
- import { Input, Select, Spinner, Textarea } from "@parhelia/core";
4
- import { WizardStepShell } from "./WizardStepShell";
5
- import { suggestBatchName } from "../api/discovery";
6
- export function PromptCustomizationStep({ isActive = true, data, setData, onStepCompleted, editContext, }) {
2
+ import { useState, useEffect, useMemo, useRef, useCallback } from "react";
3
+ export function PromptCustomizationStep({ stepIndex, isActive = true, data, setData, onStepCompleted, editContext, }) {
7
4
  const [customPrompt, setCustomPrompt] = useState("");
8
5
  const [customizationType, setCustomizationType] = useState("extend");
9
- // Local mirror of the wizard's batch name so typing is responsive.
10
- const [batchName, setBatchName] = useState(data.batchName ?? "");
11
- const [isSuggesting, setIsSuggesting] = useState(false);
12
- // Whether the user has manually edited the name. If so, we never overwrite
13
- // it with a fresh AI suggestion.
14
- const userTouchedNameRef = useRef(!!data.batchName);
15
- const dataRef = useRef(data);
16
- useEffect(() => {
17
- dataRef.current = data;
18
- }, [data]);
19
- // Push name changes back into wizard data (debounced via simple equality).
20
- useEffect(() => {
21
- if ((dataRef.current.batchName ?? "") === batchName)
22
- return;
23
- setData({ ...dataRef.current, batchName });
24
- }, [batchName, setData]);
25
- // Auto-suggest a name when the step becomes active and the user hasn't
26
- // already provided/edited one. Fires once per item+language combination so
27
- // navigating away and back doesn't re-fetch.
28
- const lastSuggestionKeyRef = useRef("");
29
- const sessionId = editContext?.sessionId;
30
- useEffect(() => {
31
- if (!isActive)
32
- return;
33
- if (userTouchedNameRef.current)
34
- return;
35
- const itemIds = (data.selectionTreeItems && data.selectionTreeItems.length > 0
36
- ? data.selectionTreeItems.map((s) => s.descriptor.id)
37
- : data.items.map((i) => i.descriptor.id)).filter(Boolean);
38
- const langs = [...data.targetLanguages].sort();
39
- if (itemIds.length === 0 || langs.length === 0)
40
- return;
41
- const key = JSON.stringify({ itemIds: [...itemIds].sort(), langs });
42
- if (lastSuggestionKeyRef.current === key)
43
- return;
44
- lastSuggestionKeyRef.current = key;
45
- let cancelled = false;
46
- setIsSuggesting(true);
47
- void (async () => {
48
- try {
49
- const includeSubitems = !!data.selectionTreeItems?.some((s) => s.includeSubitems);
50
- const name = await suggestBatchName({ itemIds, targetLanguages: langs, includeSubitems }, sessionId);
51
- if (cancelled || userTouchedNameRef.current)
52
- return;
53
- if (name)
54
- setBatchName(name);
55
- }
56
- finally {
57
- if (!cancelled)
58
- setIsSuggesting(false);
59
- }
60
- })();
61
- return () => {
62
- cancelled = true;
63
- };
64
- }, [
65
- isActive,
66
- sessionId,
67
- data.selectionTreeItems,
68
- data.items,
69
- data.targetLanguages,
70
- ]);
6
+ // Use refs to track current values without triggering re-renders
71
7
  const customPromptRef = useRef(customPrompt);
72
8
  const customizationTypeRef = useRef(customizationType);
9
+ // Track if we've initialized from parent data to prevent re-initialization during typing
73
10
  const hasInitializedRef = useRef(false);
74
11
  const lastProviderRef = useRef(data.translationProvider);
12
+ // Debounce timer ref for parent updates
75
13
  const updateTimerRef = useRef(null);
76
14
  useEffect(() => {
77
15
  customPromptRef.current = customPrompt;
@@ -79,32 +17,36 @@ export function PromptCustomizationStep({ isActive = true, data, setData, onStep
79
17
  useEffect(() => {
80
18
  customizationTypeRef.current = customizationType;
81
19
  }, [customizationType]);
82
- const selectedProvider = useMemo(() => data.translationProviders.find((p) => p.name === data.translationProvider), [data.translationProviders, data.translationProvider]);
20
+ // Get service-specific custom data for the selected provider
83
21
  const serviceData = useMemo(() => {
84
22
  if (!data.serviceCustomData || !data.translationProvider)
85
23
  return null;
86
24
  return data.serviceCustomData.get(data.translationProvider);
87
25
  }, [data.serviceCustomData, data.translationProvider]);
88
26
  const enableCustomPrompt = serviceData?.enableCustomPrompt === true;
89
- const supportsPromptCustomization = data.translationProvider === "AI";
27
+ // Get default prompt from provider settings (no fallback)
90
28
  const defaultPrompt = useMemo(() => {
91
- const prompt = selectedProvider?.defaultPrompt;
29
+ const provider = data.translationProviders.find(p => p.name === data.translationProvider);
30
+ const prompt = provider?.defaultPrompt;
31
+ // Return null if prompt is null, undefined, or empty string
92
32
  return prompt && prompt.trim() ? prompt : null;
93
- }, [selectedProvider?.defaultPrompt]);
94
- const hasDefaultPrompt = defaultPrompt != null && defaultPrompt.length > 0;
33
+ }, [data.translationProviders, data.translationProvider]);
34
+ const hasDefaultPrompt = defaultPrompt != null && defaultPrompt.trim().length > 0;
35
+ // Initialize from existing data - only on mount or provider change
95
36
  useEffect(() => {
37
+ // Reset initialization when provider changes
96
38
  if (lastProviderRef.current !== data.translationProvider) {
97
39
  hasInitializedRef.current = false;
98
40
  lastProviderRef.current = data.translationProvider;
99
41
  }
100
- if (hasInitializedRef.current)
42
+ // Skip if already initialized (prevents re-init during typing)
43
+ if (hasInitializedRef.current) {
101
44
  return;
102
- const nextCustomizationType = serviceData?.promptCustomizationType ||
103
- "extend";
45
+ }
46
+ const nextCustomizationType = serviceData?.promptCustomizationType || "extend";
104
47
  let nextCustomPrompt = serviceData?.customPrompt || "";
105
- if (hasDefaultPrompt &&
106
- nextCustomizationType === "extend" &&
107
- nextCustomPrompt.startsWith(defaultPrompt || "")) {
48
+ // If stored prompt already includes default (legacy), strip it for editing
49
+ if (hasDefaultPrompt && nextCustomizationType === "extend" && nextCustomPrompt.startsWith(defaultPrompt || "")) {
108
50
  nextCustomPrompt = nextCustomPrompt.slice((defaultPrompt || "").length);
109
51
  nextCustomPrompt = nextCustomPrompt.replace(/^\s*\n\s*\n?/, "");
110
52
  }
@@ -118,70 +60,29 @@ export function PromptCustomizationStep({ isActive = true, data, setData, onStep
118
60
  }
119
61
  hasInitializedRef.current = true;
120
62
  }, [
121
- data.translationProvider,
122
- defaultPrompt,
123
63
  enableCustomPrompt,
124
- hasDefaultPrompt,
125
64
  serviceData,
65
+ hasDefaultPrompt,
66
+ defaultPrompt,
67
+ data.translationProvider,
126
68
  ]);
127
- useEffect(() => {
128
- if (!isActive)
129
- return;
130
- onStepCompleted(!!data.translationProvider);
131
- }, [data.translationProvider, isActive, onStepCompleted]);
132
- const handleProviderChange = (e) => {
133
- const newProvider = e.target.value;
134
- const newServiceCustomData = new Map();
135
- data.serviceCustomData?.forEach((value, key) => {
136
- if (key !== "AI" || newProvider === "AI") {
137
- newServiceCustomData.set(key, value);
138
- }
139
- });
140
- const newData = {
141
- ...data,
142
- translationProvider: newProvider,
143
- serviceCustomData: newServiceCustomData,
144
- };
145
- setData(newData);
146
- };
147
- const handleCustomPromptToggle = (enabled) => {
148
- const newServiceCustomData = new Map(data.serviceCustomData || new Map());
149
- if (enabled) {
150
- newServiceCustomData.set(data.translationProvider, {
151
- enableCustomPrompt: true,
152
- customPrompt: "",
153
- promptCustomizationType: "extend",
154
- });
155
- }
156
- else {
157
- newServiceCustomData.delete(data.translationProvider);
158
- }
159
- setData({
160
- ...data,
161
- serviceCustomData: newServiceCustomData,
162
- });
163
- };
69
+ // Preview of final prompt
164
70
  const previewPrompt = useMemo(() => {
165
71
  if (!enableCustomPrompt || !customPrompt.trim()) {
166
72
  return defaultPrompt || "";
167
73
  }
74
+ // If no default prompt, just show custom prompt
168
75
  if (!hasDefaultPrompt) {
169
76
  return customPrompt;
170
77
  }
78
+ // If default prompt exists, show based on customization type
171
79
  if (customizationType === "replace") {
172
80
  return customPrompt;
173
81
  }
174
82
  return `${defaultPrompt}\n\n${customPrompt}`;
175
- }, [
176
- customPrompt,
177
- customizationType,
178
- defaultPrompt,
179
- enableCustomPrompt,
180
- hasDefaultPrompt,
181
- ]);
83
+ }, [enableCustomPrompt, customPrompt, customizationType, defaultPrompt, hasDefaultPrompt]);
84
+ // Debounced update to parent - prevents rapid state updates during typing
182
85
  const updateParentData = useCallback(() => {
183
- if (!data.translationProvider)
184
- return;
185
86
  const trimmedCustomPrompt = customPromptRef.current.trim();
186
87
  const currentCustomizationType = customizationTypeRef.current;
187
88
  const newServiceCustomData = new Map(data.serviceCustomData || new Map());
@@ -194,28 +95,33 @@ export function PromptCustomizationStep({ isActive = true, data, setData, onStep
194
95
  };
195
96
  const isSame = currentServiceData?.enableCustomPrompt === true &&
196
97
  (currentServiceData.customPrompt || "") === trimmedCustomPrompt &&
197
- (currentServiceData.promptCustomizationType || "extend") ===
198
- currentCustomizationType;
199
- if (isSame)
98
+ (currentServiceData.promptCustomizationType || "extend") === currentCustomizationType;
99
+ if (isSame) {
200
100
  return;
101
+ }
201
102
  newServiceCustomData.set(data.translationProvider, nextServiceData);
202
103
  }
203
104
  else {
204
- if (!currentServiceData)
105
+ if (!currentServiceData) {
205
106
  return;
107
+ }
206
108
  newServiceCustomData.delete(data.translationProvider);
207
109
  }
208
- setData({
110
+ const newData = {
209
111
  ...data,
210
112
  serviceCustomData: newServiceCustomData,
211
- });
212
- }, [data, enableCustomPrompt, setData]);
113
+ };
114
+ setData(newData);
115
+ }, [enableCustomPrompt, data, setData]);
116
+ // Update wizard data when settings change - debounced to prevent rapid fire
213
117
  useEffect(() => {
214
- if (!isActive || !supportsPromptCustomization)
118
+ if (!isActive)
215
119
  return;
120
+ // Clear any pending update
216
121
  if (updateTimerRef.current) {
217
122
  clearTimeout(updateTimerRef.current);
218
123
  }
124
+ // Debounce the update to parent (100ms delay)
219
125
  updateTimerRef.current = setTimeout(() => {
220
126
  updateParentData();
221
127
  }, 100);
@@ -225,33 +131,24 @@ export function PromptCustomizationStep({ isActive = true, data, setData, onStep
225
131
  }
226
132
  };
227
133
  }, [
134
+ enableCustomPrompt,
228
135
  customPrompt,
229
136
  customizationType,
230
137
  isActive,
231
- supportsPromptCustomization,
232
138
  updateParentData,
233
139
  ]);
234
- return (_jsx(WizardStepShell, { fillHeight: true, testId: "prompt-customization-step", children: _jsxs("div", { className: "mx-auto flex min-h-0 w-full max-w-3xl flex-1 flex-col gap-6 overflow-y-auto", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: "translation-batch-name", className: "text-[11px] font-bold tracking-wider text-neutral-grey-50 ", children: "Name" }), isSuggesting && (_jsx("div", { role: "status", "aria-label": "Suggesting name", className: "text-muted-foreground flex h-3.5 w-3.5 items-center justify-center", children: _jsx(Spinner, { size: "xs" }) }))] }), _jsx("p", { className: "text-muted-foreground mt-1 text-xs", children: "A short label for this translation batch." }), _jsx(Input, { id: "translation-batch-name", type: "text", value: batchName, placeholder: "Translation batch", onChange: (e) => {
235
- userTouchedNameRef.current = true;
236
- setBatchName(e.target.value);
237
- }, className: "mt-2", "data-testid": "translation-batch-name-input" })] }), _jsxs("div", { children: [_jsx("label", { className: "text-[11px] font-bold tracking-wider text-neutral-grey-50 ", children: "Translation provider" }), _jsx("p", { className: "text-muted-foreground mt-1 text-xs", children: "\"Create Versions\" will create new language versions without automatic translation." }), _jsx(Select, { value: data.translationProvider || "", onValueChange: (value) => handleProviderChange({
238
- target: { value },
239
- }), options: data.translationProviders.map((provider) => ({
240
- value: provider.name,
241
- label: provider.displayName || provider.name,
242
- })), placeholder: "Select a provider\u2026", size: "sm", className: "mt-2 w-full", "data-testid": "translation-provider-select" })] }), supportsPromptCustomization && (_jsxs(_Fragment, { children: [_jsxs("label", { className: "-mb-2 flex cursor-pointer items-start gap-2.5", children: [_jsx("input", { type: "checkbox", checked: enableCustomPrompt, onChange: (e) => handleCustomPromptToggle(e.target.checked), className: "mt-0.5 h-3.5 w-3.5 rounded border-border-default text-[var(--color-highlight-100)] accent-[var(--color-highlight-100)] focus:ring-[var(--color-highlight-100)]", "data-testid": "enable-custom-prompt-checkbox" }), _jsxs("div", { className: "min-w-0", children: [_jsx("span", { className: "block text-[13px] font-medium text-neutral-grey-100", children: "Customize translation prompt" }), _jsx("span", { className: "text-muted-foreground mt-0.5 block text-xs", children: "Override or extend the provider's default instructions." })] })] }), enableCustomPrompt && (_jsxs(_Fragment, { children: [hasDefaultPrompt && (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("span", { className: "text-[11px] font-bold tracking-wider text-neutral-grey-50 ", children: "Default prompt" }), _jsx("pre", { className: "mt-2 max-h-40 overflow-y-auto rounded-md bg-neutral-grey-5/70 p-3 font-mono text-xs leading-relaxed whitespace-pre-wrap text-neutral-grey-100", children: defaultPrompt })] }), _jsxs("div", { children: [_jsx("span", { className: "text-[11px] font-bold tracking-wider text-neutral-grey-50 ", children: "Customization type" }), _jsx("div", { className: "mt-2 grid gap-2 sm:grid-cols-2", children: [
243
- {
244
- value: "extend",
245
- title: "Extend",
246
- hint: "Append to the default prompt.",
247
- },
248
- {
249
- value: "replace",
250
- title: "Replace",
251
- hint: "Use the custom prompt only.",
252
- },
253
- ].map((opt) => {
254
- const selected = customizationType === opt.value;
255
- return (_jsxs("label", { className: `group flex cursor-pointer items-start gap-2.5 rounded-lg p-2.5 transition-colors ${selected ? "bg-primary/5" : "hover:bg-neutral-grey-5"}`, children: [_jsx("input", { type: "radio", name: "customizationType", value: opt.value, checked: selected, onChange: () => setCustomizationType(opt.value), className: "mt-0.5 h-3.5 w-3.5 border-border-default text-[var(--color-highlight-100)] accent-[var(--color-highlight-100)] focus:ring-[var(--color-highlight-100)]", "data-testid": `customization-type-${opt.value}` }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-xs font-medium text-neutral-grey-100", children: opt.title }), _jsx("div", { className: "text-muted-foreground mt-0.5 text-[11px]", children: opt.hint })] })] }, opt.value));
256
- }) })] })] })), _jsxs("div", { children: [_jsx("span", { className: "text-[11px] font-bold tracking-wider text-neutral-grey-50 ", children: "Custom prompt" }), _jsx(Textarea, { value: customPrompt, onChange: (e) => setCustomPrompt(e.target.value), className: "mt-2 font-mono", rows: 6, placeholder: "Enter your custom prompt instructions here\u2026", "data-testid": "custom-prompt-textarea" })] }), hasDefaultPrompt && (_jsxs("div", { children: [_jsx("span", { className: "text-[11px] font-bold tracking-wider text-neutral-grey-50 ", children: "Preview" }), _jsx("pre", { className: "mt-2 max-h-52 overflow-y-auto rounded-md bg-neutral-grey-5/70 p-3 font-mono text-xs leading-relaxed whitespace-pre-wrap text-neutral-grey-100", children: previewPrompt })] }))] }))] }))] }) }));
140
+ // Update completion status
141
+ useEffect(() => {
142
+ if (!isActive)
143
+ return;
144
+ // Step is always complete (it's optional)
145
+ onStepCompleted(true);
146
+ }, [isActive, onStepCompleted]);
147
+ // Skip condition: hide step when checkbox is disabled
148
+ // This is handled by skipCondition in wizard config
149
+ return (_jsxs("div", { className: "p-6 space-y-6 h-full flex flex-col", "data-testid": "prompt-customization-step", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-xl font-semibold text-[var(--color-dark)] mb-2", children: "Customize Translation Prompt" }), _jsxs("p", { className: "text-sm text-[var(--color-gray-2)] mb-6", children: ["Optionally customize the prompt used for translation. This allows you to provide specific instructions or context for the translation service.", _jsx("br", {}), _jsx("span", { className: "text-xs text-[var(--color-gray-2)] mt-1 block", children: "Note: Your custom prompt will be appended to the system instructions that ensure proper translation structure." })] })] }), _jsxs("div", { className: "space-y-6 flex-1", children: [!enableCustomPrompt && (_jsx("div", { className: "border border-[var(--color-gray-3)] rounded-lg p-4 bg-[var(--color-gray-5)]", children: _jsx("p", { className: "text-sm text-[var(--color-gray-2)]", children: "Enable \"Customize translation prompt\" in the previous step to customize the prompt." }) })), enableCustomPrompt && (_jsxs(_Fragment, { children: [hasDefaultPrompt && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "bg-background rounded-lg border border-[var(--color-gray-3)] p-4", children: [_jsx("h3", { className: "text-sm font-medium text-[var(--color-dark)] mb-2", children: "Default Prompt" }), _jsx("div", { className: "border border-[var(--color-gray-3)] rounded-md p-3 bg-[var(--color-gray-5)]", children: _jsx("pre", { className: "text-xs text-[var(--color-gray-1)] whitespace-pre-wrap font-mono", children: defaultPrompt }) })] }), _jsxs("div", { className: "bg-background rounded-lg border border-[var(--color-gray-3)] p-4", children: [_jsx("h3", { className: "text-sm font-medium text-[var(--color-dark)] mb-3", children: "Customization Type" }), _jsxs("div", { className: "space-y-3", children: [_jsxs("label", { className: "flex items-center cursor-pointer py-1.5 px-2 rounded-md hover:bg-[var(--color-gray-5)] transition-colors", children: [_jsx("input", { type: "radio", name: "customizationType", value: "extend", checked: customizationType === "extend", onChange: () => setCustomizationType("extend"), className: "h-4 w-4 text-[#9650fb] focus:ring-[#9650fb] border-[var(--color-gray-3)] accent-[#9650fb]", "data-testid": "customization-type-extend" }), _jsx("span", { className: "ml-2 text-sm text-[var(--color-dark)]", children: "Extend (append to default)" })] }), _jsxs("label", { className: "flex items-center cursor-pointer py-1.5 px-2 rounded-md hover:bg-[var(--color-gray-5)] transition-colors", children: [_jsx("input", { type: "radio", name: "customizationType", value: "replace", checked: customizationType === "replace", onChange: () => setCustomizationType("replace"), className: "h-4 w-4 text-[#9650fb] focus:ring-[#9650fb] border-[var(--color-gray-3)] accent-[#9650fb]", "data-testid": "customization-type-replace" }), _jsx("span", { className: "ml-2 text-sm text-[var(--color-dark)]", children: "Replace (use custom prompt only)" })] })] })] })] })), _jsxs("div", { className: "bg-background rounded-lg border border-[var(--color-gray-3)] p-4", children: [_jsx("h3", { className: "text-sm font-medium text-[var(--color-dark)] mb-2", children: "Custom Prompt" }), _jsx("textarea", { value: customPrompt, onChange: (e) => setCustomPrompt(e.target.value), className: "w-full px-3 py-2.5 border border-[var(--color-gray-3)] rounded-md bg-[var(--color-gray-5)] text-[var(--color-dark)] focus:outline-none focus:ring-2 focus:ring-[#9650fb] focus:border-[#9650fb] text-sm font-mono transition-colors", rows: 6, placeholder: "Enter your custom prompt instructions here...", "data-testid": "custom-prompt-textarea" }), _jsx("p", { className: "text-xs text-[var(--color-gray-2)] mt-2", children: hasDefaultPrompt
150
+ ? customizationType === "extend"
151
+ ? "This will be appended to the default prompt. The final prompt (default + custom) will then be appended to the system instructions on the backend."
152
+ : "This will replace the default prompt. The custom prompt will then be appended to the system instructions on the backend."
153
+ : "Your custom prompt will be appended to the system instructions on the backend." })] }), hasDefaultPrompt && _jsxs("div", { className: "bg-background rounded-lg border border-[var(--color-gray-3)] p-4", children: [_jsx("h3", { className: "text-sm font-medium text-[var(--color-dark)] mb-2", children: "Preview" }), _jsx("div", { className: "border border-[var(--color-gray-3)] rounded-md p-3 bg-[var(--color-gray-5)] max-h-64 overflow-y-auto", children: _jsx("pre", { className: "text-xs text-[var(--color-gray-1)] whitespace-pre-wrap font-mono", children: previewPrompt }) }), _jsx("p", { className: "text-xs text-[var(--color-gray-2)] mt-2", children: "This is how the final prompt will look when sent to the translation service." })] })] }))] })] }));
257
154
  }
@@ -1,8 +1,3 @@
1
1
  import { TranslationStepProps } from "./types";
2
- /**
3
- * Language-only step. Item selection lives in its own step
4
- * (see ItemSelectionStep). The legacy name is kept so existing imports
5
- * keep working.
6
- */
7
- export declare function ServiceLanguageSelectionStep({ isActive, data, setData, onStepCompleted, editContext, }: TranslationStepProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function ServiceLanguageSelectionStep({ stepIndex, isActive, data, setData, onStepCompleted, editContext, setFooterActions, requestClose }: TranslationStepProps): import("react/jsx-runtime").JSX.Element;
8
3
  //# sourceMappingURL=ServiceLanguageSelectionStep.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceLanguageSelectionStep.d.ts","sourceRoot":"","sources":["../../src/steps/ServiceLanguageSelectionStep.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAyB,MAAM,SAAS,CAAC;AAGtE;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,QAAe,EACf,IAAI,EACJ,OAAO,EACP,eAAe,EACf,WAAW,GACZ,EAAE,oBAAoB,2CA4OtB"}
1
+ {"version":3,"file":"ServiceLanguageSelectionStep.d.ts","sourceRoot":"","sources":["../../src/steps/ServiceLanguageSelectionStep.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAyB,MAAM,SAAS,CAAC;AAkBtE,wBAAgB,4BAA4B,CAAC,EAAE,SAAS,EAAE,QAAe,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE,oBAAoB,2CAuZ7K"}