neutronium 0.0.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +11 -0
- package/README.md +177 -1
- package/cli/index.js +123 -0
- package/compiler/compiler.js +104 -0
- package/compiler/template.js +26 -0
- package/compiler/utils.js +22 -0
- package/package.json +39 -8
- package/src/index.js +41 -0
- package/test-open.js +6 -0
package/.babelrc
ADDED
package/README.md
CHANGED
|
@@ -1 +1,177 @@
|
|
|
1
|
-
|
|
1
|
+
# Neutronium
|
|
2
|
+
|
|
3
|
+
> Ultra-dense JavaScript framework - maximum performance, minimal overhead
|
|
4
|
+
|
|
5
|
+
Neutronium is a lightweight, efficient JavaScript framework designed for building modern web applications with the density and stability of neutron star matter.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 🚀 **Ultra-fast** - Optimized for performance
|
|
10
|
+
- 📦 **Minimal bundle size** - Dense with features, light on complexity
|
|
11
|
+
- 🎯 **Simple API** - Easy to learn and use
|
|
12
|
+
- 🔧 **Flexible** - Adaptable to your project needs
|
|
13
|
+
- 🌟 **Modern** - Built with current JavaScript standards
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install neutronium
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
import { createComponent, render } from 'neutronium';
|
|
25
|
+
|
|
26
|
+
// Create a simple component
|
|
27
|
+
const HelloWorld = createComponent({
|
|
28
|
+
template: '<h1>Hello, {{name}}!</h1>',
|
|
29
|
+
props: { name: 'World' }
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Render to DOM
|
|
33
|
+
render(HelloWorld, document.getElementById('app'));
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## API Reference
|
|
37
|
+
|
|
38
|
+
### `createComponent(options)`
|
|
39
|
+
|
|
40
|
+
Creates a new component with the specified options.
|
|
41
|
+
|
|
42
|
+
**Parameters:**
|
|
43
|
+
- `options` (Object): Component configuration
|
|
44
|
+
- `template` (String): HTML template
|
|
45
|
+
- `props` (Object): Component properties
|
|
46
|
+
- `methods` (Object): Component methods
|
|
47
|
+
|
|
48
|
+
**Returns:** Component instance
|
|
49
|
+
|
|
50
|
+
### `render(component, target)`
|
|
51
|
+
|
|
52
|
+
Renders a component to the specified DOM element.
|
|
53
|
+
|
|
54
|
+
**Parameters:**
|
|
55
|
+
- `component`: Component instance
|
|
56
|
+
- `target`: DOM element to render into
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
### Basic Component
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
import { createComponent, render } from 'neutronium';
|
|
64
|
+
|
|
65
|
+
const Counter = createComponent({
|
|
66
|
+
template: `
|
|
67
|
+
<div>
|
|
68
|
+
<h2>Count: {{count}}</h2>
|
|
69
|
+
<button onclick="increment()">+</button>
|
|
70
|
+
<button onclick="decrement()">-</button>
|
|
71
|
+
</div>
|
|
72
|
+
`,
|
|
73
|
+
props: {
|
|
74
|
+
count: 0
|
|
75
|
+
},
|
|
76
|
+
methods: {
|
|
77
|
+
increment() {
|
|
78
|
+
this.props.count++;
|
|
79
|
+
},
|
|
80
|
+
decrement() {
|
|
81
|
+
this.props.count--;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
render(Counter, document.getElementById('app'));
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Component with State
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
import { createComponent, render } from 'neutronium';
|
|
93
|
+
|
|
94
|
+
const TodoList = createComponent({
|
|
95
|
+
template: `
|
|
96
|
+
<div>
|
|
97
|
+
<input type="text" placeholder="Add todo..." />
|
|
98
|
+
<button onclick="addTodo()">Add</button>
|
|
99
|
+
<ul>
|
|
100
|
+
{{#each todos}}
|
|
101
|
+
<li>{{this}}</li>
|
|
102
|
+
{{/each}}
|
|
103
|
+
</ul>
|
|
104
|
+
</div>
|
|
105
|
+
`,
|
|
106
|
+
props: {
|
|
107
|
+
todos: []
|
|
108
|
+
},
|
|
109
|
+
methods: {
|
|
110
|
+
addTodo() {
|
|
111
|
+
const input = this.element.querySelector('input');
|
|
112
|
+
if (input.value.trim()) {
|
|
113
|
+
this.props.todos.push(input.value);
|
|
114
|
+
input.value = '';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
render(TodoList, document.getElementById('app'));
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Browser Support
|
|
124
|
+
|
|
125
|
+
- Chrome 60+
|
|
126
|
+
- Firefox 60+
|
|
127
|
+
- Safari 12+
|
|
128
|
+
- Edge 79+
|
|
129
|
+
|
|
130
|
+
## Development
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Clone the repository
|
|
134
|
+
git clone https://github.com/yourusername/neutronium.git
|
|
135
|
+
|
|
136
|
+
# Install dependencies
|
|
137
|
+
npm install
|
|
138
|
+
|
|
139
|
+
# Run tests
|
|
140
|
+
npm test
|
|
141
|
+
|
|
142
|
+
# Build for production
|
|
143
|
+
npm run build
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Contributing
|
|
147
|
+
|
|
148
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
149
|
+
|
|
150
|
+
1. Fork the repository
|
|
151
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
152
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
153
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
154
|
+
5. Open a Pull Request
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT License - see the [LICENSE](LICENSE) file for details.
|
|
159
|
+
|
|
160
|
+
## Roadmap
|
|
161
|
+
|
|
162
|
+
- [ ] Server-side rendering support
|
|
163
|
+
- [ ] TypeScript definitions
|
|
164
|
+
- [ ] Developer tools integration
|
|
165
|
+
- [ ] Plugin system
|
|
166
|
+
- [ ] Performance optimizations
|
|
167
|
+
- [ ] Advanced component lifecycle methods
|
|
168
|
+
|
|
169
|
+
## Why Neutronium?
|
|
170
|
+
|
|
171
|
+
Just like neutronium is the densest stable matter in the universe, Neutronium framework packs maximum functionality into minimal code. It's designed for developers who want powerful features without the bloat.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
**Built with ⚛️ by [Your Name]**
|
|
176
|
+
|
|
177
|
+
*"Dense with features, light on complexity"*
|
package/cli/index.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { default: inquirer } = require('inquirer');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const babel = require('@babel/core');
|
|
7
|
+
|
|
8
|
+
const [, , command, ...args] = process.argv;
|
|
9
|
+
|
|
10
|
+
// App.js with JSX
|
|
11
|
+
const AppJs = `
|
|
12
|
+
import { h, createApp } from 'neutronium';
|
|
13
|
+
|
|
14
|
+
function App() {
|
|
15
|
+
return (
|
|
16
|
+
<div class="container">
|
|
17
|
+
<h1>Hello from Neutronium!</h1>
|
|
18
|
+
<p>Start building your app in JSX!</p>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
createApp(App).mount('#app');
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
// HTML template with __SCRIPT__ placeholder
|
|
27
|
+
const htmlTemplate = `
|
|
28
|
+
<!DOCTYPE html>
|
|
29
|
+
<html>
|
|
30
|
+
<head>
|
|
31
|
+
<meta charset="UTF-8" />
|
|
32
|
+
<title>${appName}</title>
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
<div id="app"></div>
|
|
36
|
+
<script type="module">
|
|
37
|
+
__SCRIPT__
|
|
38
|
+
</script>
|
|
39
|
+
</body>
|
|
40
|
+
</html>
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
async function init() {
|
|
44
|
+
let targetPath = process.cwd();
|
|
45
|
+
let createdFolder = false;
|
|
46
|
+
|
|
47
|
+
const { confirmInit } = await inquirer.prompt([
|
|
48
|
+
{
|
|
49
|
+
type: 'confirm',
|
|
50
|
+
name: 'confirmInit',
|
|
51
|
+
message: 'Initialize a Neutronium app in this folder?',
|
|
52
|
+
default: true
|
|
53
|
+
}
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
if (!confirmInit) {
|
|
57
|
+
const { projectName } = await inquirer.prompt([
|
|
58
|
+
{
|
|
59
|
+
type: 'input',
|
|
60
|
+
name: 'projectName',
|
|
61
|
+
message: 'Please enter your project name:',
|
|
62
|
+
default: 'neutronium-app'
|
|
63
|
+
}
|
|
64
|
+
]);
|
|
65
|
+
targetPath = path.resolve(process.cwd(), projectName);
|
|
66
|
+
createdFolder = true;
|
|
67
|
+
if (!fs.existsSync(targetPath)) fs.mkdirSync(targetPath);
|
|
68
|
+
else console.log('⚠️ Folder already exists. Using it anyway.');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Write App.js
|
|
72
|
+
const appPath = path.join(targetPath, 'App.js');
|
|
73
|
+
fs.writeFileSync(appPath, AppJs.trim());
|
|
74
|
+
|
|
75
|
+
// Init package.json
|
|
76
|
+
execSync('npm init -y', { cwd: targetPath, stdio: 'inherit' });
|
|
77
|
+
|
|
78
|
+
// Install neutronium
|
|
79
|
+
execSync('npm install neutronium', { cwd: targetPath, stdio: 'inherit' });
|
|
80
|
+
|
|
81
|
+
// Install Babel for JSX support
|
|
82
|
+
execSync('npm install --save-dev @babel/core @babel/cli @babel/plugin-transform-react-jsx', {
|
|
83
|
+
cwd: targetPath,
|
|
84
|
+
stdio: 'inherit'
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Compile App.js to script string
|
|
88
|
+
const appJsCode = fs.readFileSync(appPath, 'utf-8');
|
|
89
|
+
const result = babel.transformSync(appJsCode, {
|
|
90
|
+
filename: 'App.js',
|
|
91
|
+
plugins: [['@babel/plugin-transform-react-jsx', { pragma: 'h' }]]
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Inject into HTML
|
|
95
|
+
const finalHtml = htmlTemplate.replace('__SCRIPT__', result.code);
|
|
96
|
+
|
|
97
|
+
const distPath = path.join(targetPath, 'dist');
|
|
98
|
+
if (!fs.existsSync(distPath)) fs.mkdirSync(distPath);
|
|
99
|
+
fs.writeFileSync(path.join(distPath, 'index.html'), finalHtml);
|
|
100
|
+
|
|
101
|
+
const folder = createdFolder ? `cd ${path.basename(targetPath)}` : '';
|
|
102
|
+
console.log('\n✅ Neutronium app is ready!');
|
|
103
|
+
console.log(`➡️ Run the following to get started:\n\n ${folder}\n npx serve dist\n`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const { compileProject, compileProjectWatch } = require('../compiler/compiler');
|
|
107
|
+
|
|
108
|
+
switch (command) {
|
|
109
|
+
case 'init':
|
|
110
|
+
case 'create-app':
|
|
111
|
+
case 'create-neutronium-app':
|
|
112
|
+
init();
|
|
113
|
+
break;
|
|
114
|
+
case 'start':
|
|
115
|
+
if (args[0] == "--watch") {
|
|
116
|
+
compileProjectWatch(); // Will read App.js and output dist/index.html
|
|
117
|
+
} else {
|
|
118
|
+
compileProject()
|
|
119
|
+
}
|
|
120
|
+
default:
|
|
121
|
+
console.log('❌ Unknown command.');
|
|
122
|
+
console.log('Usage: neu-cli init');
|
|
123
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const babel = require('@babel/core');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { baseHtml } = require('./template');
|
|
5
|
+
const { log, writeFile, ensureDir } = require('./utils');
|
|
6
|
+
const chokidar = require('chokidar');
|
|
7
|
+
const http = require('http');
|
|
8
|
+
const { default: Mime } = require('mime');
|
|
9
|
+
const WebSocket = require('ws');
|
|
10
|
+
const { default: open } = require('open');
|
|
11
|
+
|
|
12
|
+
function compileProject(projectDir = process.cwd()) {
|
|
13
|
+
const appJsPath = path.join(projectDir, 'App.js');
|
|
14
|
+
const distDir = path.join(projectDir, 'dist');
|
|
15
|
+
const outHtmlPath = path.join(distDir, 'index.html');
|
|
16
|
+
const outJsPath = path.join(distDir, 'App.compiled.js');
|
|
17
|
+
const srcIndexPath = path.relative(distDir, path.join(projectDir, 'src/index.js')).replace(/\\/g, '/');
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
log('📖 Reading App.js...');
|
|
21
|
+
const sourceCode = fs.readFileSync(appJsPath, 'utf-8');
|
|
22
|
+
|
|
23
|
+
log('⚙️ Compiling JSX with Babel...');
|
|
24
|
+
const { code: transpiled } = babel.transformSync(sourceCode, {
|
|
25
|
+
filename: 'App.js',
|
|
26
|
+
presets: [['@babel/preset-env', { targets: { esmodules: true } }]],
|
|
27
|
+
plugins: [['@babel/plugin-transform-react-jsx', { pragma: 'h' }]],
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Inject framework import + mount call
|
|
31
|
+
const finalJsCode = `
|
|
32
|
+
import { h, createApp } from '${srcIndexPath}';
|
|
33
|
+
|
|
34
|
+
${transpiled}
|
|
35
|
+
|
|
36
|
+
createApp(App).mount('#app');
|
|
37
|
+
`.trim();
|
|
38
|
+
|
|
39
|
+
ensureDir(distDir);
|
|
40
|
+
writeFile(outJsPath, finalJsCode);
|
|
41
|
+
|
|
42
|
+
log('🛠️ Generating index.html...');
|
|
43
|
+
const finalHtml = baseHtml(`<div id="app"></div>`, 'App.compiled.js');
|
|
44
|
+
writeFile(outHtmlPath, finalHtml);
|
|
45
|
+
|
|
46
|
+
log('✅ Compilation complete!');
|
|
47
|
+
log(`➡️ Output: ${outHtmlPath}`);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.error('❌ Compilation failed:', e.message);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function compileProjectWatch(projectDir = process.cwd(), port = 3000) {
|
|
54
|
+
const appJsPath = path.join(projectDir, 'App.js');
|
|
55
|
+
|
|
56
|
+
const server = serveProject(projectDir, port);
|
|
57
|
+
compileProject(projectDir);
|
|
58
|
+
|
|
59
|
+
log('👀 Watching App.js for changes...');
|
|
60
|
+
chokidar.watch(appJsPath).on('change', () => {
|
|
61
|
+
console.clear();
|
|
62
|
+
log('🔁 Detected change in App.js...');
|
|
63
|
+
compileProject(projectDir);
|
|
64
|
+
if (server.broadcastReload) {
|
|
65
|
+
server.broadcastReload();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function serveProject(projectDir = process.cwd(), port = 3000) {
|
|
71
|
+
const distDir = path.join(projectDir, 'dist');
|
|
72
|
+
const server = http.createServer((req, res) => {
|
|
73
|
+
let reqPath = req.url === '/' ? '/index.html' : req.url;
|
|
74
|
+
const filePath = path.join(distDir, reqPath);
|
|
75
|
+
|
|
76
|
+
if (!fs.existsSync(filePath)) {
|
|
77
|
+
res.writeHead(404);
|
|
78
|
+
return res.end('404 Not Found');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const content = fs.readFileSync(filePath);
|
|
82
|
+
res.writeHead(200, { 'Content-Type': Mime.getType(filePath) });
|
|
83
|
+
res.end(content);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const wss = new WebSocket.Server({ server });
|
|
87
|
+
|
|
88
|
+
server.broadcastReload = () => {
|
|
89
|
+
wss.clients.forEach(client => {
|
|
90
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
91
|
+
client.send('reload');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
server.listen(port, () => {
|
|
97
|
+
log(`🚀 Server running at http://localhost:${port}`);
|
|
98
|
+
open(`http://localhost:${port}`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return server;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = { compileProject, compileProjectWatch };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
function baseHtml(bodyHtml, scriptFile = 'App.compiled.js') {
|
|
2
|
+
return `
|
|
3
|
+
<!DOCTYPE html>
|
|
4
|
+
<html>
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset="UTF-8" />
|
|
7
|
+
<title>Neutronium App</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
${bodyHtml}
|
|
11
|
+
<script type="module" src="./${scriptFile}"></script>
|
|
12
|
+
<script>
|
|
13
|
+
const ws = new WebSocket('ws://' + location.host);
|
|
14
|
+
ws.onmessage = (msg) => {
|
|
15
|
+
if (msg.data === 'reload') {
|
|
16
|
+
console.log('[Neutronium] Reloading...');
|
|
17
|
+
location.reload();
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
</script>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
|
23
|
+
`.trim();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = { baseHtml };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// compiler/utils.js
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
function writeFile(filePath, content) {
|
|
7
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function readFile(filePath) {
|
|
11
|
+
return fs.readFileSync(filePath, 'utf-8');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function ensureDir(dir) {
|
|
15
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function log(msg) {
|
|
19
|
+
console.log(`🔹 ${msg}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = { writeFile, readFile, ensureDir, log };
|
package/package.json
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neutronium",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "index.js",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A dense, efficient JavaScript framework for building modern web applications",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "commonjs",
|
|
6
7
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
+
"start": "node test/App.js"
|
|
8
9
|
},
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
10
|
+
"export": {
|
|
11
|
+
".": "src/index.js"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"neu-cli": "./cli/index.js",
|
|
15
|
+
"neu": "src/index.js"
|
|
16
|
+
},
|
|
17
|
+
"exports": {
|
|
18
|
+
".": "./src/index.js"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"framework",
|
|
22
|
+
"javascript",
|
|
23
|
+
"frontend",
|
|
24
|
+
"ui",
|
|
25
|
+
"components"
|
|
26
|
+
],
|
|
27
|
+
"author": "PFMCODES",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"chokidar": "^4.0.3",
|
|
31
|
+
"inquirer": "^12.7.0",
|
|
32
|
+
"jsdom": "^26.1.0",
|
|
33
|
+
"mime": "^4.0.7",
|
|
34
|
+
"open": "^10.1.2",
|
|
35
|
+
"ws": "^8.18.3"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@babel/cli": "^7.28.0",
|
|
39
|
+
"@babel/core": "^7.28.0",
|
|
40
|
+
"@babel/plugin-transform-react-jsx": "^7.27.1",
|
|
41
|
+
"@babel/preset-env": "^7.28.0",
|
|
42
|
+
"@babel/preset-react": "^7.27.1"
|
|
43
|
+
}
|
|
13
44
|
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/index.js
|
|
2
|
+
|
|
3
|
+
function h(type, props = {}, ...children) {
|
|
4
|
+
const el = document.createElement(type);
|
|
5
|
+
|
|
6
|
+
for (const [key, value] of Object.entries(props || {})) {
|
|
7
|
+
if (key.startsWith('on') && typeof value === 'function') {
|
|
8
|
+
el.addEventListener(key.slice(2).toLowerCase(), value);
|
|
9
|
+
} else {
|
|
10
|
+
el.setAttribute(key, value);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
children.flat().forEach(child => {
|
|
15
|
+
if (typeof child === 'string' || typeof child === 'number') {
|
|
16
|
+
el.appendChild(document.createTextNode(child));
|
|
17
|
+
} else if (child instanceof Node) {
|
|
18
|
+
el.appendChild(child);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return el;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createApp(component) {
|
|
26
|
+
return {
|
|
27
|
+
mount(selector) {
|
|
28
|
+
const root = document.querySelector(selector);
|
|
29
|
+
if (!root) {
|
|
30
|
+
console.error(`❌ Root element '${selector}' not found`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const vnode = component();
|
|
35
|
+
root.innerHTML = '';
|
|
36
|
+
root.appendChild(vnode);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = { h, createApp };
|