olova 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +4 -3
  2. package/dist/olova.js +202 -1115
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -19,16 +19,18 @@ applications with ease.
19
19
 
20
20
  To get started with Olova, first install the core library via npm or yarn.
21
21
 
22
- ````bash
22
+ ```bash
23
23
  npm install olova
24
24
  ```
25
+
25
26
  or
27
+
26
28
  ```bash
27
29
  yarn add olova
28
30
  ```
29
31
 
30
-
31
32
  ## Example Usage
33
+
32
34
  Here is an example of a basic component in Olova:
33
35
 
34
36
  ```js
@@ -49,5 +51,4 @@ export default function Home() {
49
51
  </>
50
52
  );
51
53
  }
52
-
53
54
  ```
package/dist/olova.js CHANGED
@@ -1,1139 +1,226 @@
1
- /**
2
- * @license
3
- * Olova Framework v2.0.0
4
- * (c) 2025 Olova
5
- * This source code is licensed under the MIT license
6
- *
7
- * Author: Nazmul Hossain
8
- * Made in Bangladesh
9
- */
10
-
11
- /** @jsx Olova.createElement */
12
-
13
- const Olova = {};
14
- let currentComponent = null,
15
- currentHook = 0;
16
- const states = new WeakMap(),
17
- effects = new WeakMap(),
18
- memos = new WeakMap(),
19
- refs = new WeakMap();
20
- let isBatchingUpdates = !1;
21
- const effectComponentIds = new Set(),
22
- customHookComponentIds = new Set();
23
- Olova.createHook = (e) => {
24
- if ("function" != typeof e)
25
- throw new Error("createHook: Hook implementation must be a function");
26
- return (...t) => {
27
- if (!currentComponent)
28
- throw new Error(
29
- "Custom hooks can only be called inside component render"
30
- );
31
- const o = currentHook++,
32
- r = currentComponent;
33
- customHooks.has(r) ||
34
- (customHooks.set(r, new Map()), customHookComponentIds.add(r));
35
- const n = customHooks.get(r);
36
- n.has(o) || n.set(o, { state: void 0, cleanup: void 0 });
37
- const a = {
38
- useState: Olova.State,
39
- useEffect: Olova.Effect,
40
- useMemo: Olova.Memo,
41
- useRef: Olova.Ref,
42
- getHookState: () => n.get(o).state,
43
- setHookState: (e) => {
44
- n.get(o).state = e;
45
- },
46
- setCleanup: (e) => {
47
- "function" == typeof e && (n.get(o).cleanup = e);
48
- },
49
- };
50
- return e(a, ...t);
51
- };
52
- };
53
- const customHooks = new WeakMap();
54
- Olova.State = (e) => {
55
- const t = currentComponent,
56
- o = currentHook++;
57
- states.has(t) || states.set(t, []);
58
- const r = states.get(t);
59
- void 0 === r[o] && (r[o] = e);
60
- return [
61
- r[o],
62
- (e) => {
63
- const t = "function" == typeof e ? e(r[o]) : e;
64
- queueUpdate(() => {
65
- (r[o] = t), rerender();
66
- });
67
- },
68
- ];
69
- };
70
- const flattenChildren = (e) =>
71
- e.reduce(
72
- (e, t) =>
73
- null == t || "boolean" == typeof t
74
- ? e
75
- : Array.isArray(t)
76
- ? e.concat(flattenChildren(t))
77
- : e.concat("object" == typeof t ? t : createTextElement(t)),
78
- []
79
- );
80
- Olova.createElement = (e, t, ...o) =>
81
- e === Olova.Fragment
82
- ? { type: "FRAGMENT", props: { children: flattenChildren(o) } }
83
- : { type: e, props: { ...t, children: flattenChildren(o) } };
84
- const createTextElement = (e) => ({
85
- type: "TEXT_ELEMENT",
86
- props: { nodeValue: e, children: [] },
87
- }),
88
- createDom = (e) => {
89
- const t =
90
- "TEXT_ELEMENT" === e.type
91
- ? document.createTextNode("")
92
- : document.createElement(e.type),
93
- o = sanitizeProps(e.props);
94
- return updateDom(t, {}, o), t;
95
- },
96
- updateDom = (e, t, o) => {
97
- t.style &&
98
- Object.keys(t.style).forEach((r) => {
99
- (o.style && t.style[r] === o.style[r]) || (e.style[r] = "");
100
- });
101
- const r = new Map();
102
- Object.keys(t || {}).forEach((e) => {
103
- "children" === e || e in o || r.set(e, null);
104
- }),
105
- Object.keys(o || {}).forEach((e) => {
106
- "children" !== e && t[e] !== o[e] && r.set(e, o[e]);
107
- }),
108
- r.forEach((o, r) => {
109
- if (r.startsWith("on")) {
110
- const n = r.slice(2).toLowerCase();
111
- t[r] && e.removeEventListener(n, t[r]), o && e.addEventListener(n, o);
112
- } else
113
- "style" === r && "object" == typeof o
114
- ? Object.assign(e.style, o)
115
- : "className" === r
116
- ? e.setAttribute("class", o || "")
117
- : "boolean" == typeof o
118
- ? o
119
- ? e.setAttribute(r, "")
120
- : e.removeAttribute(r)
121
- : (e[r] = o ?? "");
122
- });
123
- };
124
- let rootElement = null,
125
- currentRoot = null;
126
- Olova.render = (e, t) => {
127
- (rootElement = t),
128
- (currentRoot = { dom: t, props: { children: [e] } }),
129
- rerender();
130
- };
131
- const rerender = () => {
132
- if (rootElement && currentRoot) {
133
- for (
134
- effectComponentIds.forEach((e) => {
135
- const t = effects.get(e);
136
- t &&
137
- t.forEach((e) => {
138
- e && e.cleanup && e.cleanup();
139
- });
140
- }),
141
- customHookComponentIds.forEach((e) => {
142
- const t = customHooks.get(e);
143
- t &&
144
- t.forEach((e) => {
145
- e.cleanup && e.cleanup();
146
- });
147
- });
148
- rootElement.firstChild;
149
-
150
- )
151
- rootElement.removeChild(rootElement.firstChild);
152
- renderElement(currentRoot.props.children[0], rootElement);
153
- }
154
- },
155
- cleanupEffects = () => {
156
- effects.forEach((e, t) => {
157
- e.forEach((e) => {
158
- e && e.cleanup && e.cleanup();
159
- });
160
- });
161
- },
162
- cleanupCustomHooks = () => {
163
- customHooks.forEach((e, t) => {
164
- e.forEach((e) => {
165
- e.cleanup && e.cleanup();
166
- });
167
- });
168
- },
169
- contexts = new Map();
170
- let contextIndex = 0;
171
- (Olova.createContext = (e) => {
172
- const t = contextIndex++;
173
- return (
174
- contexts.set(t, { defaultValue: e, value: e }),
175
- {
176
- Provider: ({ value: e, children: o }) => (
177
- (contexts.get(t).value = e), o[0]
178
- ),
179
- Consumer: ({ children: e }) => e[0](contexts.get(t).value),
180
- _contextId: t,
181
- }
182
- );
183
- }),
184
- (Olova.Context = (e) => {
185
- if (!e || "number" != typeof e._contextId)
186
- throw new Error(
187
- "Context: Invalid context object. Make sure you're passing a context created by createContext()"
188
- );
189
- return currentHook++, contexts.get(e._contextId).value;
190
- });
191
- const renderElement = (e, t) => {
192
- if (!t || !(t instanceof Element || t instanceof DocumentFragment))
193
- throw new Error("Invalid container element provided to render");
194
- if (!e && 0 !== e && "" !== e) return;
195
- if ("FRAGMENT" === e.type) {
196
- const o = document.createDocumentFragment();
1
+ let currentObserver = null;
2
+ function diffProps(e = {}, t = {}, r) {
3
+ for (const [n, o] of Object.entries(e))
4
+ n in t ||
5
+ (n.startsWith("on")
6
+ ? r.removeEventListener(n.slice(2).toLowerCase(), o)
7
+ : "style" === n
8
+ ? (r.style.cssText = "")
9
+ : r.removeAttribute(n));
10
+ for (const [n, o] of Object.entries(t))
11
+ if (null != o && e[n] !== o)
12
+ if (n.startsWith("on")) {
13
+ const t = n.slice(2).toLowerCase();
14
+ e[n] && r.removeEventListener(t, e[n]), r.addEventListener(t, o);
15
+ } else if ("ref" === n)
16
+ o && "object" == typeof o && "current" in o
17
+ ? (o.current = r)
18
+ : "function" == typeof o && o(r);
19
+ else if ("style" === n) {
20
+ const e = r.style;
21
+ "object" == typeof o ? Object.assign(e, o) : (e.cssText = o);
22
+ } else r.setAttribute(n, o);
23
+ }
24
+ function diffChildren(e, t, r) {
25
+ const n = Array.isArray(e) ? e.flat() : [e],
26
+ o = Array.isArray(t) ? t.flat() : [t],
27
+ s = Math.max(n.length, o.length);
28
+ for (let e = 0; e < s; e++) {
29
+ const t = n[e],
30
+ s = o[e];
31
+ if (!t || s)
32
+ if (t || !s) {
33
+ if (t instanceof Node && s instanceof Node)
34
+ t.nodeType !== s.nodeType || t.nodeName !== s.nodeName
35
+ ? r.replaceChild(s, t)
36
+ : (diffProps(t.attributes, s.attributes, t),
37
+ diffChildren(
38
+ Array.from(t.childNodes),
39
+ Array.from(s.childNodes),
40
+ t
41
+ ));
42
+ else if (t !== s) {
43
+ const t = r.childNodes[e];
44
+ t && (t.textContent = String(s));
45
+ }
46
+ } else {
47
+ const e = s instanceof Node ? s : document.createTextNode(String(s));
48
+ r.appendChild(e);
49
+ }
50
+ else t instanceof Node && r.removeChild(t);
51
+ }
52
+ }
53
+ class Signal {
54
+ constructor(e) {
55
+ (this._value = e), (this.observers = new Map());
56
+ }
57
+ get value() {
197
58
  return (
198
- e.props.children.forEach((e) => renderElement(e, o)),
199
- void t.appendChild(o)
59
+ currentObserver &&
60
+ (this.observers.has("_root") || this.observers.set("_root", new Set()),
61
+ this.observers.get("_root").add(currentObserver)),
62
+ this._value
200
63
  );
201
64
  }
202
- if ("object" == typeof e.type && e.type.Consumer) {
203
- const o = contexts.get(e.type._contextId).value,
204
- r = e.props.children[0](o);
205
- return void renderElement(r, t);
206
- }
207
- if ("object" == typeof e.type && e.type.Provider) {
208
- const o = e.props.children[0];
209
- return void renderElement(o, t);
65
+ set value(e) {
66
+ if (this._value === e) return;
67
+ const t = this._value;
68
+ if (((this._value = e), this.observers.has("_root")))
69
+ for (const e of this.observers.get("_root")) e();
70
+ if ("object" == typeof t && "object" == typeof e) {
71
+ const r = new Set([...Object.keys(t), ...Object.keys(e)]);
72
+ for (const n of r)
73
+ if (t[n] !== e[n] && this.observers.has(n))
74
+ for (const e of this.observers.get(n)) e();
75
+ }
210
76
  }
211
- if ("function" == typeof e.type) {
212
- (currentComponent = e.type), (currentHook = 0);
213
- const o = e.type(e.props);
214
- return void renderElement(o, t);
77
+ observe(e, t) {
78
+ this.observers.has(e) || this.observers.set(e, new Set()),
79
+ this.observers.get(e).add(t);
215
80
  }
216
- const o = createDom(e);
217
- e.props.children.forEach((e) => renderElement(e, o)), t.appendChild(o);
218
- };
219
- (Olova.Effect = (e, t) => {
220
- if ("function" != typeof e)
221
- throw new Error("Effect: First argument must be a function");
222
- if (void 0 !== t && !Array.isArray(t))
223
- throw new Error("Effect: Second argument must be an array or undefined");
224
- const o = currentComponent,
225
- r = currentHook++;
226
- effects.has(o) || (effects.set(o, []), effectComponentIds.add(o));
227
- const n = effects.get(o),
228
- a = n[r];
229
- if (!a || !t || t.some((e, t) => !Object.is(e, a.deps[t]))) {
230
- a && a.cleanup && a.cleanup();
231
- const o = e();
232
- n[r] = { deps: t, cleanup: "function" == typeof o ? o : void 0 };
81
+ unobserve(e, t) {
82
+ this.observers.has(e) && this.observers.get(e).delete(t);
233
83
  }
234
- }),
235
- (Olova.Reducer = (e, t, o) => {
236
- const r = currentComponent,
237
- n = currentHook++;
238
- states.has(r) || states.set(r, []);
239
- const a = states.get(r);
240
- void 0 === a[n] && (a[n] = o ? o(t) : t);
241
- return [
242
- a[n],
243
- (t) => {
244
- (a[n] = e(a[n], t)), rerender();
84
+ }
85
+ function State(e) {
86
+ const t = new Signal(e),
87
+ r = () => t.value;
88
+ return (
89
+ (r.toString = () => t.value),
90
+ (r.observe = (e, r) => t.observe(e, r)),
91
+ (r.unobserve = (e, r) => t.unobserve(e, r)),
92
+ [
93
+ r,
94
+ (e) => {
95
+ t.value = "function" == typeof e ? e(t.value) : e;
245
96
  },
246
- ];
247
- }),
248
- (Olova.Callback = (e, t) => Olova.Memo(() => e, t)),
249
- (Olova.Memo = (e, t) => {
250
- const o = currentComponent,
251
- r = currentHook++;
252
- memos.has(o) || memos.set(o, []);
253
- const n = memos.get(o),
254
- a = n[r];
255
- if (
256
- !a ||
257
- !t ||
258
- t.length !== a.deps.length ||
259
- t.some(
260
- (e, t) =>
261
- !Object.is(e, a.deps[t]) &&
262
- ("object" != typeof e ||
263
- null === e ||
264
- JSON.stringify(e) !== JSON.stringify(a.deps[t]))
265
- )
266
- ) {
267
- const o = e();
268
- return (n[r] = { value: o, deps: t }), o;
269
- }
270
- return a.value;
271
- }),
272
- (Olova.Ref = (e) => {
273
- const t = currentComponent,
274
- o = currentHook++;
275
- refs.has(t) || refs.set(t, []);
276
- const r = refs.get(t);
277
- return void 0 === r[o] && (r[o] = { current: e }), r[o];
278
- }),
279
- (Olova.LayoutEffect = (e, t) => {
280
- Olova.Effect(e, t);
281
- }),
282
- (Olova.ImperativeHandle = (e, t, o) => {
283
- Olova.LayoutEffect(() => {
284
- e && (e.current = t());
285
- }, o);
286
- }),
287
- (Olova.Fragment = Symbol("Fragment"));
288
- let nextUnitOfWork = null,
289
- wipRoot = null;
290
- function createFiber(e, t, o = null) {
291
- return {
292
- type: e,
293
- props: t,
294
- key: o,
295
- dom: null,
296
- parent: null,
297
- child: null,
298
- sibling: null,
299
- alternate: null,
300
- effectTag: null,
301
- lastProps: null,
302
- shouldUpdate: !0,
303
- dependencies: new Set(),
304
- memoizedState: null,
305
- };
97
+ ]
98
+ );
306
99
  }
307
- const schedulerPriorities = {
308
- ImmediatePriority: 1,
309
- UserBlockingPriority: 2,
310
- NormalPriority: 3,
311
- LowPriority: 4,
312
- IdlePriority: 5,
313
- },
314
- objectPool = {
315
- fibers: [],
316
- effects: [],
317
- acquireFiber() {
318
- return this.fibers.pop() || createFiber();
319
- },
320
- releaseFiber(e) {
321
- Object.keys(e).forEach((t) => {
322
- e[t] = null;
323
- }),
324
- this.fibers.push(e);
325
- },
326
- },
327
- workLoop = (e) => {
328
- let t = !1;
329
- for (; nextUnitOfWork && !t; ) {
330
- const o = nextUnitOfWork;
331
- if (
332
- (o.priorityLevel || schedulerPriorities.NormalPriority) >
333
- schedulerPriorities.ImmediatePriority &&
334
- e.timeRemaining() < 500
335
- ) {
336
- t = !0;
337
- break;
338
- }
339
- nextUnitOfWork = performUnitOfWork(o);
340
- }
341
- !nextUnitOfWork && wipRoot && commitRoot(), requestIdleCallback(workLoop);
100
+ function Effect(e) {
101
+ const t = () => {
102
+ (currentObserver = t), e(), (currentObserver = null);
342
103
  };
343
- function performUnitOfWork(e) {
344
- if (
345
- ("function" == typeof e.type
346
- ? updateFunctionComponent(e)
347
- : updateHostComponent(e),
348
- e.child)
349
- )
350
- return e.child;
351
- let t = e;
352
- for (; t; ) {
353
- if (t.sibling) return t.sibling;
354
- t = t.parent;
355
- }
104
+ t();
356
105
  }
357
- function updateFunctionComponent(e) {
358
- (currentComponent = e), (currentHook = 0), (e.hooks = []);
359
- try {
360
- const t = [e.type(e.props)];
361
- reconcileChildren(e, t);
362
- } catch (t) {
363
- handleWorkInProgressError(e, t);
364
- }
106
+ function Memo(e) {
107
+ const [t, r] = State(e());
108
+ return Effect(() => r(e())), t;
365
109
  }
366
- function updateHostComponent(e) {
367
- e.dom || (e.dom = createDom(e)), reconcileChildren(e, e.props.children);
368
- }
369
- function reconcileChildren(e, t, o) {
370
- let r = null,
371
- n = null;
372
- const a = new Map();
373
- let s = t;
374
- for (; s; ) {
375
- const e = s.key || s.index;
376
- a.set(e, s), (s = s.sibling);
377
- }
378
- for (let t = 0; t < o.length; t++) {
379
- const s = o[t],
380
- c = s.key || t,
381
- l = a.get(c);
382
- l && l.type === s.type
383
- ? (n = {
384
- ...l,
385
- props: s.props,
386
- alternate: l,
387
- effectTag: "UPDATE",
388
- shouldUpdate: !shallowEqual(l.props, s.props),
389
- })
390
- : ((n = createFiber(s.type, s.props, c)),
391
- (n.effectTag = "PLACEMENT"),
392
- (n.shouldUpdate = !0),
393
- l && ((l.effectTag = "DELETION"), deletions.push(l))),
394
- null === r ? (e.child = n) : (r.sibling = n),
395
- (r = n),
396
- a.delete(c);
397
- }
398
- a.forEach((e) => {
399
- (e.effectTag = "DELETION"), deletions.push(e);
110
+ function Ref(e) {
111
+ const [t, r] = State({
112
+ current: e,
113
+ toString() {
114
+ return this.current;
115
+ },
116
+ valueOf() {
117
+ return this.current;
118
+ },
400
119
  });
120
+ return {
121
+ get current() {
122
+ return t().current;
123
+ },
124
+ set current(e) {
125
+ r((t) => (t.current === e ? t : { ...t, current: e }));
126
+ },
127
+ toString() {
128
+ return this.current.toString();
129
+ },
130
+ valueOf() {
131
+ return this.current;
132
+ },
133
+ };
401
134
  }
402
- function shallowEqual(e, t) {
403
- if (Object.is(e, t)) return !0;
404
- if (!e || !t) return !1;
405
- const o = Object.keys(e),
406
- r = Object.keys(t);
407
- if (o.length !== r.length) return !1;
408
- for (let r = 0; r < o.length; r++) {
409
- const n = o[r];
410
- if ("children" !== n && !Object.is(e[n], t[n])) return !1;
411
- }
412
- return !0;
413
- }
414
- function handleWorkInProgressError(e, t) {
415
- let o = null,
416
- r = e;
417
- for (; r; ) {
418
- if (r.type?.prototype instanceof Olova.ErrorBoundary) {
419
- o = r;
420
- break;
135
+ function h(e, t, ...r) {
136
+ if (e === Fragment || Array.isArray(e)) {
137
+ const n = document.createDocumentFragment(),
138
+ o = e === Fragment ? t?.children || r : e;
139
+ if (Array.isArray(o)) {
140
+ const e = document.createTextNode.bind(document);
141
+ o.forEach((t) => {
142
+ n.appendChild(t instanceof Node ? t : null != t ? e(String(t)) : null);
143
+ });
421
144
  }
422
- r = r.parent;
423
- }
424
- if (!o) throw t;
425
- {
426
- const r = {
427
- componentStack: getComponentStack(e),
428
- error: t,
429
- errorBoundary: o,
430
- };
431
- (o.updateQueue = o.updateQueue || []),
432
- o.updateQueue.push({ action: "ERROR", error: r }),
433
- scheduleWork(o, schedulerPriorities.ImmediatePriority);
434
- }
145
+ return n;
146
+ }
147
+ if (!e) return null;
148
+ const n = "function" == typeof e ? e(t) : document.createElement(e);
149
+ if (("string" == typeof e && n && t && diffProps({}, t, n), r.length)) {
150
+ const e = document.createDocumentFragment(),
151
+ t = (r) => {
152
+ if (null != r)
153
+ if ("function" == typeof r) {
154
+ const t = document.createTextNode("");
155
+ Effect(() => (t.textContent = r())), e.appendChild(t);
156
+ } else
157
+ r instanceof Node
158
+ ? e.appendChild(r)
159
+ : Array.isArray(r)
160
+ ? r.flat().forEach(t)
161
+ : e.appendChild(document.createTextNode(String(r)));
162
+ };
163
+ r.forEach(t), n.appendChild(e);
164
+ }
165
+ return n;
435
166
  }
436
- function commitRoot() {
437
- deletions.forEach(commitWork),
438
- commitWork(wipRoot.child),
439
- (currentRoot = wipRoot),
440
- (wipRoot = null);
441
- }
442
- const commitWork = (e) => {
443
- if (e) {
444
- if (e.shouldUpdate)
445
- switch (e.effectTag) {
446
- case "PLACEMENT":
447
- if (e.dom) {
448
- const t = getParentFiber(e);
449
- t && t.dom.appendChild(e.dom);
450
- }
451
- break;
452
- case "UPDATE":
453
- e.dom && updateDom(e.dom, e.alternate.props, e.props);
454
- break;
455
- case "DELETION":
456
- commitDeletion(e);
457
- }
458
- commitWork(e.child), commitWork(e.sibling);
459
- }
460
- };
461
- function getParentFiber(e) {
462
- let t = e.parent;
463
- for (; t && !t.dom; ) t = t.parent;
464
- return t;
465
- }
466
- (Olova.createStore = (e, t) => {
467
- if ("function" != typeof e)
468
- throw new Error("createStore: Reducer must be a function");
469
- let o = t,
470
- r = new Set();
471
- const n = (t) => {
472
- (o = e(o, t)), r.forEach((e) => e());
473
- };
474
- return (
475
- n({ type: "@@INIT" }),
476
- {
477
- getState: () => o,
478
- dispatch: n,
479
- subscribe: (e) => (r.add(e), () => r.delete(e)),
480
- }
481
- );
482
- }),
483
- (Olova.Provider = ({ store: e, children: t }) => {
484
- if (
485
- !e ||
486
- "function" != typeof e.getState ||
487
- "function" != typeof e.dispatch
488
- )
489
- throw new Error(
490
- "Provider: Invalid store object. Make sure you're passing a store created by createStore()"
491
- );
492
- if (!t) throw new Error("Provider: Must include children elements");
493
- const o = Olova.createContext(null),
494
- r = () => o.Provider({ value: e, children: [t] });
495
- return (r.Context = o), r();
496
- }),
497
- (Olova.Selector = (e) => {
167
+ const Component = (e, t) => {
498
168
  if ("function" != typeof e)
499
- throw new Error("Selector: Selector must be a function");
500
- const t = Olova.Context(Olova.Provider.Context);
501
- if (!t) throw new Error("Selector must be used within a Provider");
502
- const [, o] = Olova.State({});
503
- Olova.Effect(
504
- () =>
505
- t.subscribe(() => {
506
- const n = e(t.getState());
507
- r !== n && o({});
508
- }),
509
- [t, e]
510
- );
511
- const r = e(t.getState());
512
- return r;
513
- }),
514
- (Olova.Dispatch = () => {
515
- const e = Olova.Context(Olova.Provider.Context);
516
- if (!e) throw new Error("Dispatch must be used within a Provider");
517
- return e.dispatch;
518
- }),
519
- (Olova.combineReducers =
520
- (e) =>
521
- (t = {}, o) => {
522
- const r = {};
523
- let n = !1;
169
+ throw new Error("Invalid Component: must be a function");
170
+ return e(t);
171
+ },
172
+ Fragment = (e) => e.children;
173
+ window.Fragment = Fragment;
174
+ const Olova = {
175
+ render(e, t) {
176
+ const r = "function" == typeof e ? e() : e;
524
177
  return (
525
- Object.entries(e).forEach(([e, a]) => {
526
- const s = t[e],
527
- c = a(s, o);
528
- (r[e] = c), (n = n || c !== s);
529
- }),
530
- n ? r : t
531
- );
532
- }),
533
- (Olova.createAction = (e) => {
534
- const t = (t) => ({ type: e, payload: t });
535
- return (t.toString = () => e), t;
536
- }),
537
- (Olova.applyMiddleware =
538
- (...e) =>
539
- (t) =>
540
- (o, r) => {
541
- const n = t(o, r);
542
- let a = n.dispatch;
543
- const s = { getState: n.getState, dispatch: (e) => a(e) },
544
- c = e.map((e) => e(s));
545
- return (a = c.reduce((e, t) => t(e))(n.dispatch)), { ...n, dispatch: a };
546
- }),
547
- (Olova.Suspense = ({ fallback: e, children: t }) => {
548
- const [o, r] = Olova.State(!1),
549
- [n, a] = Olova.State(null);
550
- try {
551
- return Olova.createElement(
552
- SuspenseProvider,
553
- { value: { isPending: o, setPending: r, setError: a } },
554
- t
178
+ t.firstChild ? diffChildren([t.firstChild], [r], t) : t.appendChild(r),
179
+ r
555
180
  );
556
- } catch (t) {
557
- if (t instanceof Promise) return t.then(() => r(!1)), r(!0), e;
558
- throw t;
559
- }
560
- }),
561
- (Olova.ErrorBoundary = class {
562
- constructor(e) {
563
- (this.state = { hasError: !1, error: null }),
564
- (this.fallback = e.fallback);
565
- }
566
- static getDerivedStateFromError(e) {
567
- return { hasError: !0, error: e };
568
- }
569
- componentDidCatch(e, t) {
570
- console.error("Error caught by ErrorBoundary:", e, t),
571
- this.props.onError && this.props.onError(e, t);
572
- }
573
- render() {
574
- return this.state.hasError
575
- ? "function" == typeof this.fallback
576
- ? this.fallback(this.state.error)
577
- : this.fallback
578
- : this.props.children;
579
- }
580
- });
581
- const createVirtualDom = (e) => ({
582
- type: e.type,
583
- key: e.key || null,
584
- ref: e.ref || null,
585
- props: {
586
- ...e.props,
587
- children: Array.isArray(e.props.children)
588
- ? e.props.children.map((e) =>
589
- "object" == typeof e ? createVirtualDom(e) : e
590
- )
591
- : e.props.children,
592
181
  },
593
- _owner: currentComponent,
594
- _store: { validated: !1 },
595
- _self: null,
596
- _source:
597
- "production" !== process.env.NODE_ENV
598
- ? {
599
- fileName: e._source?.fileName || "unknown",
600
- lineNumber: e._source?.lineNumber || 0,
601
- }
602
- : null,
603
- }),
604
- reconcileChildrenArray = (e, t, o) => {
605
- let r = t,
606
- n = null,
607
- a = null,
608
- s = 0,
609
- c = null;
610
- const l = new Map();
611
- let i = t;
612
- for (; i; ) {
613
- const e = i.key || s;
614
- l.set(e, i), (i = i.sibling);
615
- }
616
- for (; r && s < o.length; s++) {
617
- c = r.sibling;
618
- const t = o[s],
619
- l = t.key || s;
620
- if (l !== (r.key || s)) {
621
- r = c;
622
- break;
623
- }
624
- (a = {
625
- type: t.type,
626
- key: l,
627
- props: t.props,
628
- dom: r.dom,
629
- parent: e,
630
- alternate: r,
631
- effectTag: "UPDATE",
632
- lanes: 0,
633
- childLanes: 0,
634
- }),
635
- null === n ? (e.child = a) : (n.sibling = a),
636
- (n = a),
637
- (r = c);
638
- }
639
- for (; s < o.length; ) {
640
- const t = o[s];
641
- (a = {
642
- type: t.type,
643
- key: t.key || s,
644
- props: t.props,
645
- dom: null,
646
- parent: e,
647
- alternate: null,
648
- effectTag: "PLACEMENT",
649
- lanes: 0,
650
- childLanes: 0,
651
- }),
652
- null === n ? (e.child = a) : (n.sibling = a),
653
- (n = a),
654
- s++;
655
- }
656
- for (; r; ) (r.effectTag = "DELETION"), deletions.push(r), (r = r.sibling);
657
- return e.child;
658
- },
659
- memoizedDiff = (() => {
660
- const e = new WeakMap();
661
- return (t, o) => {
662
- const r = `${t?.type}-${o?.type}`;
663
- e.has(t) || e.set(t, new Map());
664
- const n = e.get(t);
665
- if (n.has(r)) return n.get(r);
666
- const a = [];
667
- if (t?.type !== o?.type)
668
- return a.push({ type: "REPLACE", newNode: o }), n.set(r, a), a;
669
- if ("object" != typeof o)
670
- return t !== o && a.push({ type: "TEXT", content: o }), n.set(r, a), a;
671
- const s = diffProps(t.props, o.props);
672
- return (
673
- s && a.push({ type: "PROPS", patches: s }),
674
- o.props.skipChildrenDiff ||
675
- diffChildren(t.props.children, o.props.children, a),
676
- n.set(r, a),
677
- a
678
- );
679
- };
680
- })(),
681
- diffProps = (e, t) => {
682
- const o = {};
683
- let r = !1;
684
- for (const n in e) "children" === n || n in t || ((r = !0), (o[n] = null));
685
- for (const n in t)
686
- "children" !== n && e[n] !== t[n] && ((r = !0), (o[n] = t[n]));
687
- return r ? o : null;
688
- },
689
- diffChildren = (e, t, o) => {
690
- const r = Array.isArray(e) ? e : [e],
691
- n = Array.isArray(t) ? t : [t],
692
- a = new Map();
693
- r.forEach((e, t) => {
694
- const o = e?.key || `index:${t}`;
695
- a.set(o, { child: e, index: t });
696
- });
697
- const s = [];
698
- let c = 0;
699
- n.forEach((e, t) => {
700
- const o = e?.key || `index:${t}`,
701
- r = a.get(o);
702
- if (r) {
703
- const t = r.child,
704
- n = r.index;
705
- n !== c && s.push({ type: "REORDER", from: n, to: c });
706
- const l = memoizedDiff(t, e);
707
- l.length > 0 && s.push({ type: "UPDATE", index: c, patches: l }),
708
- a.delete(o);
709
- } else s.push({ type: "INSERT", index: c, node: e });
710
- c++;
711
- }),
712
- a.forEach(({ index: e }) => {
713
- s.push({ type: "REMOVE", index: e });
714
- }),
715
- s.length > 0 && o.push({ type: "CHILDREN", patches: s });
716
- },
717
- applyPatches = (e, t) => {
718
- t.forEach((t) => {
719
- switch (t.type) {
720
- case "REPLACE":
721
- const o = createDom(t.newNode);
722
- e.parentNode.replaceChild(o, e);
723
- break;
724
- case "TEXT":
725
- e.textContent = t.content;
726
- break;
727
- case "PROPS":
728
- updateDomProperties(e, t.patches);
729
- break;
730
- case "CHILDREN":
731
- applyChildrenPatches(e, t.patches);
732
- }
733
- });
734
- },
735
- updateDomProperties = (e, t) => {
736
- Object.entries(t).forEach(([t, o]) => {
737
- if (t.startsWith("on")) {
738
- const r = t.toLowerCase().substring(2);
739
- e._listeners &&
740
- e._listeners[r] &&
741
- e.removeEventListener(r, e._listeners[r]),
742
- o &&
743
- (e._listeners || (e._listeners = {}),
744
- (e._listeners[r] = o),
745
- e.addEventListener(r, o));
746
- } else
747
- "style" === t && "object" == typeof o
748
- ? Object.assign(e.style, o)
749
- : "className" === t
750
- ? e.setAttribute("class", o)
751
- : "boolean" == typeof o
752
- ? o
753
- ? e.setAttribute(t, "")
754
- : e.removeAttribute(t)
755
- : null === o
756
- ? e.removeAttribute(t)
757
- : e.setAttribute(t, o);
758
- });
759
- },
760
- applyChildrenPatches = (e, t) => {
761
- const o = Array.from(e.childNodes),
762
- r = [];
763
- t.forEach((e) => {
764
- switch (e.type) {
765
- case "REORDER":
766
- r.push({ type: "MOVE", from: e.from, to: e.to, node: o[e.from] });
767
- break;
768
- case "REMOVE":
769
- r.push({ type: "REMOVE", index: e.index, node: o[e.index] });
770
- break;
771
- case "INSERT":
772
- r.push({ type: "INSERT", index: e.index, node: createDom(e.node) });
773
- break;
774
- case "UPDATE":
775
- applyPatches(o[e.index], e.patches);
776
- }
777
- }),
778
- r
779
- .sort((e, t) =>
780
- "REMOVE" === e.type ? -1 : "REMOVE" === t.type ? 1 : e.index - t.index
781
- )
782
- .forEach((t) => {
783
- switch (t.type) {
784
- case "MOVE":
785
- e.insertBefore(t.node, e.childNodes[t.to] || null);
786
- break;
787
- case "REMOVE":
788
- e.removeChild(t.node);
789
- break;
790
- case "INSERT":
791
- e.insertBefore(t.node, e.childNodes[t.index] || null);
792
- }
793
- });
794
- },
795
- priorityLevels = {
796
- IMMEDIATE: 1,
797
- USER_BLOCKING: 2,
798
- NORMAL: 3,
799
- LOW: 4,
800
- IDLE: 5,
801
- },
802
- scheduleWork = (e, t) => {
803
- new Map().set(t, e);
804
- };
805
- let batchQueue = new Set(),
806
- isProcessingBatch = !1;
807
- const batchedUpdates = (e) => {
808
- const t = isBatchingUpdates;
809
- isBatchingUpdates = !0;
810
- try {
811
- return e();
812
- } finally {
813
- (isBatchingUpdates = t), isBatchingUpdates || flushBatchQueue();
814
- }
815
- },
816
- flushBatchQueue = () => {
817
- if (!isProcessingBatch) {
818
- isProcessingBatch = !0;
819
- try {
820
- batchQueue.forEach((e) => {
821
- e();
822
- });
823
- } finally {
824
- (isProcessingBatch = !1), batchQueue.clear();
825
- }
826
- performSyncWork();
827
- }
828
- },
829
- queueUpdate = (e) => {
830
- batchQueue.add(e), isBatchingUpdates || flushBatchQueue();
831
- },
832
- performSyncWork = () => {
833
- rerender();
834
- };
835
- (Olova.Transition = () => {
836
- const [e, t] = Olova.State(!1);
837
- return [
838
- e,
839
- Olova.Callback((e) => {
840
- t(!0),
841
- queueMicrotask(() => {
842
- try {
843
- e();
844
- } finally {
845
- t(!1);
846
- }
847
- });
848
- }, []),
849
- ];
850
- }),
851
- (Olova.DeferredValue = (e, t) => {
852
- const [o, r] = Olova.State(e);
853
- return (
854
- Olova.Effect(() => {
855
- const o = setTimeout(() => {
856
- r(e);
857
- }, t?.timeoutMs || 2e3);
858
- return () => clearTimeout(o);
859
- }, [e, t?.timeoutMs]),
860
- o
861
- );
862
- }),
863
- (Olova.renderToString = (e) => {
864
- let t = "";
865
- var o;
866
- return "string" != typeof (o = e) || (t += o), t;
867
- });
868
- const SyntheticEvent = {
869
- preventDefault() {},
870
- stopPropagation() {},
871
- persist() {},
872
- isPersistent() {},
873
- nativeEvent: null,
874
- target: null,
875
- currentTarget: null,
876
- type: null,
877
- };
878
- Olova.lazy = (e) => {
879
- let t = null,
880
- o = null;
881
- return (r) => {
882
- if (
883
- (t ||
884
- o ||
885
- (o = e()
886
- .then((e) => {
887
- t = e.default || e;
888
- })
889
- .catch((e) => {
890
- throw e;
891
- })),
892
- t)
893
- )
894
- return Olova.createElement(t, r);
895
- throw o;
896
- };
897
- };
898
- export const {
899
- State: State,
900
- createContext: createContext,
901
- Context: Context,
902
- Effect: Effect,
903
- Reducer: Reducer,
904
- Callback: Callback,
905
- Memo: Memo,
906
- Ref: Ref,
907
- LayoutEffect: LayoutEffect,
908
- ImperativeHandle: ImperativeHandle,
909
- Fragment: Fragment,
910
- createStore: createStore,
911
- Provider: Provider,
912
- Selector: Selector,
913
- Dispatch: Dispatch,
914
- combineReducers: combineReducers,
915
- createAction: createAction,
916
- applyMiddleware: applyMiddleware,
917
- Suspense: Suspense,
918
- ErrorBoundary: ErrorBoundary,
919
- Transition: Transition,
920
- DeferredValue: DeferredValue,
921
- renderToString: renderToString,
922
- lazy: lazy,
923
- StrictMode: StrictMode,
924
- Profiler: Profiler,
925
- DebugValue: DebugValue,
926
- Id: Id,
927
- InsertionEffect: InsertionEffect,
928
- Optimistic: Optimistic,
929
- SyncExternalStore: SyncExternalStore,
930
- ActionState: ActionState,
931
- } = Olova;
932
- export default Olova;
933
- (Olova.StrictMode = ({ children: e }) => {
934
- const t = (e) => {
935
- if ("function" == typeof e.type) {
936
- Object.getOwnPropertyNames(e.type.prototype).forEach((t) => {
937
- t.startsWith("UNSAFE_") &&
938
- console.warn(
939
- `StrictMode: Detected deprecated method ${t} in component ${e.type.name}`
940
- );
941
- }),
942
- e.props && e.props.children && e.props.children.forEach(t);
943
- }
944
- };
945
- return e.forEach(t), e[0];
946
- }),
947
- (Olova.Profiler = ({ id: e, onRender: t, children: o }) => {
948
- if ("function" != typeof t)
949
- return console.warn("Profiler requires an onRender callback"), o;
950
- const r = performance.now();
951
- return (
952
- Olova.Effect(() => {
953
- const o = performance.now(),
954
- n = o - r;
955
- t({
956
- id: e,
957
- actualDuration: n,
958
- baseDuration: n,
959
- startTime: r,
960
- commitTime: o,
961
- interactions: new Set(),
962
- phase: "mount",
963
- });
964
- }, []),
965
- o
966
- );
967
- }),
968
- "production" !== process.env.NODE_ENV &&
969
- (Olova.__DEV__ = {
970
- componentStack: [],
971
- markComponentRender: (e) => {
972
- Olova.__DEV__.componentStack.push(e),
973
- console.log(`Component rendered: ${e.name || "Anonymous"}`);
974
- },
975
- clearComponentStack: () => {
976
- Olova.__DEV__.componentStack = [];
977
- },
978
- });
979
- const handleError = (e, t) => {
980
- console.error("Error in Olova application:", e),
981
- console.error("Component stack:", t);
982
- let o = null,
983
- r = t[t.length - 1];
984
- for (; r && !o; )
985
- r.type && r.type.prototype instanceof Olova.ErrorBoundary && (o = r),
986
- (r = r.parent);
987
- if (!o) throw e;
988
- o.setState({ hasError: !0, error: e });
989
- },
990
- cleanupComponent = (e) => {
991
- effects.has(e) &&
992
- (effects.get(e).forEach((e) => {
993
- e.cleanup && e.cleanup();
994
- }),
995
- effects.delete(e)),
996
- states.has(e) && states.delete(e),
997
- memos.has(e) && memos.delete(e),
998
- refs.has(e) && refs.delete(e);
182
+ mount(e, t) {
183
+ return this.render(e, t);
184
+ },
185
+ unmount(e) {
186
+ e.innerHTML = "";
187
+ },
188
+ Fragment: Fragment,
999
189
  },
1000
- sanitizeProps = (e) => {
1001
- if (e.dangerouslySetInnerHTML) {
1002
- const t = e.dangerouslySetInnerHTML.__html.replace(
1003
- /<script[^>]*>([\S\s]*?)<\/script>/gi,
1004
- ""
1005
- );
1006
- e.dangerouslySetInnerHTML.__html = t;
1007
- }
1008
- return e;
1009
- };
1010
- (Olova.DebugValue = (e, t) => {
1011
- if ("production" !== process.env.NODE_ENV) {
1012
- const o = t ? t(e) : e;
1013
- console.log("Debug value:", o);
1014
- }
1015
- }),
1016
- (Olova.Id = () => {
1017
- const [e] = Olova.State(
1018
- () => `olova-${Math.random().toString(36).slice(2)}`
1019
- );
1020
- return e;
1021
- }),
1022
- (Olova.InsertionEffect = (e, t) => {
1023
- Olova.LayoutEffect(e, t);
1024
- }),
1025
- (Olova.SyncExternalStore = (e, t, o) => {
1026
- const [r, n] = Olova.State(t);
1027
- return (
1028
- Olova.Effect(
1029
- () => (
1030
- n(t()),
1031
- e(() => {
1032
- n(t());
1033
- })
1034
- ),
1035
- [e, t]
1036
- ),
1037
- r
1038
- );
1039
- }),
1040
- (Olova.Optimistic = (e, t) => {
1041
- const [o, r] = Olova.State(e),
1042
- [n, a] = Olova.Transition();
1043
- return [
1044
- o,
1045
- (e) => {
1046
- a(() => {
1047
- const n = t(o, e);
1048
- r(n);
1049
- });
190
+ contextRegistry = new Map();
191
+ function Context(e) {
192
+ const t = Symbol("context");
193
+ return (
194
+ contextRegistry.set(t, e),
195
+ {
196
+ Provider({ value: e, children: r }) {
197
+ const n = contextRegistry.get(t);
198
+ contextRegistry.set(t, e);
199
+ const o = r;
200
+ return contextRegistry.set(t, n), o;
1050
201
  },
1051
- ];
1052
- }),
1053
- (Olova.ActionState = (e, t) => {
1054
- const [o, r] = Olova.State(e),
1055
- [n, a] = Olova.State(null),
1056
- [s, c] = Olova.State(null);
1057
- return [
1058
- o,
1059
- async (e) => {
1060
- try {
1061
- a(o);
1062
- const n = await t(o, e);
1063
- r(n), a(null), c(null);
1064
- } catch (e) {
1065
- c(e), a(null);
1066
- }
202
+ use() {
203
+ const r = contextRegistry.get(t);
204
+ if (void 0 === r && void 0 === e)
205
+ throw new Error("Context used outside of Provider");
206
+ return r ?? e;
1067
207
  },
1068
- { pending: n, error: s },
1069
- ];
1070
- });
1071
- const diffCache = new WeakMap(),
1072
- memoizedCreateVirtualDom = (e) => {
1073
- if (diffCache.has(e)) return diffCache.get(e);
1074
- const t = createVirtualDom(e);
1075
- return diffCache.set(e, t), t;
1076
- };
1077
- class UpdateQueue {
1078
- constructor() {
1079
- this.updates = new Map();
1080
- }
1081
- enqueue(e, t) {
1082
- this.updates.has(e) || this.updates.set(e, new Set()),
1083
- this.updates.get(e).add(t);
1084
- }
1085
- dequeue() {
1086
- const e = Array.from(this.updates.keys()).sort();
1087
- for (const t of e) {
1088
- const e = this.updates.get(t);
1089
- if (e.size > 0) {
1090
- const o = e.values().next().value;
1091
- return e.delete(o), 0 === e.size && this.updates.delete(t), o;
1092
- }
1093
208
  }
1094
- return null;
1095
- }
209
+ );
1096
210
  }
1097
- const updateQueue = new UpdateQueue(),
1098
- componentCache = new WeakMap(),
1099
- getCachedComponent = (e, t) => {
1100
- const o = JSON.stringify(t);
1101
- componentCache.has(e) || componentCache.set(e, new Map());
1102
- const r = componentCache.get(e);
1103
- return r.has(o) || r.set(o, new e(t)), r.get(o);
1104
- },
1105
- batchDomOperations = (e) => {
1106
- const t = document.createDocumentFragment();
1107
- return (
1108
- e.forEach((e) => {
1109
- if ("INSERT" === e.type) t.appendChild(e.node);
1110
- }),
1111
- t
1112
- );
1113
- },
1114
- eventDelegator = {
1115
- handlers: new Map(),
1116
- delegate(e, t) {
1117
- this.handlers.has(e) ||
1118
- (this.handlers.set(e, new Set()),
1119
- document.addEventListener(e, this.handleEvent.bind(this))),
1120
- this.handlers.get(e).add(t);
1121
- },
1122
- handleEvent(e) {
1123
- const t = this.handlers.get(e.type);
1124
- t && t.forEach((t) => t(e));
1125
- },
1126
- },
1127
- createImmutableState = (e) => ({
1128
- value: e,
1129
- set(e) {
1130
- return !Object.is(this.value, e) && ((this.value = e), !0);
1131
- },
1132
- });
1133
- let renderThrottleTimeout = null;
1134
- const throttledRerender = () => {
1135
- renderThrottleTimeout ||
1136
- (renderThrottleTimeout = setTimeout(() => {
1137
- rerender(), (renderThrottleTimeout = null);
1138
- }, 16));
1139
- };
211
+ function Callback(e, t) {
212
+ const [r, n] = State(() => ({ fn: e, deps: t, memoized: (...t) => e(...t) }));
213
+ return (
214
+ Effect(() => {
215
+ const o = r();
216
+ t &&
217
+ ((o.deps &&
218
+ t.length === o.deps.length &&
219
+ !t.some((e, t) => e !== o.deps[t])) ||
220
+ n({ fn: e, deps: t, memoized: (...t) => e(...t) }));
221
+ }),
222
+ () => r().memoized
223
+ );
224
+ }
225
+ export { State, Effect, Memo, Ref, Context, Callback, Component, h, Fragment };
226
+ export default Olova;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "olova",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "A lightweight JavaScript framework for building reactive applications.",
5
5
  "main": "dist/olova.js",
6
6
  "keywords": [