@process.co/element-dev-server 0.0.1 → 0.0.2
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/.process/eds.css +18 -0
- package/.process/index.tsx +262 -56
- package/.process/vite-env.d.ts +3 -0
- package/.process/vite.config.cjs +292 -14
- package/README.md +185 -64
- package/dist/chunk-JIIM2FST.js +1 -0
- package/dist/chunk-TP2HSEPI.js +1 -0
- package/dist/cli.js +1 -1
- package/dist/ui.js +1 -1
- package/package.json +36 -2
- package/src/ui.tsx +38 -4
package/.process/eds.css
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
body {
|
|
2
|
+
background-color: #f0f0f0;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.eds-container {
|
|
6
|
+
background-color: #f0f0f0;
|
|
7
|
+
padding: 20px;
|
|
8
|
+
border-radius: 10px;
|
|
9
|
+
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.eds-container h2 {
|
|
13
|
+
color: #333;
|
|
14
|
+
font-size: 24px;
|
|
15
|
+
font-weight: 600;
|
|
16
|
+
margin-bottom: 20px;
|
|
17
|
+
text-align: center;
|
|
18
|
+
}
|
package/.process/index.tsx
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { ErrorBoundary } from 'react-error-boundary';
|
|
4
|
+
import { DevProvider, DevToolbar } from '@process.co/ui/dev';
|
|
5
|
+
import { Button } from '@process.co/ui';
|
|
3
6
|
|
|
4
|
-
|
|
7
|
+
// Import the CSS from @process.co/ui so it's available for all components
|
|
8
|
+
import '@process.co/ui/styles';
|
|
9
|
+
import './eds.css';
|
|
5
10
|
|
|
6
11
|
// This will be dynamically loaded based on the selected element
|
|
7
12
|
interface ElementComponent {
|
|
@@ -9,6 +14,9 @@ interface ElementComponent {
|
|
|
9
14
|
[key: string]: any;
|
|
10
15
|
}
|
|
11
16
|
|
|
17
|
+
// Storage key for persisting component value
|
|
18
|
+
const VALUE_STORAGE_KEY = 'process-dev:component-value';
|
|
19
|
+
|
|
12
20
|
function DevServer() {
|
|
13
21
|
const [ElementComponent, setElementComponent] = useState<any>(null);
|
|
14
22
|
const [loading, setLoading] = useState(true);
|
|
@@ -16,26 +24,66 @@ function DevServer() {
|
|
|
16
24
|
|
|
17
25
|
|
|
18
26
|
const [readonly, setReadonly] = useState(false);
|
|
19
|
-
|
|
27
|
+
|
|
28
|
+
// Persist value to localStorage for stable IDs across reloads
|
|
29
|
+
const [value, setValue] = useState<any>(() => {
|
|
30
|
+
try {
|
|
31
|
+
const stored = localStorage.getItem(VALUE_STORAGE_KEY);
|
|
32
|
+
if (stored) {
|
|
33
|
+
return JSON.parse(stored);
|
|
34
|
+
}
|
|
35
|
+
} catch (e) {
|
|
36
|
+
console.warn('Failed to load value from localStorage:', e);
|
|
37
|
+
}
|
|
38
|
+
return {};
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Save value to localStorage when it changes
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
try {
|
|
44
|
+
localStorage.setItem(VALUE_STORAGE_KEY, JSON.stringify(value));
|
|
45
|
+
} catch (e) {
|
|
46
|
+
console.warn('Failed to save value to localStorage:', e);
|
|
47
|
+
}
|
|
48
|
+
}, [value]);
|
|
20
49
|
|
|
21
50
|
const handleReadonly = () => {
|
|
22
51
|
setReadonly(!readonly);
|
|
23
52
|
}
|
|
24
53
|
|
|
54
|
+
interface ImportMetaEnv {
|
|
55
|
+
// readonly VITE_ELEMENT?: string;
|
|
56
|
+
readonly VITE_ELEMENT_PATH?: string;
|
|
57
|
+
readonly VITE_ELEMENT_TYPE?: string;
|
|
58
|
+
readonly VITE_ELEMENT_NAME?: string;
|
|
59
|
+
readonly VITE_ACTION_SIGNAL_KEY?: string;
|
|
60
|
+
readonly VITE_PROPERTY_KEY?: string;
|
|
61
|
+
readonly VITE_PROPERTY_TYPE?: string;
|
|
62
|
+
readonly VITE_PROPERTY_UI_PATH?: string;
|
|
63
|
+
readonly VITE_MODULE_PATH?: string;
|
|
64
|
+
readonly VITE_UI_DIRECTORY?: string;
|
|
65
|
+
readonly VITE_ELEMENT_MODULE?: { actions: any[], signals: any[] };
|
|
66
|
+
readonly VITE_CURRENT_ACTION_SIGNAL?: { ui: string };
|
|
67
|
+
readonly VITE_SELECTED_PROPERTY?: { propertyKey: string, type: string, uiPath: string, propertyData: any };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
25
71
|
useEffect(() => {
|
|
26
72
|
const loadElement = async () => {
|
|
27
73
|
try {
|
|
28
74
|
|
|
75
|
+
const env = (import.meta as any).env as ImportMetaEnv;
|
|
76
|
+
|
|
29
77
|
// Get element path and type from environment variables (passed by CLI)
|
|
30
|
-
const elementPath =
|
|
31
|
-
const elementType =
|
|
32
|
-
const elementName =
|
|
33
|
-
const actionSignalKey =
|
|
34
|
-
const propertyKey =
|
|
35
|
-
const propertyType =
|
|
36
|
-
const propertyUIPath =
|
|
37
|
-
const modulePath =
|
|
38
|
-
const uiDirectory =
|
|
78
|
+
const elementPath = env.VITE_ELEMENT_PATH;
|
|
79
|
+
const elementType = env.VITE_ELEMENT_TYPE || 'action';
|
|
80
|
+
const elementName = env.VITE_ELEMENT_NAME;
|
|
81
|
+
const actionSignalKey = env.VITE_ACTION_SIGNAL_KEY;
|
|
82
|
+
const propertyKey = env.VITE_PROPERTY_KEY;
|
|
83
|
+
const propertyType = env.VITE_PROPERTY_TYPE;
|
|
84
|
+
const propertyUIPath = env.VITE_PROPERTY_UI_PATH;
|
|
85
|
+
const modulePath = env.VITE_MODULE_PATH;
|
|
86
|
+
const uiDirectory = env.VITE_UI_DIRECTORY;
|
|
39
87
|
|
|
40
88
|
// console.log('Element data:', {
|
|
41
89
|
// elementPath,
|
|
@@ -67,9 +115,9 @@ function DevServer() {
|
|
|
67
115
|
// debugger;
|
|
68
116
|
|
|
69
117
|
// Use the complete element data from the compatibility module passed via environment variables
|
|
70
|
-
const elementModule =
|
|
71
|
-
const currentActionSignal =
|
|
72
|
-
const selectedProperty =
|
|
118
|
+
const elementModule = env.VITE_ELEMENT_MODULE || {} as { actions: any[], signals: any[] };
|
|
119
|
+
const currentActionSignal = env.VITE_CURRENT_ACTION_SIGNAL || {} as { ui: string };
|
|
120
|
+
const selectedProperty = env.VITE_SELECTED_PROPERTY || {} as { propertyKey: string, type: string, uiPath: string, propertyData: any };
|
|
73
121
|
|
|
74
122
|
// console.log('Element module from compatibility:', elementModule);
|
|
75
123
|
// console.log('Current action/signal:', currentActionSignal);
|
|
@@ -226,52 +274,210 @@ function DevServer() {
|
|
|
226
274
|
<h2>Element Development Server</h2>
|
|
227
275
|
|
|
228
276
|
<h3>Rendered Component</h3>
|
|
229
|
-
<div style={{ marginBottom: '10px' }}>
|
|
230
|
-
<
|
|
277
|
+
<div style={{ marginBottom: '10px', display: 'flex', gap: '8px' }}>
|
|
278
|
+
<Button variant="outline"
|
|
279
|
+
size="sm"
|
|
231
280
|
onClick={handleReadonly}
|
|
232
281
|
>
|
|
233
282
|
{readonly ? 'Make Editable' : 'Make Read Only'}
|
|
234
|
-
</
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
) : (
|
|
247
|
-
<div style={{ color: '#666', fontStyle: 'italic' }}>
|
|
248
|
-
Component is not a valid React component. Type: {typeof ElementComponent}
|
|
249
|
-
<br />
|
|
250
|
-
<small>This might be the element metadata instead of the UI component.</small>
|
|
251
|
-
</div>
|
|
252
|
-
)}
|
|
253
|
-
</div>
|
|
254
|
-
<div style={{ marginBottom: '10px' }}>
|
|
255
|
-
<h3>Value</h3>
|
|
256
|
-
<pre style={{ backgroundColor: '#f5f5f5', padding: '10px', overflow: 'auto' }}>
|
|
257
|
-
{JSON.stringify(value, null, 2)}
|
|
258
|
-
</pre>
|
|
259
|
-
</div>
|
|
260
|
-
<div style={{ border: '1px solid #ccc', padding: '20px', marginTop: '20px', marginBottom: '20px', backgroundColor: '#f8f9fa' }}>
|
|
261
|
-
<h3>Loaded Component Information</h3>
|
|
262
|
-
<p><strong>Element:</strong> {import.meta.env.VITE_ELEMENT_NAME}</p>
|
|
263
|
-
<p><strong>Type:</strong> {import.meta.env.VITE_ELEMENT_TYPE}</p>
|
|
264
|
-
<p><strong>Action/Signal:</strong> {import.meta.env.VITE_ACTION_SIGNAL_KEY}</p>
|
|
265
|
-
<p><strong>Module Path:</strong> {import.meta.env.VITE_ELEMENT_PATH}</p>
|
|
266
|
-
<p><strong>UI Directory:</strong> {import.meta.env.VITE_UI_DIRECTORY || 'Not available'}</p>
|
|
267
|
-
|
|
268
|
-
<h3>Component Details</h3>
|
|
269
|
-
<pre style={{ backgroundColor: '#f5f5f5', padding: '10px', overflow: 'auto' }}>
|
|
270
|
-
{JSON.stringify(ElementComponent, null, 2)}
|
|
271
|
-
</pre>
|
|
272
|
-
|
|
283
|
+
</Button>
|
|
284
|
+
{/* <Button
|
|
285
|
+
onClick={() => {
|
|
286
|
+
if (confirm('Clear component value? This will reset all data and IDs.')) {
|
|
287
|
+
setValue({});
|
|
288
|
+
localStorage.removeItem(VALUE_STORAGE_KEY);
|
|
289
|
+
}
|
|
290
|
+
}}
|
|
291
|
+
style={{ backgroundColor: '#fee2e2', color: '#991b1b' }}
|
|
292
|
+
>
|
|
293
|
+
Clear Value
|
|
294
|
+
</Button> */}
|
|
273
295
|
</div>
|
|
274
|
-
|
|
296
|
+
<DevProvider storageKey="process-dev" >
|
|
297
|
+
<div style={{ border: '2px solid #007acc', padding: '20px', borderRadius: '8px', backgroundColor: '#f8f9fa' }}>
|
|
298
|
+
|
|
299
|
+
<ErrorBoundary fallbackRender={({ error, resetErrorBoundary }) => (
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
<div style={{
|
|
303
|
+
border: '2px solid #dc2626',
|
|
304
|
+
borderRadius: '8px',
|
|
305
|
+
padding: '20px',
|
|
306
|
+
margin: '10px 0',
|
|
307
|
+
backgroundColor: '#fef2f2',
|
|
308
|
+
fontFamily: 'Monaco, Consolas, "Courier New", monospace',
|
|
309
|
+
fontSize: '14px'
|
|
310
|
+
}}>
|
|
311
|
+
<div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px' }}>
|
|
312
|
+
<span style={{
|
|
313
|
+
fontSize: '20px',
|
|
314
|
+
marginRight: '8px'
|
|
315
|
+
}}>💥</span>
|
|
316
|
+
<h3 style={{
|
|
317
|
+
margin: 0,
|
|
318
|
+
color: '#dc2626',
|
|
319
|
+
fontSize: '18px',
|
|
320
|
+
fontWeight: 'bold'
|
|
321
|
+
}}>
|
|
322
|
+
Component Error
|
|
323
|
+
</h3>
|
|
324
|
+
</div>
|
|
325
|
+
|
|
326
|
+
<div style={{
|
|
327
|
+
backgroundColor: '#1f2937',
|
|
328
|
+
color: '#f9fafb',
|
|
329
|
+
padding: '16px',
|
|
330
|
+
borderRadius: '4px',
|
|
331
|
+
marginBottom: '16px',
|
|
332
|
+
overflow: 'auto',
|
|
333
|
+
maxHeight: '300px'
|
|
334
|
+
}}>
|
|
335
|
+
<div style={{ color: '#fca5a5', fontWeight: 'bold', marginBottom: '8px' }}>
|
|
336
|
+
{error.name}: {error.message}
|
|
337
|
+
</div>
|
|
338
|
+
{error.stack && (
|
|
339
|
+
<pre style={{
|
|
340
|
+
margin: 0,
|
|
341
|
+
whiteSpace: 'pre-wrap',
|
|
342
|
+
fontSize: '12px',
|
|
343
|
+
lineHeight: '1.4'
|
|
344
|
+
}}>
|
|
345
|
+
{error.stack}
|
|
346
|
+
</pre>
|
|
347
|
+
)}
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
<div style={{ marginBottom: '16px' }}>
|
|
351
|
+
<h4 style={{ margin: '0 0 8px 0', color: '#374151', fontSize: '14px' }}>
|
|
352
|
+
Error Details:
|
|
353
|
+
</h4>
|
|
354
|
+
<div style={{
|
|
355
|
+
backgroundColor: '#f9fafb',
|
|
356
|
+
padding: '12px',
|
|
357
|
+
borderRadius: '4px',
|
|
358
|
+
fontSize: '12px'
|
|
359
|
+
}}>
|
|
360
|
+
<div><strong>Error Type:</strong> {error.name}</div>
|
|
361
|
+
<div><strong>Message:</strong> {error.message}</div>
|
|
362
|
+
{error.cause && <div><strong>Cause:</strong> {String(error.cause)}</div>}
|
|
363
|
+
<div><strong>Timestamp:</strong> {new Date().toISOString()}</div>
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
|
|
367
|
+
<div style={{
|
|
368
|
+
display: 'flex',
|
|
369
|
+
gap: '12px',
|
|
370
|
+
alignItems: 'center'
|
|
371
|
+
}}>
|
|
372
|
+
<button
|
|
373
|
+
onClick={resetErrorBoundary}
|
|
374
|
+
style={{
|
|
375
|
+
backgroundColor: '#dc2626',
|
|
376
|
+
color: 'white',
|
|
377
|
+
border: 'none',
|
|
378
|
+
padding: '8px 16px',
|
|
379
|
+
borderRadius: '4px',
|
|
380
|
+
cursor: 'pointer',
|
|
381
|
+
fontSize: '14px',
|
|
382
|
+
fontWeight: '500'
|
|
383
|
+
}}
|
|
384
|
+
onMouseOver={(e) => (e.target as HTMLElement).style.backgroundColor = '#b91c1c'}
|
|
385
|
+
onMouseOut={(e) => (e.target as HTMLElement).style.backgroundColor = '#dc2626'}
|
|
386
|
+
>
|
|
387
|
+
🔄 Try Again
|
|
388
|
+
</button>
|
|
389
|
+
|
|
390
|
+
<button
|
|
391
|
+
onClick={() => {
|
|
392
|
+
console.error('Component Error Details:', {
|
|
393
|
+
error,
|
|
394
|
+
stack: error.stack,
|
|
395
|
+
timestamp: new Date().toISOString(),
|
|
396
|
+
userAgent: navigator.userAgent,
|
|
397
|
+
url: window.location.href
|
|
398
|
+
});
|
|
399
|
+
alert('Error details logged to console');
|
|
400
|
+
}}
|
|
401
|
+
style={{
|
|
402
|
+
backgroundColor: '#6b7280',
|
|
403
|
+
color: 'white',
|
|
404
|
+
border: 'none',
|
|
405
|
+
padding: '8px 16px',
|
|
406
|
+
borderRadius: '4px',
|
|
407
|
+
cursor: 'pointer',
|
|
408
|
+
fontSize: '14px',
|
|
409
|
+
fontWeight: '500'
|
|
410
|
+
}}
|
|
411
|
+
onMouseOver={(e) => (e.target as HTMLElement).style.backgroundColor = '#4b5563'}
|
|
412
|
+
onMouseOut={(e) => (e.target as HTMLElement).style.backgroundColor = '#6b7280'}
|
|
413
|
+
>
|
|
414
|
+
📋 Log to Console
|
|
415
|
+
</button>
|
|
416
|
+
</div>
|
|
417
|
+
|
|
418
|
+
<div style={{
|
|
419
|
+
marginTop: '16px',
|
|
420
|
+
padding: '12px',
|
|
421
|
+
backgroundColor: '#eff6ff',
|
|
422
|
+
borderRadius: '4px',
|
|
423
|
+
fontSize: '12px',
|
|
424
|
+
color: '#1e40af'
|
|
425
|
+
}}>
|
|
426
|
+
<strong>💡 Debug Tips:</strong>
|
|
427
|
+
<ul style={{ margin: '8px 0 0 0', paddingLeft: '20px' }}>
|
|
428
|
+
<li>Check the console for detailed error information</li>
|
|
429
|
+
<li>Verify all required props are being passed to the component</li>
|
|
430
|
+
<li>Check for undefined variables or missing imports</li>
|
|
431
|
+
<li>Use browser dev tools to inspect the component state</li>
|
|
432
|
+
</ul>
|
|
433
|
+
</div>
|
|
434
|
+
</div>
|
|
435
|
+
)}>
|
|
436
|
+
{typeof ElementComponent === 'function' ? (
|
|
437
|
+
<ElementComponent
|
|
438
|
+
fieldName="devField"
|
|
439
|
+
fieldId="dev-field-1"
|
|
440
|
+
value={value}
|
|
441
|
+
onChange={(newValue: any) => setValue(newValue)}
|
|
442
|
+
onBlur={() => console.log('Component onBlur')}
|
|
443
|
+
readonly={readonly}
|
|
444
|
+
/>
|
|
445
|
+
) : (
|
|
446
|
+
<div style={{ color: '#666', fontStyle: 'italic' }}>
|
|
447
|
+
Component is not a valid React component. Type: {typeof ElementComponent}
|
|
448
|
+
<br />
|
|
449
|
+
<small>This might be the element metadata instead of the UI component.</small>
|
|
450
|
+
</div>
|
|
451
|
+
)}
|
|
452
|
+
</ErrorBoundary>
|
|
453
|
+
</div>
|
|
454
|
+
{/* <div style={{ marginBottom: '10px' }}>
|
|
455
|
+
<h3>Value</h3>
|
|
456
|
+
<pre style={{ backgroundColor: '#f5f5f5', padding: '10px', overflow: 'auto' }}>
|
|
457
|
+
{JSON.stringify(value, null, 2)}
|
|
458
|
+
</pre>
|
|
459
|
+
</div> */}
|
|
460
|
+
<div style={{ marginTop: '10px' }}>
|
|
461
|
+
<DevToolbar />
|
|
462
|
+
</div>
|
|
463
|
+
|
|
464
|
+
<div style={{ border: '1px solid #ccc', padding: '20px', marginTop: '20px', marginBottom: '20px', backgroundColor: '#f8f9fa' }}>
|
|
465
|
+
<h3>Loaded Component Information</h3>
|
|
466
|
+
<p><strong>Element:</strong> {import.meta.env.VITE_ELEMENT_NAME}</p>
|
|
467
|
+
<p><strong>Type:</strong> {import.meta.env.VITE_ELEMENT_TYPE}</p>
|
|
468
|
+
<p><strong>Action/Signal:</strong> {import.meta.env.VITE_ACTION_SIGNAL_KEY}</p>
|
|
469
|
+
<p><strong>Module Path:</strong> {import.meta.env.VITE_ELEMENT_PATH}</p>
|
|
470
|
+
<p><strong>UI Directory:</strong> {import.meta.env.VITE_UI_DIRECTORY || 'Not available'}</p>
|
|
471
|
+
|
|
472
|
+
<h3>Component Details</h3>
|
|
473
|
+
<pre style={{ backgroundColor: '#f5f5f5', padding: '10px', overflow: 'auto' }}>
|
|
474
|
+
{JSON.stringify(ElementComponent, null, 2)}
|
|
475
|
+
</pre>
|
|
476
|
+
|
|
477
|
+
</div>
|
|
478
|
+
</DevProvider>
|
|
479
|
+
|
|
480
|
+
</div >
|
|
275
481
|
);
|
|
276
482
|
}
|
|
277
483
|
|
package/.process/vite-env.d.ts
CHANGED
|
@@ -11,6 +11,9 @@ interface ImportMetaEnv {
|
|
|
11
11
|
readonly VITE_PROPERTY_UI_PATH?: string;
|
|
12
12
|
readonly VITE_MODULE_PATH?: string;
|
|
13
13
|
readonly VITE_UI_DIRECTORY?: string;
|
|
14
|
+
readonly VITE_ELEMENT_MODULE?: string;
|
|
15
|
+
readonly VITE_CURRENT_ACTION_SIGNAL?: string;
|
|
16
|
+
readonly VITE_SELECTED_PROPERTY?: string;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
interface ImportMeta {
|
package/.process/vite.config.cjs
CHANGED
|
@@ -4,6 +4,66 @@ const { defineConfig } = require('vite');
|
|
|
4
4
|
const react = require('@vitejs/plugin-react');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
// Find where element-dev-server is installed
|
|
9
|
+
// This could be in the user's node_modules or in a monorepo
|
|
10
|
+
const elementDevServerRoot = path.resolve(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
// Debug mode - set PROC_DEV_DEBUG=true to see detailed logging
|
|
13
|
+
const DEBUG = process.env.PROC_DEV_DEBUG === 'true';
|
|
14
|
+
|
|
15
|
+
// Find the local @process.co/ui source for development (monorepo override)
|
|
16
|
+
const localUISource = path.resolve(elementDevServerRoot, '..', 'ui', 'src');
|
|
17
|
+
const localUIPackageRoot = path.resolve(elementDevServerRoot, '..', 'ui');
|
|
18
|
+
const localUIBuiltCSS = path.resolve(localUIPackageRoot, 'css', 'ui.css');
|
|
19
|
+
const hasLocalUISource = fs.existsSync(localUISource);
|
|
20
|
+
if (DEBUG) {
|
|
21
|
+
if (hasLocalUISource) {
|
|
22
|
+
console.log('🎨 Using local @process.co/ui source from monorepo');
|
|
23
|
+
console.log(' Source:', localUISource);
|
|
24
|
+
console.log(' CSS:', localUIBuiltCSS);
|
|
25
|
+
console.log(' CSS exists?', fs.existsSync(localUIBuiltCSS));
|
|
26
|
+
} else {
|
|
27
|
+
console.log('📦 Using published @process.co/ui from npm');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Find the local @process.co/utilities source for development (monorepo override)
|
|
32
|
+
const localUtilitiesSource = path.resolve(elementDevServerRoot, '..', 'utilities', 'src');
|
|
33
|
+
const hasLocalUtilitiesSource = fs.existsSync(localUtilitiesSource);
|
|
34
|
+
if (DEBUG) {
|
|
35
|
+
if (hasLocalUtilitiesSource) {
|
|
36
|
+
console.log('🔧 Using local @process.co/utilities source from monorepo');
|
|
37
|
+
console.log(' Source:', localUtilitiesSource);
|
|
38
|
+
} else {
|
|
39
|
+
console.log('📦 Using published @process.co/utilities from npm');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Function to find node_modules that contains our dependencies
|
|
44
|
+
function findNodeModulesWithDeps() {
|
|
45
|
+
const possiblePaths = [
|
|
46
|
+
// In the element-dev-server package itself
|
|
47
|
+
path.join(elementDevServerRoot, 'node_modules'),
|
|
48
|
+
// One level up (for pnpm hoisting in user's project)
|
|
49
|
+
path.join(elementDevServerRoot, '..', '..'),
|
|
50
|
+
// Two levels up (for npm/yarn in user's project)
|
|
51
|
+
path.join(elementDevServerRoot, '..', '..', '..'),
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
for (const basePath of possiblePaths) {
|
|
55
|
+
const testPath = path.join(basePath, '@radix-ui', 'react-slot');
|
|
56
|
+
if (fs.existsSync(testPath)) {
|
|
57
|
+
return basePath;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Default to element-dev-server's node_modules
|
|
62
|
+
return path.join(elementDevServerRoot, 'node_modules');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const depsNodeModules = findNodeModulesWithDeps();
|
|
66
|
+
if (DEBUG) console.log('🔍 Resolving UI dependencies from:', depsNodeModules);
|
|
7
67
|
|
|
8
68
|
// Access environment variables passed from CLI
|
|
9
69
|
const elementPath = process.env.VITE_ELEMENT_PATH;
|
|
@@ -28,11 +88,93 @@ const propertyUIPath = process.env.VITE_PROPERTY_UI_PATH;
|
|
|
28
88
|
// console.log('Vite config index.html path:', path.resolve(__dirname, 'index.html'));
|
|
29
89
|
// console.log('Vite config index.tsx path:', path.resolve(__dirname, 'index.tsx'));
|
|
30
90
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
91
|
+
// Build plugins array
|
|
92
|
+
const plugins = [react()];
|
|
93
|
+
|
|
94
|
+
// Add CSS resolver if in monorepo
|
|
95
|
+
if (hasLocalUISource) {
|
|
96
|
+
if (DEBUG) console.log('🔧 Adding ui-css-resolver plugin');
|
|
97
|
+
plugins.push({
|
|
98
|
+
name: 'ui-css-resolver',
|
|
99
|
+
enforce: 'pre',
|
|
100
|
+
resolveId(source, importer) {
|
|
101
|
+
if (DEBUG) console.log('🔍 ui-css-resolver checking:', source);
|
|
102
|
+
if (source === '@process.co/ui/styles') {
|
|
103
|
+
if (DEBUG) console.log('✅ Resolving @process.co/ui/styles to:', localUIBuiltCSS);
|
|
104
|
+
return localUIBuiltCSS;
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
if (DEBUG) console.log('✅ ui-css-resolver plugin added, total plugins:', plugins.length);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Add UI package alias resolver if in monorepo
|
|
113
|
+
if (hasLocalUISource) {
|
|
114
|
+
plugins.push({
|
|
115
|
+
name: 'ui-package-alias-resolver',
|
|
116
|
+
enforce: 'pre',
|
|
117
|
+
resolveId(source, importer) {
|
|
118
|
+
// Only process @/ imports
|
|
119
|
+
if (!source.startsWith('@/')) return null;
|
|
120
|
+
|
|
121
|
+
// Only process if importer is from the UI source
|
|
122
|
+
if (!importer) return null;
|
|
123
|
+
|
|
124
|
+
// Convert importer to absolute path if it's relative
|
|
125
|
+
let absoluteImporter = importer;
|
|
126
|
+
if (!path.isAbsolute(importer)) {
|
|
127
|
+
// If it's a relative path like "../../ui/src/...", resolve it from the .process directory
|
|
128
|
+
// __dirname is the .process directory where this config file lives
|
|
129
|
+
absoluteImporter = path.resolve(__dirname, importer);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const normalizedImporter = path.normalize(absoluteImporter);
|
|
133
|
+
const normalizedUISource = path.normalize(localUISource);
|
|
134
|
+
|
|
135
|
+
// Check if the importer is from the UI source
|
|
136
|
+
if (!normalizedImporter.includes(normalizedUISource)) return null;
|
|
137
|
+
|
|
138
|
+
const relativePath = source.substring(2); // Remove '@/'
|
|
139
|
+
const resolvedPath = path.join(localUISource, relativePath);
|
|
140
|
+
|
|
141
|
+
// Try common extensions
|
|
142
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx'];
|
|
143
|
+
for (const ext of extensions) {
|
|
144
|
+
const testPath = resolvedPath + ext;
|
|
145
|
+
if (fs.existsSync(testPath)) {
|
|
146
|
+
const stats = fs.statSync(testPath);
|
|
147
|
+
if (stats.isFile()) {
|
|
148
|
+
return testPath;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Try without extension (might already have one)
|
|
154
|
+
if (fs.existsSync(resolvedPath)) {
|
|
155
|
+
const stats = fs.statSync(resolvedPath);
|
|
156
|
+
if (stats.isFile()) {
|
|
157
|
+
return resolvedPath;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// It's a directory, try index files
|
|
161
|
+
if (stats.isDirectory()) {
|
|
162
|
+
for (const indexFile of ['index.ts', 'index.tsx', 'index.js', 'index.jsx']) {
|
|
163
|
+
const indexPath = path.join(resolvedPath, indexFile);
|
|
164
|
+
if (fs.existsSync(indexPath)) {
|
|
165
|
+
return indexPath;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
plugins.push({
|
|
177
|
+
name: 'element-virtual-modules',
|
|
36
178
|
resolveId(source) {
|
|
37
179
|
// Main element module
|
|
38
180
|
if (source === '/element-main') {
|
|
@@ -77,9 +219,10 @@ module.exports = defineConfig({
|
|
|
77
219
|
}
|
|
78
220
|
return null;
|
|
79
221
|
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
plugins.push({
|
|
225
|
+
name: 'external-element-loader',
|
|
83
226
|
|
|
84
227
|
configureServer(server) {
|
|
85
228
|
// Set up file watching for the element directory
|
|
@@ -113,6 +256,99 @@ module.exports = defineConfig({
|
|
|
113
256
|
}
|
|
114
257
|
});
|
|
115
258
|
}
|
|
259
|
+
|
|
260
|
+
// Also watch the local @process.co/ui source for hot reloading
|
|
261
|
+
if (hasLocalUISource) {
|
|
262
|
+
if (DEBUG) console.log(`🔍 Setting up file watching for @process.co/ui source: ${localUISource}`);
|
|
263
|
+
server.watcher.add(localUISource);
|
|
264
|
+
|
|
265
|
+
// Watch CSS source files and trigger rebuild
|
|
266
|
+
const cssSourceFiles = [
|
|
267
|
+
path.join(localUISource, 'styles'),
|
|
268
|
+
path.join(localUISource, 'themes')
|
|
269
|
+
];
|
|
270
|
+
cssSourceFiles.forEach(dir => {
|
|
271
|
+
if (fs.existsSync(dir)) {
|
|
272
|
+
server.watcher.add(dir);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
let cssRebuildTimeout = null;
|
|
277
|
+
|
|
278
|
+
server.watcher.on('change', (file) => {
|
|
279
|
+
if (file.startsWith(localUISource)) {
|
|
280
|
+
if (DEBUG) console.log(`🎨 @process.co/ui source file changed: ${file}`);
|
|
281
|
+
|
|
282
|
+
// Check if it's a CSS-related file
|
|
283
|
+
const isCSSFile = file.includes('/styles/') || file.includes('/themes/') || file.endsWith('.css');
|
|
284
|
+
|
|
285
|
+
if (isCSSFile) {
|
|
286
|
+
console.log(`🎨 CSS source changed, rebuilding...`);
|
|
287
|
+
|
|
288
|
+
// Debounce CSS rebuilds
|
|
289
|
+
clearTimeout(cssRebuildTimeout);
|
|
290
|
+
cssRebuildTimeout = setTimeout(async () => {
|
|
291
|
+
try {
|
|
292
|
+
const { exec } = require('child_process');
|
|
293
|
+
const { promisify } = require('util');
|
|
294
|
+
const execAsync = promisify(exec);
|
|
295
|
+
|
|
296
|
+
if (DEBUG) console.log('📦 Rebuilding CSS...');
|
|
297
|
+
await execAsync('pnpm run generate:css', { cwd: localUIPackageRoot });
|
|
298
|
+
console.log('✅ CSS rebuilt');
|
|
299
|
+
|
|
300
|
+
// Invalidate the CSS module and trigger full reload
|
|
301
|
+
const cssModule = server.moduleGraph.getModuleById(localUIBuiltCSS);
|
|
302
|
+
if (cssModule) {
|
|
303
|
+
server.moduleGraph.invalidateModule(cssModule);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
server.ws.send({
|
|
307
|
+
type: 'full-reload',
|
|
308
|
+
path: '*'
|
|
309
|
+
});
|
|
310
|
+
} catch (error) {
|
|
311
|
+
console.error('❌ Failed to rebuild CSS:', error.message);
|
|
312
|
+
}
|
|
313
|
+
}, 500);
|
|
314
|
+
} else {
|
|
315
|
+
// For non-CSS files, just trigger HMR
|
|
316
|
+
const module = server.moduleGraph.getModuleById(file);
|
|
317
|
+
if (module) {
|
|
318
|
+
server.moduleGraph.invalidateModule(module);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
server.ws.send({
|
|
322
|
+
type: 'full-reload',
|
|
323
|
+
path: '*'
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Also watch the local @process.co/utilities source for hot reloading
|
|
331
|
+
if (hasLocalUtilitiesSource) {
|
|
332
|
+
if (DEBUG) console.log(`🔍 Setting up file watching for @process.co/utilities source: ${localUtilitiesSource}`);
|
|
333
|
+
server.watcher.add(localUtilitiesSource);
|
|
334
|
+
|
|
335
|
+
server.watcher.on('change', (file) => {
|
|
336
|
+
if (file.startsWith(localUtilitiesSource)) {
|
|
337
|
+
if (DEBUG) console.log(`🔧 @process.co/utilities source file changed: ${file}`);
|
|
338
|
+
|
|
339
|
+
// Trigger HMR
|
|
340
|
+
const module = server.moduleGraph.getModuleById(file);
|
|
341
|
+
if (module) {
|
|
342
|
+
server.moduleGraph.invalidateModule(module);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
server.ws.send({
|
|
346
|
+
type: 'full-reload',
|
|
347
|
+
path: '*'
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
}
|
|
116
352
|
},
|
|
117
353
|
|
|
118
354
|
resolveId(source, importer) {
|
|
@@ -230,16 +466,28 @@ module.exports = defineConfig({
|
|
|
230
466
|
|
|
231
467
|
return ctx.modules;
|
|
232
468
|
}
|
|
233
|
-
}
|
|
234
|
-
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
module.exports = defineConfig({
|
|
472
|
+
plugins,
|
|
235
473
|
// root is set programmatically in the CLI
|
|
236
474
|
server: {
|
|
237
475
|
port: 5173,
|
|
238
476
|
open: true,
|
|
239
477
|
host: true,
|
|
240
478
|
fs: {
|
|
241
|
-
// Allow serving files from outside the root
|
|
242
|
-
allow: [
|
|
479
|
+
// Allow serving files from outside the root, including our deps node_modules
|
|
480
|
+
allow: [
|
|
481
|
+
'..',
|
|
482
|
+
elementDevServerRoot,
|
|
483
|
+
depsNodeModules,
|
|
484
|
+
// Allow the user's element directory
|
|
485
|
+
...(elementPath ? [elementPath, path.dirname(elementPath)] : []),
|
|
486
|
+
// Allow the local @process.co/ui source for hot reloading
|
|
487
|
+
...(hasLocalUISource ? [localUISource, path.dirname(localUISource)] : []),
|
|
488
|
+
// Allow the local @process.co/utilities source for hot reloading
|
|
489
|
+
...(hasLocalUtilitiesSource ? [localUtilitiesSource, path.dirname(localUtilitiesSource)] : [])
|
|
490
|
+
]
|
|
243
491
|
},
|
|
244
492
|
watch: {
|
|
245
493
|
// Watch external directories for changes
|
|
@@ -257,6 +505,19 @@ module.exports = defineConfig({
|
|
|
257
505
|
resolve: {
|
|
258
506
|
alias: {
|
|
259
507
|
'@': path.resolve(process.cwd(), 'src'),
|
|
508
|
+
// Override @process.co/ui with local monorepo source in dev mode
|
|
509
|
+
// ORDER MATTERS: More specific paths must come BEFORE more general ones!
|
|
510
|
+
...(hasLocalUISource && {
|
|
511
|
+
// Put subpath exports FIRST so they match before the general @process.co/ui
|
|
512
|
+
'@process.co/ui/styles': localUIBuiltCSS,
|
|
513
|
+
'@process.co/ui/fields': path.join(localUISource, 'components', 'fields'),
|
|
514
|
+
'@process.co/ui/dev': path.join(localUISource, 'components', 'dev'),
|
|
515
|
+
'@process.co/ui': localUISource
|
|
516
|
+
}),
|
|
517
|
+
// Override @process.co/utilities with local monorepo source in dev mode
|
|
518
|
+
...(hasLocalUtilitiesSource && {
|
|
519
|
+
'@process.co/utilities': localUtilitiesSource
|
|
520
|
+
}),
|
|
260
521
|
// Dynamically map element paths based on the elementPath from CLI
|
|
261
522
|
...(elementPath && {
|
|
262
523
|
// Map the element directory to a virtual path that Vite can resolve
|
|
@@ -267,10 +528,27 @@ module.exports = defineConfig({
|
|
|
267
528
|
'ui'
|
|
268
529
|
)
|
|
269
530
|
})
|
|
270
|
-
}
|
|
531
|
+
},
|
|
532
|
+
// Resolve modules from the element-dev-server's node_modules
|
|
533
|
+
// This allows the dev server to provide all dependencies
|
|
534
|
+
preserveSymlinks: false,
|
|
271
535
|
},
|
|
536
|
+
// Tell Vite where to find dependencies - use the discovered node_modules
|
|
537
|
+
cacheDir: path.join(depsNodeModules, '.vite'),
|
|
272
538
|
optimizeDeps: {
|
|
273
|
-
include: ['react', 'react-dom']
|
|
539
|
+
include: ['react', 'react-dom', 'clsx', 'tailwind-merge', 'zustand', 'uuid', '@monaco-editor/react', '@fortawesome/react-fontawesome', '@fortawesome/pro-regular-svg-icons', '@fortawesome/pro-solid-svg-icons', '@fortawesome/pro-duotone-svg-icons', '@fortawesome/pro-light-svg-icons', '@radix-ui/react-slot', '@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu', '@radix-ui/react-separator', '@radix-ui/react-tooltip', '@radix-ui/react-popover', '@radix-ui/react-accordion', '@radix-ui/react-tabs', '@radix-ui/react-toggle', '@radix-ui/react-toggle-group', '@radix-ui/react-progress', '@radix-ui/react-radio-group', '@radix-ui/react-scroll-area', '@radix-ui/react-select', '@radix-ui/react-slider', '@radix-ui/react-switch'],
|
|
540
|
+
// Exclude local UI source, utilities source, and external elements from optimization for hot reloading
|
|
541
|
+
exclude: [
|
|
542
|
+
...(hasLocalUISource ? ['@process.co/ui'] : []),
|
|
543
|
+
...(hasLocalUtilitiesSource ? ['@process.co/utilities'] : []),
|
|
544
|
+
...(elementPath ? [elementPath] : [])
|
|
545
|
+
],
|
|
546
|
+
// Force Vite to look in element-dev-server's node_modules for these deps
|
|
547
|
+
esbuildOptions: {
|
|
548
|
+
resolveExtensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs'],
|
|
549
|
+
// Use the discovered node_modules path
|
|
550
|
+
nodePaths: [depsNodeModules]
|
|
551
|
+
}
|
|
274
552
|
},
|
|
275
553
|
// Environment variables will be passed programmatically
|
|
276
554
|
});
|
package/README.md
CHANGED
|
@@ -1,107 +1,228 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @process.co/element-dev-server
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A development harness for previewing and testing Process.co element UI components without needing to set up a full development environment.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## ✨ Features
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- **Zero Configuration**: Just install and run - no need to install UI dependencies separately
|
|
8
|
+
- **Auto-Discovery**: Automatically finds and serves all required UI library dependencies
|
|
9
|
+
- **FontAwesome Pro Included**: All FontAwesome Pro icon sets bundled (if you have access)
|
|
10
|
+
- **Hot Reload**: Instant updates as you modify your element UI components
|
|
11
|
+
- **Interactive Selection**: Visual interface to select elements, actions, and properties to test
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
## 📦 Installation
|
|
10
14
|
|
|
15
|
+
```bash
|
|
16
|
+
# In your element project
|
|
17
|
+
pnpm add -D @process.co/element-dev-server
|
|
11
18
|
```
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
That's it! No need to install:
|
|
21
|
+
- ❌ `@process.co/ui`
|
|
22
|
+
- ❌ `@radix-ui/*` components
|
|
23
|
+
- ❌ `@fortawesome/*` packages
|
|
24
|
+
- ❌ `zustand`, `@monaco-editor/react`, etc.
|
|
14
25
|
|
|
15
|
-
|
|
26
|
+
All dependencies are automatically provided by the dev server! 🎉
|
|
16
27
|
|
|
17
|
-
|
|
28
|
+
## 🚀 Usage
|
|
29
|
+
|
|
30
|
+
### Basic Usage
|
|
18
31
|
|
|
19
32
|
```bash
|
|
33
|
+
npx proc-dev
|
|
34
|
+
```
|
|
20
35
|
|
|
21
|
-
|
|
36
|
+
This will:
|
|
37
|
+
1. Scan your project for elements
|
|
38
|
+
2. Show an interactive menu to select an element
|
|
39
|
+
3. Let you choose an action/signal and property to preview
|
|
40
|
+
4. Launch a Vite dev server at `http://localhost:5173`
|
|
22
41
|
|
|
42
|
+
### What You'll See
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
╭─────────────────────────────────────────╮
|
|
46
|
+
│ Process.co Element Development Server │
|
|
47
|
+
╰─────────────────────────────────────────╯
|
|
48
|
+
|
|
49
|
+
Select an element to develop:
|
|
50
|
+
> process_internal
|
|
51
|
+
my-custom-element
|
|
52
|
+
another-element
|
|
53
|
+
|
|
54
|
+
Select an action/signal:
|
|
55
|
+
> Action: Switch
|
|
56
|
+
Action: Transform
|
|
57
|
+
Signal: DataReceived
|
|
58
|
+
|
|
59
|
+
Select a property to preview:
|
|
60
|
+
> cases (ui.switch)
|
|
61
|
+
defaultValue (text)
|
|
23
62
|
```
|
|
24
63
|
|
|
64
|
+
The dev server will then launch with your selected UI component loaded and ready to test!
|
|
25
65
|
|
|
26
|
-
##
|
|
66
|
+
## 🔍 How It Works
|
|
27
67
|
|
|
28
|
-
|
|
29
|
-
- **Path Validation**: Automatically validates that the provided path exists and is a directory
|
|
30
|
-
- **Element Discovery**: Uses the @process.co/elements library to discover and load element modules
|
|
31
|
-
- **Dev Server Launch**: Launches a Vite development server for the selected element
|
|
32
|
-
- **Smart Directory Detection**: Automatically finds the appropriate dev directory for each element
|
|
68
|
+
### Automatic Dependency Resolution
|
|
33
69
|
|
|
34
|
-
|
|
70
|
+
The dev server uses a smart resolution strategy to find UI dependencies:
|
|
35
71
|
|
|
36
|
-
|
|
72
|
+
1. **Searches multiple locations**:
|
|
73
|
+
- In the element-dev-server package itself
|
|
74
|
+
- One level up (for pnpm hoisting)
|
|
75
|
+
- Two levels up (for npm/yarn nesting)
|
|
37
76
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
77
|
+
2. **Provides all dependencies** including:
|
|
78
|
+
- ✅ `@process.co/ui` - Complete UI library
|
|
79
|
+
- ✅ All `@radix-ui/*` components (18+ packages)
|
|
80
|
+
- ✅ FontAwesome Pro icons (regular, solid, light, duotone)
|
|
81
|
+
- ✅ `@monaco-editor/react` - Code editor
|
|
82
|
+
- ✅ `zustand` - State management
|
|
83
|
+
- ✅ Common utilities (bundled: `clsx`, `tailwind-merge`, `class-variance-authority`)
|
|
42
84
|
|
|
43
|
-
|
|
85
|
+
3. **Logs the resolution**:
|
|
86
|
+
```
|
|
87
|
+
🔍 Resolving UI dependencies from: /path/to/node_modules
|
|
88
|
+
```
|
|
44
89
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
90
|
+
### Vite Configuration
|
|
91
|
+
|
|
92
|
+
The dev server automatically configures Vite to:
|
|
93
|
+
- Allow serving files from outside the project root
|
|
94
|
+
- Resolve modules from the discovered dependency location
|
|
95
|
+
- Pre-bundle and optimize all UI dependencies
|
|
96
|
+
- Watch your element files for changes and hot-reload
|
|
48
97
|
|
|
49
|
-
|
|
50
|
-
pnpm cli
|
|
98
|
+
## 📁 Project Structure Expected
|
|
51
99
|
|
|
52
|
-
|
|
53
|
-
|
|
100
|
+
Your element project should have this structure:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
your-element-project/
|
|
104
|
+
├── package.json
|
|
105
|
+
├── node_modules/
|
|
106
|
+
│ └── @process.co/element-dev-server/ # Installed here
|
|
107
|
+
└── elements/
|
|
108
|
+
└── your-element/
|
|
109
|
+
├── index.ts (or .mts)
|
|
110
|
+
├── actions/
|
|
111
|
+
│ └── someAction/
|
|
112
|
+
│ ├── index.ts
|
|
113
|
+
│ └── ui/
|
|
114
|
+
│ └── someProperty.tsx # Your UI component
|
|
115
|
+
└── signals/
|
|
116
|
+
└── someSignal/
|
|
117
|
+
├── index.ts
|
|
118
|
+
└── ui/
|
|
119
|
+
└── someProperty.tsx
|
|
54
120
|
```
|
|
55
121
|
|
|
56
|
-
##
|
|
122
|
+
## 🎨 Developing UI Components
|
|
123
|
+
|
|
124
|
+
### Example UI Component
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// elements/your-element/actions/transform/ui/config.tsx
|
|
128
|
+
import { Button, Input } from '@process.co/ui';
|
|
129
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
130
|
+
import { faWand } from '@fortawesome/pro-solid-svg-icons';
|
|
131
|
+
|
|
132
|
+
export default function ConfigUI({ value, onChange, readonly }) {
|
|
133
|
+
return (
|
|
134
|
+
<div className="space-y-4">
|
|
135
|
+
<Input
|
|
136
|
+
value={value.name}
|
|
137
|
+
onChange={(e) => onChange({ ...value, name: e.target.value })}
|
|
138
|
+
disabled={readonly}
|
|
139
|
+
placeholder="Enter name..."
|
|
140
|
+
/>
|
|
141
|
+
<Button onClick={() => console.log('Transform!')}>
|
|
142
|
+
<FontAwesomeIcon icon={faWand} className="mr-2" />
|
|
143
|
+
Transform
|
|
144
|
+
</Button>
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
57
149
|
|
|
58
|
-
-
|
|
59
|
-
- A directory containing Process.co element modules (`.mjs` or `.mts` files)
|
|
60
|
-
- Each element should have proper exports with `name` and `type` properties
|
|
61
|
-
- Elements should have a `dev/` directory with a `vite.config.js` file (optional)
|
|
150
|
+
All imports work automatically - no additional setup required!
|
|
62
151
|
|
|
63
|
-
##
|
|
152
|
+
## 🛠️ Troubleshooting
|
|
64
153
|
|
|
65
|
-
|
|
154
|
+
### Dependencies Not Found
|
|
66
155
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
name: 'Example Element',
|
|
71
|
-
type: 'app', // or 'action', 'signal', 'credential'
|
|
72
|
-
description: 'An example element',
|
|
73
|
-
// ... other properties
|
|
74
|
-
};
|
|
156
|
+
If you see errors like:
|
|
157
|
+
```
|
|
158
|
+
ERROR: Could not resolve "@radix-ui/react-slot"
|
|
75
159
|
```
|
|
76
160
|
|
|
77
|
-
|
|
161
|
+
**Solution**: Check the console output for the dependency resolution path:
|
|
162
|
+
```
|
|
163
|
+
🔍 Resolving UI dependencies from: /path/to/node_modules
|
|
164
|
+
```
|
|
78
165
|
|
|
79
|
-
|
|
166
|
+
Verify that path contains the expected packages. If not, try:
|
|
167
|
+
```bash
|
|
168
|
+
rm -rf node_modules
|
|
169
|
+
pnpm install
|
|
170
|
+
```
|
|
80
171
|
|
|
81
|
-
|
|
82
|
-
- **Path is not a directory**: Validates that the path points to a directory
|
|
83
|
-
- **No elements found**: Provides guidance when no valid element modules are found
|
|
84
|
-
- **Module loading errors**: Shows specific errors when element modules fail to load
|
|
172
|
+
### Vite Port Already in Use
|
|
85
173
|
|
|
86
|
-
|
|
174
|
+
The dev server uses port `5173` by default. If it's in use, you'll see an error.
|
|
87
175
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
176
|
+
**Solution**: Stop any other Vite servers or modify the port in `.process/vite.config.cjs`
|
|
177
|
+
|
|
178
|
+
### FontAwesome Icons Not Working
|
|
179
|
+
|
|
180
|
+
If you don't have FontAwesome Pro access, some icons won't be available.
|
|
181
|
+
|
|
182
|
+
**Solution**: The dev server gracefully handles missing FontAwesome packages. If you need specific icon sets, ensure you have access to FontAwesome Pro and they're installed in the monorepo.
|
|
183
|
+
|
|
184
|
+
## 📝 Package Manager Compatibility
|
|
185
|
+
|
|
186
|
+
### pnpm (Recommended) ✅
|
|
187
|
+
Works perfectly with pnpm's hoisting strategy.
|
|
91
188
|
|
|
92
|
-
|
|
93
|
-
|
|
189
|
+
### npm ✅
|
|
190
|
+
Works with npm's nested node_modules.
|
|
94
191
|
|
|
95
|
-
|
|
96
|
-
|
|
192
|
+
### yarn ✅
|
|
193
|
+
Works with yarn's hoisting.
|
|
194
|
+
|
|
195
|
+
## 🔐 FontAwesome Pro
|
|
196
|
+
|
|
197
|
+
If you have FontAwesome Pro access configured in your `.npmrc`:
|
|
198
|
+
|
|
199
|
+
```ini
|
|
200
|
+
@fortawesome:registry=https://npm.fontawesome.com/
|
|
201
|
+
//npm.fontawesome.com/:_authToken=YOUR-TOKEN
|
|
97
202
|
```
|
|
98
203
|
|
|
99
|
-
|
|
204
|
+
The dev server automatically includes these icon sets:
|
|
205
|
+
- `@fortawesome/pro-regular-svg-icons`
|
|
206
|
+
- `@fortawesome/pro-solid-svg-icons`
|
|
207
|
+
- `@fortawesome/pro-light-svg-icons`
|
|
208
|
+
- `@fortawesome/pro-duotone-svg-icons`
|
|
209
|
+
|
|
210
|
+
## 📚 Additional Documentation
|
|
211
|
+
|
|
212
|
+
- [Dependency Resolution](./DEPENDENCY-RESOLUTION.md) - Deep dive into how dependencies are discovered and served
|
|
213
|
+
- [UI Library Peer Dependencies](../ui/PEER_DEPENDENCIES.md) - Complete list of available UI components
|
|
214
|
+
|
|
215
|
+
## 🤝 Contributing
|
|
216
|
+
|
|
217
|
+
When publishing to npm, this package should include:
|
|
218
|
+
- All Radix UI components
|
|
219
|
+
- FontAwesome React wrapper
|
|
220
|
+
- Monaco Editor
|
|
221
|
+
- Zustand
|
|
222
|
+
- The `.process/` directory with Vite config
|
|
100
223
|
|
|
101
|
-
The CLI
|
|
224
|
+
The `tsup` build only bundles the CLI code - dependencies are included via package.json.
|
|
102
225
|
|
|
103
|
-
|
|
104
|
-
- Have proper exports with `name` and `type` properties
|
|
105
|
-
- Can be successfully imported by the `@process.co/elements` library
|
|
226
|
+
## 📄 License
|
|
106
227
|
|
|
107
|
-
|
|
228
|
+
ISC
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useState as y,useEffect as H,useRef as ce}from"react";import{Box as m,Text as e}from"ink";import W from"ink-select-input";import T from"fs";import u from"path";import{createServer as ue}from"vite";import{fileURLToPath as me}from"url";import S from"@process.co/element-dev-support/dist/index.js";import{Fragment as fe,jsx as r,jsxs as o}from"react/jsx-runtime";var Pe=({rootDir:g})=>{let[L,w]=y([]),[E,Q]=y(null),[C,Z]=y([]),[A,ee]=y(null),[j,te]=y([]),[ne,U]=y(null),[K,oe]=y(null),[x,c]=y("loading"),[V,G]=y("elements"),[B,X]=y([]),R=ce(X);R.current=X;let[$,re]=y(null),[pe,ie]=y(null),[se,le]=y(!1),ae=async(a,t,i)=>{try{let l=T.statSync(a).isDirectory()?a:u.dirname(a),s=i==="action"?"actions":"sources",n=u.join(l,s);if(!T.existsSync(n))return null;let p=(await S.importFolderModulesOfType(s,i,l,["common"])).find(d=>d.key===t);if(!p)return null;let P=T.readdirSync(n).filter(d=>{let I=u.join(n,d);return T.statSync(I).isDirectory()}),_=null,M=null;for(let d of P){let I=u.join(n,d),J=[`${d}.mjs`,`${d}.mts`,`${d}.js`,`${d}.ts`,"index.mjs","index.mts","index.js","index.ts"];for(let F of J){let h=u.join(I,F);if(T.existsSync(h))try{let{module:D}=await S.importFromPath(h);if(D.key===t){_=h,M=I;break}}catch{continue}}if(_)break}if(!_)return null;let N=u.join(l,"ui");return p&&p.ui&&(N=u.join(l,"ui",p.ui)),{modulePath:_,uiDir:N}}catch{return null}};H(()=>{(async()=>{try{try{let s=await S.autoDetectElement(g);if(s!=="pipedream"){let n=await S.loadElementPointers(g,s);w([{label:`${n.name} (${n.elementType})`,value:n.name,info:n,path:g}]),c("ready");return}}catch{}let t=T.readdirSync(g,{withFileTypes:!0}),i=[];for(let s of t){let n=u.join(g,s.name);if(s.isDirectory())try{T.readdirSync(n).some(p=>p.endsWith(".mjs")||p.endsWith(".mts")||p.endsWith(".js")||p.endsWith(".ts")||p.endsWith(".tsx")||p.endsWith(".jsx"))&&i.push(n)}catch{}}if(i.length===0){c("no-elements");return}let l=[];for(let s of i)try{let n=await S.loadElementPointers(s,"auto");l.push({label:`${n.name} (${n.elementType})`,value:n.name,info:n,path:s})}catch{}if(l.length>0){w(l),c("ready");return}else c("no-elements")}catch{c("error")}})()},[g]),H(()=>{$&&x==="launching"&&c("dev-server-running")},[$,x]),H(()=>{},[x]);let k=async(a,t,i)=>{if(!a)return;let l=await ae(a.path,t.value,t.type);if(!l){c("error");return}let s=T.statSync(a.path).isDirectory()?a.path:u.dirname(a.path),n=u.join(s,"dev"),O=T.existsSync(n)?n:s,p=me(import.meta.url),P=u.dirname(p),_=u.resolve(P,"../.process/vite.config.cjs"),M=u.join(O,"vite.config.js"),N=u.join(O,"vite.config.ts"),d=_;T.existsSync(M)?d=M:T.existsSync(N)&&(d=N);let I=await S.loadElementPointers(a.path,"auto"),J=I.actions?.find(f=>f.key===t.value)||I.signals?.find(f=>f.key===t.value),F=[u.resolve(process.cwd(),"process-co","ui","src"),u.resolve(P,"..","..","ui","src"),u.resolve(P,"..","ui","src")];console.log("\u{1F50D} Checking for local UI source..."),console.log(" process.cwd():",process.cwd()),console.log(" __dirname:",P);let h=!1;for(let f of F)if(console.log(" Checking path:",f,"exists:",T.existsSync(f)),T.existsSync(f)){h=!0,console.log(" \u2705 Found local UI source at:",f);break}console.log(" hasLocalUISource:",h),le(h),process.env.VITE_ELEMENT_PATH=a.path,process.env.VITE_ELEMENT_TYPE=t.type,process.env.VITE_ELEMENT_NAME=a.info.name,process.env.VITE_ACTION_SIGNAL_KEY=t.value,process.env.VITE_PROPERTY_KEY=i?.propertyKey||"",process.env.VITE_PROPERTY_TYPE=i?.type||"",process.env.VITE_PROPERTY_UI_PATH=i?.uiPath||"",process.env.VITE_MODULE_PATH=l.modulePath,process.env.VITE_UI_DIRECTORY=l.uiDir,process.env.VITE_HAS_LOCAL_UI_SOURCE=h?"true":"false";let D=1;try{let f=await ue({configFile:d,root:u.resolve(P,"../.process"),optimizeDeps:{include:["react","react-dom"],exclude:[a.path]},define:{"import.meta.env.VITE_ELEMENT_PATH":JSON.stringify(a.path),"import.meta.env.VITE_ELEMENT_TYPE":JSON.stringify(t.type),"import.meta.env.VITE_ELEMENT_NAME":JSON.stringify(a.info.name),"import.meta.env.VITE_ACTION_SIGNAL_KEY":JSON.stringify(t.value),"import.meta.env.VITE_PROPERTY_KEY":JSON.stringify(i?.propertyKey||null),"import.meta.env.VITE_PROPERTY_TYPE":JSON.stringify(i?.type||null),"import.meta.env.VITE_PROPERTY_UI_PATH":JSON.stringify(i?.uiPath||null),"import.meta.env.VITE_MODULE_PATH":JSON.stringify(l.modulePath),"import.meta.env.VITE_UI_DIRECTORY":JSON.stringify(l.uiDir),"import.meta.env.VITE_ELEMENT_MODULE":JSON.stringify(I),"import.meta.env.VITE_CURRENT_ACTION_SIGNAL":JSON.stringify(J),"import.meta.env.VITE_SELECTED_PROPERTY":JSON.stringify(i),"import.meta.env.VITE_HAS_LOCAL_UI_SOURCE":JSON.stringify(h)},logLevel:"info",customLogger:{info(v){R.current(b=>[...b,v].slice(-D))},warn(v){console.warn(`[warn] ${v}`),R.current(b=>[...b,`[warn] ${v}`].slice(-D))},error(v){console.error(`[error] ${v}`),R.current(b=>[...b,`[error] ${v}`].slice(-D))},clearScreen(){},hasWarned:!1,warnOnce(v){},hasErrorLogged:()=>!1}});await f.listen();let z=`http://localhost:${f.config.server?.port||5173}`;re(z),ie(`Dev server running at ${z}`);let q=()=>{f.close()};process.on("SIGINT",q),process.on("SIGTERM",q),f.watcher.on("change",v=>{}),c("dev-server-running"),process.stdin.resume()}catch{c("error")}},Y=async a=>{if(V==="elements"){let t=L.find(i=>i.value===a.value);if(!t)return;Q(t),c("loading-actions-signals");try{let i=await S.loadElementPointers(t.path,"auto"),l=[];i.actions&&Array.isArray(i.actions)&&i.actions.forEach((s,n)=>{l.push({label:`Action: ${s.name||s.key}`,value:s.key,type:"action",path:t.path,description:s.description})}),i.signals&&Array.isArray(i.signals)&&i.signals.forEach((s,n)=>{l.push({label:`Signal: ${s.name||s.key}`,value:s.key,type:"signal",path:t.path,description:s.description})}),l.length===0&&l.push({label:"Default Component",value:"default",type:"action",path:t.path,description:"Default component from element"}),Z(l),G("actions-signals"),c("ready")}catch{c("error")}}else if(V==="actions-signals"){let t=C.find(i=>i.value===a.value);if(!t||!E)return;ee(t),c("loading-properties");try{let i=await S.loadElementPointers(E.path,"auto"),l=i.actions?.find(n=>n.key===t.value)||i.signals?.find(n=>n.key===t.value);if(l&&l.ui){U(t.value),c("launching"),k(E,t,null).catch(n=>{c("error")});return}if(!l||!l.props){U(t.value),c("launching");try{await k(E,t,null)}catch{c("error")}return}let s=[];if(l.props.forEach(n=>{n.ui&&s.push({label:`\u{1F3A8} ${n.key} (${n.ui})`,value:`ui-${n.key}`,propertyKey:n.key,type:"ui-variant",uiPath:n.ui,description:n.description,propertyData:n})}),s.length===0){U(t.value),c("launching"),await k(E,t,null);return}te(s),G("properties"),c("ready")}catch{c("error")}}else{let t=j.find(i=>i.value===a.value);if(!t||!A||!E)return;oe(t),U(t.value),c("launching"),await k(E,A,t)}};return x==="loading"?o(m,{flexDirection:"column",marginTop:2,children:[o(e,{children:["\u{1F50D} Loading elements from: ",r(e,{color:"cyan",children:g})]}),r(e,{children:"Loading..."})]}):x==="no-elements"?o(m,{flexDirection:"column",marginTop:2,children:[o(e,{color:"red",children:["\u274C No valid elements found in: ",r(e,{color:"cyan",children:g})]}),r(e,{color:"yellow",children:"Make sure the directory contains valid element modules."}),r(e,{color:"yellow",children:"Supported formats: Pipedream, n8n, Doflo, Process.co"}),r(e,{color:"yellow",children:"Supported file types: .js, .ts, .mjs, .mts, .jsx, .tsx"})]}):x==="error"?o(m,{flexDirection:"column",marginTop:2,children:[o(e,{color:"red",children:["\u274C Error loading elements from: ",r(e,{color:"cyan",children:g})]}),r(e,{color:"yellow",children:"Check that the directory contains valid element modules."})]}):x==="loading-actions-signals"?o(m,{flexDirection:"column",marginTop:2,children:[o(e,{children:["\u{1F50D} Loading actions and signals for '",r(e,{color:"cyan",children:E?.info.name}),"'..."]}),r(e,{children:"Loading..."})]}):x==="loading-properties"?o(m,{flexDirection:"column",marginTop:2,children:[o(e,{children:["\u{1F50D} Loading properties for '",r(e,{color:"cyan",children:A?.label}),"'..."]}),r(e,{children:"Loading..."})]}):x==="launching"?o(m,{flexDirection:"column",marginTop:2,children:[o(e,{color:"green",children:["\u{1F680} Launching dev server for '",r(e,{color:"cyan",children:ne}),"'..."]}),o(e,{children:["Directory: ",r(e,{color:"cyan",children:g})]})]}):x==="dev-server-running"?o(fe,{children:[o(m,{flexDirection:"column",flexShrink:1,borderStyle:"round",margin:2,marginBottom:1,paddingX:2,paddingY:1,borderColor:"#8759F2",children:[o(e,{children:["Server Running: ",r(e,{color:"#01D4E7",underline:!0,children:$})]}),o(e,{children:["Element: ",r(e,{color:"#01D4E7",children:E?.info.name})]}),o(e,{children:["Action/Signal: ",r(e,{color:"#01D4E7",children:A?.label})]}),K?o(e,{children:["Property UI: ",r(e,{color:"#01D4E7",children:K.label})]}):o(e,{children:["UI Mode: ",r(e,{color:"#01D4E7",children:"Action/Signal Level"})]}),se&&o(e,{children:["UI Source: ",r(e,{color:"#8759F2",children:"Local Monorepo (Hot Reload Enabled)"})]}),r(e,{color:"yellow",children:"Press Ctrl+C to stop the server"})]}),o(m,{marginTop:1,marginLeft:4,flexDirection:"column",children:[r(e,{color:"gray",children:"Server Status:"}),B.length>0?B.map((a,t)=>r(e,{color:"gray",children:a},t)):r(e,{color:"gray",children:"Waiting for activity..."})]})]}):V==="properties"?o(m,{flexDirection:"column",children:[o(e,{children:["\u{1F4C1} Element: ",r(e,{color:"cyan",children:E?.info.name})]}),o(e,{children:["\u{1F4CB} Action/Signal: ",r(e,{color:"#01D4E7",children:A?.label})]}),o(e,{children:["Found ",j.length," property(ies):"]}),r(W,{items:j,onSelect:Y})]}):V==="actions-signals"?o(m,{flexDirection:"column",marginTop:2,marginBottom:2,children:[o(e,{children:["\u{1F4C1} Element: ",r(e,{color:"#01D4E7",children:E?.info.name})]}),o(m,{flexDirection:"column",marginTop:1,children:[o(e,{children:["Found ",C.length," action(s)/signal(s):"]}),r(W,{items:C,onSelect:Y})]})]}):o(m,{flexDirection:"column",marginTop:2,marginBottom:2,children:[o(m,{flexDirection:"column",children:[o(e,{children:["\u{1F4C1} Directory: ",r(e,{color:"#01D4E7",children:g})]}),o(m,{flexDirection:"column",marginTop:1,children:[o(e,{children:["Found ",L.length," element(s):"]}),r(W,{items:L,onSelect:Y})]})]}),r(ge,{logs:B})]})},ge=({logs:g})=>g.length?o(m,{flexDirection:"column",marginTop:1,children:[r(e,{color:"gray",children:"Output:"}),g.map((L,w)=>r(e,{color:"gray",children:L},w))]}):null;export{Pe as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useState as d,useEffect as H,useRef as ce}from"react";import{Box as m,Text as e}from"ink";import W from"ink-select-input";import y from"fs";import u from"path";import{createServer as ue}from"vite";import{fileURLToPath as me}from"url";import S from"@process.co/element-dev-support/dist/index.js";import{Fragment as ge,jsx as o,jsxs as r}from"react/jsx-runtime";var Pe=({rootDir:f})=>{let[L,V]=d([]),[T,Q]=d(null),[k,Z]=d([]),[A,ee]=d(null),[B,te]=d([]),[ne,R]=d(null),[K,re]=d(null),[x,c]=d("loading"),[w,G]=d("elements"),[C,X]=d([]),U=ce(X);U.current=X;let[$,oe]=d(null),[pe,ie]=d(null),[se,le]=d(!1),ae=async(a,t,i)=>{try{let l=y.statSync(a).isDirectory()?a:u.dirname(a),s=i==="action"?"actions":"sources",n=u.join(l,s);if(!y.existsSync(n))return null;let g=(await S.importFolderModulesOfType(s,i,l,["common"])).find(p=>p.key===t);if(!g)return null;let P=y.readdirSync(n).filter(p=>{let h=u.join(n,p);return y.statSync(h).isDirectory()}),_=null,j=null;for(let p of P){let h=u.join(n,p),J=[`${p}.mjs`,`${p}.mts`,`${p}.js`,`${p}.ts`,"index.mjs","index.mts","index.js","index.ts"];for(let F of J){let I=u.join(h,F);if(y.existsSync(I))try{let{module:D}=await S.importFromPath(I);if(D.key===t){_=I,j=h;break}}catch{continue}}if(_)break}if(!_)return null;let N=u.join(l,"ui");return g&&g.ui&&(N=u.join(l,"ui",g.ui)),{modulePath:_,uiDir:N}}catch{return null}};H(()=>{(async()=>{try{try{let s=await S.autoDetectElement(f);if(s!=="pipedream"){let n=await S.loadElementPointers(f,s);V([{label:`${n.name} (${n.elementType})`,value:n.name,info:n,path:f}]),c("ready");return}}catch{}let t=y.readdirSync(f,{withFileTypes:!0}),i=[];for(let s of t){let n=u.join(f,s.name);if(s.isDirectory())try{y.readdirSync(n).some(g=>g.endsWith(".mjs")||g.endsWith(".mts")||g.endsWith(".js")||g.endsWith(".ts")||g.endsWith(".tsx")||g.endsWith(".jsx"))&&i.push(n)}catch{}}if(i.length===0){c("no-elements");return}let l=[];for(let s of i)try{let n=await S.loadElementPointers(s,"auto");l.push({label:`${n.name} (${n.elementType})`,value:n.name,info:n,path:s})}catch{}if(l.length>0){V(l),c("ready");return}else c("no-elements")}catch{c("error")}})()},[f]),H(()=>{$&&x==="launching"&&c("dev-server-running")},[$,x]),H(()=>{},[x]);let M=async(a,t,i)=>{if(!a)return;let l=await ae(a.path,t.value,t.type);if(!l){c("error");return}let s=y.statSync(a.path).isDirectory()?a.path:u.dirname(a.path),n=u.join(s,"dev"),O=y.existsSync(n)?n:s,g=me(import.meta.url),P=u.dirname(g),_=u.resolve(P,"../.process/vite.config.cjs"),j=u.join(O,"vite.config.js"),N=u.join(O,"vite.config.ts"),p=_;y.existsSync(j)?p=j:y.existsSync(N)&&(p=N);let h=await S.loadElementPointers(a.path,"auto"),J=h.actions?.find(E=>E.key===t.value)||h.signals?.find(E=>E.key===t.value),F=[u.resolve(process.cwd(),"process-co","ui","src"),u.resolve(P,"..","..","ui","src"),u.resolve(P,"..","ui","src")],I=!1;for(let E of F)if(y.existsSync(E)){I=!0;break}le(I),process.env.VITE_ELEMENT_PATH=a.path,process.env.VITE_ELEMENT_TYPE=t.type,process.env.VITE_ELEMENT_NAME=a.info.name,process.env.VITE_ACTION_SIGNAL_KEY=t.value,process.env.VITE_PROPERTY_KEY=i?.propertyKey||"",process.env.VITE_PROPERTY_TYPE=i?.type||"",process.env.VITE_PROPERTY_UI_PATH=i?.uiPath||"",process.env.VITE_MODULE_PATH=l.modulePath,process.env.VITE_UI_DIRECTORY=l.uiDir,process.env.VITE_HAS_LOCAL_UI_SOURCE=I?"true":"false";let D=1;try{let E=await ue({configFile:p,root:u.resolve(P,"../.process"),optimizeDeps:{include:["react","react-dom"],exclude:[a.path]},define:{"import.meta.env.VITE_ELEMENT_PATH":JSON.stringify(a.path),"import.meta.env.VITE_ELEMENT_TYPE":JSON.stringify(t.type),"import.meta.env.VITE_ELEMENT_NAME":JSON.stringify(a.info.name),"import.meta.env.VITE_ACTION_SIGNAL_KEY":JSON.stringify(t.value),"import.meta.env.VITE_PROPERTY_KEY":JSON.stringify(i?.propertyKey||null),"import.meta.env.VITE_PROPERTY_TYPE":JSON.stringify(i?.type||null),"import.meta.env.VITE_PROPERTY_UI_PATH":JSON.stringify(i?.uiPath||null),"import.meta.env.VITE_MODULE_PATH":JSON.stringify(l.modulePath),"import.meta.env.VITE_UI_DIRECTORY":JSON.stringify(l.uiDir),"import.meta.env.VITE_ELEMENT_MODULE":JSON.stringify(h),"import.meta.env.VITE_CURRENT_ACTION_SIGNAL":JSON.stringify(J),"import.meta.env.VITE_SELECTED_PROPERTY":JSON.stringify(i),"import.meta.env.VITE_HAS_LOCAL_UI_SOURCE":JSON.stringify(I)},logLevel:"info",customLogger:{info(v){U.current(b=>[...b,v].slice(-D))},warn(v){console.warn(`[warn] ${v}`),U.current(b=>[...b,`[warn] ${v}`].slice(-D))},error(v){console.error(`[error] ${v}`),U.current(b=>[...b,`[error] ${v}`].slice(-D))},clearScreen(){},hasWarned:!1,warnOnce(v){},hasErrorLogged:()=>!1}});await E.listen();let z=`http://localhost:${E.config.server?.port||5173}`;oe(z),ie(`Dev server running at ${z}`);let q=()=>{E.close()};process.on("SIGINT",q),process.on("SIGTERM",q),E.watcher.on("change",v=>{}),c("dev-server-running"),process.stdin.resume()}catch{c("error")}},Y=async a=>{if(w==="elements"){let t=L.find(i=>i.value===a.value);if(!t)return;Q(t),c("loading-actions-signals");try{let i=await S.loadElementPointers(t.path,"auto"),l=[];i.actions&&Array.isArray(i.actions)&&i.actions.forEach((s,n)=>{l.push({label:`Action: ${s.name||s.key}`,value:s.key,type:"action",path:t.path,description:s.description})}),i.signals&&Array.isArray(i.signals)&&i.signals.forEach((s,n)=>{l.push({label:`Signal: ${s.name||s.key}`,value:s.key,type:"signal",path:t.path,description:s.description})}),l.length===0&&l.push({label:"Default Component",value:"default",type:"action",path:t.path,description:"Default component from element"}),Z(l),G("actions-signals"),c("ready")}catch{c("error")}}else if(w==="actions-signals"){let t=k.find(i=>i.value===a.value);if(!t||!T)return;ee(t),c("loading-properties");try{let i=await S.loadElementPointers(T.path,"auto"),l=i.actions?.find(n=>n.key===t.value)||i.signals?.find(n=>n.key===t.value);if(l&&l.ui){R(t.value),c("launching"),M(T,t,null).catch(n=>{c("error")});return}if(!l||!l.props){R(t.value),c("launching");try{await M(T,t,null)}catch{c("error")}return}let s=[];if(l.props.forEach(n=>{n.ui&&s.push({label:`\u{1F3A8} ${n.key} (${n.ui})`,value:`ui-${n.key}`,propertyKey:n.key,type:"ui-variant",uiPath:n.ui,description:n.description,propertyData:n})}),s.length===0){R(t.value),c("launching"),await M(T,t,null);return}te(s),G("properties"),c("ready")}catch{c("error")}}else{let t=B.find(i=>i.value===a.value);if(!t||!A||!T)return;re(t),R(t.value),c("launching"),await M(T,A,t)}};return x==="loading"?r(m,{flexDirection:"column",marginTop:2,children:[r(e,{children:["\u{1F50D} Loading elements from: ",o(e,{color:"cyan",children:f})]}),o(e,{children:"Loading..."})]}):x==="no-elements"?r(m,{flexDirection:"column",marginTop:2,children:[r(e,{color:"red",children:["\u274C No valid elements found in: ",o(e,{color:"cyan",children:f})]}),o(e,{color:"yellow",children:"Make sure the directory contains valid element modules."}),o(e,{color:"yellow",children:"Supported formats: Pipedream, n8n, Doflo, Process.co"}),o(e,{color:"yellow",children:"Supported file types: .js, .ts, .mjs, .mts, .jsx, .tsx"})]}):x==="error"?r(m,{flexDirection:"column",marginTop:2,children:[r(e,{color:"red",children:["\u274C Error loading elements from: ",o(e,{color:"cyan",children:f})]}),o(e,{color:"yellow",children:"Check that the directory contains valid element modules."})]}):x==="loading-actions-signals"?r(m,{flexDirection:"column",marginTop:2,children:[r(e,{children:["\u{1F50D} Loading actions and signals for '",o(e,{color:"cyan",children:T?.info.name}),"'..."]}),o(e,{children:"Loading..."})]}):x==="loading-properties"?r(m,{flexDirection:"column",marginTop:2,children:[r(e,{children:["\u{1F50D} Loading properties for '",o(e,{color:"cyan",children:A?.label}),"'..."]}),o(e,{children:"Loading..."})]}):x==="launching"?r(m,{flexDirection:"column",marginTop:2,children:[r(e,{color:"green",children:["\u{1F680} Launching dev server for '",o(e,{color:"cyan",children:ne}),"'..."]}),r(e,{children:["Directory: ",o(e,{color:"cyan",children:f})]})]}):x==="dev-server-running"?r(ge,{children:[r(m,{flexDirection:"column",flexShrink:1,borderStyle:"round",margin:2,marginBottom:1,paddingX:2,paddingY:1,borderColor:"#8759F2",children:[r(e,{children:["Server Running: ",o(e,{color:"#01D4E7",underline:!0,children:$})]}),r(e,{children:["Element: ",o(e,{color:"#01D4E7",children:T?.info.name})]}),r(e,{children:["Action/Signal: ",o(e,{color:"#01D4E7",children:A?.label})]}),K?r(e,{children:["Property UI: ",o(e,{color:"#01D4E7",children:K.label})]}):r(e,{children:["UI Mode: ",o(e,{color:"#01D4E7",children:"Action/Signal Level"})]}),se&&r(e,{children:["UI Source: ",o(e,{color:"#8759F2",children:"Local Monorepo (Hot Reload Enabled)"})]}),o(e,{color:"yellow",children:"Press Ctrl+C to stop the server"})]}),r(m,{marginTop:1,marginLeft:4,flexDirection:"column",children:[o(e,{color:"gray",children:"Server Status:"}),C.length>0?C.map((a,t)=>o(e,{color:"gray",children:a},t)):o(e,{color:"gray",children:"Waiting for activity..."})]})]}):w==="properties"?r(m,{flexDirection:"column",children:[r(e,{children:["\u{1F4C1} Element: ",o(e,{color:"cyan",children:T?.info.name})]}),r(e,{children:["\u{1F4CB} Action/Signal: ",o(e,{color:"#01D4E7",children:A?.label})]}),r(e,{children:["Found ",B.length," property(ies):"]}),o(W,{items:B,onSelect:Y})]}):w==="actions-signals"?r(m,{flexDirection:"column",marginTop:2,marginBottom:2,children:[r(e,{children:["\u{1F4C1} Element: ",o(e,{color:"#01D4E7",children:T?.info.name})]}),r(m,{flexDirection:"column",marginTop:1,children:[r(e,{children:["Found ",k.length," action(s)/signal(s):"]}),o(W,{items:k,onSelect:Y})]})]}):r(m,{flexDirection:"column",marginTop:2,marginBottom:2,children:[r(m,{flexDirection:"column",children:[r(e,{children:["\u{1F4C1} Directory: ",o(e,{color:"#01D4E7",children:f})]}),r(m,{flexDirection:"column",marginTop:1,children:[r(e,{children:["Found ",L.length," element(s):"]}),o(W,{items:L,onSelect:Y})]})]}),o(fe,{logs:C})]})},fe=({logs:f})=>f.length?r(m,{flexDirection:"column",marginTop:1,children:[o(e,{color:"gray",children:"Output:"}),f.map((L,V)=>o(e,{color:"gray",children:L},V))]}):null;export{Pe as a};
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{b as t}from"./chunk-QPYNK3X7.js";import{a as r}from"./chunk-
|
|
2
|
+
import{b as t}from"./chunk-QPYNK3X7.js";import{a as r}from"./chunk-TP2HSEPI.js";import{render as p}from"ink";import c from"meow";import m from"path";import i from"fs";import{Fragment as f,jsx as o,jsxs as d}from"react/jsx-runtime";process.stdout.write("\x1Bc");var s=c(`
|
|
3
3
|
Usage
|
|
4
4
|
$ process-element [path]
|
|
5
5
|
|
package/dist/ui.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a}from"./chunk-
|
|
1
|
+
import{a}from"./chunk-TP2HSEPI.js";export{a as DevUI};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@process.co/element-dev-server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Helper Library for developing elements for Process.co",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"registry": "https://registry.npmjs.org",
|
|
23
23
|
"scope": "@process.co"
|
|
24
24
|
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/process-co/npm-element-dev-server.git"
|
|
28
|
+
},
|
|
25
29
|
"release": {
|
|
26
30
|
"branches": [
|
|
27
31
|
"main"
|
|
@@ -46,9 +50,36 @@
|
|
|
46
50
|
},
|
|
47
51
|
"license": "ISC",
|
|
48
52
|
"dependencies": {
|
|
53
|
+
"@fortawesome/pro-duotone-svg-icons": "^6.7.2",
|
|
54
|
+
"@fortawesome/pro-light-svg-icons": "^6.7.2",
|
|
55
|
+
"@fortawesome/pro-regular-svg-icons": "^6.7.2",
|
|
56
|
+
"@fortawesome/pro-solid-svg-icons": "^6.7.2",
|
|
57
|
+
"@fortawesome/react-fontawesome": "^0.2.2",
|
|
58
|
+
"@monaco-editor/react": "^4.7.0",
|
|
49
59
|
"@process.co/element-dev-support": "github:process-co/npm-element-dev-support#main",
|
|
60
|
+
"@process.co/ui": "workspace:0.0.0-development",
|
|
61
|
+
"@process.co/utilities": "workspace:0.0.0-development",
|
|
62
|
+
"uuid": "^11.1.0",
|
|
63
|
+
"@radix-ui/react-accordion": "^1.2.3",
|
|
64
|
+
"@radix-ui/react-dialog": "^1.1.6",
|
|
65
|
+
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
|
66
|
+
"@radix-ui/react-popover": "^1.1.6",
|
|
67
|
+
"@radix-ui/react-progress": "^1.1.2",
|
|
68
|
+
"@radix-ui/react-radio-group": "^1.2.3",
|
|
69
|
+
"@radix-ui/react-scroll-area": "^1.2.3",
|
|
70
|
+
"@radix-ui/react-select": "^2.1.6",
|
|
71
|
+
"@radix-ui/react-separator": "^1.1.2",
|
|
72
|
+
"@radix-ui/react-slider": "^1.2.3",
|
|
73
|
+
"@radix-ui/react-slot": "^1.1.2",
|
|
74
|
+
"@radix-ui/react-switch": "^1.1.3",
|
|
75
|
+
"@radix-ui/react-tabs": "^1.1.3",
|
|
76
|
+
"@radix-ui/react-toggle": "^1.1.2",
|
|
77
|
+
"@radix-ui/react-toggle-group": "^1.1.2",
|
|
78
|
+
"@radix-ui/react-tooltip": "^1.1.8",
|
|
50
79
|
"@vitejs/plugin-react": "^4.3.4",
|
|
51
80
|
"axios": "^1.8.4",
|
|
81
|
+
"class-variance-authority": "^0.7.1",
|
|
82
|
+
"clsx": "^2.1.1",
|
|
52
83
|
"ink": "^6.0.1",
|
|
53
84
|
"ink-select-input": "^6.2.0",
|
|
54
85
|
"io-ts": "^2.2.22",
|
|
@@ -56,10 +87,13 @@
|
|
|
56
87
|
"querystring": "^0.2.1",
|
|
57
88
|
"react": "^19.1.0",
|
|
58
89
|
"react-dom": "^19.1.0",
|
|
90
|
+
"react-error-boundary": "^5.0.0",
|
|
91
|
+
"tailwind-merge": "^3.0.2",
|
|
59
92
|
"tsup": "^8.5.0",
|
|
60
93
|
"tsx": "^4.19.1",
|
|
61
94
|
"type-fest": "^4.21.0",
|
|
62
|
-
"vite": "^7.0.2"
|
|
95
|
+
"vite": "^7.0.2",
|
|
96
|
+
"zustand": "^5.0.3"
|
|
63
97
|
},
|
|
64
98
|
"devDependencies": {
|
|
65
99
|
"@babel/core": "^7.26.9",
|
package/src/ui.tsx
CHANGED
|
@@ -49,6 +49,7 @@ export const DevUI = ({ rootDir }: { rootDir: string }) => {
|
|
|
49
49
|
const [viteUrl, setViteUrl] = useState<string | null>(null);
|
|
50
50
|
// Add a serverMessage state for display messages
|
|
51
51
|
const [serverMessage, setServerMessage] = useState<string | null>(null);
|
|
52
|
+
const [usingLocalUI, setUsingLocalUI] = useState<boolean>(false);
|
|
52
53
|
|
|
53
54
|
// Function to get the actual module path for an action/signal
|
|
54
55
|
const getModulePath = async (elementPath: string, actionSignalKey: string, type: 'action' | 'signal'): Promise<{ modulePath: string; uiDir: string } | null> => {
|
|
@@ -282,6 +283,25 @@ export const DevUI = ({ rootDir }: { rootDir: string }) => {
|
|
|
282
283
|
const currentActionSignal = (elementModule.actions as any[])?.find(action => action.key === actionSignal.value) ||
|
|
283
284
|
(elementModule.signals as any[])?.find(signal => signal.key === actionSignal.value);
|
|
284
285
|
|
|
286
|
+
// Check if we're in monorepo with local UI source (from Node.js context)
|
|
287
|
+
// Try multiple possible paths to find the UI source
|
|
288
|
+
const possibleUIPaths = [
|
|
289
|
+
path.resolve(process.cwd(), 'process-co', 'ui', 'src'),
|
|
290
|
+
path.resolve(__dirname, '..', '..', 'ui', 'src'),
|
|
291
|
+
path.resolve(__dirname, '..', 'ui', 'src'),
|
|
292
|
+
];
|
|
293
|
+
|
|
294
|
+
let hasLocalUISource = false;
|
|
295
|
+
for (const uiPath of possibleUIPaths) {
|
|
296
|
+
if (fs.existsSync(uiPath)) {
|
|
297
|
+
hasLocalUISource = true;
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Update state to show in banner
|
|
303
|
+
setUsingLocalUI(hasLocalUISource);
|
|
304
|
+
|
|
285
305
|
// Set process.env variables for Vite config
|
|
286
306
|
process.env.VITE_ELEMENT_PATH = element.path;
|
|
287
307
|
process.env.VITE_ELEMENT_TYPE = actionSignal.type;
|
|
@@ -292,6 +312,7 @@ export const DevUI = ({ rootDir }: { rootDir: string }) => {
|
|
|
292
312
|
process.env.VITE_PROPERTY_UI_PATH = property?.uiPath || '';
|
|
293
313
|
process.env.VITE_MODULE_PATH = moduleInfo.modulePath;
|
|
294
314
|
process.env.VITE_UI_DIRECTORY = moduleInfo.uiDir;
|
|
315
|
+
process.env.VITE_HAS_LOCAL_UI_SOURCE = hasLocalUISource ? 'true' : 'false';
|
|
295
316
|
|
|
296
317
|
|
|
297
318
|
const viteLogLength = 1;
|
|
@@ -319,13 +340,25 @@ export const DevUI = ({ rootDir }: { rootDir: string }) => {
|
|
|
319
340
|
// Pass the complete element data from compatibility module
|
|
320
341
|
'import.meta.env.VITE_ELEMENT_MODULE': JSON.stringify(elementModule),
|
|
321
342
|
'import.meta.env.VITE_CURRENT_ACTION_SIGNAL': JSON.stringify(currentActionSignal),
|
|
322
|
-
'import.meta.env.VITE_SELECTED_PROPERTY': JSON.stringify(property)
|
|
343
|
+
'import.meta.env.VITE_SELECTED_PROPERTY': JSON.stringify(property),
|
|
344
|
+
'import.meta.env.VITE_HAS_LOCAL_UI_SOURCE': JSON.stringify(hasLocalUISource)
|
|
323
345
|
},
|
|
324
346
|
logLevel: 'info',
|
|
325
347
|
customLogger: {
|
|
326
|
-
info(msg) {
|
|
327
|
-
|
|
328
|
-
|
|
348
|
+
info(msg) {
|
|
349
|
+
// Only capture in UI, don't output to console (prevents HMR noise)
|
|
350
|
+
viteLogsRef.current(logs => [...logs, msg].slice(-viteLogLength));
|
|
351
|
+
},
|
|
352
|
+
warn(msg) {
|
|
353
|
+
// Show warnings in console
|
|
354
|
+
console.warn(`[warn] ${msg}`);
|
|
355
|
+
viteLogsRef.current(logs => [...logs, `[warn] ${msg}`].slice(-viteLogLength));
|
|
356
|
+
},
|
|
357
|
+
error(msg) {
|
|
358
|
+
// Show errors in console
|
|
359
|
+
console.error(`[error] ${msg}`);
|
|
360
|
+
viteLogsRef.current(logs => [...logs, `[error] ${msg}`].slice(-viteLogLength));
|
|
361
|
+
},
|
|
329
362
|
clearScreen() { },
|
|
330
363
|
hasWarned: false,
|
|
331
364
|
warnOnce(msg) { },
|
|
@@ -574,6 +607,7 @@ export const DevUI = ({ rootDir }: { rootDir: string }) => {
|
|
|
574
607
|
) : (
|
|
575
608
|
<Text>UI Mode: <Text color="#01D4E7">Action/Signal Level</Text></Text>
|
|
576
609
|
)}
|
|
610
|
+
{usingLocalUI && <Text>UI Source: <Text color="#8759F2">Local Monorepo (Hot Reload Enabled)</Text></Text>}
|
|
577
611
|
<Text color="yellow">Press Ctrl+C to stop the server</Text>
|
|
578
612
|
</Box>
|
|
579
613
|
<Box marginTop={1} marginLeft={4} flexDirection="column">
|