@flowdrop/flowdrop 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/components/App.svelte +153 -84
- package/dist/components/App.svelte.d.ts +16 -1
- package/dist/components/ConfigModal.svelte +2 -1
- package/dist/components/ConfigPanel.svelte +3 -2
- package/dist/components/FlowDropZone.svelte +2 -1
- package/dist/components/LogsSidebar.svelte +3 -2
- package/dist/components/Navbar.svelte +10 -6
- package/dist/components/NodeSidebar.svelte +4 -3
- package/dist/components/NodeStatusOverlay.svelte +14 -7
- package/dist/components/NodeSwapPicker.svelte +2 -1
- package/dist/components/PipelineStatus.svelte +10 -7
- package/dist/components/ReadOnlyDetails.svelte +4 -2
- package/dist/components/SchemaForm.svelte +20 -9
- package/dist/components/SchemaForm.svelte.d.ts +2 -4
- package/dist/components/SettingsModal.svelte +4 -3
- package/dist/components/SettingsPanel.svelte +3 -2
- package/dist/components/SwapMappingEditor.svelte +2 -1
- package/dist/components/WorkflowEditor.svelte +3 -2
- package/dist/components/chat/AIChatPanel.svelte +22 -7
- package/dist/components/chat/AIChatPanel.svelte.d.ts +3 -0
- package/dist/components/chat/CommandPreview.svelte +10 -6
- package/dist/components/console/CommandConsole.svelte +4 -3
- package/dist/components/form/FormArray.svelte +33 -20
- package/dist/components/form/FormArray.svelte.d.ts +3 -1
- package/dist/components/form/FormAutocomplete.svelte +18 -7
- package/dist/components/form/FormCodeEditor.svelte +6 -4
- package/dist/components/form/FormFieldWrapper.svelte +2 -1
- package/dist/components/form/FormMarkdownEditor.svelte +152 -108
- package/dist/components/form/FormMarkdownEditor.svelte.d.ts +1 -1
- package/dist/components/form/FormTemplateEditor.svelte +2 -1
- package/dist/components/form/FormToggle.svelte +23 -5
- package/dist/components/form/FormToggle.svelte.d.ts +6 -2
- package/dist/components/interrupt/ChoicePrompt.svelte +14 -5
- package/dist/components/interrupt/ConfirmationPrompt.svelte +8 -5
- package/dist/components/interrupt/FormPrompt.svelte +28 -7
- package/dist/components/interrupt/InterruptBubble.svelte +27 -18
- package/dist/components/interrupt/ReviewPrompt.svelte +32 -22
- package/dist/components/interrupt/TextInputPrompt.svelte +12 -5
- package/dist/components/layouts/MainLayout.svelte +4 -3
- package/dist/components/nodes/GatewayNode.svelte +8 -3
- package/dist/components/nodes/IdeaNode.svelte +2 -1
- package/dist/components/nodes/NotesNode.svelte +18 -12
- package/dist/components/nodes/SimpleNode.svelte +8 -8
- package/dist/components/nodes/WorkflowNode.svelte +8 -3
- package/dist/components/playground/ChatPanel.svelte +36 -24
- package/dist/components/playground/MessageBubble.svelte +15 -7
- package/dist/components/playground/Playground.svelte +2 -1
- package/dist/components/playground/PlaygroundModal.svelte +2 -1
- package/dist/components/playground/SessionManager.svelte +14 -10
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +9 -0
- package/dist/editor/index.d.ts +1 -1
- package/dist/editor/index.js +1 -1
- package/dist/messages/context.d.ts +29 -0
- package/dist/messages/context.js +38 -0
- package/dist/messages/defaults.d.ts +396 -0
- package/dist/messages/defaults.js +356 -0
- package/dist/messages/deprecation.d.ts +20 -0
- package/dist/messages/deprecation.js +33 -0
- package/dist/messages/index.d.ts +11 -0
- package/dist/messages/index.js +10 -0
- package/dist/messages/merge.d.ts +28 -0
- package/dist/messages/merge.js +53 -0
- package/dist/messages/types.d.ts +29 -0
- package/dist/messages/types.js +13 -0
- package/dist/schemas/v1/workflow.schema.json +5 -0
- package/dist/services/draftStorage.d.ts +13 -0
- package/dist/services/draftStorage.js +36 -0
- package/dist/stores/workflowStore.svelte.d.ts +1 -0
- package/dist/stores/workflowStore.svelte.js +1 -0
- package/dist/styles/base.css +13 -4
- package/dist/svelte-app.d.ts +11 -0
- package/dist/svelte-app.js +11 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/utils/connections.d.ts +4 -0
- package/dist/utils/connections.js +6 -0
- package/package.json +1 -1
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
import type { FieldOption } from './types.js';
|
|
28
28
|
import { buildFetchHeaders } from '../../utils/fetchWithAuth.js';
|
|
29
29
|
import { logger } from '../../utils/logger.js';
|
|
30
|
+
import { m } from '../../messages/index.js';
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* Props interface for FormAutocomplete component
|
|
@@ -68,6 +69,10 @@
|
|
|
68
69
|
);
|
|
69
70
|
const getBaseUrl = getContext<(() => string) | undefined>('flowdrop:getBaseUrl');
|
|
70
71
|
|
|
72
|
+
// Hoist the autocomplete branch — seven reads in the template, one inside
|
|
73
|
+
// an {#each tag} loop. One getter walk per render.
|
|
74
|
+
const t = $derived(m().form.autocomplete);
|
|
75
|
+
|
|
71
76
|
// Configuration with defaults
|
|
72
77
|
const queryParam = $derived(autocomplete.queryParam ?? 'q');
|
|
73
78
|
const minChars = $derived(autocomplete.minChars ?? 0);
|
|
@@ -579,7 +584,9 @@
|
|
|
579
584
|
<button
|
|
580
585
|
type="button"
|
|
581
586
|
class="form-autocomplete__tag-remove"
|
|
582
|
-
aria-label={
|
|
587
|
+
aria-label={t.removeTag({
|
|
588
|
+
label: getDisplayLabel(selectedVal)
|
|
589
|
+
})}
|
|
583
590
|
onclick={(e) => {
|
|
584
591
|
e.stopPropagation();
|
|
585
592
|
removeTag(selectedVal);
|
|
@@ -622,14 +629,14 @@
|
|
|
622
629
|
<!-- Status icons -->
|
|
623
630
|
<div class="form-autocomplete__icons">
|
|
624
631
|
{#if isLoading}
|
|
625
|
-
<span class="form-autocomplete__spinner" aria-label=
|
|
632
|
+
<span class="form-autocomplete__spinner" aria-label={t.loading}>
|
|
626
633
|
<Icon icon="heroicons:arrow-path" />
|
|
627
634
|
</span>
|
|
628
635
|
{:else if selectedValues.length > 0 && !disabled}
|
|
629
636
|
<button
|
|
630
637
|
type="button"
|
|
631
638
|
class="form-autocomplete__clear"
|
|
632
|
-
aria-label=
|
|
639
|
+
aria-label={t.clearAll}
|
|
633
640
|
onclick={(e) => {
|
|
634
641
|
e.stopPropagation();
|
|
635
642
|
handleClearAll();
|
|
@@ -657,24 +664,28 @@
|
|
|
657
664
|
style={popoverStyle}
|
|
658
665
|
onmousedown={(e) => e.preventDefault()}
|
|
659
666
|
>
|
|
660
|
-
<ul
|
|
667
|
+
<ul
|
|
668
|
+
class="form-autocomplete__listbox"
|
|
669
|
+
role="listbox"
|
|
670
|
+
aria-label={t.suggestions}
|
|
671
|
+
>
|
|
661
672
|
{#if isLoading}
|
|
662
673
|
<li class="form-autocomplete__status form-autocomplete__status--loading">
|
|
663
674
|
<Icon icon="heroicons:arrow-path" class="form-autocomplete__status-icon" />
|
|
664
|
-
<span>
|
|
675
|
+
<span>{t.loadingPending}</span>
|
|
665
676
|
</li>
|
|
666
677
|
{:else if error}
|
|
667
678
|
<li class="form-autocomplete__status form-autocomplete__status--error">
|
|
668
679
|
<Icon icon="heroicons:exclamation-triangle" class="form-autocomplete__status-icon" />
|
|
669
680
|
<span>{error}</span>
|
|
670
681
|
<button type="button" class="form-autocomplete__retry" onclick={handleRetry}>
|
|
671
|
-
|
|
682
|
+
{t.retry}
|
|
672
683
|
</button>
|
|
673
684
|
</li>
|
|
674
685
|
{:else if suggestions.length === 0}
|
|
675
686
|
<li class="form-autocomplete__status form-autocomplete__status--empty">
|
|
676
687
|
<Icon icon="heroicons:magnifying-glass" class="form-autocomplete__status-icon" />
|
|
677
|
-
<span>
|
|
688
|
+
<span>{t.noResults}</span>
|
|
678
689
|
</li>
|
|
679
690
|
{:else}
|
|
680
691
|
{#each suggestions as option, index (option.value)}
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
import { json, jsonParseLinter } from '@codemirror/lang-json';
|
|
32
32
|
import { oneDark } from '@codemirror/theme-one-dark';
|
|
33
33
|
import { linter } from '@codemirror/lint';
|
|
34
|
+
import { m } from '../../messages/index.js';
|
|
34
35
|
|
|
35
36
|
interface Props {
|
|
36
37
|
/** Field identifier */
|
|
@@ -91,13 +92,14 @@
|
|
|
91
92
|
return '';
|
|
92
93
|
}
|
|
93
94
|
if (typeof val === 'string') {
|
|
94
|
-
//
|
|
95
|
+
// If the string is already a valid JSON representation (e.g. '{"a":1}' or '"foo"'),
|
|
96
|
+
// use it as-is to avoid double-encoding
|
|
95
97
|
try {
|
|
96
98
|
JSON.parse(val);
|
|
97
99
|
return val;
|
|
98
100
|
} catch {
|
|
99
|
-
//
|
|
100
|
-
return val;
|
|
101
|
+
// Plain JS string value — serialize it as a JSON string literal (adds quotes)
|
|
102
|
+
return JSON.stringify(val);
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
// Convert object to formatted JSON string
|
|
@@ -321,7 +323,7 @@
|
|
|
321
323
|
class:form-code-editor__container--dark={darkTheme}
|
|
322
324
|
role="textbox"
|
|
323
325
|
aria-multiline="true"
|
|
324
|
-
aria-label=
|
|
326
|
+
aria-label={m().form.code.editor}
|
|
325
327
|
onblur={formatContent}
|
|
326
328
|
></div>
|
|
327
329
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
<script lang="ts">
|
|
13
13
|
import type { Snippet } from 'svelte';
|
|
14
|
+
import { m } from '../../messages/index.js';
|
|
14
15
|
|
|
15
16
|
interface Props {
|
|
16
17
|
/** Field identifier for label association */
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
{label}
|
|
43
44
|
</span>
|
|
44
45
|
{#if required}
|
|
45
|
-
<span class="form-field__required" aria-label=
|
|
46
|
+
<span class="form-field__required" aria-label={m().form.field.required}>*</span>
|
|
46
47
|
{/if}
|
|
47
48
|
</label>
|
|
48
49
|
|
|
@@ -18,20 +18,21 @@
|
|
|
18
18
|
|
|
19
19
|
<script lang="ts">
|
|
20
20
|
import { onMount, onDestroy } from 'svelte';
|
|
21
|
-
import { EditorView, lineNumbers, drawSelection, keymap } from '@codemirror/view';
|
|
21
|
+
import { EditorView, lineNumbers, drawSelection, keymap, placeholder } from '@codemirror/view';
|
|
22
22
|
import { EditorState, Compartment } from '@codemirror/state';
|
|
23
23
|
import { history, historyKeymap, defaultKeymap, indentWithTab } from '@codemirror/commands';
|
|
24
24
|
import { highlightSpecialChars, highlightActiveLine } from '@codemirror/view';
|
|
25
25
|
import { syntaxHighlighting, defaultHighlightStyle } from '@codemirror/language';
|
|
26
26
|
import { markdown } from '@codemirror/lang-markdown';
|
|
27
27
|
import { oneDark } from '@codemirror/theme-one-dark';
|
|
28
|
+
import { m } from '../../messages/index.js';
|
|
28
29
|
|
|
29
30
|
interface Props {
|
|
30
31
|
/** Field identifier */
|
|
31
32
|
id: string;
|
|
32
33
|
/** Current value (markdown string) */
|
|
33
34
|
value: string;
|
|
34
|
-
/** Placeholder text shown when empty */
|
|
35
|
+
/** Placeholder text shown when empty. Falls back to `messages.form.markdown.placeholder`. */
|
|
35
36
|
placeholder?: string;
|
|
36
37
|
/** Whether the field is required */
|
|
37
38
|
required?: boolean;
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
let {
|
|
61
62
|
id,
|
|
62
63
|
value = '',
|
|
63
|
-
placeholder
|
|
64
|
+
placeholder: placeholderProp,
|
|
64
65
|
required = false,
|
|
65
66
|
height = '300px',
|
|
66
67
|
showToolbar = true,
|
|
@@ -97,6 +98,12 @@
|
|
|
97
98
|
/** Theme compartment for dynamic theme switching */
|
|
98
99
|
const themeCompartment = new Compartment();
|
|
99
100
|
|
|
101
|
+
/** Placeholder compartment so locale changes can reconfigure without rebuilding the editor */
|
|
102
|
+
const placeholderCompartment = new Compartment();
|
|
103
|
+
|
|
104
|
+
/** aria-label compartment so locale changes update the editor's accessible name */
|
|
105
|
+
const ariaLabelCompartment = new Compartment();
|
|
106
|
+
|
|
100
107
|
// ── Toolbar actions ──────────────────────────────────────
|
|
101
108
|
|
|
102
109
|
type ToolbarAction = {
|
|
@@ -165,104 +172,110 @@
|
|
|
165
172
|
editorView.focus();
|
|
166
173
|
}
|
|
167
174
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
175
|
+
// Derived so `label` strings refresh whenever the consumer's i18n source
|
|
176
|
+
// changes locale. Action closures recreate alongside, but they're cheap —
|
|
177
|
+
// they only capture a stable reference to `editorView` (a state).
|
|
178
|
+
const toolbarActions: (ToolbarAction | '|')[] = $derived.by(() => {
|
|
179
|
+
const md = m().form.markdown;
|
|
180
|
+
return [
|
|
181
|
+
{
|
|
182
|
+
id: 'bold',
|
|
183
|
+
label: md.bold,
|
|
184
|
+
icon: 'B',
|
|
185
|
+
shortcut: 'Mod-b',
|
|
186
|
+
action: () => wrapSelection('**', '**')
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
id: 'italic',
|
|
190
|
+
label: md.italic,
|
|
191
|
+
icon: 'I',
|
|
192
|
+
shortcut: 'Mod-i',
|
|
193
|
+
action: () => wrapSelection('_', '_')
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: 'strikethrough',
|
|
197
|
+
label: md.strikethrough,
|
|
198
|
+
icon: 'S',
|
|
199
|
+
action: () => wrapSelection('~~', '~~')
|
|
200
|
+
},
|
|
201
|
+
'|',
|
|
202
|
+
{
|
|
203
|
+
id: 'heading-1',
|
|
204
|
+
label: md.heading1,
|
|
205
|
+
icon: 'H1',
|
|
206
|
+
action: () => prefixLine('# ')
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: 'heading-2',
|
|
210
|
+
label: md.heading2,
|
|
211
|
+
icon: 'H2',
|
|
212
|
+
action: () => prefixLine('## ')
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: 'heading-3',
|
|
216
|
+
label: md.heading3,
|
|
217
|
+
icon: 'H3',
|
|
218
|
+
action: () => prefixLine('### ')
|
|
219
|
+
},
|
|
220
|
+
'|',
|
|
221
|
+
{
|
|
222
|
+
id: 'quote',
|
|
223
|
+
label: md.quote,
|
|
224
|
+
icon: '"',
|
|
225
|
+
action: () => prefixLine('> ')
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
id: 'unordered-list',
|
|
229
|
+
label: md.unorderedList,
|
|
230
|
+
icon: '•',
|
|
231
|
+
action: () => prefixLine('- ')
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: 'ordered-list',
|
|
235
|
+
label: md.orderedList,
|
|
236
|
+
icon: '1.',
|
|
237
|
+
action: () => prefixLine('1. ')
|
|
238
|
+
},
|
|
239
|
+
'|',
|
|
240
|
+
{
|
|
241
|
+
id: 'link',
|
|
242
|
+
label: md.link,
|
|
243
|
+
icon: icons.link,
|
|
244
|
+
isSvg: true,
|
|
245
|
+
shortcut: 'Mod-k',
|
|
246
|
+
action: () => {
|
|
247
|
+
if (!editorView) return;
|
|
248
|
+
const { from, to } = editorView.state.selection.main;
|
|
249
|
+
const selected = editorView.state.sliceDoc(from, to);
|
|
250
|
+
const text = selected || 'link text';
|
|
251
|
+
const replacement = `[${text}](url)`;
|
|
252
|
+
editorView.dispatch({
|
|
253
|
+
changes: { from, to, insert: replacement },
|
|
254
|
+
selection: {
|
|
255
|
+
anchor: from + text.length + 3,
|
|
256
|
+
head: from + text.length + 6
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
editorView.focus();
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
id: 'image',
|
|
264
|
+
label: md.image,
|
|
265
|
+
icon: icons.image,
|
|
266
|
+
isSvg: true,
|
|
267
|
+
action: () => insertAtCursor('')
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
id: 'table',
|
|
271
|
+
label: md.table,
|
|
272
|
+
icon: icons.table,
|
|
273
|
+
isSvg: true,
|
|
274
|
+
action: () =>
|
|
275
|
+
insertAtCursor('\n| Header | Header |\n| ------ | ------ |\n| Cell | Cell |\n')
|
|
248
276
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
id: 'image',
|
|
252
|
-
label: 'Image',
|
|
253
|
-
icon: icons.image,
|
|
254
|
-
isSvg: true,
|
|
255
|
-
action: () => insertAtCursor('')
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
id: 'table',
|
|
259
|
-
label: 'Table',
|
|
260
|
-
icon: icons.table,
|
|
261
|
-
isSvg: true,
|
|
262
|
-
action: () =>
|
|
263
|
-
insertAtCursor('\n| Header | Header |\n| ------ | ------ |\n| Cell | Cell |\n')
|
|
264
|
-
}
|
|
265
|
-
];
|
|
277
|
+
];
|
|
278
|
+
});
|
|
266
279
|
|
|
267
280
|
// ── CM6 Keyboard shortcuts for toolbar actions ───────────
|
|
268
281
|
|
|
@@ -327,11 +340,14 @@
|
|
|
327
340
|
// ── Editor setup ─────────────────────────────────────────
|
|
328
341
|
|
|
329
342
|
function createExtensions() {
|
|
343
|
+
const placeholderText = placeholderProp ?? m().form.markdown.placeholder;
|
|
344
|
+
|
|
330
345
|
const extensions = [
|
|
331
346
|
lineNumbers(),
|
|
332
347
|
highlightSpecialChars(),
|
|
333
348
|
highlightActiveLine(),
|
|
334
349
|
drawSelection(),
|
|
350
|
+
placeholderCompartment.of(placeholder(placeholderText)),
|
|
335
351
|
|
|
336
352
|
// Editing features (skip when read-only)
|
|
337
353
|
...(disabled
|
|
@@ -394,10 +410,12 @@
|
|
|
394
410
|
EditorView.lineWrapping,
|
|
395
411
|
|
|
396
412
|
// Accessibility
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
413
|
+
ariaLabelCompartment.of(
|
|
414
|
+
EditorView.contentAttributes.of({
|
|
415
|
+
'aria-label': m().form.markdown.editor,
|
|
416
|
+
'aria-multiline': 'true'
|
|
417
|
+
})
|
|
418
|
+
)
|
|
401
419
|
];
|
|
402
420
|
|
|
403
421
|
return extensions;
|
|
@@ -462,6 +480,27 @@
|
|
|
462
480
|
updateStats(editorView.state.doc);
|
|
463
481
|
}
|
|
464
482
|
});
|
|
483
|
+
|
|
484
|
+
// Reconfigure CodeMirror-owned strings (placeholder, content aria-label)
|
|
485
|
+
// when the consumer's locale or `placeholder` prop changes. Toolbar and
|
|
486
|
+
// status-bar strings rerender via `$derived` in the template; CodeMirror
|
|
487
|
+
// lives outside Svelte's reactivity graph, so this effect bridges the gap.
|
|
488
|
+
$effect(() => {
|
|
489
|
+
const placeholderText = placeholderProp ?? m().form.markdown.placeholder;
|
|
490
|
+
const ariaLabel = m().form.markdown.editor;
|
|
491
|
+
if (!editorView) return;
|
|
492
|
+
editorView.dispatch({
|
|
493
|
+
effects: [
|
|
494
|
+
placeholderCompartment.reconfigure(placeholder(placeholderText)),
|
|
495
|
+
ariaLabelCompartment.reconfigure(
|
|
496
|
+
EditorView.contentAttributes.of({
|
|
497
|
+
'aria-label': ariaLabel,
|
|
498
|
+
'aria-multiline': 'true'
|
|
499
|
+
})
|
|
500
|
+
)
|
|
501
|
+
]
|
|
502
|
+
});
|
|
503
|
+
});
|
|
465
504
|
</script>
|
|
466
505
|
|
|
467
506
|
<div
|
|
@@ -481,7 +520,11 @@
|
|
|
481
520
|
|
|
482
521
|
<!-- Toolbar -->
|
|
483
522
|
{#if showToolbar && !disabled}
|
|
484
|
-
<div
|
|
523
|
+
<div
|
|
524
|
+
class="form-markdown-editor__toolbar"
|
|
525
|
+
role="toolbar"
|
|
526
|
+
aria-label={m().form.markdown.toolbar}
|
|
527
|
+
>
|
|
485
528
|
{#each toolbarActions as item}
|
|
486
529
|
{#if item === '|'}
|
|
487
530
|
<span class="form-markdown-editor__separator"></span>
|
|
@@ -514,10 +557,11 @@
|
|
|
514
557
|
|
|
515
558
|
<!-- Status bar -->
|
|
516
559
|
{#if showStatusBar}
|
|
560
|
+
{@const md = m().form.markdown}
|
|
517
561
|
<div class="form-markdown-editor__status">
|
|
518
|
-
<span>words: {wordCount}</span>
|
|
519
|
-
<span>lines: {lineCount}</span>
|
|
520
|
-
<span>characters: {charCount}</span>
|
|
562
|
+
<span>{md.words}: {wordCount}</span>
|
|
563
|
+
<span>{md.lines}: {lineCount}</span>
|
|
564
|
+
<span>{md.characters}: {charCount}</span>
|
|
521
565
|
</div>
|
|
522
566
|
{/if}
|
|
523
567
|
</div>
|
|
@@ -3,7 +3,7 @@ interface Props {
|
|
|
3
3
|
id: string;
|
|
4
4
|
/** Current value (markdown string) */
|
|
5
5
|
value: string;
|
|
6
|
-
/** Placeholder text shown when empty */
|
|
6
|
+
/** Placeholder text shown when empty. Falls back to `messages.form.markdown.placeholder`. */
|
|
7
7
|
placeholder?: string;
|
|
8
8
|
/** Whether the field is required */
|
|
9
9
|
required?: boolean;
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
import { createTemplateAutocomplete } from './templateAutocomplete.js';
|
|
47
47
|
import { getVariableSchema } from '../../services/variableService.js';
|
|
48
48
|
import { logger } from '../../utils/logger.js';
|
|
49
|
+
import { m } from '../../messages/index.js';
|
|
49
50
|
|
|
50
51
|
interface Props {
|
|
51
52
|
/** Field identifier */
|
|
@@ -506,7 +507,7 @@
|
|
|
506
507
|
class:form-template-editor__container--dark={darkTheme}
|
|
507
508
|
role="textbox"
|
|
508
509
|
aria-multiline="true"
|
|
509
|
-
aria-label=
|
|
510
|
+
aria-label={m().form.template.editor}
|
|
510
511
|
></div>
|
|
511
512
|
|
|
512
513
|
<!-- Loading banner (shown while fetching variables from API) -->
|
|
@@ -9,14 +9,20 @@
|
|
|
9
9
|
-->
|
|
10
10
|
|
|
11
11
|
<script lang="ts">
|
|
12
|
+
import { m, warnDeprecatedProp } from '../../messages/index.js';
|
|
13
|
+
|
|
12
14
|
interface Props {
|
|
13
15
|
/** Field identifier */
|
|
14
16
|
id: string;
|
|
15
17
|
/** Current value */
|
|
16
18
|
value: boolean;
|
|
17
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated since v1.8 — use `messages.form.toggle.enabled`. Removed in v2.0.
|
|
21
|
+
*/
|
|
18
22
|
onLabel?: string;
|
|
19
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated since v1.8 — use `messages.form.toggle.disabled`. Removed in v2.0.
|
|
25
|
+
*/
|
|
20
26
|
offLabel?: string;
|
|
21
27
|
/** Whether the field is disabled (read-only) */
|
|
22
28
|
disabled?: boolean;
|
|
@@ -29,13 +35,25 @@
|
|
|
29
35
|
let {
|
|
30
36
|
id,
|
|
31
37
|
value = false,
|
|
32
|
-
onLabel
|
|
33
|
-
offLabel
|
|
38
|
+
onLabel,
|
|
39
|
+
offLabel,
|
|
34
40
|
disabled = false,
|
|
35
41
|
ariaDescribedBy,
|
|
36
42
|
onChange
|
|
37
43
|
}: Props = $props();
|
|
38
44
|
|
|
45
|
+
// svelte-ignore state_referenced_locally — deprecation warns once per mount; later prop rebinds aren't relevant
|
|
46
|
+
if (onLabel !== undefined) {
|
|
47
|
+
warnDeprecatedProp('FormToggle', 'onLabel', 'messages.form.toggle.enabled');
|
|
48
|
+
}
|
|
49
|
+
// svelte-ignore state_referenced_locally
|
|
50
|
+
if (offLabel !== undefined) {
|
|
51
|
+
warnDeprecatedProp('FormToggle', 'offLabel', 'messages.form.toggle.disabled');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const resolvedOnLabel = $derived(onLabel ?? m().form.toggle.enabled);
|
|
55
|
+
const resolvedOffLabel = $derived(offLabel ?? m().form.toggle.disabled);
|
|
56
|
+
|
|
39
57
|
/**
|
|
40
58
|
* Handle toggle changes
|
|
41
59
|
*/
|
|
@@ -59,7 +77,7 @@
|
|
|
59
77
|
<span class="form-toggle__thumb"></span>
|
|
60
78
|
</span>
|
|
61
79
|
<span class="form-toggle__label">
|
|
62
|
-
{value ?
|
|
80
|
+
{value ? resolvedOnLabel : resolvedOffLabel}
|
|
63
81
|
</span>
|
|
64
82
|
</label>
|
|
65
83
|
|
|
@@ -3,9 +3,13 @@ interface Props {
|
|
|
3
3
|
id: string;
|
|
4
4
|
/** Current value */
|
|
5
5
|
value: boolean;
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated since v1.8 — use `messages.form.toggle.enabled`. Removed in v2.0.
|
|
8
|
+
*/
|
|
7
9
|
onLabel?: string;
|
|
8
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated since v1.8 — use `messages.form.toggle.disabled`. Removed in v2.0.
|
|
12
|
+
*/
|
|
9
13
|
offLabel?: string;
|
|
10
14
|
/** Whether the field is disabled (read-only) */
|
|
11
15
|
disabled?: boolean;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
<script lang="ts">
|
|
11
11
|
import Icon from '@iconify/svelte';
|
|
12
12
|
import type { ChoiceConfig, InterruptChoice } from '../../types/interrupt.js';
|
|
13
|
+
import { m } from '../../messages/index.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Component props
|
|
@@ -41,6 +42,9 @@
|
|
|
41
42
|
onSubmit
|
|
42
43
|
}: Props = $props();
|
|
43
44
|
|
|
45
|
+
// Hoist the choice branch — counter, min, max, submit reads.
|
|
46
|
+
const t = $derived(m().interrupt.choice);
|
|
47
|
+
|
|
44
48
|
/** Local state for selected values */
|
|
45
49
|
let selectedValues = $state<Set<string>>(new Set());
|
|
46
50
|
|
|
@@ -165,12 +169,15 @@
|
|
|
165
169
|
{#if isMultiple && !isResolved}
|
|
166
170
|
<div class="choice-prompt__info">
|
|
167
171
|
<span>
|
|
168
|
-
{
|
|
172
|
+
{t.selectedCount({
|
|
173
|
+
n: selectedValues.size,
|
|
174
|
+
total: config.options.length
|
|
175
|
+
})}
|
|
169
176
|
{#if minSelections > 0}
|
|
170
|
-
(
|
|
177
|
+
{t.min({ n: minSelections })}
|
|
171
178
|
{/if}
|
|
172
179
|
{#if maxSelections < config.options.length}
|
|
173
|
-
(
|
|
180
|
+
{t.max({ n: maxSelections })}
|
|
174
181
|
{/if}
|
|
175
182
|
</span>
|
|
176
183
|
</div>
|
|
@@ -190,7 +197,7 @@
|
|
|
190
197
|
{:else}
|
|
191
198
|
<Icon icon="mdi:check" />
|
|
192
199
|
{/if}
|
|
193
|
-
<span>
|
|
200
|
+
<span>{t.submit}</span>
|
|
194
201
|
</button>
|
|
195
202
|
</div>
|
|
196
203
|
{/if}
|
|
@@ -200,7 +207,9 @@
|
|
|
200
207
|
<div class="choice-prompt__resolved-badge">
|
|
201
208
|
<Icon icon="mdi:check-circle" />
|
|
202
209
|
<span>
|
|
203
|
-
{resolvedByUserName
|
|
210
|
+
{resolvedByUserName
|
|
211
|
+
? m().interrupt.responseSubmittedBy({ name: resolvedByUserName })
|
|
212
|
+
: m().interrupt.responseSubmitted}
|
|
204
213
|
</span>
|
|
205
214
|
</div>
|
|
206
215
|
{/if}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
<script lang="ts">
|
|
11
11
|
import Icon from '@iconify/svelte';
|
|
12
12
|
import type { ConfirmationConfig } from '../../types/interrupt.js';
|
|
13
|
+
import { m } from '../../messages/index.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Component props
|
|
@@ -44,11 +45,11 @@
|
|
|
44
45
|
onDecline
|
|
45
46
|
}: Props = $props();
|
|
46
47
|
|
|
47
|
-
/** Computed label for confirm button */
|
|
48
|
-
const confirmLabel = $derived(config.confirmLabel ??
|
|
48
|
+
/** Computed label for confirm button — config wins, falls back to messages tree. */
|
|
49
|
+
const confirmLabel = $derived(config.confirmLabel ?? m().interrupt.confirmation.yes);
|
|
49
50
|
|
|
50
|
-
/** Computed label for decline/cancel button */
|
|
51
|
-
const declineLabel = $derived(config.cancelLabel ??
|
|
51
|
+
/** Computed label for decline/cancel button — config wins, falls back to messages tree. */
|
|
52
|
+
const declineLabel = $derived(config.cancelLabel ?? m().interrupt.confirmation.no);
|
|
52
53
|
</script>
|
|
53
54
|
|
|
54
55
|
<div
|
|
@@ -119,7 +120,9 @@
|
|
|
119
120
|
<div class="confirmation-prompt__resolved-badge">
|
|
120
121
|
<Icon icon="mdi:check-circle" />
|
|
121
122
|
<span>
|
|
122
|
-
{resolvedByUserName
|
|
123
|
+
{resolvedByUserName
|
|
124
|
+
? m().interrupt.responseSubmittedBy({ name: resolvedByUserName })
|
|
125
|
+
: m().interrupt.responseSubmitted}
|
|
123
126
|
</span>
|
|
124
127
|
</div>
|
|
125
128
|
{/if}
|