frontend-hamroun 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/LICENSE ADDED
File without changes
package/README.md ADDED
@@ -0,0 +1,228 @@
1
+ # Lightweight Frontend Framework
2
+
3
+ A modern, lightweight framework for building user interfaces with hooks, context, and efficient rendering.
4
+
5
+ ## Features
6
+ - 🎯 Hooks-based Components
7
+ - 🔄 Virtual DOM Diffing
8
+ - 📦 Batch Updates
9
+ - 🌍 Context API
10
+ - 💾 Memoization
11
+ - ⚡ Async Rendering
12
+ - 🛡️ Error Boundaries
13
+ - 🎨 Style Management
14
+ - 🔌 Event Handling
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install lightweight-frontend
20
+ ```
21
+
22
+ ## Basic Usage
23
+
24
+ ```tsx
25
+ import { render, useState } from 'lightweight-frontend';
26
+
27
+ function Counter() {
28
+ const [count, setCount] = useState(0);
29
+
30
+ return (
31
+ <div>
32
+ <h1>Count: {count}</h1>
33
+ <button onClick={() => setCount(count + 1)}>
34
+ Increment
35
+ </button>
36
+ </div>
37
+ );
38
+ }
39
+
40
+ render(<Counter />, document.getElementById('root'));
41
+ ```
42
+
43
+ ## Hooks
44
+
45
+ ### useState
46
+ Manages component state.
47
+
48
+ ```tsx
49
+ const [state, setState] = useState(initialValue);
50
+ ```
51
+
52
+ ### useEffect
53
+ Handles side effects in components.
54
+
55
+ ```tsx
56
+ useEffect(() => {
57
+ // Effect code
58
+ return () => {
59
+ // Cleanup code
60
+ };
61
+ }, [dependencies]);
62
+ ```
63
+
64
+ ### useMemo
65
+ Memoizes expensive computations.
66
+
67
+ ```tsx
68
+ const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
69
+ ```
70
+
71
+ ### useRef
72
+ Creates a mutable reference.
73
+
74
+ ```tsx
75
+ const ref = useRef(initialValue);
76
+ ```
77
+
78
+ ### useErrorBoundary
79
+ Handles component errors.
80
+
81
+ ```tsx
82
+ const [error, resetError] = useErrorBoundary();
83
+ ```
84
+
85
+ ## Context API
86
+
87
+ Create and use shared state across components.
88
+
89
+ ```tsx
90
+ const ThemeContext = createContext('light');
91
+
92
+ function App() {
93
+ return (
94
+ <ThemeContext.Provider value="dark">
95
+ <Child />
96
+ </ThemeContext.Provider>
97
+ );
98
+ }
99
+
100
+ function Child() {
101
+ const theme = useContext(ThemeContext);
102
+ // Or use selector for performance
103
+ const isDark = ThemeContext.useSelector(theme => theme === 'dark');
104
+ }
105
+ ```
106
+
107
+ ## Performance Optimization
108
+
109
+ ### Batch Updates
110
+ Group multiple state updates together.
111
+
112
+ ```tsx
113
+ import { batchUpdates } from 'lightweight-frontend';
114
+
115
+ batchUpdates(() => {
116
+ setValue1(newValue1);
117
+ setValue2(newValue2);
118
+ });
119
+ ```
120
+
121
+ ### Component Memoization
122
+ Prevent unnecessary re-renders.
123
+
124
+ ```tsx
125
+ const MemoizedComponent = useMemo(() => (
126
+ <ExpensiveComponent prop={value} />
127
+ ), [value]);
128
+ ```
129
+
130
+ ## Server-Side Rendering
131
+
132
+ ```tsx
133
+ import { hydrate } from 'lightweight-frontend';
134
+
135
+ // On the client
136
+ hydrate(<App />, document.getElementById('root'));
137
+ ```
138
+
139
+ ## Event Handling
140
+
141
+ ```tsx
142
+ function Button() {
143
+ return (
144
+ <button
145
+ onClick={(e) => handleClick(e)}
146
+ onMouseOver={(e) => handleHover(e)}
147
+ >
148
+ Click me
149
+ </button>
150
+ );
151
+ }
152
+ ```
153
+
154
+ ## Styling
155
+
156
+ ```tsx
157
+ function StyledComponent() {
158
+ return (
159
+ <div style={{
160
+ color: 'blue',
161
+ padding: '20px'
162
+ }}>
163
+ Styled content
164
+ </div>
165
+ );
166
+ }
167
+ ```
168
+
169
+ ## Error Handling
170
+
171
+ ```tsx
172
+ function ErrorBoundary() {
173
+ const [error, resetError] = useErrorBoundary();
174
+
175
+ if (error) {
176
+ return (
177
+ <div>
178
+ <h1>Something went wrong!</h1>
179
+ <button onClick={resetError}>Try again</button>
180
+ </div>
181
+ );
182
+ }
183
+
184
+ return <ComponentThatMightError />;
185
+ }
186
+ ```
187
+
188
+ ## Best Practices
189
+
190
+ 1. Use batch updates for multiple state changes
191
+ 2. Implement error boundaries for error handling
192
+ 3. Use context selectors for better performance
193
+ 4. Memoize expensive computations
194
+ 5. Clean up effects when components unmount
195
+ 6. Keep components small and focused
196
+ 7. Use proper TypeScript types for better development experience
197
+
198
+ ## API Reference
199
+
200
+ ### Core
201
+ - `render(element, container)`
202
+ - `hydrate(element, container)`
203
+ - `createElement(vnode)`
204
+
205
+ ### Hooks
206
+ - `useState<T>(initial: T)`
207
+ - `useEffect(callback, deps?)`
208
+ - `useMemo(factory, deps)`
209
+ - `useRef(initial)`
210
+ - `useErrorBoundary()`
211
+
212
+ ### Context
213
+ - `createContext(defaultValue)`
214
+ - `useContext(Context)`
215
+ - `Context.Provider`
216
+ - `Context.Consumer`
217
+ - `Context.useSelector`
218
+
219
+ ### Performance
220
+ - `batchUpdates(callback)`
221
+
222
+ ## License
223
+
224
+ MIT License - feel free to use in any project.
225
+
226
+ ## Contributing
227
+
228
+ Contributions are welcome! Please read our contributing guidelines and submit pull requests.
@@ -0,0 +1,4 @@
1
+ type BatchCallback = () => void;
2
+ export declare function batchUpdates(callback: BatchCallback): void;
3
+ export declare function isBatching(): boolean;
4
+ export {};
@@ -0,0 +1,14 @@
1
+ export declare class Component {
2
+ state: any;
3
+ props: any;
4
+ element: HTMLElement | null;
5
+ private _mounted;
6
+ constructor(props?: any);
7
+ componentDidMount(): void;
8
+ setState(newState: any): Promise<void>;
9
+ private _replayEvents;
10
+ private _deepCloneWithEvents;
11
+ update(): Promise<Text | HTMLElement>;
12
+ private _updateElement;
13
+ render(): any;
14
+ }
@@ -0,0 +1,13 @@
1
+ export interface Context<T> {
2
+ Provider: (props: {
3
+ value: T;
4
+ children?: any;
5
+ }) => any;
6
+ Consumer: (props: {
7
+ children: (value: T) => any;
8
+ }) => any;
9
+ _id: symbol;
10
+ useSelector: <S>(selector: (state: T) => S) => S;
11
+ }
12
+ export declare function createContext<T>(defaultValue: T): Context<T>;
13
+ export declare function useContext<T>(context: Context<T>): T;
@@ -0,0 +1,192 @@
1
+ async function m(t) {
2
+ var e;
3
+ if (console.log("Creating element from:", t), t == null || typeof t == "boolean")
4
+ return document.createTextNode("");
5
+ if (typeof t == "number" || typeof t == "string")
6
+ return document.createTextNode(String(t));
7
+ if (Array.isArray(t)) {
8
+ const r = document.createDocumentFragment();
9
+ for (const s of t) {
10
+ const n = await m(s);
11
+ r.appendChild(n);
12
+ }
13
+ return r;
14
+ }
15
+ if ("type" in t && t.props !== void 0) {
16
+ const { type: r, props: s } = t;
17
+ if (typeof r == "function")
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;
21
+ } catch (c) {
22
+ return console.error("Error rendering component:", c), document.createTextNode("");
23
+ }
24
+ const n = document.createElement(r);
25
+ for (const [c, a] of Object.entries(s || {}))
26
+ if (c !== "children")
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;
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));
32
+ const i = s == null ? void 0 : s.children;
33
+ if (i != null) {
34
+ const c = Array.isArray(i) ? i.flat() : [i];
35
+ for (const a of c) {
36
+ const f = await m(a);
37
+ n.appendChild(f);
38
+ }
39
+ }
40
+ return n;
41
+ }
42
+ return document.createTextNode(String(t));
43
+ }
44
+ let h = [], p = !1;
45
+ function _(t) {
46
+ if (p) {
47
+ h.push(t);
48
+ return;
49
+ }
50
+ p = !0;
51
+ try {
52
+ for (t(); h.length > 0; ) {
53
+ const e = h.shift();
54
+ e == null || e();
55
+ }
56
+ } finally {
57
+ p = !1;
58
+ }
59
+ }
60
+ function R() {
61
+ return p;
62
+ }
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;
68
+ }
69
+ function T() {
70
+ return o++, u.set(o, 0), o;
71
+ }
72
+ function j() {
73
+ o = 0;
74
+ }
75
+ function v(t) {
76
+ if (!o)
77
+ 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));
84
+ };
85
+ return u.set(o, r + 1), [s, n];
86
+ }
87
+ function L(t, e) {
88
+ if (!o)
89
+ 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(() => {
94
+ const i = t() || void 0;
95
+ s[r] = { cleanup: i, deps: e };
96
+ })), u.set(o, r + 1);
97
+ }
98
+ function I(t, e) {
99
+ if (!o)
100
+ 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]))) {
105
+ const i = t();
106
+ return s[r] = { value: i, deps: e }, u.set(o, r + 1), i;
107
+ }
108
+ return u.set(o, r + 1), n.value;
109
+ }
110
+ function O(t) {
111
+ if (!o)
112
+ 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;
119
+ }
120
+ const s = r[e];
121
+ return u.set(o, e + 1), s;
122
+ }
123
+ async function C(t) {
124
+ 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);
129
+ } catch (e) {
130
+ console.error("Error during rerender:", e);
131
+ }
132
+ }
133
+ function k() {
134
+ const [t, e] = v(null);
135
+ return [t, () => e(null)];
136
+ }
137
+ const l = /* @__PURE__ */ new Map();
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
154
+ };
155
+ }
156
+ function H(t) {
157
+ return l.get(t._id);
158
+ }
159
+ let M = !1;
160
+ async function U(t, e) {
161
+ M = !0;
162
+ try {
163
+ await N(t, e);
164
+ } finally {
165
+ M = !1;
166
+ }
167
+ }
168
+ async function N(t, e) {
169
+ console.log("Rendering to:", e.id), _(async () => {
170
+ const r = T();
171
+ try {
172
+ A(N, t, e);
173
+ const s = await m(t);
174
+ M || (e.innerHTML = ""), e.appendChild(s);
175
+ } finally {
176
+ j();
177
+ }
178
+ });
179
+ }
180
+ export {
181
+ _ as batchUpdates,
182
+ B as createContext,
183
+ U as hydrate,
184
+ N as render,
185
+ H as useContext,
186
+ L as useEffect,
187
+ k as useErrorBoundary,
188
+ I as useMemo,
189
+ O as useRef,
190
+ v as useState
191
+ };
192
+ //# sourceMappingURL=frontend-hamroun.js.map
@@ -0,0 +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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"}
@@ -0,0 +1,8 @@
1
+ export declare function setRenderCallback(callback: (element: any, container: HTMLElement) => void, element: any, container: HTMLElement): void;
2
+ export declare function prepareRender(): number;
3
+ export declare function finishRender(): void;
4
+ export declare function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void];
5
+ export declare function useEffect(callback: () => (() => void) | void, deps?: any[]): void;
6
+ export declare function useMemo<T>(factory: () => T, deps: any[]): T;
7
+ export declare function useRef<T>(initial: T): any;
8
+ export declare function useErrorBoundary(): [Error | null, () => void];
@@ -0,0 +1,5 @@
1
+ export { useState, useEffect, useMemo, useRef, useErrorBoundary } from './hooks';
2
+ export { createContext, useContext } from './context';
3
+ export { batchUpdates } from './batch';
4
+ export declare function hydrate(element: any, container: HTMLElement): Promise<void>;
5
+ export declare function render(element: any, container: HTMLElement): Promise<void>;
@@ -0,0 +1,10 @@
1
+ interface VNode {
2
+ type: string | Function;
3
+ props: Record<string, any>;
4
+ }
5
+ export declare function jsx(type: string | Function, props: any): VNode;
6
+ export { jsx as jsxs, jsx as jsxDEV };
7
+ export declare const Fragment: ({ children }: {
8
+ children: any;
9
+ }) => any;
10
+ export declare function createElement(vnode: VNode | any): Promise<Node>;
package/dist/test.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/vdom.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ interface VNode {
2
+ type: string | Function;
3
+ props: Record<string, any>;
4
+ key?: string | number;
5
+ }
6
+ export declare function diff(oldNode: VNode | any, newNode: VNode | any): boolean;
7
+ export declare function shouldComponentUpdate(oldProps: any, newProps: any): boolean;
8
+ export {};
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "frontend-hamroun",
3
+ "version": "1.0.0",
4
+ "description": "A lightweight frontend framework with hooks and virtual DOM",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.es.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "import": "./dist/index.es.js",
17
+ "require": "./dist/index.js",
18
+ "types": "./dist/index.d.ts"
19
+ }
20
+ },
21
+ "scripts": {
22
+ "build": "vite build && tsc --emitDeclarationOnly",
23
+ "clean": "node -e \"if(require('fs').existsSync('dist')) require('fs').rmSync('dist',{recursive:true})\"",
24
+ "prepublishOnly": "npm run clean && npm run build"
25
+ },
26
+ "keywords": [
27
+ "frontend",
28
+ "framework",
29
+ "jsx",
30
+ "hooks",
31
+ "virtual-dom"
32
+ ],
33
+ "author": "Hamroun",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "your-repo-url"
38
+ },
39
+ "devDependencies": {
40
+ "@types/react": "^19.0.8",
41
+ "@vitejs/plugin-react": "^4.0.4",
42
+ "typescript": "^5.0.0",
43
+ "vite": "^4.4.9",
44
+ "vitest": "^0.34.0"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ }
49
+ }