frontend-hamroun 1.1.10 → 1.1.12

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 CHANGED
@@ -8,6 +8,23 @@ A lightweight Virtual DOM and hooks implementation with JSX support.
8
8
  npm install your-package-name
9
9
  ```
10
10
 
11
+ ## Quick Start
12
+
13
+ Create a new project using:
14
+
15
+ ```bash
16
+ npx create-frontend-app my-app
17
+ # or
18
+ npm create frontend-app@latest my-app
19
+ ```
20
+ Then:
21
+
22
+ ```bash
23
+ cd my-app
24
+ npm install
25
+ npm run dev
26
+ ```
27
+
11
28
  ## Usage
12
29
 
13
30
  ```jsx
@@ -220,4 +237,4 @@ MIT License - feel free to use in any project.
220
237
  ## Contributing
221
238
 
222
239
  Contributions are welcome! Please read our contributing guidelines and submit pull requests.
223
- ````
240
+ `````
package/bin/cli.js CHANGED
@@ -69,44 +69,50 @@ async function createProject(projectName, options) {
69
69
  }
70
70
 
71
71
  program
72
- .name('frontend-hamroun')
73
- .description('CLI for Frontend Hamroun Framework')
74
- .version('1.0.0');
72
+ .name('create-frontend-app')
73
+ .description('Create a new Frontend Hamroun application')
74
+ .argument('[name]', 'Project name')
75
+ .action(async (name) => {
76
+ let projectName = name;
77
+
78
+ if (!projectName) {
79
+ const response = await inquirer.prompt([{
80
+ type: 'input',
81
+ name: 'projectName',
82
+ message: 'What is your project named?',
83
+ default: 'my-frontend-app'
84
+ }]);
85
+ projectName = response.projectName;
86
+ }
75
87
 
76
- program
77
- .command('create <project-name>')
78
- .description('Create a new project')
79
- .action(async (projectName) => {
80
- const answers = await inquirer.prompt([
81
- {
82
- type: 'list',
83
- name: 'template',
84
- message: 'What type of project do you want to create?',
85
- choices: Object.values(CHOICES)
86
- }
87
- ]);
88
-
89
- await createProject(projectName, {
90
- template: answers.template === CHOICES.SPA ? 'spa' : 'component'
91
- });
92
- });
88
+ const spinner = createSpinner('Creating project...').start();
93
89
 
94
- program
95
- .command('dev')
96
- .description('Start development server')
97
- .action(() => {
98
- const spinner = createSpinner('Starting development server...').start();
99
- // Add dev server logic here
100
- spinner.success({ text: 'Development server started on http://localhost:3000' });
101
- });
90
+ try {
91
+ // Copy template
92
+ const templateDir = path.join(__dirname, '..', 'templates', 'basic-app');
93
+ const targetDir = path.join(process.cwd(), projectName);
102
94
 
103
- program
104
- .command('build')
105
- .description('Build for production')
106
- .action(() => {
107
- const spinner = createSpinner('Building for production...').start();
108
- // Add build logic here
109
- spinner.success({ text: 'Build complete!' });
95
+ await fs.ensureDir(targetDir);
96
+ await fs.copy(templateDir, targetDir);
97
+
98
+ // Update package.json
99
+ const pkgJsonPath = path.join(targetDir, 'package.json');
100
+ const pkgJson = await fs.readJson(pkgJsonPath);
101
+ pkgJson.name = projectName;
102
+ await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
103
+
104
+ spinner.success({ text: chalk.green(`Project ${projectName} created successfully!`) });
105
+
106
+ console.log('\nNext steps:');
107
+ console.log(chalk.cyan(` cd ${projectName}`));
108
+ console.log(chalk.cyan(' npm install'));
109
+ console.log(chalk.cyan(' npm run dev'));
110
+
111
+ } catch (error) {
112
+ spinner.error({ text: chalk.red('Failed to create project') });
113
+ console.error(error);
114
+ process.exit(1);
115
+ }
110
116
  });
111
117
 
112
- program.parse(process.argv);
118
+ program.parse();
package/dist/batch.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- type BatchCallback = () => void;
2
- export declare function batchUpdates(callback: BatchCallback): void;
3
- export declare function isBatching(): boolean;
4
- export {};
1
+ export declare let isBatching: boolean;
2
+ export declare function batchUpdates(fn: Function): void;
3
+ export declare function getIsBatching(): boolean;
File without changes
package/dist/context.d.ts CHANGED
@@ -10,4 +10,4 @@ export interface Context<T> {
10
10
  useSelector: <S>(selector: (state: T) => S) => S;
11
11
  }
12
12
  export declare function createContext<T>(defaultValue: T): Context<T>;
13
- export declare function useContext<T>(context: Context<T>): T;
13
+ export declare function useContext<T>(context: any): T;
@@ -1,192 +1,182 @@
1
- async function m(t) {
1
+ async function d(t) {
2
2
  var e;
3
3
  if (console.log("Creating element from:", t), t == null || typeof t == "boolean")
4
4
  return document.createTextNode("");
5
5
  if (typeof t == "number" || typeof t == "string")
6
6
  return document.createTextNode(String(t));
7
7
  if (Array.isArray(t)) {
8
- const r = document.createDocumentFragment();
8
+ const n = document.createDocumentFragment();
9
9
  for (const s of t) {
10
- const n = await m(s);
11
- r.appendChild(n);
10
+ const o = await d(s);
11
+ n.appendChild(o);
12
12
  }
13
- return r;
13
+ return n;
14
14
  }
15
15
  if ("type" in t && t.props !== void 0) {
16
- const { type: r, props: s } = t;
17
- if (typeof r == "function")
16
+ const { type: n, props: s } = t;
17
+ if (typeof n == "function")
18
18
  try {
19
- const c = await r(s || {}), a = await m(c);
20
- return a instanceof Element && a.setAttribute("data-component-id", r.name || r.toString()), a;
19
+ const c = await n(s || {}), a = await d(c);
20
+ return a instanceof Element && a.setAttribute("data-component-id", n.name || n.toString()), a;
21
21
  } catch (c) {
22
22
  return console.error("Error rendering component:", c), document.createTextNode("");
23
23
  }
24
- const n = document.createElement(r);
24
+ const o = document.createElement(n);
25
25
  for (const [c, a] of Object.entries(s || {}))
26
26
  if (c !== "children")
27
27
  if (c.startsWith("on") && typeof a == "function") {
28
- const f = c.toLowerCase().slice(2), S = (e = n.__events) == null ? void 0 : e[f];
29
- S && n.removeEventListener(f, S), n.addEventListener(f, a), n.__events || (n.__events = {}), n.__events[f] = a;
28
+ const f = c.toLowerCase().slice(2), C = (e = o.__events) == null ? void 0 : e[f];
29
+ C && o.removeEventListener(f, C), o.addEventListener(f, a), o.__events || (o.__events = {}), o.__events[f] = a;
30
30
  } else
31
- c === "style" && typeof a == "object" ? Object.assign(n.style, a) : c === "className" ? n.setAttribute("class", String(a)) : c !== "key" && c !== "ref" && n.setAttribute(c, String(a));
31
+ c === "style" && typeof a == "object" ? Object.assign(o.style, a) : c === "className" ? o.setAttribute("class", String(a)) : c !== "key" && c !== "ref" && o.setAttribute(c, String(a));
32
32
  const i = s == null ? void 0 : s.children;
33
33
  if (i != null) {
34
34
  const c = Array.isArray(i) ? i.flat() : [i];
35
35
  for (const a of c) {
36
- const f = await m(a);
37
- n.appendChild(f);
36
+ const f = await d(a);
37
+ o.appendChild(f);
38
38
  }
39
39
  }
40
- return n;
40
+ return o;
41
41
  }
42
42
  return document.createTextNode(String(t));
43
43
  }
44
- let h = [], p = !1;
45
- function _(t) {
46
- if (p) {
44
+ let m = !1;
45
+ const h = [];
46
+ function S(t) {
47
+ if (m) {
47
48
  h.push(t);
48
49
  return;
49
50
  }
50
- p = !0;
51
+ m = !0;
51
52
  try {
52
53
  for (t(); h.length > 0; ) {
53
54
  const e = h.shift();
54
55
  e == null || e();
55
56
  }
56
57
  } finally {
57
- p = !1;
58
+ m = !1;
58
59
  }
59
60
  }
60
61
  function R() {
61
- return p;
62
+ return m;
62
63
  }
63
- let o = 0;
64
- const g = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), w = /* @__PURE__ */ new Map();
65
- let b = null, E = null, x = null;
66
- function A(t, e, r) {
67
- b = t, E = r, x = e;
64
+ let r = 0;
65
+ const p = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), g = /* @__PURE__ */ new Map();
66
+ let w = null, b = null, E = null;
67
+ function _(t, e, n) {
68
+ w = t, b = n, E = e;
68
69
  }
69
- function T() {
70
- return o++, u.set(o, 0), o;
70
+ function A() {
71
+ return r++, u.set(r, 0), r;
71
72
  }
72
- function j() {
73
- o = 0;
73
+ function T() {
74
+ r = 0;
74
75
  }
75
- function v(t) {
76
- if (!o)
76
+ function k(t) {
77
+ if (!r)
77
78
  throw new Error("useState must be called within a render");
78
- g.has(o) || g.set(o, []);
79
- const e = g.get(o), r = u.get(o);
80
- r >= e.length && e.push(t);
81
- const s = e[r], n = (i) => {
82
- const c = typeof i == "function" ? i(e[r]) : i;
83
- e[r] !== c && (e[r] = c, R() ? _(() => C(o)) : C(o));
79
+ p.has(r) || p.set(r, []);
80
+ const e = p.get(r), n = u.get(r);
81
+ n >= e.length && e.push(t);
82
+ const s = e[n], o = (i) => {
83
+ const c = typeof i == "function" ? i(e[n]) : i;
84
+ e[n] !== c && (e[n] = c, R() ? S(() => M(r)) : M(r));
84
85
  };
85
- return u.set(o, r + 1), [s, n];
86
+ return u.set(r, n + 1), [s, o];
86
87
  }
87
- function L(t, e) {
88
- if (!o)
88
+ function I(t, e) {
89
+ if (!r)
89
90
  throw new Error("useEffect must be called within a render");
90
- const r = u.get(o);
91
- d.has(o) || d.set(o, []);
92
- const s = d.get(o), n = s[r];
93
- (!n || !e || !n.deps || e.some((i, c) => i !== n.deps[c])) && (n != null && n.cleanup && n.cleanup(), queueMicrotask(() => {
91
+ const n = u.get(r);
92
+ l.has(r) || l.set(r, []);
93
+ const s = l.get(r), o = s[n];
94
+ (!o || !e || !o.deps || e.some((i, c) => i !== o.deps[c])) && (o != null && o.cleanup && o.cleanup(), queueMicrotask(() => {
94
95
  const i = t() || void 0;
95
- s[r] = { cleanup: i, deps: e };
96
- })), u.set(o, r + 1);
96
+ s[n] = { cleanup: i, deps: e };
97
+ })), u.set(r, n + 1);
97
98
  }
98
- function I(t, e) {
99
- if (!o)
99
+ function j(t, e) {
100
+ if (!r)
100
101
  throw new Error("useMemo must be called within a render");
101
- const r = u.get(o);
102
- y.has(o) || y.set(o, []);
103
- const s = y.get(o), n = s[r];
104
- if (!n || e && e.some((i, c) => !Object.is(i, n.deps[c]))) {
102
+ const n = u.get(r);
103
+ y.has(r) || y.set(r, []);
104
+ const s = y.get(r), o = s[n];
105
+ if (!o || e && e.some((i, c) => !Object.is(i, o.deps[c]))) {
105
106
  const i = t();
106
- return s[r] = { value: i, deps: e }, u.set(o, r + 1), i;
107
+ return s[n] = { value: i, deps: e }, u.set(r, n + 1), i;
107
108
  }
108
- return u.set(o, r + 1), n.value;
109
+ return u.set(r, n + 1), o.value;
109
110
  }
110
- function O(t) {
111
- if (!o)
111
+ function v(t) {
112
+ if (!r)
112
113
  throw new Error("useRef must be called within a render");
113
- const e = u.get(o);
114
- w.has(o) || w.set(o, []);
115
- const r = w.get(o);
116
- if (e >= r.length) {
117
- const n = { current: t };
118
- return r.push(n), u.set(o, e + 1), n;
114
+ const e = u.get(r);
115
+ g.has(r) || g.set(r, []);
116
+ const n = g.get(r);
117
+ if (e >= n.length) {
118
+ const o = { current: t };
119
+ return n.push(o), u.set(r, e + 1), o;
119
120
  }
120
- const s = r[e];
121
- return u.set(o, e + 1), s;
121
+ const s = n[e];
122
+ return u.set(r, e + 1), s;
122
123
  }
123
- async function C(t) {
124
+ async function M(t) {
124
125
  try {
125
- const e = d.get(t);
126
- e && (e.forEach((r) => {
127
- r.cleanup && r.cleanup();
128
- }), d.set(t, [])), b && E && x && await b(x, E);
126
+ const e = l.get(t);
127
+ e && (e.forEach((n) => {
128
+ n.cleanup && n.cleanup();
129
+ }), l.set(t, [])), w && b && E && await w(E, b);
129
130
  } catch (e) {
130
131
  console.error("Error during rerender:", e);
131
132
  }
132
133
  }
133
- function k() {
134
- const [t, e] = v(null);
134
+ function L() {
135
+ const [t, e] = k(null);
135
136
  return [t, () => e(null)];
136
137
  }
137
- const l = /* @__PURE__ */ new Map();
138
138
  function B(t) {
139
- const e = Symbol();
140
- return l.set(e, t), {
141
- Provider: ({ value: s, children: n }) => {
142
- const i = l.get(e);
143
- return Object.is(i, s) || l.set(e, s), n;
144
- },
145
- Consumer: ({ children: s }) => {
146
- const n = l.get(e);
147
- return s(n);
148
- },
149
- useSelector: (s) => {
150
- const n = l.get(e);
151
- return I(() => s(n), [n]);
152
- },
153
- _id: e
139
+ return {
140
+ Provider: ({ value: n, children: s }) => s,
141
+ Consumer: ({ children: n }) => n(t),
142
+ _id: Symbol(),
143
+ useSelector: (n) => n(t)
154
144
  };
155
145
  }
156
146
  function H(t) {
157
- return l.get(t._id);
147
+ return t;
158
148
  }
159
- let M = !1;
160
- async function U(t, e) {
161
- M = !0;
149
+ let x = !1;
150
+ async function O(t, e) {
151
+ x = !0;
162
152
  try {
163
153
  await N(t, e);
164
154
  } finally {
165
- M = !1;
155
+ x = !1;
166
156
  }
167
157
  }
168
158
  async function N(t, e) {
169
- console.log("Rendering to:", e.id), _(async () => {
170
- const r = T();
159
+ console.log("Rendering to:", e.id), S(async () => {
160
+ const n = A();
171
161
  try {
172
- A(N, t, e);
173
- const s = await m(t);
174
- M || (e.innerHTML = ""), e.appendChild(s);
162
+ _(N, t, e);
163
+ const s = await d(t);
164
+ x || (e.innerHTML = ""), e.appendChild(s);
175
165
  } finally {
176
- j();
166
+ T();
177
167
  }
178
168
  });
179
169
  }
180
170
  export {
181
- _ as batchUpdates,
171
+ S as batchUpdates,
182
172
  B as createContext,
183
- U as hydrate,
173
+ O as hydrate,
184
174
  N as render,
185
175
  H as useContext,
186
- L as useEffect,
187
- k as useErrorBoundary,
188
- I as useMemo,
189
- O as useRef,
190
- v as useState
176
+ I as useEffect,
177
+ L as useErrorBoundary,
178
+ j as useMemo,
179
+ v as useRef,
180
+ k as useState
191
181
  };
192
182
  //# sourceMappingURL=frontend-hamroun.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frontend-hamroun.js","sources":["../src/jsx-runtime.ts","../src/batch.ts","../src/hooks.ts","../src/context.ts","../src/index.ts"],"sourcesContent":["import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nexport function jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nexport { jsx as jsxs, jsx as jsxDEV };\r\nexport const Fragment = ({ children }: { children: any }) => children;\r\n\r\nexport async function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n","type BatchCallback = () => void;\r\nlet batchQueue: BatchCallback[] = [];\r\nlet isBatchingUpdates = false;\r\n\r\nexport function batchUpdates(callback: BatchCallback) {\r\n if (isBatchingUpdates) {\r\n batchQueue.push(callback);\r\n return;\r\n }\r\n\r\n isBatchingUpdates = true;\r\n try {\r\n callback();\r\n while (batchQueue.length > 0) {\r\n const queuedCallback = batchQueue.shift();\r\n queuedCallback?.();\r\n }\r\n } finally {\r\n isBatchingUpdates = false;\r\n }\r\n}\r\n\r\nexport function isBatching() {\r\n return isBatchingUpdates;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (isBatching()) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","import { useMemo } from \"./hooks\";\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const id = Symbol();\r\n contexts.set(id, defaultValue);\r\n \r\n const useSelector = <S>(selector: (state: T) => S): S => {\r\n const value = contexts.get(id);\r\n return useMemo(() => selector(value), [value]);\r\n };\r\n\r\n return {\r\n Provider: ({ value, children }) => {\r\n const prevValue = contexts.get(id);\r\n if (!Object.is(prevValue, value)) {\r\n contexts.set(id, value);\r\n }\r\n return children;\r\n },\r\n Consumer: ({ children }) => {\r\n const value = contexts.get(id);\r\n return children(value);\r\n },\r\n useSelector,\r\n _id: id\r\n };\r\n}\r\n\r\nexport function useContext<T>(context: Context<T>): T {\r\n return contexts.get(context._id);\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nexport { \r\n useState, \r\n useEffect, \r\n useMemo, \r\n useRef,\r\n useErrorBoundary \r\n} from './hooks';\r\n\r\nexport { createContext, useContext } from './context';\r\nexport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n\r\n"],"names":["createElement","vnode","_a","fragment","child","node","type","props","result","error","element","key","value","eventName","existingHandler","children","childArray","childNode","batchQueue","isBatchingUpdates","batchUpdates","callback","queuedCallback","isBatching","currentRender","states","stateIndices","effects","memos","refs","globalRenderCallback","globalContainer","currentElement","setRenderCallback","container","prepareRender","finishRender","useState","initial","componentStates","index","state","setState","newValue","nextValue","rerender","useEffect","deps","effectIndex","componentEffects","prevEffect","dep","i","cleanup","useMemo","factory","memoIndex","componentMemos","prevMemo","useRef","refIndex","componentRefs","ref","rendererId","effect","useErrorBoundary","setError","contexts","createContext","defaultValue","id","prevValue","selector","useContext","context","isHydrating","hydrate","render","domNode"],"mappings":"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"}
1
+ {"version":3,"file":"frontend-hamroun.js","sources":["../src/jsx-runtime.ts","../src/batch.ts","../src/hooks.ts","../src/context.ts","../src/index.ts"],"sourcesContent":["import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nexport function jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nexport { jsx as jsxs, jsx as jsxDEV };\r\nexport const Fragment = ({ children }: { children: any }) => children;\r\n\r\nexport async function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n","export let isBatching = false;\r\nconst queue: Function[] = [];\r\n\r\nexport function batchUpdates(fn: Function) {\r\n if (isBatching) {\r\n queue.push(fn);\r\n return;\r\n }\r\n\r\n isBatching = true;\r\n try {\r\n fn();\r\n while (queue.length > 0) {\r\n const nextFn = queue.shift();\r\n nextFn?.();\r\n }\r\n } finally {\r\n isBatching = false;\r\n }\r\n}\r\n\r\nexport function getIsBatching() {\r\n return isBatching;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, getIsBatching, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (getIsBatching()) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const context = {\r\n Provider: ({ value, children }: { value: T, children?: any }) => {\r\n return children;\r\n },\r\n Consumer: ({ children }: { children: (value: T) => any }) => {\r\n return children(defaultValue);\r\n },\r\n _id: Symbol(),\r\n useSelector: <S>(selector: (state: T) => S) => {\r\n return selector(defaultValue);\r\n }\r\n };\r\n\r\n return context;\r\n}\r\n\r\nexport function useContext<T>(context: any): T {\r\n return context;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nexport { \r\n useState, \r\n useEffect, \r\n useMemo, \r\n useRef,\r\n useErrorBoundary \r\n} from './hooks';\r\n\r\nexport { createContext, useContext } from './context';\r\nexport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n\r\n"],"names":["createElement","vnode","_a","fragment","child","node","type","props","result","error","element","key","value","eventName","existingHandler","children","childArray","childNode","isBatching","queue","batchUpdates","fn","nextFn","getIsBatching","currentRender","states","stateIndices","effects","memos","refs","globalRenderCallback","globalContainer","currentElement","setRenderCallback","callback","container","prepareRender","finishRender","useState","initial","componentStates","index","state","setState","newValue","nextValue","rerender","useEffect","deps","effectIndex","componentEffects","prevEffect","dep","i","cleanup","useMemo","factory","memoIndex","componentMemos","prevMemo","useRef","refIndex","componentRefs","ref","rendererId","effect","useErrorBoundary","setError","createContext","defaultValue","selector","useContext","context","isHydrating","hydrate","render","domNode"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function jsx(type: string | Function, props: any, key?: string): any;
2
+ export declare function jsxs(type: string | Function, props: any, key?: string): any;
3
+ export declare function createElement(vnode: any): HTMLElement | Text;
4
+ export declare const Fragment: unique symbol;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontend-hamroun",
3
- "version": "1.1.10",
3
+ "version": "1.1.12",
4
4
  "description": "A lightweight frontend framework with hooks and virtual DOM",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>My Frontend App</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "my-app",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "preview": "vite preview"
9
+ },
10
+ "dependencies": {
11
+ "frontend-hamroun": "^1.1.11"
12
+ },
13
+ "devDependencies": {
14
+ "typescript": "^5.0.0",
15
+ "vite": "^4.4.9"
16
+ }
17
+ }
@@ -0,0 +1,18 @@
1
+ import { useState, useEffect } from 'frontend-hamroun';
2
+
3
+ export function Counter({ initial = 0 }) {
4
+ const [count, setCount] = useState(initial);
5
+
6
+ useEffect(() => {
7
+ document.title = `Count: ${count}`;
8
+ }, [count]);
9
+
10
+ return (
11
+ <div>
12
+ <h2>Counter Component</h2>
13
+ <button onClick={() => setCount(count - 1)}>-</button>
14
+ <span style={{ margin: '0 10px' }}>{count}</span>
15
+ <button onClick={() => setCount(count + 1)}>+</button>
16
+ </div>
17
+ );
18
+ }
@@ -0,0 +1,18 @@
1
+ import { render, useState } from 'frontend-hamroun';
2
+
3
+ function App() {
4
+ const [count, setCount] = useState(0);
5
+
6
+ return (
7
+ <div>
8
+ <h1>Welcome to Frontend Hamroun</h1>
9
+ <div>
10
+ <button onClick={() => setCount(count - 1)}>-</button>
11
+ <span style={{ margin: '0 10px' }}>{count}</span>
12
+ <button onClick={() => setCount(count + 1)}>+</button>
13
+ </div>
14
+ </div>
15
+ );
16
+ }
17
+
18
+ render(<App />, document.getElementById('root')!);
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "jsx": "preserve",
7
+ "moduleResolution": "bundler",
8
+ "esModuleInterop": true,
9
+ "strict": true,
10
+ "skipLibCheck": true
11
+ },
12
+ "include": ["src"]
13
+ }
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from 'vite';
2
+
3
+ export default defineConfig({
4
+ esbuild: {
5
+ jsxFactory: 'jsx',
6
+ jsxFragment: 'Fragment'
7
+ }
8
+ });