frontend-hamroun 1.2.15 → 1.2.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/bin/cli.js +673 -0
- package/dist/component.d.ts +1 -1
- package/dist/context.d.ts +4 -3
- package/dist/index.client.d.ts +11 -0
- package/dist/index.d.ts +9 -89
- package/dist/index.js +396 -67
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +392 -0
- package/dist/index.mjs.map +1 -0
- package/dist/jsx-runtime/jsx-runtime.d.ts +0 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/renderer.d.ts +0 -10
- package/dist/server-renderer.d.ts +0 -3
- package/dist/server-types.d.ts +42 -0
- package/package.json +69 -50
- package/templates/basic-app/index.html +6 -6
- package/templates/basic-app/package.json +15 -11
- package/templates/basic-app/postcss.config.js +0 -1
- package/templates/basic-app/src/main.tsx +1 -10
- package/templates/basic-app/tailwind.config.js +2 -23
- package/templates/basic-app/tsconfig.json +4 -17
- package/templates/basic-app/vite.config.ts +3 -54
- package/templates/fullstack-app/api/hello.ts +18 -0
- package/templates/fullstack-app/api/users/[id].ts +73 -0
- package/templates/fullstack-app/api/users/index.ts +32 -0
- package/templates/fullstack-app/package.json +31 -0
- package/templates/fullstack-app/server.ts +46 -0
- package/templates/fullstack-app/src/pages/index.tsx +59 -0
- package/templates/ssr-template/vite.config.ts +1 -11
- package/bin/cli.cjs +0 -16
- package/bin/cli.mjs +0 -237
- package/dist/backend/api-utils.d.ts +0 -38
- package/dist/backend/api-utils.js +0 -135
- package/dist/backend/auth.d.ts +0 -134
- package/dist/backend/auth.js +0 -387
- package/dist/backend/database.d.ts +0 -27
- package/dist/backend/database.js +0 -91
- package/dist/backend/model.d.ts +0 -43
- package/dist/backend/model.js +0 -178
- package/dist/backend/router.d.ts +0 -27
- package/dist/backend/router.js +0 -137
- package/dist/backend/server.d.ts +0 -19
- package/dist/backend/server.js +0 -268
- package/dist/backend/types.d.ts +0 -217
- package/dist/backend/types.js +0 -1
- package/dist/batch.js +0 -22
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.js +0 -215
- package/dist/component.js +0 -84
- package/dist/components/Counter.js +0 -2
- package/dist/context.js +0 -18
- package/dist/frontend-hamroun.es.js +0 -1378
- package/dist/frontend-hamroun.umd.js +0 -66
- package/dist/hooks.js +0 -164
- package/dist/jsx-runtime/index.d.ts +0 -11
- package/dist/jsx-runtime/index.js +0 -19
- package/dist/jsx-runtime/jsx-dev-runtime.js +0 -1
- package/dist/jsx-runtime/jsx-runtime.js +0 -95
- package/dist/jsx-runtime.js +0 -192
- package/dist/renderer.js +0 -51
- package/dist/server-renderer.js +0 -102
- package/dist/types.js +0 -1
- package/dist/vdom.js +0 -27
- package/scripts/build-cli.js +0 -1107
- package/scripts/generate.js +0 -134
- package/src/backend/api-utils.ts +0 -178
- package/src/backend/auth.ts +0 -544
- package/src/backend/database.ts +0 -104
- package/src/backend/model.ts +0 -198
- package/src/backend/router.ts +0 -176
- package/src/backend/server.ts +0 -330
- package/src/backend/types.ts +0 -257
- package/src/batch.ts +0 -24
- package/src/cli/index.js +0 -554
- package/src/cli/index.ts +0 -257
- package/src/component.ts +0 -98
- package/src/components/Counter.tsx +0 -4
- package/src/context.ts +0 -29
- package/src/hooks.ts +0 -211
- package/src/index.ts +0 -144
- package/src/jsx-runtime/index.ts +0 -27
- package/src/jsx-runtime/jsx-dev-runtime.ts +0 -0
- package/src/jsx-runtime/jsx-runtime.ts +0 -104
- package/src/jsx-runtime.ts +0 -226
- package/src/renderer.ts +0 -55
- package/src/server-renderer.ts +0 -114
- package/src/shims.d.ts +0 -20
- package/src/types/bcrypt.d.ts +0 -30
- package/src/types/jsonwebtoken.d.ts +0 -55
- package/src/types.d.ts +0 -26
- package/src/types.ts +0 -21
- package/src/vdom.ts +0 -34
- package/templates/basic/.eslintignore +0 -5
- package/templates/basic/.eslintrc.json +0 -25
- package/templates/basic/docs/rapport_pfe.aux +0 -27
- package/templates/basic/docs/rapport_pfe.log +0 -399
- package/templates/basic/docs/rapport_pfe.out +0 -10
- package/templates/basic/docs/rapport_pfe.pdf +0 -0
- package/templates/basic/docs/rapport_pfe.tex +0 -68
- package/templates/basic/docs/rapport_pfe.toc +0 -14
- package/templates/basic/index.html +0 -12
- package/templates/basic/jsconfig.json +0 -14
- package/templates/basic/package.json +0 -20
- package/templates/basic/postcss.config.js +0 -7
- package/templates/basic/src/App.js +0 -105
- package/templates/basic/src/App.tsx +0 -65
- package/templates/basic/src/api.ts +0 -58
- package/templates/basic/src/components/Counter.tsx +0 -26
- package/templates/basic/src/components/Header.tsx +0 -9
- package/templates/basic/src/components/TodoList.tsx +0 -90
- package/templates/basic/src/main.css +0 -3
- package/templates/basic/src/main.js +0 -11
- package/templates/basic/src/main.ts +0 -20
- package/templates/basic/src/main.tsx +0 -144
- package/templates/basic/src/server.ts +0 -99
- package/templates/basic/tailwind.config.js +0 -32
- package/templates/basic/tsconfig.json +0 -20
- package/templates/basic/tsconfig.node.json +0 -10
- package/templates/basic/vite.config.js +0 -18
- package/templates/basic/vite.config.ts +0 -86
- package/templates/basic-app/src/App.js +0 -105
- package/templates/basic-app/src/App.tsx +0 -143
- package/templates/basic-app/src/api.ts +0 -58
- package/templates/basic-app/src/components/Counter.tsx +0 -26
- package/templates/basic-app/src/components/Header.tsx +0 -9
- package/templates/basic-app/src/components/TodoList.tsx +0 -90
- package/templates/basic-app/src/main.js +0 -10
- package/templates/basic-app/src/main.ts +0 -21
- package/templates/basic-app/src/react/index.ts +0 -35
- package/templates/basic-app/src/react/jsx-dev-runtime.ts +0 -13
- package/templates/basic-app/src/react/jsx-runtime.ts +0 -12
- package/templates/basic-app/src/server.ts +0 -99
- package/templates/basic-app/src/shims.ts +0 -9
- package/templates/basic-app/tsconfig.node.json +0 -10
- package/templates/basic-app/vite.config.js +0 -22
- package/templates/full-stack/.env.example +0 -11
- package/templates/full-stack/README.md +0 -51
- package/templates/full-stack/index.html +0 -12
- package/templates/full-stack/jsconfig.json +0 -14
- package/templates/full-stack/package.json +0 -20
- package/templates/full-stack/src/App.js +0 -105
- package/templates/full-stack/src/client/App.tsx +0 -50
- package/templates/full-stack/src/client/components/Header.tsx +0 -42
- package/templates/full-stack/src/client/components/UserList.tsx +0 -29
- package/templates/full-stack/src/client/main.tsx +0 -5
- package/templates/full-stack/src/main.css +0 -3
- package/templates/full-stack/src/main.js +0 -11
- package/templates/full-stack/src/main.ts +0 -20
- package/templates/full-stack/src/server/index.ts +0 -99
- package/templates/full-stack/src/server/routes/auth.ts +0 -39
- package/templates/full-stack/src/server/routes/users.ts +0 -48
- package/templates/full-stack/src/shims.ts +0 -9
- package/templates/full-stack/tsconfig.json +0 -20
- package/templates/full-stack/tsconfig.node.json +0 -10
- package/templates/full-stack/tsconfig.server.json +0 -15
- package/templates/full-stack/vite.config.js +0 -18
- package/templates/full-stack/vite.config.ts +0 -85
package/src/cli/index.ts
DELETED
@@ -1,257 +0,0 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
|
3
|
-
import fs from 'fs';
|
4
|
-
import path from 'path';
|
5
|
-
import { fileURLToPath } from 'url';
|
6
|
-
import { execSync } from 'child_process';
|
7
|
-
import readline from 'readline';
|
8
|
-
|
9
|
-
const __filename = fileURLToPath(import.meta.url);
|
10
|
-
const __dirname = path.dirname(__filename);
|
11
|
-
|
12
|
-
// Get package.json to read version
|
13
|
-
const packageJsonPath = path.resolve(__dirname, '../../package.json');
|
14
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
15
|
-
|
16
|
-
// Define interfaces for type safety
|
17
|
-
interface ProjectOptions {
|
18
|
-
template: string;
|
19
|
-
skipInstall: boolean;
|
20
|
-
}
|
21
|
-
|
22
|
-
// Available templates
|
23
|
-
const TEMPLATES: Record<string, string> = {
|
24
|
-
'basic': 'Basic frontend only template',
|
25
|
-
'full-stack': 'Complete frontend and backend template',
|
26
|
-
'api-only': 'Backend API only template'
|
27
|
-
};
|
28
|
-
|
29
|
-
// CLI colors
|
30
|
-
const colors = {
|
31
|
-
reset: '\x1b[0m',
|
32
|
-
bright: '\x1b[1m',
|
33
|
-
green: '\x1b[32m',
|
34
|
-
blue: '\x1b[34m',
|
35
|
-
red: '\x1b[31m',
|
36
|
-
yellow: '\x1b[33m'
|
37
|
-
};
|
38
|
-
|
39
|
-
// Create readline interface
|
40
|
-
function createInterface(): readline.Interface {
|
41
|
-
return readline.createInterface({
|
42
|
-
input: process.stdin,
|
43
|
-
output: process.stdout
|
44
|
-
});
|
45
|
-
}
|
46
|
-
|
47
|
-
// Print banner
|
48
|
-
function printBanner(): void {
|
49
|
-
console.log(`
|
50
|
-
${colors.blue}${colors.bright}╔══════════════════════════════════════════════╗
|
51
|
-
║ ║
|
52
|
-
║ Frontend Hamroun v${packageJson.version.padEnd(25)}║
|
53
|
-
║ A lightweight frontend & backend framework ║
|
54
|
-
║ ║
|
55
|
-
╚══════════════════════════════════════════════╝${colors.reset}
|
56
|
-
`);
|
57
|
-
}
|
58
|
-
|
59
|
-
// Print help
|
60
|
-
function printHelp(): void {
|
61
|
-
console.log(`
|
62
|
-
${colors.bright}USAGE:${colors.reset}
|
63
|
-
${colors.blue}npx frontend-hamroun${colors.reset} [command] [options]
|
64
|
-
|
65
|
-
${colors.bright}COMMANDS:${colors.reset}
|
66
|
-
${colors.blue}create${colors.reset} <project-name> [options] Create a new project
|
67
|
-
${colors.blue}help${colors.reset} Display this help message
|
68
|
-
${colors.blue}version${colors.reset} Display version information
|
69
|
-
|
70
|
-
${colors.bright}OPTIONS:${colors.reset}
|
71
|
-
${colors.blue}--template${colors.reset}, ${colors.blue}-t${colors.reset} <template> Specify template (default: basic)
|
72
|
-
${colors.blue}--skip-install${colors.reset}, ${colors.blue}-s${colors.reset} Skip package installation
|
73
|
-
|
74
|
-
${colors.bright}AVAILABLE TEMPLATES:${colors.reset}
|
75
|
-
${Object.entries(TEMPLATES).map(([name, desc]) => ` ${colors.blue}${name.padEnd(12)}${colors.reset} ${desc}`).join('\n')}
|
76
|
-
|
77
|
-
${colors.bright}EXAMPLES:${colors.reset}
|
78
|
-
${colors.blue}npx frontend-hamroun create${colors.reset} my-app
|
79
|
-
${colors.blue}npx frontend-hamroun create${colors.reset} my-app --template full-stack
|
80
|
-
${colors.blue}npx frontend-hamroun create${colors.reset} my-api -t api-only --skip-install
|
81
|
-
`);
|
82
|
-
}
|
83
|
-
|
84
|
-
// Create project from template
|
85
|
-
async function createProject(projectName: string, options: ProjectOptions): Promise<void> {
|
86
|
-
const template = options.template || 'basic';
|
87
|
-
|
88
|
-
// Check if template exists
|
89
|
-
if (!Object.keys(TEMPLATES).includes(template)) {
|
90
|
-
console.error(`${colors.red}error:${colors.reset} Template "${template}" not found.`);
|
91
|
-
console.log(`Available templates: ${Object.keys(TEMPLATES).join(', ')}`);
|
92
|
-
process.exit(1);
|
93
|
-
}
|
94
|
-
|
95
|
-
// Check if project directory already exists
|
96
|
-
const projectPath = path.resolve(process.cwd(), projectName);
|
97
|
-
if (fs.existsSync(projectPath)) {
|
98
|
-
console.error(`${colors.red}error:${colors.reset} Directory ${projectName} already exists.`);
|
99
|
-
process.exit(1);
|
100
|
-
}
|
101
|
-
|
102
|
-
console.log(`
|
103
|
-
${colors.bright}Creating a new project with Frontend Hamroun...${colors.reset}
|
104
|
-
${colors.blue}• Project name:${colors.reset} ${projectName}
|
105
|
-
${colors.blue}• Template:${colors.reset} ${template}
|
106
|
-
${colors.blue}• Directory:${colors.reset} ${projectPath}
|
107
|
-
`);
|
108
|
-
|
109
|
-
try {
|
110
|
-
// Find templates directory
|
111
|
-
const templateDir = path.resolve(__dirname, '../../templates', template);
|
112
|
-
|
113
|
-
// Create project directory
|
114
|
-
fs.mkdirSync(projectPath, { recursive: true });
|
115
|
-
|
116
|
-
// Copy template files
|
117
|
-
copyTemplateFiles(templateDir, projectPath);
|
118
|
-
|
119
|
-
// Update package.json with project name
|
120
|
-
const projectPackageJsonPath = path.join(projectPath, 'package.json');
|
121
|
-
if (fs.existsSync(projectPackageJsonPath)) {
|
122
|
-
const projectPackageJson = JSON.parse(fs.readFileSync(projectPackageJsonPath, 'utf8'));
|
123
|
-
projectPackageJson.name = projectName;
|
124
|
-
fs.writeFileSync(
|
125
|
-
projectPackageJsonPath,
|
126
|
-
JSON.stringify(projectPackageJson, null, 2)
|
127
|
-
);
|
128
|
-
}
|
129
|
-
|
130
|
-
// Install dependencies
|
131
|
-
if (!options.skipInstall) {
|
132
|
-
console.log(`\n${colors.blue}Installing dependencies...${colors.reset}`);
|
133
|
-
|
134
|
-
const command = getPackageManager() === 'yarn'
|
135
|
-
? 'yarn'
|
136
|
-
: 'npm install';
|
137
|
-
|
138
|
-
execSync(command, {
|
139
|
-
cwd: projectPath,
|
140
|
-
stdio: 'inherit'
|
141
|
-
});
|
142
|
-
}
|
143
|
-
|
144
|
-
// Success message
|
145
|
-
console.log(`
|
146
|
-
${colors.green}${colors.bright}Success!${colors.reset} Created ${projectName} at ${projectPath}
|
147
|
-
|
148
|
-
${colors.blue}Inside that directory, you can run several commands:${colors.reset}
|
149
|
-
|
150
|
-
${colors.bright}npm run dev${colors.reset}
|
151
|
-
Starts the development server.
|
152
|
-
|
153
|
-
${colors.bright}npm run build${colors.reset}
|
154
|
-
Builds the app for production.
|
155
|
-
|
156
|
-
${colors.bright}npm start${colors.reset}
|
157
|
-
Runs the built app in production mode.
|
158
|
-
|
159
|
-
${colors.blue}We suggest that you begin by typing:${colors.reset}
|
160
|
-
|
161
|
-
${colors.bright}cd${colors.reset} ${projectName}
|
162
|
-
${colors.bright}npm run dev${colors.reset}
|
163
|
-
|
164
|
-
${colors.green}Happy coding!${colors.reset}
|
165
|
-
`);
|
166
|
-
|
167
|
-
} catch (error) {
|
168
|
-
console.error(`${colors.red}Failed to create project:${colors.reset}`, error);
|
169
|
-
process.exit(1);
|
170
|
-
}
|
171
|
-
}
|
172
|
-
|
173
|
-
// Copy template files recursively
|
174
|
-
function copyTemplateFiles(source: string, destination: string): void {
|
175
|
-
const files = fs.readdirSync(source);
|
176
|
-
|
177
|
-
for (const file of files) {
|
178
|
-
const sourcePath = path.join(source, file);
|
179
|
-
const destPath = path.join(destination, file);
|
180
|
-
|
181
|
-
const stats = fs.statSync(sourcePath);
|
182
|
-
|
183
|
-
if (stats.isDirectory()) {
|
184
|
-
fs.mkdirSync(destPath, { recursive: true });
|
185
|
-
copyTemplateFiles(sourcePath, destPath);
|
186
|
-
} else {
|
187
|
-
fs.copyFileSync(sourcePath, destPath);
|
188
|
-
}
|
189
|
-
}
|
190
|
-
|
191
|
-
console.log(`${colors.green}•${colors.reset} Copied template files`);
|
192
|
-
}
|
193
|
-
|
194
|
-
// Detect package manager
|
195
|
-
function getPackageManager(): string {
|
196
|
-
try {
|
197
|
-
const userAgent = process.env.npm_config_user_agent;
|
198
|
-
if (userAgent && userAgent.startsWith('yarn')) {
|
199
|
-
return 'yarn';
|
200
|
-
}
|
201
|
-
return 'npm';
|
202
|
-
} catch (error) {
|
203
|
-
return 'npm';
|
204
|
-
}
|
205
|
-
}
|
206
|
-
|
207
|
-
// Parse command line arguments
|
208
|
-
function parseArgs(): void {
|
209
|
-
const args = process.argv.slice(2);
|
210
|
-
const command = args[0];
|
211
|
-
|
212
|
-
if (!command || command === 'help') {
|
213
|
-
printBanner();
|
214
|
-
printHelp();
|
215
|
-
process.exit(0);
|
216
|
-
}
|
217
|
-
|
218
|
-
if (command === 'version') {
|
219
|
-
console.log(`frontend-hamroun v${packageJson.version}`);
|
220
|
-
process.exit(0);
|
221
|
-
}
|
222
|
-
|
223
|
-
if (command === 'create') {
|
224
|
-
const projectName = args[1];
|
225
|
-
|
226
|
-
if (!projectName) {
|
227
|
-
console.error(`${colors.red}error:${colors.reset} Project name is required.`);
|
228
|
-
console.log(`Run ${colors.blue}npx frontend-hamroun help${colors.reset} for usage information.`);
|
229
|
-
process.exit(1);
|
230
|
-
}
|
231
|
-
|
232
|
-
// Parse options
|
233
|
-
const options: ProjectOptions = {
|
234
|
-
template: 'basic',
|
235
|
-
skipInstall: false
|
236
|
-
};
|
237
|
-
|
238
|
-
for (let i = 2; i < args.length; i++) {
|
239
|
-
if (args[i] === '--template' || args[i] === '-t') {
|
240
|
-
options.template = args[++i];
|
241
|
-
} else if (args[i] === '--skip-install' || args[i] === '-s') {
|
242
|
-
options.skipInstall = true;
|
243
|
-
}
|
244
|
-
}
|
245
|
-
|
246
|
-
printBanner();
|
247
|
-
createProject(projectName, options);
|
248
|
-
return;
|
249
|
-
}
|
250
|
-
|
251
|
-
console.error(`${colors.red}error:${colors.reset} Unknown command: ${command}`);
|
252
|
-
console.log(`Run ${colors.blue}npx frontend-hamroun help${colors.reset} for usage information.`);
|
253
|
-
process.exit(1);
|
254
|
-
}
|
255
|
-
|
256
|
-
// Run CLI
|
257
|
-
parseArgs();
|
package/src/component.ts
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
import { createElement } from './jsx-runtime';
|
2
|
-
|
3
|
-
export class Component {
|
4
|
-
state: any = {};
|
5
|
-
props: any;
|
6
|
-
element: HTMLElement | null = null;
|
7
|
-
private _mounted: boolean = false;
|
8
|
-
|
9
|
-
constructor(props: any = {}) {
|
10
|
-
this.props = props;
|
11
|
-
}
|
12
|
-
|
13
|
-
componentDidMount() {
|
14
|
-
// Hook for after component is mounted
|
15
|
-
}
|
16
|
-
|
17
|
-
async setState(newState: any) {
|
18
|
-
const prevState = { ...this.state };
|
19
|
-
this.state = { ...prevState, ...newState };
|
20
|
-
console.log(`${this.constructor.name} state updated:`, {
|
21
|
-
prev: prevState,
|
22
|
-
next: this.state
|
23
|
-
});
|
24
|
-
|
25
|
-
await Promise.resolve(); // Ensure state is updated before re-render
|
26
|
-
if (this._mounted) {
|
27
|
-
await this.update();
|
28
|
-
} else {
|
29
|
-
await this.update();
|
30
|
-
}
|
31
|
-
}
|
32
|
-
|
33
|
-
private _replayEvents(oldElement: HTMLElement, newElement: HTMLElement) {
|
34
|
-
const oldEvents = (oldElement as any).__events || {};
|
35
|
-
Object.entries(oldEvents).forEach(([event, handler]) => {
|
36
|
-
newElement.addEventListener(event as keyof HTMLElementEventMap, handler as EventListener);
|
37
|
-
});
|
38
|
-
(newElement as any).__events = oldEvents;
|
39
|
-
}
|
40
|
-
|
41
|
-
private _deepCloneWithEvents(node: HTMLElement): HTMLElement {
|
42
|
-
const clone = node.cloneNode(false) as HTMLElement;
|
43
|
-
|
44
|
-
// Copy events from original element
|
45
|
-
const events = (node as any).__events || {};
|
46
|
-
(clone as any).__events = events;
|
47
|
-
Object.entries(events).forEach(([event, handler]) => {
|
48
|
-
clone.addEventListener(event as keyof HTMLElementEventMap, handler as EventListener);
|
49
|
-
});
|
50
|
-
|
51
|
-
// Clone children
|
52
|
-
Array.from(node.childNodes).forEach(child => {
|
53
|
-
if (child instanceof HTMLElement) {
|
54
|
-
clone.appendChild(this._deepCloneWithEvents(child));
|
55
|
-
} else {
|
56
|
-
clone.appendChild(child.cloneNode(true));
|
57
|
-
}
|
58
|
-
});
|
59
|
-
|
60
|
-
return clone;
|
61
|
-
}
|
62
|
-
|
63
|
-
async update() {
|
64
|
-
const vdom = this.render();
|
65
|
-
if (!vdom) return document.createTextNode('');
|
66
|
-
|
67
|
-
const rendered = await createElement(vdom);
|
68
|
-
if (rendered instanceof HTMLElement) {
|
69
|
-
return this._updateElement(rendered);
|
70
|
-
}
|
71
|
-
|
72
|
-
const wrapper = document.createElement('div');
|
73
|
-
wrapper.appendChild(rendered);
|
74
|
-
return this._updateElement(wrapper);
|
75
|
-
}
|
76
|
-
|
77
|
-
private async _updateElement(rendered: HTMLElement) {
|
78
|
-
const newElement = this._deepCloneWithEvents(rendered);
|
79
|
-
(newElement as any).__instance = this;
|
80
|
-
|
81
|
-
if (!this.element) {
|
82
|
-
this.element = newElement;
|
83
|
-
if (!this._mounted) {
|
84
|
-
this._mounted = true;
|
85
|
-
queueMicrotask(() => this.componentDidMount());
|
86
|
-
}
|
87
|
-
} else if (this.element.parentNode) {
|
88
|
-
this.element.parentNode.replaceChild(newElement, this.element);
|
89
|
-
this.element = newElement;
|
90
|
-
}
|
91
|
-
|
92
|
-
return this.element;
|
93
|
-
}
|
94
|
-
|
95
|
-
render(): any {
|
96
|
-
throw new Error('Component must implement render() method');
|
97
|
-
}
|
98
|
-
}
|
package/src/context.ts
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
import { useState, useEffect } from './hooks';
|
2
|
-
|
3
|
-
const contexts = new Map<symbol, any>();
|
4
|
-
let currentRender: Function | null = null;
|
5
|
-
|
6
|
-
export interface Context<T> {
|
7
|
-
Provider: (props: { value: T; children: any }) => any;
|
8
|
-
Consumer: (props: { children: (value: T) => any }) => any;
|
9
|
-
_currentValue: T;
|
10
|
-
}
|
11
|
-
|
12
|
-
export function createContext<T>(defaultValue: T): Context<T> {
|
13
|
-
const context: Context<T> = {
|
14
|
-
_currentValue: defaultValue,
|
15
|
-
Provider: function Provider({ value, children }) {
|
16
|
-
context._currentValue = value;
|
17
|
-
return children;
|
18
|
-
},
|
19
|
-
Consumer: function Consumer({ children }) {
|
20
|
-
return children(context._currentValue);
|
21
|
-
}
|
22
|
-
};
|
23
|
-
|
24
|
-
return context;
|
25
|
-
}
|
26
|
-
|
27
|
-
export function useContext<T>(context: Context<T>): T {
|
28
|
-
return context._currentValue;
|
29
|
-
}
|
package/src/hooks.ts
DELETED
@@ -1,211 +0,0 @@
|
|
1
|
-
import { createElement } from './jsx-runtime';
|
2
|
-
import { batchUpdates, isBatching } from './batch';
|
3
|
-
import { diff } from './vdom';
|
4
|
-
|
5
|
-
let currentRender: number = 0;
|
6
|
-
const states = new Map<number, any[]>();
|
7
|
-
const stateIndices = new Map<number, number>();
|
8
|
-
const effects = new Map<number, Effect[]>();
|
9
|
-
const memos = new Map<number, { value: any; deps: any[] }[]>();
|
10
|
-
const refs = new Map<number, any[]>();
|
11
|
-
|
12
|
-
interface Effect {
|
13
|
-
cleanup?: () => void;
|
14
|
-
deps?: any[];
|
15
|
-
}
|
16
|
-
|
17
|
-
// Add at the top with other declarations
|
18
|
-
let globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;
|
19
|
-
let globalContainer: HTMLElement | null = null;
|
20
|
-
let currentElement: any = null;
|
21
|
-
|
22
|
-
const isServer = typeof window === 'undefined';
|
23
|
-
const serverStates = new Map<number, any>();
|
24
|
-
|
25
|
-
export function setRenderCallback(
|
26
|
-
callback: (element: any, container: HTMLElement) => void,
|
27
|
-
element: any,
|
28
|
-
container: HTMLElement
|
29
|
-
) {
|
30
|
-
globalRenderCallback = callback;
|
31
|
-
globalContainer = container;
|
32
|
-
currentElement = element;
|
33
|
-
}
|
34
|
-
|
35
|
-
export function prepareRender() {
|
36
|
-
currentRender++;
|
37
|
-
stateIndices.set(currentRender, 0);
|
38
|
-
return currentRender;
|
39
|
-
}
|
40
|
-
|
41
|
-
export function finishRender() {
|
42
|
-
if (isServer) {
|
43
|
-
serverStates.delete(currentRender);
|
44
|
-
}
|
45
|
-
currentRender = 0;
|
46
|
-
}
|
47
|
-
|
48
|
-
export function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {
|
49
|
-
if (!currentRender) {
|
50
|
-
throw new Error('useState must be called within a render');
|
51
|
-
}
|
52
|
-
|
53
|
-
if (isServer) {
|
54
|
-
// Server-side state handling
|
55
|
-
if (!serverStates.has(currentRender)) {
|
56
|
-
serverStates.set(currentRender, new Map());
|
57
|
-
}
|
58
|
-
const componentState = serverStates.get(currentRender)!;
|
59
|
-
const index = stateIndices.get(currentRender) || 0;
|
60
|
-
|
61
|
-
if (!componentState.has(index)) {
|
62
|
-
componentState.set(index, initial);
|
63
|
-
}
|
64
|
-
|
65
|
-
const state = componentState.get(index);
|
66
|
-
const setState = (newValue: T | ((prev: T) => T)) => {
|
67
|
-
// No-op for server-side
|
68
|
-
};
|
69
|
-
|
70
|
-
stateIndices.set(currentRender, index + 1);
|
71
|
-
return [state, setState];
|
72
|
-
}
|
73
|
-
|
74
|
-
if (!states.has(currentRender)) {
|
75
|
-
states.set(currentRender, []);
|
76
|
-
}
|
77
|
-
|
78
|
-
const componentStates = states.get(currentRender)!;
|
79
|
-
const index = stateIndices.get(currentRender)!;
|
80
|
-
|
81
|
-
if (index >= componentStates.length) {
|
82
|
-
componentStates.push(initial);
|
83
|
-
}
|
84
|
-
|
85
|
-
const state = componentStates[index];
|
86
|
-
const setState = (newValue: T | ((prev: T) => T)) => {
|
87
|
-
const nextValue = typeof newValue === 'function'
|
88
|
-
? (newValue as Function)(componentStates[index])
|
89
|
-
: newValue;
|
90
|
-
|
91
|
-
if (componentStates[index] === nextValue) return; // Skip if value hasn't changed
|
92
|
-
|
93
|
-
componentStates[index] = nextValue;
|
94
|
-
|
95
|
-
if (isBatching) {
|
96
|
-
batchUpdates(() => rerender(currentRender));
|
97
|
-
} else {
|
98
|
-
rerender(currentRender);
|
99
|
-
}
|
100
|
-
};
|
101
|
-
|
102
|
-
stateIndices.set(currentRender, index + 1);
|
103
|
-
return [state, setState];
|
104
|
-
}
|
105
|
-
|
106
|
-
export function useEffect(callback: () => (() => void) | void, deps?: any[]) {
|
107
|
-
if (!currentRender) throw new Error('useEffect must be called within a render');
|
108
|
-
|
109
|
-
const effectIndex = stateIndices.get(currentRender)!;
|
110
|
-
|
111
|
-
if (!effects.has(currentRender)) {
|
112
|
-
effects.set(currentRender, []);
|
113
|
-
}
|
114
|
-
|
115
|
-
const componentEffects = effects.get(currentRender)!;
|
116
|
-
const prevEffect = componentEffects[effectIndex];
|
117
|
-
|
118
|
-
// Run effect if deps changed
|
119
|
-
if (!prevEffect || !deps || !prevEffect.deps ||
|
120
|
-
deps.some((dep, i) => dep !== prevEffect.deps![i])) {
|
121
|
-
|
122
|
-
// Cleanup previous effect
|
123
|
-
if (prevEffect?.cleanup) {
|
124
|
-
prevEffect.cleanup();
|
125
|
-
}
|
126
|
-
|
127
|
-
// Schedule new effect
|
128
|
-
queueMicrotask(() => {
|
129
|
-
const cleanup = callback() || undefined;
|
130
|
-
componentEffects[effectIndex] = { cleanup: cleanup, deps };
|
131
|
-
});
|
132
|
-
}
|
133
|
-
|
134
|
-
stateIndices.set(currentRender, effectIndex + 1);
|
135
|
-
}
|
136
|
-
|
137
|
-
export function useMemo<T>(factory: () => T, deps: any[]): T {
|
138
|
-
if (!currentRender) throw new Error('useMemo must be called within a render');
|
139
|
-
|
140
|
-
const memoIndex = stateIndices.get(currentRender)!;
|
141
|
-
|
142
|
-
if (!memos.has(currentRender)) {
|
143
|
-
memos.set(currentRender, []);
|
144
|
-
}
|
145
|
-
|
146
|
-
const componentMemos = memos.get(currentRender)!;
|
147
|
-
const prevMemo = componentMemos[memoIndex];
|
148
|
-
|
149
|
-
if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {
|
150
|
-
const value = factory();
|
151
|
-
componentMemos[memoIndex] = { value, deps };
|
152
|
-
stateIndices.set(currentRender, memoIndex + 1);
|
153
|
-
return value;
|
154
|
-
}
|
155
|
-
|
156
|
-
stateIndices.set(currentRender, memoIndex + 1);
|
157
|
-
return prevMemo.value;
|
158
|
-
}
|
159
|
-
|
160
|
-
export function useRef<T>(initial: T) {
|
161
|
-
if (!currentRender) throw new Error('useRef must be called within a render');
|
162
|
-
|
163
|
-
const refIndex = stateIndices.get(currentRender)!;
|
164
|
-
|
165
|
-
if (!refs.has(currentRender)) {
|
166
|
-
refs.set(currentRender, []);
|
167
|
-
}
|
168
|
-
|
169
|
-
const componentRefs = refs.get(currentRender)!;
|
170
|
-
if (refIndex >= componentRefs.length) {
|
171
|
-
// Initialize with an object that has a current property
|
172
|
-
const ref = { current: initial };
|
173
|
-
componentRefs.push(ref);
|
174
|
-
stateIndices.set(currentRender, refIndex + 1);
|
175
|
-
return ref;
|
176
|
-
}
|
177
|
-
|
178
|
-
const ref = componentRefs[refIndex];
|
179
|
-
stateIndices.set(currentRender, refIndex + 1);
|
180
|
-
return ref;
|
181
|
-
}
|
182
|
-
|
183
|
-
// Add a map to track component DOM nodes
|
184
|
-
const componentNodes = new Map<Function, Node>();
|
185
|
-
|
186
|
-
async function rerender(rendererId: number) {
|
187
|
-
try {
|
188
|
-
// Clean up effects
|
189
|
-
const componentEffects = effects.get(rendererId);
|
190
|
-
if (componentEffects) {
|
191
|
-
componentEffects.forEach(effect => {
|
192
|
-
if (effect.cleanup) effect.cleanup();
|
193
|
-
});
|
194
|
-
effects.set(rendererId, []);
|
195
|
-
}
|
196
|
-
|
197
|
-
if (globalRenderCallback && globalContainer && currentElement) {
|
198
|
-
await globalRenderCallback(currentElement, globalContainer);
|
199
|
-
}
|
200
|
-
} catch (error) {
|
201
|
-
console.error('Error during rerender:', error);
|
202
|
-
}
|
203
|
-
}
|
204
|
-
|
205
|
-
// Add new hook for error boundaries
|
206
|
-
export function useErrorBoundary(): [Error | null, () => void] {
|
207
|
-
const [error, setError] = useState<Error | null>(null);
|
208
|
-
return [error, () => setError(null)];
|
209
|
-
}
|
210
|
-
|
211
|
-
// Remove withHooks export
|