juxscript 1.0.19 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/bin/cli.js +121 -72
  2. package/lib/components/alert.ts +212 -165
  3. package/lib/components/badge.ts +93 -103
  4. package/lib/components/base/BaseComponent.ts +397 -0
  5. package/lib/components/base/FormInput.ts +322 -0
  6. package/lib/components/button.ts +63 -122
  7. package/lib/components/card.ts +109 -155
  8. package/lib/components/charts/areachart.ts +315 -0
  9. package/lib/components/charts/barchart.ts +421 -0
  10. package/lib/components/charts/doughnutchart.ts +263 -0
  11. package/lib/components/charts/lib/BaseChart.ts +402 -0
  12. package/lib/components/charts/lib/chart-types.ts +159 -0
  13. package/lib/components/charts/lib/chart-utils.ts +160 -0
  14. package/lib/components/charts/lib/chart.ts +707 -0
  15. package/lib/components/checkbox.ts +264 -127
  16. package/lib/components/code.ts +75 -108
  17. package/lib/components/container.ts +113 -130
  18. package/lib/components/data.ts +37 -5
  19. package/lib/components/datepicker.ts +195 -147
  20. package/lib/components/dialog.ts +187 -157
  21. package/lib/components/divider.ts +85 -191
  22. package/lib/components/docs-data.json +544 -2027
  23. package/lib/components/dropdown.ts +178 -136
  24. package/lib/components/element.ts +227 -171
  25. package/lib/components/fileupload.ts +285 -228
  26. package/lib/components/guard.ts +92 -0
  27. package/lib/components/heading.ts +46 -69
  28. package/lib/components/helpers.ts +13 -6
  29. package/lib/components/hero.ts +107 -95
  30. package/lib/components/icon.ts +160 -0
  31. package/lib/components/icons.ts +175 -0
  32. package/lib/components/include.ts +153 -5
  33. package/lib/components/input.ts +174 -374
  34. package/lib/components/kpicard.ts +16 -16
  35. package/lib/components/list.ts +378 -240
  36. package/lib/components/loading.ts +142 -211
  37. package/lib/components/menu.ts +103 -97
  38. package/lib/components/modal.ts +138 -144
  39. package/lib/components/nav.ts +169 -90
  40. package/lib/components/paragraph.ts +49 -150
  41. package/lib/components/progress.ts +118 -200
  42. package/lib/components/radio.ts +297 -149
  43. package/lib/components/script.ts +19 -87
  44. package/lib/components/select.ts +184 -186
  45. package/lib/components/sidebar.ts +152 -140
  46. package/lib/components/style.ts +19 -82
  47. package/lib/components/switch.ts +258 -188
  48. package/lib/components/table.ts +1117 -170
  49. package/lib/components/tabs.ts +162 -145
  50. package/lib/components/theme-toggle.ts +108 -169
  51. package/lib/components/tooltip.ts +86 -157
  52. package/lib/components/write.ts +108 -127
  53. package/lib/jux.ts +86 -41
  54. package/machinery/build.js +466 -0
  55. package/machinery/compiler.js +354 -105
  56. package/machinery/server.js +23 -100
  57. package/machinery/watcher.js +153 -130
  58. package/package.json +1 -2
  59. package/presets/base.css +1166 -0
  60. package/presets/notion.css +2 -1975
  61. package/lib/adapters/base-adapter.js +0 -35
  62. package/lib/adapters/index.js +0 -33
  63. package/lib/adapters/mysql-adapter.js +0 -65
  64. package/lib/adapters/postgres-adapter.js +0 -70
  65. package/lib/adapters/sqlite-adapter.js +0 -56
  66. package/lib/components/areachart.ts +0 -1246
  67. package/lib/components/areachartsmooth.ts +0 -1380
  68. package/lib/components/barchart.ts +0 -1250
  69. package/lib/components/chart.ts +0 -127
  70. package/lib/components/doughnutchart.ts +0 -1191
  71. package/lib/components/footer.ts +0 -165
  72. package/lib/components/header.ts +0 -187
  73. package/lib/components/layout.ts +0 -239
  74. package/lib/components/main.ts +0 -137
  75. package/lib/layouts/default.jux +0 -8
  76. package/lib/layouts/figma.jux +0 -0
  77. /package/lib/{themes → components/charts/lib}/charts.js +0 -0
@@ -0,0 +1,466 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import esbuild from 'esbuild';
4
+ import {
5
+ bundleJuxFilesToRouter,
6
+ generateRouterIndex
7
+ } from './compiler.js';
8
+
9
+ /**
10
+ * Generate import map script tag
11
+ */
12
+ function generateImportMapScript() {
13
+ return `<script type="importmap">
14
+ {
15
+ "imports": {
16
+ "juxscript": "./lib/jux.js",
17
+ "juxscript/": "./lib/",
18
+ "juxscript/reactivity": "./lib/reactivity/state.js",
19
+ "juxscript/presets/": "./presets/",
20
+ "juxscript/components/": "./lib/components/"
21
+ }
22
+ }
23
+ </script>`;
24
+ }
25
+
26
+ /**
27
+ * Compile a .jux file to .js and .html
28
+ *
29
+ * @param {string} juxFilePath - Path to the .jux file
30
+ * @param {Object} options - Compilation options
31
+ * @param {string} options.distDir - Output directory
32
+ * @param {string} options.projectRoot - Project root directory
33
+ * @param {boolean} options.isServe - Whether serving for development
34
+ * @returns {Promise<{jsOutputPath: string, htmlOutputPath: string}>}
35
+ */
36
+ export async function compileJuxFile(juxFilePath, options = {}) {
37
+ const { distDir, projectRoot, isServe = false } = options;
38
+
39
+ const relativePath = path.relative(projectRoot, juxFilePath);
40
+ const parsedPath = path.parse(relativePath);
41
+
42
+ // Output paths
43
+ const outputDir = path.join(distDir, parsedPath.dir);
44
+ const jsOutputPath = path.join(outputDir, `${parsedPath.name}.js`);
45
+ const htmlOutputPath = path.join(outputDir, `${parsedPath.name}.html`);
46
+
47
+ // Ensure output directory exists
48
+ if (!fs.existsSync(outputDir)) {
49
+ fs.mkdirSync(outputDir, { recursive: true });
50
+ }
51
+
52
+ console.log(`📝 Compiling: ${relativePath}`);
53
+
54
+ // Read the .jux file
55
+ const juxContent = fs.readFileSync(juxFilePath, 'utf-8');
56
+
57
+ // Calculate depth for relative paths
58
+ const depth = parsedPath.dir.split(path.sep).filter(p => p).length;
59
+ const libPath = depth === 0 ? './lib/jux.js' : '../'.repeat(depth) + 'lib/jux.js';
60
+
61
+ // Transform imports
62
+ let transformedContent = juxContent;
63
+
64
+ // Replace common import patterns with calculated path
65
+ transformedContent = transformedContent.replace(
66
+ /from\s+['"]\.\.?\/lib\/jux\.js['"]/g,
67
+ `from '${libPath}'`
68
+ );
69
+
70
+ // Only inject import if:
71
+ // 1. File is not empty (ignoring whitespace and comments)
72
+ // 2. File uses 'jux.' but has no import statement
73
+ const contentWithoutComments = transformedContent
74
+ .replace(/\/\*[\s\S]*?\*\//g, '') // Remove block comments
75
+ .replace(/\/\/.*/g, '') // Remove line comments
76
+ .trim();
77
+
78
+ const hasContent = contentWithoutComments.length > 0;
79
+ const usesJux = /\bjux\./g.test(contentWithoutComments);
80
+ const hasImport = /import\s+.*from/.test(transformedContent);
81
+
82
+ if (hasContent && usesJux && !hasImport) {
83
+ transformedContent = `import { jux } from '${libPath}';\n\n${transformedContent}`;
84
+ }
85
+
86
+ // Write the transformed JS
87
+ fs.writeFileSync(jsOutputPath, transformedContent);
88
+
89
+ console.log(` ✓ JS: ${path.relative(projectRoot, jsOutputPath)}`);
90
+
91
+ // Generate HTML with import map and correct script path
92
+ const scriptPath = `./${parsedPath.name}.js`;
93
+ const importMapScript = generateImportMapScript();
94
+
95
+ const html = `<!DOCTYPE html>
96
+ <html lang="en">
97
+ <head>
98
+ <meta charset="UTF-8">
99
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
100
+ <title>${parsedPath.name}</title>
101
+ </head>
102
+ <body data-theme="">
103
+ <!-- App container -->
104
+ <div id="app" data-jux-page="${parsedPath.name}"></div>
105
+
106
+ ${importMapScript}
107
+ <script type="module" src="${scriptPath}"></script>
108
+ ${isServe ? `
109
+ <!-- Hot reload -->
110
+ <script type="module">
111
+ const ws = new WebSocket('ws://localhost:3001');
112
+ ws.onmessage = (msg) => {
113
+ const data = JSON.parse(msg.data);
114
+ if (data.type === 'reload') {
115
+ console.log('🔄 Reloading page...');
116
+ location.reload();
117
+ }
118
+ };
119
+ ws.onerror = () => console.warn('⚠️ WebSocket connection failed');
120
+ </script>
121
+ ` : ''}
122
+ </body>
123
+ </html>`;
124
+
125
+ fs.writeFileSync(htmlOutputPath, html);
126
+ console.log(` ✓ HTML: ${path.relative(projectRoot, htmlOutputPath)}`);
127
+
128
+ return { jsOutputPath, htmlOutputPath };
129
+ }
130
+
131
+ /**
132
+ * Copy and build the JUX library from TypeScript to JavaScript
133
+ *
134
+ * @param {string} projectRoot - Root directory containing lib/
135
+ * @param {string} distDir - Destination directory for built files
136
+ */
137
+ export async function copyLibToOutput(projectRoot, distDir) {
138
+ // Simplified lib path resolution
139
+ const libSrc = path.resolve(projectRoot, '../lib');
140
+
141
+ if (!fs.existsSync(libSrc)) {
142
+ throw new Error(`lib/ directory not found at ${libSrc}`);
143
+ }
144
+
145
+ const libDest = path.join(distDir, 'lib');
146
+
147
+ console.log('📦 Building TypeScript library...');
148
+ console.log(` From: ${libSrc}`);
149
+ console.log(` To: ${libDest}`);
150
+
151
+ if (fs.existsSync(libDest)) {
152
+ fs.rmSync(libDest, { recursive: true });
153
+ }
154
+
155
+ fs.mkdirSync(libDest, { recursive: true });
156
+
157
+ // Find all TypeScript entry points
158
+ const tsFiles = findFiles(libSrc, '.ts');
159
+
160
+ if (tsFiles.length === 0) {
161
+ console.warn('⚠️ No TypeScript files found in lib/');
162
+ return;
163
+ }
164
+
165
+ console.log(` Found ${tsFiles.length} TypeScript files`);
166
+
167
+ // Build all TypeScript files with esbuild
168
+ try {
169
+ await esbuild.build({
170
+ entryPoints: tsFiles,
171
+ bundle: false,
172
+ format: 'esm',
173
+ outdir: libDest,
174
+ outbase: libSrc,
175
+ platform: 'browser',
176
+ target: 'es2020',
177
+ loader: {
178
+ '.ts': 'ts'
179
+ },
180
+ logLevel: 'warning'
181
+ });
182
+
183
+ console.log(' ✓ TypeScript compiled to JavaScript');
184
+
185
+ // Copy non-TS files (CSS, HTML, etc.)
186
+ console.log(' Copying lib assets...');
187
+ copyNonTsFiles(libSrc, libDest);
188
+ console.log(' ✓ Lib assets copied');
189
+
190
+ } catch (err) {
191
+ console.error('❌ Failed to build TypeScript:', err.message);
192
+ throw err;
193
+ }
194
+
195
+ console.log('✅ Library ready\n');
196
+ }
197
+
198
+ /**
199
+ * Copy project assets (CSS, JS, images) from jux/ to dist/
200
+ *
201
+ * @param {string} projectRoot - Source directory (jux/)
202
+ * @param {string} distDir - Destination directory (jux-dist/)
203
+ */
204
+ export async function copyProjectAssets(projectRoot, distDir) {
205
+ console.log('📦 Copying project assets...');
206
+
207
+ // Find all CSS and JS files in project root (excluding node_modules, dist, .git)
208
+ const allFiles = [];
209
+ findProjectFiles(projectRoot, ['.css', '.js'], allFiles, projectRoot);
210
+
211
+ console.log(` Found ${allFiles.length} asset file(s)`);
212
+
213
+ for (const srcPath of allFiles) {
214
+ const relativePath = path.relative(projectRoot, srcPath);
215
+ const destPath = path.join(distDir, relativePath);
216
+ const destDir = path.dirname(destPath);
217
+
218
+ // Create destination directory if needed
219
+ if (!fs.existsSync(destDir)) {
220
+ fs.mkdirSync(destDir, { recursive: true });
221
+ }
222
+
223
+ // Copy file
224
+ fs.copyFileSync(srcPath, destPath);
225
+ console.log(` ✓ ${relativePath}`);
226
+ }
227
+
228
+ console.log('✅ Project assets copied\n');
229
+ }
230
+
231
+ /**
232
+ * Transpile TypeScript files from jux/ to jux-dist/, preserving folder structure
233
+ *
234
+ * @param {string} srcDir - Source directory (jux/)
235
+ * @param {string} destDir - Destination directory (jux-dist/)
236
+ * @example
237
+ * // jux/samples/mypage.ts -> jux-dist/samples/mypage.js
238
+ * await transpileProjectTypeScript('jux/', 'jux-dist/');
239
+ */
240
+ export async function transpileProjectTypeScript(srcDir, destDir) {
241
+ console.log('🔷 Transpiling TypeScript files...');
242
+
243
+ // Find all TypeScript files in the project
244
+ const tsFiles = findFiles(srcDir, '.ts');
245
+
246
+ if (tsFiles.length === 0) {
247
+ console.log(' No TypeScript files found in project');
248
+ return;
249
+ }
250
+
251
+ console.log(` Found ${tsFiles.length} TypeScript file(s)`);
252
+
253
+ try {
254
+ // Build all TypeScript files with esbuild
255
+ await esbuild.build({
256
+ entryPoints: tsFiles,
257
+ bundle: false,
258
+ format: 'esm',
259
+ outdir: destDir,
260
+ outbase: srcDir,
261
+ platform: 'browser',
262
+ target: 'es2020',
263
+ loader: {
264
+ '.ts': 'ts'
265
+ },
266
+ logLevel: 'warning'
267
+ });
268
+
269
+ // Log each transpiled file
270
+ tsFiles.forEach(tsFile => {
271
+ const relativePath = path.relative(srcDir, tsFile);
272
+ const jsPath = relativePath.replace(/\.ts$/, '.js');
273
+ console.log(` ✓ ${relativePath} → ${jsPath}`);
274
+ });
275
+
276
+ console.log('✅ TypeScript transpiled\n');
277
+
278
+ } catch (err) {
279
+ console.error('❌ Failed to transpile TypeScript:', err.message);
280
+ throw err;
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Copy presets folder from lib to dist
286
+ *
287
+ * @param {string} packageRoot - Source package root directory
288
+ * @param {string} distDir - Destination directory
289
+ */
290
+ export async function copyPresetsToOutput(packageRoot, distDir) {
291
+ console.log('📦 Copying presets...');
292
+
293
+ const presetsSrc = path.join(packageRoot, 'presets');
294
+ const presetsDest = path.join(distDir, 'presets');
295
+
296
+ if (!fs.existsSync(presetsSrc)) {
297
+ console.log(' No presets directory found');
298
+ return;
299
+ }
300
+
301
+ if (fs.existsSync(presetsDest)) {
302
+ fs.rmSync(presetsDest, { recursive: true });
303
+ }
304
+
305
+ fs.mkdirSync(presetsDest, { recursive: true });
306
+
307
+ // Copy all files in presets directory
308
+ const files = fs.readdirSync(presetsSrc);
309
+ let copiedCount = 0;
310
+
311
+ for (const file of files) {
312
+ const srcPath = path.join(presetsSrc, file);
313
+ const destPath = path.join(presetsDest, file);
314
+
315
+ if (fs.statSync(srcPath).isFile()) {
316
+ fs.copyFileSync(srcPath, destPath);
317
+ console.log(` ✓ ${file}`);
318
+ copiedCount++;
319
+ }
320
+ }
321
+
322
+ console.log(`✅ Copied ${copiedCount} preset file(s)\n`);
323
+ }
324
+
325
+ /**
326
+ * Recursively find files with a specific extension
327
+ *
328
+ * @param {string} dir - Directory to search
329
+ * @param {string} extension - File extension (e.g., '.ts')
330
+ * @param {string[]} fileList - Accumulator for found files
331
+ * @returns {string[]} Array of file paths
332
+ */
333
+ async function findFiles(dir, extension, fileList = []) {
334
+ const fs = await import('fs');
335
+ const path = await import('path');
336
+ const files = fs.readdirSync(dir);
337
+
338
+ files.forEach(file => {
339
+ const filePath = path.join(dir, file);
340
+ const stat = fs.statSync(filePath);
341
+
342
+ if (stat.isDirectory() && !['node_modules', 'jux-dist', '.git', 'lib'].includes(file)) {
343
+ findFiles(filePath, extension, fileList);
344
+ } else if (file.endsWith(extension)) {
345
+ fileList.push(filePath);
346
+ }
347
+ });
348
+
349
+ return fileList;
350
+ }
351
+
352
+ /**
353
+ * Copy non-TypeScript files (CSS, JSON, JS, SVG, etc.)
354
+ *
355
+ * @param {string} src - Source directory
356
+ * @param {string} dest - Destination directory
357
+ */
358
+ function copyNonTsFiles(src, dest) {
359
+ const entries = fs.readdirSync(src, { withFileTypes: true });
360
+
361
+ for (const entry of entries) {
362
+ const srcPath = path.join(src, entry.name);
363
+ const destPath = path.join(dest, entry.name);
364
+
365
+ if (entry.isDirectory()) {
366
+ if (!fs.existsSync(destPath)) {
367
+ fs.mkdirSync(destPath, { recursive: true });
368
+ }
369
+ copyNonTsFiles(srcPath, destPath);
370
+ } else if (entry.isFile()) {
371
+ const ext = path.extname(entry.name);
372
+ // Copy CSS, JSON, SVG, and JS files (but not .ts files)
373
+ if (['.css', '.json', '.js', '.svg', '.png', '.jpg', '.jpeg', '.gif', '.webp'].includes(ext)) {
374
+ fs.copyFileSync(srcPath, destPath);
375
+ }
376
+ }
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Find project files with specific extensions, excluding certain directories
382
+ *
383
+ * @param {string} dir - Directory to search
384
+ * @param {string[]} extensions - File extensions to find
385
+ * @param {string[]} fileList - Accumulator for found files
386
+ * @param {string} rootDir - Root directory for relative paths
387
+ * @param {string[]} excludeDirs - Directories to exclude
388
+ * @returns {string[]} Array of file paths
389
+ */
390
+ function findProjectFiles(dir, extensions, fileList = [], rootDir = dir, excludeDirs = ['node_modules', 'jux-dist', '.git', 'lib']) {
391
+ if (!fs.existsSync(dir)) return fileList;
392
+
393
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
394
+
395
+ for (const entry of entries) {
396
+ const fullPath = path.join(dir, entry.name);
397
+
398
+ if (entry.isDirectory()) {
399
+ // Skip excluded directories
400
+ if (excludeDirs.includes(entry.name)) {
401
+ continue;
402
+ }
403
+ findProjectFiles(fullPath, extensions, fileList, rootDir, excludeDirs);
404
+ } else {
405
+ // Check if file has one of the desired extensions
406
+ const hasExtension = extensions.some(ext => entry.name.endsWith(ext));
407
+ if (hasExtension) {
408
+ fileList.push(fullPath);
409
+ }
410
+ }
411
+ }
412
+
413
+ return fileList;
414
+ }
415
+
416
+ /**
417
+ * Build a project
418
+ *
419
+ * @param {string} projectRoot - Root directory containing lib/
420
+ * @param {string} distDir - Destination directory for built files
421
+ * @param {Object} options - Compilation options
422
+ * @param {string} options.routePrefix - Route prefix
423
+ * @returns {Promise<{jsOutputPath: string, htmlOutputPath: string}>}
424
+ */
425
+ export async function buildProject(options = {}) {
426
+ const { projectRoot, distDir } = options;
427
+
428
+ // Ensure project root and dist directory exist
429
+ if (!fs.existsSync(projectRoot)) {
430
+ throw new Error(`Project root directory not found: ${projectRoot}`);
431
+ }
432
+ if (!fs.existsSync(distDir)) {
433
+ fs.mkdirSync(distDir, { recursive: true });
434
+ }
435
+
436
+ // Option to use router mode
437
+ if (options.router) {
438
+ console.log('🔀 Building in router mode...\n');
439
+
440
+ await bundleJuxFilesToRouter(projectRoot, distDir, {
441
+ routePrefix: options.routePrefix || ''
442
+ });
443
+
444
+ // Get route information for index generation
445
+ const juxFiles = findFiles(projectRoot, '.jux');
446
+ const routes = juxFiles.map(juxFile => {
447
+ const relativePath = path.relative(projectRoot, juxFile);
448
+ const parsedPath = path.parse(relativePath);
449
+ const functionName = parsedPath.dir
450
+ ? `${parsedPath.dir.replace(/\//g, '_')}_${parsedPath.name}`
451
+ : parsedPath.name;
452
+ const routePath = (options.routePrefix || '') + '/' +
453
+ (parsedPath.dir ? `${parsedPath.dir}/` : '') + parsedPath.name;
454
+ return {
455
+ path: routePath.replace(/\/+/g, '/'),
456
+ functionName
457
+ };
458
+ });
459
+
460
+ generateRouterIndex(distDir, routes);
461
+ } else {
462
+ // ...existing individual page compilation...
463
+ }
464
+
465
+ // ...existing code...
466
+ }