@d34dman/flowdrop 0.0.29 → 0.0.30

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.
@@ -25,25 +25,34 @@
25
25
  let categories = $derived(getCategories());
26
26
 
27
27
  /**
28
- * Get all unique categories from node types
28
+ * Get all unique categories from node types, preserving API order
29
+ * Categories appear in the order their first node appears in the API response
29
30
  */
30
31
  function getCategories(): NodeCategory[] {
31
32
  const nodes = props.nodes || [];
32
33
  if (nodes.length === 0) return [];
33
- const categories = new SvelteSet<NodeCategory>();
34
- nodes.forEach((node) => categories.add(node.category));
35
- return Array.from(categories).sort();
34
+ // Use a Set to track uniqueness while preserving insertion order
35
+ const seen = new SvelteSet<NodeCategory>();
36
+ const orderedCategories: NodeCategory[] = [];
37
+ for (const node of nodes) {
38
+ if (!seen.has(node.category)) {
39
+ seen.add(node.category);
40
+ orderedCategories.push(node.category);
41
+ }
42
+ }
43
+ return orderedCategories;
36
44
  }
37
45
 
38
46
  /**
39
47
  * Filter node types based on search query and selected category
48
+ * Preserves the API order - no client-side sorting applied
40
49
  */
41
50
  function getFilteredNodes(): NodeMetadata[] {
42
51
  // Use actual node types from props
43
52
  let filtered = props.nodes || [];
44
53
 
45
54
  // Filter by category
46
- if (selectedCategory !== 'all') {
55
+ if (selectedCategory !== "all") {
47
56
  filtered = filtered.filter((node) => node.category === selectedCategory);
48
57
  }
49
58
 
@@ -58,8 +67,8 @@
58
67
  );
59
68
  }
60
69
 
61
- // Create a new array and sort it to avoid mutating the original
62
- return [...filtered].sort((a, b) => a.name.localeCompare(b.name));
70
+ // Return filtered results preserving API order
71
+ return filtered;
63
72
  }
64
73
 
65
74
  /**
@@ -149,12 +158,11 @@
149
158
 
150
159
  /**
151
160
  * Get node types for category
161
+ * Preserves the API order - no client-side sorting applied
152
162
  */
153
163
  function getNodesForCategory(category: NodeCategory): NodeMetadata[] {
154
164
  const nodes = props.nodes || [];
155
- return [...nodes]
156
- .filter((node) => node.category === category)
157
- .sort((a, b) => a.name.localeCompare(b.name));
165
+ return nodes.filter((node) => node.category === category);
158
166
  }
159
167
 
160
168
  /**
@@ -37,6 +37,7 @@
37
37
  } from '../helpers/workflowEditorHelper.js';
38
38
  import type { NodeExecutionInfo } from '../types/index.js';
39
39
  import { areNodeArraysEqual, areEdgeArraysEqual, throttle } from '../utils/performanceUtils.js';
40
+ import { Toaster } from 'svelte-5-french-toast';
40
41
 
41
42
  interface Props {
42
43
  nodes?: NodeMetadata[];
@@ -457,6 +458,9 @@
457
458
  </div>
458
459
  </SvelteFlowProvider>
459
460
 
461
+ <!-- Toast notifications container -->
462
+ <Toaster position="bottom-center" />
463
+
460
464
  <style>
461
465
  .flowdrop-workflow-editor {
462
466
  display: flex;
@@ -7,7 +7,7 @@
7
7
  <script lang="ts">
8
8
  import { Position, Handle } from '@xyflow/svelte';
9
9
  import Icon from '@iconify/svelte';
10
- import { getDataTypeColor } from '../../utils/colors';
10
+ import { getDataTypeColor, getColorVariants } from '../../utils/colors';
11
11
  import type { NodeMetadata } from '../../types/index.js';
12
12
 
13
13
  interface ToolNodeParameter {
@@ -64,6 +64,19 @@
64
64
  '1.0.0'
65
65
  );
66
66
 
67
+ // Generate color variants for theming (light tint for background, border tint for borders)
68
+ let colorVariants = $derived(getColorVariants(toolColor));
69
+
70
+ // Build inline style string for CSS custom properties
71
+ // This allows per-node color overrides while defaulting to global CSS variables
72
+ let nodeStyle = $derived(
73
+ [
74
+ `--flowdrop-tool-node-color: ${colorVariants.base}`,
75
+ `--flowdrop-tool-node-color-light: ${colorVariants.light}`,
76
+ `--flowdrop-tool-node-color-border: ${colorVariants.border}`
77
+ ].join('; ')
78
+ );
79
+
67
80
  // Check for tool interface ports in metadata
68
81
  let hasToolInputPort = $derived(
69
82
  props.data.metadata?.inputs?.some((port) => port.dataType === 'tool') || false
@@ -128,6 +141,7 @@
128
141
  class:flowdrop-tool-node--selected={props.selected}
129
142
  class:flowdrop-tool-node--processing={props.isProcessing}
130
143
  class:flowdrop-tool-node--error={props.isError}
144
+ style={nodeStyle}
131
145
  onclick={handleClick}
132
146
  ondblclick={handleDoubleClick}
133
147
  onkeydown={handleKeydown}
@@ -138,7 +152,7 @@
138
152
  <div class="flowdrop-tool-node__header">
139
153
  <div class="flowdrop-tool-node__header-content">
140
154
  <!-- Tool Icon -->
141
- <div class="flowdrop-tool-node__icon-container" style="background-color: {toolColor}">
155
+ <div class="flowdrop-tool-node__icon-container">
142
156
  <Icon icon={toolIcon} class="flowdrop-tool-node__icon" />
143
157
  </div>
144
158
 
@@ -214,7 +228,7 @@
214
228
 
215
229
  .flowdrop-tool-node--selected {
216
230
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
217
- border: 2px solid #f59e0b;
231
+ border: 2px solid var(--flowdrop-tool-node-color);
218
232
  }
219
233
 
220
234
  .flowdrop-tool-node--processing {
@@ -228,9 +242,9 @@
228
242
 
229
243
  .flowdrop-tool-node__header {
230
244
  padding: 1rem;
231
- background-color: #fffbeb;
245
+ background-color: var(--flowdrop-tool-node-color-light);
232
246
  border-radius: 0.75rem;
233
- border: 1px solid #fcd34d;
247
+ border: 1px solid var(--flowdrop-tool-node-color-border);
234
248
  }
235
249
 
236
250
  .flowdrop-tool-node__header-content {
@@ -248,6 +262,7 @@
248
262
  height: 2.5rem;
249
263
  border-radius: 0.5rem;
250
264
  flex-shrink: 0;
265
+ background-color: var(--flowdrop-tool-node-color);
251
266
  }
252
267
 
253
268
  .flowdrop-tool-node__info {
@@ -271,7 +286,7 @@
271
286
  }
272
287
 
273
288
  .flowdrop-tool-node__badge {
274
- background-color: #f59e0b;
289
+ background-color: var(--flowdrop-tool-node-color);
275
290
  color: white;
276
291
  font-size: 0.625rem;
277
292
  font-weight: 700;
@@ -375,11 +390,11 @@
375
390
 
376
391
  /* Metadata port hover effects */
377
392
  :global(.svelte-flow__node-tool .svelte-flow__handle:hover) {
378
- box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.3) !important;
393
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--flowdrop-tool-node-color) 30%, transparent) !important;
379
394
  }
380
395
 
381
396
  :global(.svelte-flow__node-tool .svelte-flow__handle:focus) {
382
- outline: 2px solid #f59e0b !important;
397
+ outline: 2px solid var(--flowdrop-tool-node-color) !important;
383
398
  outline-offset: 2px !important;
384
399
  }
385
400
  </style>
@@ -1157,6 +1157,11 @@
1157
1157
  --flowdrop-edge-data-color-hover: var(--color-ref-gray-500);
1158
1158
  --flowdrop-edge-data-color-selected: var(--color-ref-violet-600);
1159
1159
 
1160
+ /* Tool node theming tokens */
1161
+ --flowdrop-tool-node-color: var(--color-ref-amber-500);
1162
+ --flowdrop-tool-node-color-light: var(--color-ref-amber-50);
1163
+ --flowdrop-tool-node-color-border: var(--color-ref-amber-300);
1164
+
1160
1165
  /* Semantic text color tokens */
1161
1166
  --flowdrop-text-color-error: var(--color-ref-red-600);
1162
1167
  --flowdrop-text-color-success: var(--color-ref-green-600);
@@ -148,3 +148,45 @@ export declare function isArrayDataType(dataType: string): boolean;
148
148
  * @returns The element type (e.g., "string") or null if not an array
149
149
  */
150
150
  export declare function getArrayElementType(arrayDataType: string): string | null;
151
+ /**
152
+ * Parse a hex color string to RGB components
153
+ * @param hex - Hex color string (e.g., "#f59e0b" or "f59e0b")
154
+ * @returns Object with r, g, b values (0-255) or null if invalid
155
+ */
156
+ export declare function hexToRgb(hex: string): {
157
+ r: number;
158
+ g: number;
159
+ b: number;
160
+ } | null;
161
+ /**
162
+ * Convert RGB components to hex color string
163
+ * @param r - Red component (0-255)
164
+ * @param g - Green component (0-255)
165
+ * @param b - Blue component (0-255)
166
+ * @returns Hex color string with # prefix
167
+ */
168
+ export declare function rgbToHex(r: number, g: number, b: number): string;
169
+ /**
170
+ * Generate a light tint of a color (similar to Tailwind's -50 shade)
171
+ * Creates a very light background-friendly version of the color
172
+ * @param hex - Base hex color string
173
+ * @returns Light tint hex color string
174
+ */
175
+ export declare function getLightTint(hex: string): string;
176
+ /**
177
+ * Generate a border tint of a color (similar to Tailwind's -300 shade)
178
+ * Creates a medium-light version suitable for borders
179
+ * @param hex - Base hex color string
180
+ * @returns Border tint hex color string
181
+ */
182
+ export declare function getBorderTint(hex: string): string;
183
+ /**
184
+ * Generate color variants for theming a component
185
+ * @param baseColor - Base hex color string
186
+ * @returns Object with base, light, and border color variants
187
+ */
188
+ export declare function getColorVariants(baseColor: string): {
189
+ base: string;
190
+ light: string;
191
+ border: string;
192
+ };
@@ -302,3 +302,80 @@ export function getArrayElementType(arrayDataType) {
302
302
  }
303
303
  return null;
304
304
  }
305
+ /**
306
+ * Parse a hex color string to RGB components
307
+ * @param hex - Hex color string (e.g., "#f59e0b" or "f59e0b")
308
+ * @returns Object with r, g, b values (0-255) or null if invalid
309
+ */
310
+ export function hexToRgb(hex) {
311
+ const cleanHex = hex.replace(/^#/, "");
312
+ if (!/^[0-9A-Fa-f]{6}$/.test(cleanHex)) {
313
+ return null;
314
+ }
315
+ const r = parseInt(cleanHex.substring(0, 2), 16);
316
+ const g = parseInt(cleanHex.substring(2, 4), 16);
317
+ const b = parseInt(cleanHex.substring(4, 6), 16);
318
+ return { r, g, b };
319
+ }
320
+ /**
321
+ * Convert RGB components to hex color string
322
+ * @param r - Red component (0-255)
323
+ * @param g - Green component (0-255)
324
+ * @param b - Blue component (0-255)
325
+ * @returns Hex color string with # prefix
326
+ */
327
+ export function rgbToHex(r, g, b) {
328
+ const toHex = (value) => {
329
+ const clamped = Math.max(0, Math.min(255, Math.round(value)));
330
+ return clamped.toString(16).padStart(2, "0");
331
+ };
332
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
333
+ }
334
+ /**
335
+ * Generate a light tint of a color (similar to Tailwind's -50 shade)
336
+ * Creates a very light background-friendly version of the color
337
+ * @param hex - Base hex color string
338
+ * @returns Light tint hex color string
339
+ */
340
+ export function getLightTint(hex) {
341
+ const rgb = hexToRgb(hex);
342
+ if (!rgb) {
343
+ return "#fffbeb"; // Fallback to amber-50
344
+ }
345
+ // Mix with white at 95% to create a very light tint
346
+ const mixRatio = 0.95;
347
+ const r = rgb.r + (255 - rgb.r) * mixRatio;
348
+ const g = rgb.g + (255 - rgb.g) * mixRatio;
349
+ const b = rgb.b + (255 - rgb.b) * mixRatio;
350
+ return rgbToHex(r, g, b);
351
+ }
352
+ /**
353
+ * Generate a border tint of a color (similar to Tailwind's -300 shade)
354
+ * Creates a medium-light version suitable for borders
355
+ * @param hex - Base hex color string
356
+ * @returns Border tint hex color string
357
+ */
358
+ export function getBorderTint(hex) {
359
+ const rgb = hexToRgb(hex);
360
+ if (!rgb) {
361
+ return "#fcd34d"; // Fallback to amber-300
362
+ }
363
+ // Mix with white at 60% to create a medium-light tint
364
+ const mixRatio = 0.6;
365
+ const r = rgb.r + (255 - rgb.r) * mixRatio;
366
+ const g = rgb.g + (255 - rgb.g) * mixRatio;
367
+ const b = rgb.b + (255 - rgb.b) * mixRatio;
368
+ return rgbToHex(r, g, b);
369
+ }
370
+ /**
371
+ * Generate color variants for theming a component
372
+ * @param baseColor - Base hex color string
373
+ * @returns Object with base, light, and border color variants
374
+ */
375
+ export function getColorVariants(baseColor) {
376
+ return {
377
+ base: baseColor,
378
+ light: getLightTint(baseColor),
379
+ border: getBorderTint(baseColor)
380
+ };
381
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@d34dman/flowdrop",
3
3
  "license": "MIT",
4
4
  "private": false,
5
- "version": "0.0.29",
5
+ "version": "0.0.30",
6
6
  "scripts": {
7
7
  "dev": "vite dev",
8
8
  "build": "vite build && npm run prepack",