@flowdrop/flowdrop 1.7.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 +92 -54
- package/dist/components/App.svelte.d.ts +13 -0
- 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 +2 -1
- 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/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/services/draftStorage.d.ts +13 -0
- package/dist/services/draftStorage.js +36 -0
- package/dist/styles/base.css +13 -4
- package/dist/svelte-app.d.ts +11 -0
- package/dist/svelte-app.js +11 -2
- package/package.json +1 -1
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default English strings for every user-facing label, message, and tooltip
|
|
3
|
+
* rendered by FlowDrop.
|
|
4
|
+
*
|
|
5
|
+
* Consumers override any subset by passing `messages={() => partial}` to the
|
|
6
|
+
* root `<FlowDrop>` component (see `./context.ts`).
|
|
7
|
+
*
|
|
8
|
+
* Conventions:
|
|
9
|
+
* - Group by **domain** (form, interrupt, chat, navigation, status, nodes,
|
|
10
|
+
* common), not by component file path. Component paths churn; domains
|
|
11
|
+
* don't.
|
|
12
|
+
* - Parameterised strings are **functions**, not template strings with
|
|
13
|
+
* placeholders. The compiler then enforces the param shape at every call
|
|
14
|
+
* site.
|
|
15
|
+
* - Leaves are either `string` or `(params) => string`. Nothing else.
|
|
16
|
+
*
|
|
17
|
+
* The `as const` assertion is load-bearing: without it, every string widens
|
|
18
|
+
* to `string` and the `Messages` type loses its precision.
|
|
19
|
+
*/
|
|
20
|
+
export const defaultMessages = {
|
|
21
|
+
common: {
|
|
22
|
+
save: 'Save',
|
|
23
|
+
cancel: 'Cancel',
|
|
24
|
+
confirm: 'Confirm',
|
|
25
|
+
close: 'Close',
|
|
26
|
+
delete: 'Delete',
|
|
27
|
+
yes: 'Yes',
|
|
28
|
+
no: 'No'
|
|
29
|
+
},
|
|
30
|
+
form: {
|
|
31
|
+
array: {
|
|
32
|
+
// Item-level controls — `n` is the 1-based item position the user sees.
|
|
33
|
+
itemLabel: ({ n }) => `Item ${n}`,
|
|
34
|
+
expandItem: 'Expand item',
|
|
35
|
+
collapseItem: 'Collapse item',
|
|
36
|
+
moveItemUp: ({ n }) => `Move item ${n} up`,
|
|
37
|
+
moveItemDown: ({ n }) => `Move item ${n} down`,
|
|
38
|
+
deleteItem: ({ n }) => `Delete item ${n}`,
|
|
39
|
+
moveUp: 'Move up',
|
|
40
|
+
moveDown: 'Move down',
|
|
41
|
+
delete: 'Delete item',
|
|
42
|
+
// Boolean rendering inside array items.
|
|
43
|
+
yes: 'Yes',
|
|
44
|
+
no: 'No',
|
|
45
|
+
// Empty state and limits.
|
|
46
|
+
empty: 'No items yet',
|
|
47
|
+
add: 'Add Item',
|
|
48
|
+
count: ({ n }) => `${n} item${n !== 1 ? 's' : ''}`,
|
|
49
|
+
min: ({ n }) => `Min: ${n}`,
|
|
50
|
+
max: ({ n }) => `Max: ${n}`,
|
|
51
|
+
unsupported: ({ type }) => `Complex item type "${type}" is not fully supported.`
|
|
52
|
+
},
|
|
53
|
+
markdown: {
|
|
54
|
+
placeholder: 'Write your markdown here...',
|
|
55
|
+
// Toolbar action labels (rendered as `title` and used in `title` with
|
|
56
|
+
// an optional shortcut suffix appended by the component).
|
|
57
|
+
bold: 'Bold',
|
|
58
|
+
italic: 'Italic',
|
|
59
|
+
strikethrough: 'Strikethrough',
|
|
60
|
+
heading1: 'Heading 1',
|
|
61
|
+
heading2: 'Heading 2',
|
|
62
|
+
heading3: 'Heading 3',
|
|
63
|
+
quote: 'Quote',
|
|
64
|
+
unorderedList: 'Unordered List',
|
|
65
|
+
orderedList: 'Ordered List',
|
|
66
|
+
link: 'Link',
|
|
67
|
+
image: 'Image',
|
|
68
|
+
table: 'Table',
|
|
69
|
+
// Region/widget aria-labels.
|
|
70
|
+
editor: 'Markdown editor',
|
|
71
|
+
toolbar: 'Markdown formatting',
|
|
72
|
+
// Status bar metric labels (the metric value is appended after the colon).
|
|
73
|
+
words: 'words',
|
|
74
|
+
lines: 'lines',
|
|
75
|
+
characters: 'characters'
|
|
76
|
+
},
|
|
77
|
+
autocomplete: {
|
|
78
|
+
removeTag: ({ label }) => `Remove ${label}`,
|
|
79
|
+
loading: 'Loading suggestions',
|
|
80
|
+
loadingPending: 'Loading suggestions...',
|
|
81
|
+
clearAll: 'Clear all selections',
|
|
82
|
+
suggestions: 'Suggestions',
|
|
83
|
+
retry: 'Retry',
|
|
84
|
+
noResults: 'No results found'
|
|
85
|
+
},
|
|
86
|
+
field: {
|
|
87
|
+
required: 'required'
|
|
88
|
+
},
|
|
89
|
+
toggle: {
|
|
90
|
+
enabled: 'Enabled',
|
|
91
|
+
disabled: 'Disabled'
|
|
92
|
+
},
|
|
93
|
+
schema: {
|
|
94
|
+
save: 'Save',
|
|
95
|
+
cancel: 'Cancel',
|
|
96
|
+
empty: 'No schema properties defined.'
|
|
97
|
+
},
|
|
98
|
+
code: {
|
|
99
|
+
// FormCodeEditor — JSON editor aria-label.
|
|
100
|
+
editor: 'JSON editor'
|
|
101
|
+
},
|
|
102
|
+
template: {
|
|
103
|
+
// FormTemplateEditor — Mustache/template editor aria-label.
|
|
104
|
+
editor: 'Template editor'
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
interrupt: {
|
|
108
|
+
// Shared resolution notice rendered after any interrupt prompt is answered.
|
|
109
|
+
responseSubmitted: 'Response submitted',
|
|
110
|
+
responseSubmittedBy: ({ name }) => `Response submitted by ${name}`,
|
|
111
|
+
confirmation: {
|
|
112
|
+
yes: 'Yes',
|
|
113
|
+
no: 'No'
|
|
114
|
+
},
|
|
115
|
+
choice: {
|
|
116
|
+
submit: 'Submit',
|
|
117
|
+
// Selection counter rendered inside the picker, e.g. "2 of 5 selected".
|
|
118
|
+
selectedCount: ({ n, total }) => `${n} of ${total} selected`,
|
|
119
|
+
min: ({ n }) => `(min: ${n})`,
|
|
120
|
+
max: ({ n }) => `(max: ${n})`
|
|
121
|
+
},
|
|
122
|
+
review: {
|
|
123
|
+
acceptAll: 'Accept All',
|
|
124
|
+
rejectAll: 'Reject All',
|
|
125
|
+
submit: 'Submit Review',
|
|
126
|
+
empty: '(empty)',
|
|
127
|
+
yes: 'Yes',
|
|
128
|
+
no: 'No',
|
|
129
|
+
// Per-row controls.
|
|
130
|
+
acceptItem: ({ label }) => `Accept ${label}`,
|
|
131
|
+
rejectItem: ({ label }) => `Reject ${label}`,
|
|
132
|
+
accept: 'Accept',
|
|
133
|
+
reject: 'Reject',
|
|
134
|
+
accepted: 'Accepted',
|
|
135
|
+
rejected: 'Rejected',
|
|
136
|
+
// Diff/preview controls.
|
|
137
|
+
rendered: 'Rendered',
|
|
138
|
+
rawHtml: 'Raw HTML',
|
|
139
|
+
original: 'Original:',
|
|
140
|
+
proposed: 'Proposed:',
|
|
141
|
+
diff: 'Diff:',
|
|
142
|
+
// Header counter — accepted decisions out of total.
|
|
143
|
+
counter: ({ accepted, total }) => `${accepted} of ${total} accepted`,
|
|
144
|
+
// Footer summary — accepted/rejected breakdown.
|
|
145
|
+
summary: ({ accepted, rejected, total }) => `${accepted} accepted, ${rejected} rejected out of ${total} changes`
|
|
146
|
+
},
|
|
147
|
+
form: {
|
|
148
|
+
submit: 'Submit',
|
|
149
|
+
// Boolean and empty-cell rendering in the submitted-values readout.
|
|
150
|
+
yes: 'Yes',
|
|
151
|
+
no: 'No',
|
|
152
|
+
empty: '—',
|
|
153
|
+
submittedValuesTitle: 'Submitted Values'
|
|
154
|
+
},
|
|
155
|
+
text: {
|
|
156
|
+
placeholder: 'Enter your response...',
|
|
157
|
+
min: ({ n }) => `(min: ${n})`,
|
|
158
|
+
submit: 'Submit'
|
|
159
|
+
},
|
|
160
|
+
bubble: {
|
|
161
|
+
// Pre-resolution status — keyed by interrupt kind.
|
|
162
|
+
required: {
|
|
163
|
+
confirmation: 'Confirmation Required',
|
|
164
|
+
selection: 'Selection Required',
|
|
165
|
+
input: 'Input Required',
|
|
166
|
+
form: 'Form Required',
|
|
167
|
+
review: 'Review Required',
|
|
168
|
+
default: 'Action Required'
|
|
169
|
+
},
|
|
170
|
+
// Post-resolution status.
|
|
171
|
+
submitted: {
|
|
172
|
+
confirmation: 'Confirmation Submitted',
|
|
173
|
+
selection: 'Selection Made',
|
|
174
|
+
input: 'Input Submitted',
|
|
175
|
+
form: 'Form Submitted',
|
|
176
|
+
review: 'Review Submitted',
|
|
177
|
+
default: 'Response Submitted'
|
|
178
|
+
},
|
|
179
|
+
cancelled: 'Cancelled',
|
|
180
|
+
errorRetry: 'Error - Click to Retry',
|
|
181
|
+
retry: 'Retry',
|
|
182
|
+
cancel: 'Cancel',
|
|
183
|
+
fromWorkflow: 'From workflow node',
|
|
184
|
+
nodeIdTooltip: ({ id }) => `Node ID: ${id}`
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
navigation: {
|
|
188
|
+
// Navbar branding (rendered when no consumer overrides via title prop).
|
|
189
|
+
appName: 'FlowDrop',
|
|
190
|
+
tagline: 'Visual Workflow Manager',
|
|
191
|
+
breadcrumbAriaLabel: 'Breadcrumb',
|
|
192
|
+
connected: 'Connected',
|
|
193
|
+
settingsTitle: 'Settings',
|
|
194
|
+
settingsAriaLabel: 'Open settings',
|
|
195
|
+
// Default primary action labels rendered when no `navbarActions` prop is supplied.
|
|
196
|
+
save: 'Save',
|
|
197
|
+
export: 'Export',
|
|
198
|
+
import: 'Import',
|
|
199
|
+
workflowSettings: 'Workflow Settings',
|
|
200
|
+
// Right-sidebar workflow settings panel (distinct from the navbar action label above).
|
|
201
|
+
workflowSettingsPanelTitle: 'Workflow Settings',
|
|
202
|
+
workflowSettingsPanelSubtitle: 'Settings',
|
|
203
|
+
nodeConfigDescription: 'Node configuration',
|
|
204
|
+
closeSettings: 'Close settings',
|
|
205
|
+
closeConfigModal: 'Close configuration modal',
|
|
206
|
+
copyId: 'Copy ID to clipboard',
|
|
207
|
+
// Bottom panel tab labels.
|
|
208
|
+
bottomPanel: {
|
|
209
|
+
console: 'Console',
|
|
210
|
+
chat: 'AI Assistant'
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
layout: {
|
|
214
|
+
// Sidebar/main-region landmarks.
|
|
215
|
+
componentsSidebar: 'Components sidebar',
|
|
216
|
+
workflowCanvas: 'Workflow canvas',
|
|
217
|
+
executionLogs: 'Execution logs sidebar',
|
|
218
|
+
settingsCategories: 'Settings categories',
|
|
219
|
+
searchComponents: 'Search components',
|
|
220
|
+
commandConsole: 'Command Console (`)',
|
|
221
|
+
backToConfiguration: 'Back to configuration',
|
|
222
|
+
// Resize handle labels — keyboard users tab to these.
|
|
223
|
+
resizeLeftSidebar: 'Resize left sidebar',
|
|
224
|
+
resizeRightSidebar: 'Resize right sidebar',
|
|
225
|
+
resizeBottomPanel: 'Resize bottom panel',
|
|
226
|
+
expandSidebar: 'Expand sidebar',
|
|
227
|
+
collapseSidebar: 'Collapse sidebar',
|
|
228
|
+
closePlaygroundModal: 'Close playground modal',
|
|
229
|
+
closeLogsSidebar: 'Close logs sidebar',
|
|
230
|
+
closeConfigPanel: 'Close panel',
|
|
231
|
+
closeConsole: 'Close console',
|
|
232
|
+
swapNode: 'Swap node',
|
|
233
|
+
backToNodeSelection: 'Back to node selection',
|
|
234
|
+
loadSession: ({ name }) => `Load session: ${name}`
|
|
235
|
+
},
|
|
236
|
+
chat: {
|
|
237
|
+
// AIChatPanel labels.
|
|
238
|
+
aiAssistant: 'AI Assistant',
|
|
239
|
+
requiresBackend: 'AI Assistant requires backend configuration',
|
|
240
|
+
loadWorkflow: 'Load a workflow to start chatting',
|
|
241
|
+
helpBuild: 'Ask the AI to help build your workflow',
|
|
242
|
+
placeholder: 'Describe what you want to build...',
|
|
243
|
+
send: 'Send message',
|
|
244
|
+
autoRetry: ({ attempt, max }) => `Auto-retrying (attempt ${attempt}/${max})…`,
|
|
245
|
+
// CommandPreview labels.
|
|
246
|
+
commandPreview: {
|
|
247
|
+
ariaLabel: 'Command preview',
|
|
248
|
+
applying: 'Applying…',
|
|
249
|
+
applied: 'Applied',
|
|
250
|
+
dismissed: 'Dismissed',
|
|
251
|
+
applyAll: 'Apply All',
|
|
252
|
+
cancel: 'Cancel'
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
playground: {
|
|
256
|
+
chat: {
|
|
257
|
+
placeholder: 'Type your message...',
|
|
258
|
+
predefinedRun: 'Run workflow'
|
|
259
|
+
},
|
|
260
|
+
states: {
|
|
261
|
+
viewOnlyTitle: 'View only',
|
|
262
|
+
viewOnlyText: 'This playground is in view-only mode. No inputs are available.',
|
|
263
|
+
newSessionTitle: 'New session',
|
|
264
|
+
newSessionText: 'Test your flow with a prompt',
|
|
265
|
+
readyTitle: 'Ready to run',
|
|
266
|
+
readyText: 'Click Run to execute your workflow',
|
|
267
|
+
processing: 'Processing...',
|
|
268
|
+
viewOnlyHelp: 'View-only mode. Workflow execution is controlled externally.'
|
|
269
|
+
},
|
|
270
|
+
actions: {
|
|
271
|
+
stopTitle: 'Stop execution',
|
|
272
|
+
stop: 'Stop',
|
|
273
|
+
sendTitle: 'Send message',
|
|
274
|
+
send: 'Send',
|
|
275
|
+
runTitle: 'Run workflow',
|
|
276
|
+
runWaitingTitle: 'Waiting for workflow to be ready...',
|
|
277
|
+
run: 'Run'
|
|
278
|
+
},
|
|
279
|
+
// Message author labels.
|
|
280
|
+
roles: {
|
|
281
|
+
you: 'You',
|
|
282
|
+
assistant: 'Assistant',
|
|
283
|
+
system: 'System',
|
|
284
|
+
log: 'Log',
|
|
285
|
+
message: 'Message'
|
|
286
|
+
},
|
|
287
|
+
messageTooltips: {
|
|
288
|
+
nodeId: ({ id }) => `Node ID: ${id}`,
|
|
289
|
+
executionDuration: 'Execution duration'
|
|
290
|
+
},
|
|
291
|
+
sessions: {
|
|
292
|
+
header: 'Sessions',
|
|
293
|
+
newSession: 'New Session',
|
|
294
|
+
empty: 'No sessions yet',
|
|
295
|
+
clickAgainToConfirm: 'Click again to confirm',
|
|
296
|
+
cancel: 'Cancel',
|
|
297
|
+
deleteSession: 'Delete session',
|
|
298
|
+
// Relative timestamp formatting.
|
|
299
|
+
justNow: 'Just now',
|
|
300
|
+
minutesAgo: ({ n }) => `${n}m ago`,
|
|
301
|
+
hoursAgo: ({ n }) => `${n}h ago`,
|
|
302
|
+
daysAgo: ({ n }) => `${n}d ago`
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
nodes: {
|
|
306
|
+
notes: {
|
|
307
|
+
placeholder: 'Add your notes here...',
|
|
308
|
+
types: {
|
|
309
|
+
info: 'Info',
|
|
310
|
+
warning: 'Warning',
|
|
311
|
+
success: 'Success',
|
|
312
|
+
error: 'Error',
|
|
313
|
+
default: 'Note'
|
|
314
|
+
},
|
|
315
|
+
processing: 'Processing...',
|
|
316
|
+
errorOccurred: 'Error occurred',
|
|
317
|
+
configure: 'Configure note'
|
|
318
|
+
},
|
|
319
|
+
// SvelteFlow node aria-labels — every visible node and port needs a
|
|
320
|
+
// landmark. The `name`/`title` parameter is the rendered display
|
|
321
|
+
// string (already localised by the workflow author or fallback).
|
|
322
|
+
graph: {
|
|
323
|
+
workflowNode: ({ name }) => `Workflow node: ${name}`,
|
|
324
|
+
gatewayNode: ({ title }) => `Gateway node: ${title}`,
|
|
325
|
+
ideaNode: ({ title }) => `Idea node: ${title}`,
|
|
326
|
+
connectInputPort: ({ name }) => `Connect to ${name} input port`,
|
|
327
|
+
connectOutputPort: ({ name }) => `Connect from ${name} output port`,
|
|
328
|
+
connectBranch: ({ name }) => `Connect from ${name} branch`
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
status: {
|
|
332
|
+
// Pipeline status panel.
|
|
333
|
+
pipeline: {
|
|
334
|
+
refresh: 'Refresh Status',
|
|
335
|
+
refreshing: 'Refreshing...',
|
|
336
|
+
viewLogs: 'View Logs',
|
|
337
|
+
home: 'Home',
|
|
338
|
+
workflows: 'Workflows',
|
|
339
|
+
workflow: 'Workflow',
|
|
340
|
+
pipelines: 'Pipelines',
|
|
341
|
+
pipelineCrumb: ({ id, status }) => `Pipeline ${id} - ${status}`
|
|
342
|
+
},
|
|
343
|
+
// NodeStatusOverlay tooltip content. The `status` parameter is the
|
|
344
|
+
// resolved status label (typically from `getStatusLabel()` so it stays
|
|
345
|
+
// consistent with status icons elsewhere); the wrapper text is localized.
|
|
346
|
+
overlay: {
|
|
347
|
+
tooltip: ({ status, count }) => `${status} - Executed ${count} times`,
|
|
348
|
+
ariaLabel: ({ status }) => `Node execution status: ${status}`,
|
|
349
|
+
statusLabel: 'Status:',
|
|
350
|
+
executionsLabel: 'Executions:',
|
|
351
|
+
lastRunLabel: 'Last Run:',
|
|
352
|
+
durationLabel: 'Duration:',
|
|
353
|
+
errorLabel: 'Error:'
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot deprecation warning helper for the messages migration.
|
|
3
|
+
*
|
|
4
|
+
* Components that previously accepted per-string label props (e.g.
|
|
5
|
+
* `saveLabel`, `cancelLabel`, `placeholder`, `addLabel`) keep accepting them
|
|
6
|
+
* during the v1.x deprecation window. When a consumer passes one explicitly
|
|
7
|
+
* we emit a single console.warn per (component, prop) pair so the noise is
|
|
8
|
+
* bounded even if the prop is rebound on every render.
|
|
9
|
+
*
|
|
10
|
+
* Production builds skip the warning entirely.
|
|
11
|
+
*
|
|
12
|
+
* Removed in v2.0 along with the props themselves.
|
|
13
|
+
*/
|
|
14
|
+
export declare function warnDeprecatedProp(component: string, prop: string, replacement: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* Test-only: clear the warned-once cache so subsequent renders re-emit the
|
|
17
|
+
* warning. Storybook stories and Vitest specs that share a module instance
|
|
18
|
+
* need this to assert the warning fires per case.
|
|
19
|
+
*/
|
|
20
|
+
export declare function __resetDeprecationWarningsForTests(): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot deprecation warning helper for the messages migration.
|
|
3
|
+
*
|
|
4
|
+
* Components that previously accepted per-string label props (e.g.
|
|
5
|
+
* `saveLabel`, `cancelLabel`, `placeholder`, `addLabel`) keep accepting them
|
|
6
|
+
* during the v1.x deprecation window. When a consumer passes one explicitly
|
|
7
|
+
* we emit a single console.warn per (component, prop) pair so the noise is
|
|
8
|
+
* bounded even if the prop is rebound on every render.
|
|
9
|
+
*
|
|
10
|
+
* Production builds skip the warning entirely.
|
|
11
|
+
*
|
|
12
|
+
* Removed in v2.0 along with the props themselves.
|
|
13
|
+
*/
|
|
14
|
+
const warned = new Set();
|
|
15
|
+
export function warnDeprecatedProp(component, prop, replacement) {
|
|
16
|
+
if (import.meta.env.PROD)
|
|
17
|
+
return;
|
|
18
|
+
const key = `${component}.${prop}`;
|
|
19
|
+
if (warned.has(key))
|
|
20
|
+
return;
|
|
21
|
+
warned.add(key);
|
|
22
|
+
// eslint-disable-next-line no-console
|
|
23
|
+
console.warn(`[flowdrop] <${component}> prop \`${prop}\` is deprecated and will be removed in v2.0. ` +
|
|
24
|
+
`Use \`messages\` on <FlowDrop> instead: ${replacement}`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Test-only: clear the warned-once cache so subsequent renders re-emit the
|
|
28
|
+
* warning. Storybook stories and Vitest specs that share a module instance
|
|
29
|
+
* need this to assert the warning fires per case.
|
|
30
|
+
*/
|
|
31
|
+
export function __resetDeprecationWarningsForTests() {
|
|
32
|
+
warned.clear();
|
|
33
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Messages module — typed, overridable, translation-ready user-facing strings.
|
|
3
|
+
*
|
|
4
|
+
* See `./defaults.ts` for the canonical shape, `./context.ts` for the runtime
|
|
5
|
+
* plumbing, and the i18n guide in `apps/docs` for consumer recipes.
|
|
6
|
+
*/
|
|
7
|
+
export { defaultMessages } from './defaults.js';
|
|
8
|
+
export { mergeMessages } from './merge.js';
|
|
9
|
+
export { setMessages, getMessages, m } from './context.js';
|
|
10
|
+
export { warnDeprecatedProp, __resetDeprecationWarningsForTests } from './deprecation.js';
|
|
11
|
+
export type { Messages, MessagesOverride, DeepPartial } from './types.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Messages module — typed, overridable, translation-ready user-facing strings.
|
|
3
|
+
*
|
|
4
|
+
* See `./defaults.ts` for the canonical shape, `./context.ts` for the runtime
|
|
5
|
+
* plumbing, and the i18n guide in `apps/docs` for consumer recipes.
|
|
6
|
+
*/
|
|
7
|
+
export { defaultMessages } from './defaults.js';
|
|
8
|
+
export { mergeMessages } from './merge.js';
|
|
9
|
+
export { setMessages, getMessages, m } from './context.js';
|
|
10
|
+
export { warnDeprecatedProp, __resetDeprecationWarningsForTests } from './deprecation.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep-merge a `MessagesOverride` onto the canonical `Messages` tree.
|
|
3
|
+
*
|
|
4
|
+
* Hand-written rather than pulled from lodash because the shape is known and
|
|
5
|
+
* fixed: leaves are strings or functions, branches are plain objects. The
|
|
6
|
+
* walker is smaller than the lodash import and has no edge cases we don't
|
|
7
|
+
* want.
|
|
8
|
+
*
|
|
9
|
+
* Rules:
|
|
10
|
+
* - `undefined` partial returns the base reference unchanged (cheap path
|
|
11
|
+
* for the no-override case).
|
|
12
|
+
* - Override branches are walked recursively and merged with their base.
|
|
13
|
+
* - Override leaves replace base leaves wholesale. Functions and strings
|
|
14
|
+
* are interchangeable per `DeepPartial` (see `./types.ts`).
|
|
15
|
+
* - Keys not present in the override fall through to the base.
|
|
16
|
+
*
|
|
17
|
+
* Identity preservation: when a subtree of `partial` resolves to values that
|
|
18
|
+
* are already `===` to the corresponding base values (string interning makes
|
|
19
|
+
* this the common case for paraglide-style overrides — `p.save()` returns
|
|
20
|
+
* the same `'Save'` string each call), the base reference is returned
|
|
21
|
+
* unchanged. This stops downstream `$derived(m().branch)` reads in components
|
|
22
|
+
* from invalidating on every parent re-render when the consumer passes an
|
|
23
|
+
* inline `messages={{...}}` literal whose contents are stable but whose
|
|
24
|
+
* outer identity churns. Function leaves still create fresh identities, but
|
|
25
|
+
* they aren't read in render hotspots.
|
|
26
|
+
*/
|
|
27
|
+
import type { Messages, MessagesOverride } from './types.js';
|
|
28
|
+
export declare function mergeMessages(base: Messages, partial: MessagesOverride | undefined): Messages;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep-merge a `MessagesOverride` onto the canonical `Messages` tree.
|
|
3
|
+
*
|
|
4
|
+
* Hand-written rather than pulled from lodash because the shape is known and
|
|
5
|
+
* fixed: leaves are strings or functions, branches are plain objects. The
|
|
6
|
+
* walker is smaller than the lodash import and has no edge cases we don't
|
|
7
|
+
* want.
|
|
8
|
+
*
|
|
9
|
+
* Rules:
|
|
10
|
+
* - `undefined` partial returns the base reference unchanged (cheap path
|
|
11
|
+
* for the no-override case).
|
|
12
|
+
* - Override branches are walked recursively and merged with their base.
|
|
13
|
+
* - Override leaves replace base leaves wholesale. Functions and strings
|
|
14
|
+
* are interchangeable per `DeepPartial` (see `./types.ts`).
|
|
15
|
+
* - Keys not present in the override fall through to the base.
|
|
16
|
+
*
|
|
17
|
+
* Identity preservation: when a subtree of `partial` resolves to values that
|
|
18
|
+
* are already `===` to the corresponding base values (string interning makes
|
|
19
|
+
* this the common case for paraglide-style overrides — `p.save()` returns
|
|
20
|
+
* the same `'Save'` string each call), the base reference is returned
|
|
21
|
+
* unchanged. This stops downstream `$derived(m().branch)` reads in components
|
|
22
|
+
* from invalidating on every parent re-render when the consumer passes an
|
|
23
|
+
* inline `messages={{...}}` literal whose contents are stable but whose
|
|
24
|
+
* outer identity churns. Function leaves still create fresh identities, but
|
|
25
|
+
* they aren't read in render hotspots.
|
|
26
|
+
*/
|
|
27
|
+
const isPlainObject = (value) => typeof value === 'object' &&
|
|
28
|
+
value !== null &&
|
|
29
|
+
!Array.isArray(value) &&
|
|
30
|
+
typeof value !== 'function';
|
|
31
|
+
export function mergeMessages(base, partial) {
|
|
32
|
+
if (partial === undefined)
|
|
33
|
+
return base;
|
|
34
|
+
return mergeNode(base, partial);
|
|
35
|
+
}
|
|
36
|
+
function mergeNode(base, partial) {
|
|
37
|
+
if (!isPlainObject(base) || !isPlainObject(partial))
|
|
38
|
+
return partial ?? base;
|
|
39
|
+
let out = null;
|
|
40
|
+
for (const key of Object.keys(partial)) {
|
|
41
|
+
const baseChild = base[key];
|
|
42
|
+
const partialChild = partial[key];
|
|
43
|
+
const merged = isPlainObject(baseChild) && isPlainObject(partialChild)
|
|
44
|
+
? mergeNode(baseChild, partialChild)
|
|
45
|
+
: (partialChild ?? baseChild);
|
|
46
|
+
if (merged !== baseChild) {
|
|
47
|
+
if (out === null)
|
|
48
|
+
out = { ...base };
|
|
49
|
+
out[key] = merged;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out ?? base;
|
|
53
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type machinery for the FlowDrop messages system.
|
|
3
|
+
*
|
|
4
|
+
* `Messages` is the canonical shape of every user-facing string in the library.
|
|
5
|
+
* It is derived from `defaultMessages` so the defaults file is the single
|
|
6
|
+
* source of truth — adding a key there immediately widens the type.
|
|
7
|
+
*
|
|
8
|
+
* Consumers pass `DeepPartial<Messages>` to override any subset. Function
|
|
9
|
+
* leaves (parameterised strings) may be overridden with either a function of
|
|
10
|
+
* the same signature OR a plain string for cases where the override doesn't
|
|
11
|
+
* need the parameters.
|
|
12
|
+
*/
|
|
13
|
+
import type { defaultMessages } from './defaults.js';
|
|
14
|
+
export type Messages = typeof defaultMessages;
|
|
15
|
+
type AnyFn = (...args: any[]) => unknown;
|
|
16
|
+
/**
|
|
17
|
+
* A recursive partial that:
|
|
18
|
+
* - allows skipping any key at any level,
|
|
19
|
+
* - preserves function leaves with their original signature — overrides
|
|
20
|
+
* of parameterised messages MUST stay functions, because call sites
|
|
21
|
+
* invoke them with the params object,
|
|
22
|
+
* - widens string leaves to `string` so `as const` literal defaults
|
|
23
|
+
* (e.g. `'Cancel'`) accept arbitrary translations.
|
|
24
|
+
*/
|
|
25
|
+
export type DeepPartial<T> = T extends AnyFn ? T : T extends string ? string : T extends object ? {
|
|
26
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
27
|
+
} : T;
|
|
28
|
+
export type MessagesOverride = DeepPartial<Messages>;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type machinery for the FlowDrop messages system.
|
|
3
|
+
*
|
|
4
|
+
* `Messages` is the canonical shape of every user-facing string in the library.
|
|
5
|
+
* It is derived from `defaultMessages` so the defaults file is the single
|
|
6
|
+
* source of truth — adding a key there immediately widens the type.
|
|
7
|
+
*
|
|
8
|
+
* Consumers pass `DeepPartial<Messages>` to override any subset. Function
|
|
9
|
+
* leaves (parameterised strings) may be overridden with either a function of
|
|
10
|
+
* the same signature OR a plain string for cases where the override doesn't
|
|
11
|
+
* need the parameters.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -75,6 +75,19 @@ export declare function hasDraft(storageKey: string): boolean;
|
|
|
75
75
|
* @returns Draft metadata, or null if not found
|
|
76
76
|
*/
|
|
77
77
|
export declare function getDraftMetadata(storageKey: string): DraftMetadata | null;
|
|
78
|
+
/**
|
|
79
|
+
* Clear all FlowDrop drafts from localStorage
|
|
80
|
+
*
|
|
81
|
+
* Removes every key beginning with `flowdrop:draft:`. Intended to be called
|
|
82
|
+
* from a host application's logout handler so workflow drafts do not persist
|
|
83
|
+
* across user sessions on shared devices.
|
|
84
|
+
*
|
|
85
|
+
* @param extraKeys - Additional explicit keys to remove. Pass any custom
|
|
86
|
+
* `draftStorageKey` values configured at mount time so they are cleared
|
|
87
|
+
* alongside the default-prefixed keys.
|
|
88
|
+
* @returns The number of entries removed.
|
|
89
|
+
*/
|
|
90
|
+
export declare function clearAllDrafts(extraKeys?: readonly string[]): number;
|
|
78
91
|
/**
|
|
79
92
|
* Draft auto-save manager
|
|
80
93
|
*
|
|
@@ -120,6 +120,42 @@ export function getDraftMetadata(storageKey) {
|
|
|
120
120
|
const draft = loadDraft(storageKey);
|
|
121
121
|
return draft?.metadata ?? null;
|
|
122
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Clear all FlowDrop drafts from localStorage
|
|
125
|
+
*
|
|
126
|
+
* Removes every key beginning with `flowdrop:draft:`. Intended to be called
|
|
127
|
+
* from a host application's logout handler so workflow drafts do not persist
|
|
128
|
+
* across user sessions on shared devices.
|
|
129
|
+
*
|
|
130
|
+
* @param extraKeys - Additional explicit keys to remove. Pass any custom
|
|
131
|
+
* `draftStorageKey` values configured at mount time so they are cleared
|
|
132
|
+
* alongside the default-prefixed keys.
|
|
133
|
+
* @returns The number of entries removed.
|
|
134
|
+
*/
|
|
135
|
+
export function clearAllDrafts(extraKeys = []) {
|
|
136
|
+
try {
|
|
137
|
+
const keysToRemove = new Set();
|
|
138
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
139
|
+
const key = localStorage.key(i);
|
|
140
|
+
if (key && key.startsWith(`${STORAGE_KEY_PREFIX}:`)) {
|
|
141
|
+
keysToRemove.add(key);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
for (const key of extraKeys) {
|
|
145
|
+
if (localStorage.getItem(key) !== null) {
|
|
146
|
+
keysToRemove.add(key);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
for (const key of keysToRemove) {
|
|
150
|
+
localStorage.removeItem(key);
|
|
151
|
+
}
|
|
152
|
+
return keysToRemove.size;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
logger.warn('Failed to clear drafts from localStorage:', error);
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
123
159
|
/**
|
|
124
160
|
* Draft auto-save manager
|
|
125
161
|
*
|
package/dist/styles/base.css
CHANGED
|
@@ -39,13 +39,22 @@
|
|
|
39
39
|
--xy-controls-button-border-color: var(--fd-controls-button-border, var(--fd-border));
|
|
40
40
|
--xy-controls-box-shadow: var(--fd-controls-box-shadow, 0 0 2px 1px rgba(0, 0, 0, 0.08));
|
|
41
41
|
|
|
42
|
-
--xy-minimap-background-color: var(--fd-minimap-bg, var(--fd-
|
|
42
|
+
--xy-minimap-background-color: var(--fd-minimap-bg, var(--fd-muted));
|
|
43
43
|
--xy-minimap-mask-background-color: var(--fd-minimap-mask-bg, var(--fd-backdrop));
|
|
44
44
|
--xy-minimap-mask-stroke-color: var(--fd-minimap-mask-stroke, var(--fd-border));
|
|
45
45
|
--xy-minimap-mask-stroke-width: var(--fd-minimap-mask-stroke-width, 1);
|
|
46
|
-
--xy-minimap-node-background-color: var(--fd-minimap-node-bg, var(--fd-muted));
|
|
47
|
-
--xy-minimap-node-stroke-color: var(--fd-minimap-node-stroke, var(--fd-border-
|
|
48
|
-
--xy-minimap-node-stroke-width: var(--fd-minimap-node-stroke-width,
|
|
46
|
+
--xy-minimap-node-background-color: var(--fd-minimap-node-bg, var(--fd-muted-foreground));
|
|
47
|
+
--xy-minimap-node-stroke-color: var(--fd-minimap-node-stroke, var(--fd-border-strong));
|
|
48
|
+
--xy-minimap-node-stroke-width: var(--fd-minimap-node-stroke-width, 1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Minimap: render as a clearly bounded floating panel so users don't mistake
|
|
52
|
+
it for the canvas and pan unintentionally when clicking/dragging on it. */
|
|
53
|
+
.svelte-flow .svelte-flow__minimap {
|
|
54
|
+
border: 1px solid var(--fd-border-strong);
|
|
55
|
+
border-radius: var(--fd-radius-md);
|
|
56
|
+
box-shadow: var(--fd-shadow-md);
|
|
57
|
+
overflow: hidden;
|
|
49
58
|
}
|
|
50
59
|
|
|
51
60
|
/* Flow node handles: 20px connection area, 12px visible circle (::before)
|
package/dist/svelte-app.d.ts
CHANGED
|
@@ -109,6 +109,17 @@ export interface MountedFlowDropApp {
|
|
|
109
109
|
* Trigger export operation (downloads JSON)
|
|
110
110
|
*/
|
|
111
111
|
export: () => void;
|
|
112
|
+
/**
|
|
113
|
+
* Clear all FlowDrop workflow drafts from `localStorage`.
|
|
114
|
+
*
|
|
115
|
+
* Removes every key beginning with `flowdrop:draft:` plus the custom
|
|
116
|
+
* `draftStorageKey` configured at mount time (if any). Call this from
|
|
117
|
+
* the host application's logout handler so drafts do not persist across
|
|
118
|
+
* user sessions on shared devices.
|
|
119
|
+
*
|
|
120
|
+
* @returns The number of entries removed.
|
|
121
|
+
*/
|
|
122
|
+
clearAllDrafts: () => number;
|
|
112
123
|
}
|
|
113
124
|
/**
|
|
114
125
|
* Mount the full FlowDrop App with navbar, sidebars, and workflow editor
|