olova 2.0.2 → 2.0.3

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.
@@ -0,0 +1,18 @@
1
+ name: Publish to NPM
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v2
12
+ - uses: actions/setup-node@v2
13
+ with:
14
+ node-version: '14'
15
+ registry-url: 'https://registry.npmjs.org'
16
+ - run: yarn publish
17
+ env:
18
+ NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
package/README.md CHANGED
@@ -1,54 +1,54 @@
1
- # Olova JavaScript Framework
2
-
3
- Olova is a lightweight and reactive JavaScript framework that simplifies UI
4
- development with a clean, intuitive syntax. It provides a reactivity system and
5
- hooks to manage state and side effects, allowing developers to build modern web
6
- applications with ease.
7
-
8
- ## Features
9
-
10
- - **State Management**: Use the `State` hook to manage reactive state in your
11
- components.
12
- - **Side Effects**: Use the `Effect` hook to run side effects in response to
13
- state changes.
14
- - **JSX-style Syntax**: Write UI components using a simple, declarative
15
- JSX-style syntax.
16
- - **Reactivity**: Automatically re-render components when state changes.
17
-
18
- ## Installation
19
-
20
- To get started with Olova, first install the core library via npm or yarn.
21
-
22
- ```bash
23
- npm install olova
24
- ```
25
-
26
- or
27
-
28
- ```bash
29
- yarn add olova
30
- ```
31
-
32
- ## Example Usage
33
-
34
- Here is an example of a basic component in Olova:
35
-
36
- ```js
37
- import Olova, { State, Effect } from "olova";
38
-
39
- export default function Home() {
40
- const [count, setCount] = State(0);
41
-
42
- Effect(() => {
43
- console.log("Home is rendered");
44
- console.log(count);
45
- }, [count]);
46
-
47
- return (
48
- <>
49
- <h1>{count}</h1>
50
- <button onClick={() => setCount(count + 1)}>Increment</button>
51
- </>
52
- );
53
- }
54
- ```
1
+ # Olova JavaScript Framework
2
+
3
+ Olova is a lightweight and reactive JavaScript framework that simplifies UI
4
+ development with a clean, intuitive syntax. It provides a reactivity system and
5
+ hooks to manage state and side effects, allowing developers to build modern web
6
+ applications with ease.
7
+
8
+ ## Features
9
+
10
+ - **State Management**: Use the `State` hook to manage reactive state in your
11
+ components.
12
+ - **Side Effects**: Use the `Effect` hook to run side effects in response to
13
+ state changes.
14
+ - **JSX-style Syntax**: Write UI components using a simple, declarative
15
+ JSX-style syntax.
16
+ - **Reactivity**: Automatically re-render components when state changes.
17
+
18
+ ## Installation
19
+
20
+ To get started with Olova, first install the core library via npm or yarn.
21
+
22
+ ```bash
23
+ npm install olova
24
+ ```
25
+
26
+ or
27
+
28
+ ```bash
29
+ yarn add olova
30
+ ```
31
+
32
+ ## Example Usage
33
+
34
+ Here is an example of a basic component in Olova:
35
+
36
+ ```js
37
+ import Olova, { State, Effect } from "olova";
38
+
39
+ export default function Home() {
40
+ const [count, setCount] = State(0);
41
+
42
+ Effect(() => {
43
+ console.log("Home is rendered");
44
+ console.log(count);
45
+ }, [count]);
46
+
47
+ return (
48
+ <>
49
+ <h1>{count}</h1>
50
+ <button onClick={() => setCount(count + 1)}>Increment</button>
51
+ </>
52
+ );
53
+ }
54
+ ```
package/dist/olova.d.ts CHANGED
@@ -1 +1 @@
1
- declare module "olova";
1
+ declare module "olova";
package/dist/olova.js CHANGED
@@ -1,226 +1,291 @@
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() {
58
- return (
59
- currentObserver &&
60
- (this.observers.has("_root") || this.observers.set("_root", new Set()),
61
- this.observers.get("_root").add(currentObserver)),
62
- this._value
63
- );
64
- }
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
- }
76
- }
77
- observe(e, t) {
78
- this.observers.has(e) || this.observers.set(e, new Set()),
79
- this.observers.get(e).add(t);
80
- }
81
- unobserve(e, t) {
82
- this.observers.has(e) && this.observers.get(e).delete(t);
83
- }
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;
96
- },
97
- ]
98
- );
99
- }
100
- function Effect(e) {
101
- const t = () => {
102
- (currentObserver = t), e(), (currentObserver = null);
103
- };
104
- t();
105
- }
106
- function Memo(e) {
107
- const [t, r] = State(e());
108
- return Effect(() => r(e())), t;
109
- }
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
- },
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
- };
134
- }
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
- });
144
- }
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;
166
- }
167
- const Component = (e, t) => {
168
- if ("function" != typeof e)
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;
177
- return (
178
- t.firstChild ? diffChildren([t.firstChild], [r], t) : t.appendChild(r),
179
- r
180
- );
181
- },
182
- mount(e, t) {
183
- return this.render(e, t);
184
- },
185
- unmount(e) {
186
- e.innerHTML = "";
187
- },
188
- Fragment: Fragment,
189
- },
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;
201
- },
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;
207
- },
208
- }
209
- );
210
- }
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;
1
+ const memoize = (e) => {
2
+ const t = new Map();
3
+ return (...n) => {
4
+ const r = JSON.stringify(n);
5
+ return t.has(r) || t.set(r, e(...n)), t.get(r);
6
+ };
7
+ };
8
+ let currentObserver = null;
9
+ function diffProps(e = {}, t = {}, n) {
10
+ void 0 !== t.className && ((t.class = t.className), delete t.className),
11
+ void 0 !== e.className && ((e.class = e.className), delete e.className);
12
+ for (const [r, o] of Object.entries(e))
13
+ r in t ||
14
+ (r.startsWith("on")
15
+ ? n.removeEventListener(r.slice(2).toLowerCase(), o)
16
+ : "style" === r
17
+ ? (n.style.cssText = "")
18
+ : n.removeAttribute(r));
19
+ for (const [r, o] of Object.entries(t))
20
+ if (null != o && e[r] !== o)
21
+ if (r.startsWith("on")) {
22
+ const t = r.slice(2).toLowerCase();
23
+ e[r] && n.removeEventListener(t, e[r]), n.addEventListener(t, o);
24
+ } else if ("ref" === r)
25
+ o && "object" == typeof o && "current" in o
26
+ ? (o.current = n)
27
+ : "function" == typeof o && o(n);
28
+ else if ("style" === r) {
29
+ const e = n.style;
30
+ "object" == typeof o ? Object.assign(e, o) : (e.cssText = o);
31
+ } else n.setAttribute(r, o);
32
+ }
33
+ const diffChildren = memoize((e, t, n) => {
34
+ const r = Array.isArray(e) ? e.flat() : [e],
35
+ o = Array.isArray(t) ? t.flat() : [t],
36
+ s = Math.max(r.length, o.length);
37
+ for (let e = 0; e < s; e++) {
38
+ const t = r[e],
39
+ s = o[e];
40
+ if (!t || s)
41
+ if (t || !s) {
42
+ if (t instanceof Node && s instanceof Node)
43
+ t.nodeType !== s.nodeType || t.nodeName !== s.nodeName
44
+ ? n.replaceChild(s, t)
45
+ : (diffProps(t.attributes, s.attributes, t),
46
+ diffChildren(
47
+ Array.from(t.childNodes),
48
+ Array.from(s.childNodes),
49
+ t
50
+ ));
51
+ else if (t !== s) {
52
+ const t = n.childNodes[e];
53
+ t && (t.textContent = String(s));
54
+ }
55
+ } else {
56
+ const e = s instanceof Node ? s : document.createTextNode(String(s));
57
+ n.appendChild(e);
58
+ }
59
+ else t instanceof Node && n.removeChild(t);
60
+ }
61
+ });
62
+ class Signal {
63
+ constructor(e) {
64
+ (this._value = e),
65
+ (this.observers = new Map()),
66
+ (this.pending = new Set()),
67
+ (this.isBatching = !1);
68
+ }
69
+ get value() {
70
+ return (
71
+ currentObserver &&
72
+ (this.observers.has("_root") || this.observers.set("_root", new Set()),
73
+ this.observers.get("_root").add(currentObserver)),
74
+ this._value
75
+ );
76
+ }
77
+ set value(e) {
78
+ if (this._value === e) return;
79
+ const t = this._value;
80
+ if (((this._value = e), this.observers.has("_root")))
81
+ for (const e of this.observers.get("_root")) this.pending.add(e);
82
+ if ("object" == typeof t && "object" == typeof e) {
83
+ const n = new Set([...Object.keys(t), ...Object.keys(e)]);
84
+ for (const r of n)
85
+ if (t[r] !== e[r] && this.observers.has(r))
86
+ for (const e of this.observers.get(r)) this.pending.add(e);
87
+ }
88
+ this.batchUpdate();
89
+ }
90
+ batchUpdate() {
91
+ this.isBatching ||
92
+ ((this.isBatching = !0),
93
+ Promise.resolve().then(() => {
94
+ this.pending.forEach((e) => e()),
95
+ this.pending.clear(),
96
+ (this.isBatching = !1);
97
+ }));
98
+ }
99
+ observe(e, t) {
100
+ this.observers.has(e) || this.observers.set(e, new Set()),
101
+ this.observers.get(e).add(t);
102
+ }
103
+ unobserve(e, t) {
104
+ this.observers.has(e) && this.observers.get(e).delete(t);
105
+ }
106
+ }
107
+ function $signal(e) {
108
+ const t = new Signal(e),
109
+ n = () => t.value;
110
+ return (
111
+ (n.toString = () => t.value),
112
+ (n.observe = (e, n) => t.observe(e, n)),
113
+ (n.unobserve = (e, n) => t.unobserve(e, n)),
114
+ [
115
+ n,
116
+ (e) => {
117
+ t.value = "function" == typeof e ? e(t.value) : e;
118
+ },
119
+ ]
120
+ );
121
+ }
122
+ function $effect(e, t) {
123
+ let n,
124
+ r = !0,
125
+ o = null;
126
+ const s = () => {
127
+ "function" == typeof n && (n(), (n = void 0)), (currentObserver = o);
128
+ const t = e();
129
+ (currentObserver = null), "function" == typeof t && (n = t);
130
+ };
131
+ return (
132
+ (o = () => {
133
+ if (r || !t) return s(), void (r = !1);
134
+ Array.isArray(t) && 0 === t.length ? r && (s(), (r = !1)) : s();
135
+ }),
136
+ o(),
137
+ () => {
138
+ n && n();
139
+ }
140
+ );
141
+ }
142
+ function $memo(e) {
143
+ const [t, n] = $signal(e());
144
+ return $effect(() => n(e())), t;
145
+ }
146
+ function $ref(e) {
147
+ const [t, n] = $signal({
148
+ current: e,
149
+ toString() {
150
+ return this.current;
151
+ },
152
+ valueOf() {
153
+ return this.current;
154
+ },
155
+ });
156
+ return {
157
+ get current() {
158
+ return t().current;
159
+ },
160
+ set current(e) {
161
+ n((t) => (t.current === e ? t : { ...t, current: e }));
162
+ },
163
+ toString() {
164
+ return this.current.toString();
165
+ },
166
+ valueOf() {
167
+ return this.current;
168
+ },
169
+ };
170
+ }
171
+ function h(e, t, ...n) {
172
+ if (e === Fragment || Array.isArray(e)) {
173
+ const r = document.createDocumentFragment(),
174
+ o = e === Fragment ? t?.children || n : e;
175
+ return (
176
+ Array.isArray(o) &&
177
+ o.flat().forEach((e) => {
178
+ null != e &&
179
+ r.appendChild(
180
+ e instanceof Node ? e : document.createTextNode(String(e))
181
+ );
182
+ }),
183
+ r
184
+ );
185
+ }
186
+ if (!e) return null;
187
+ const r = "function" == typeof e ? e(t) : document.createElement(e);
188
+ if (("string" == typeof e && r && t && diffProps({}, t, r), n.length)) {
189
+ const e = document.createDocumentFragment(),
190
+ t = (n) => {
191
+ if (null != n)
192
+ if ("function" == typeof n) {
193
+ const t = document.createTextNode("");
194
+ $effect(() => {
195
+ const e = n();
196
+ if (Array.isArray(e)) {
197
+ const n = document.createDocumentFragment();
198
+ e.forEach((e) => {
199
+ n.appendChild(
200
+ e instanceof Node ? e : document.createTextNode(String(e))
201
+ );
202
+ }),
203
+ t.parentNode && t.parentNode.replaceChild(n, t);
204
+ } else t.textContent = String(e);
205
+ }),
206
+ e.appendChild(t);
207
+ } else
208
+ n instanceof Node
209
+ ? e.appendChild(n)
210
+ : Array.isArray(n)
211
+ ? n.flat().forEach(t)
212
+ : e.appendChild(document.createTextNode(String(n)));
213
+ };
214
+ n.forEach(t), r.appendChild(e);
215
+ }
216
+ return r;
217
+ }
218
+ const Component = (e, t) => {
219
+ if ("function" != typeof e)
220
+ throw new Error("Invalid Component: must be a function");
221
+ return e(t);
222
+ },
223
+ Fragment = (e) => e.children;
224
+ window.Fragment = Fragment;
225
+ const Olova = {
226
+ render(e, t) {
227
+ const n = "function" == typeof e ? e() : e;
228
+ return (
229
+ t.firstChild ? diffChildren([t.firstChild], [n], t) : t.appendChild(n),
230
+ n
231
+ );
232
+ },
233
+ mount(e, t) {
234
+ return this.render(e, t);
235
+ },
236
+ unmount(e) {
237
+ e.innerHTML = "";
238
+ },
239
+ Fragment: Fragment,
240
+ },
241
+ contextRegistry = new Map();
242
+ function $context(e) {
243
+ const t = Symbol("context");
244
+ return (
245
+ contextRegistry.set(t, e),
246
+ {
247
+ Provider({ value: e, children: n }) {
248
+ const r = contextRegistry.get(t);
249
+ contextRegistry.set(t, e);
250
+ const o = n;
251
+ return contextRegistry.set(t, r), o;
252
+ },
253
+ use() {
254
+ const n = contextRegistry.get(t);
255
+ if (void 0 === n && void 0 === e)
256
+ throw new Error("Context used outside of Provider");
257
+ return n ?? e;
258
+ },
259
+ }
260
+ );
261
+ }
262
+ function $callback(e, t) {
263
+ const [n, r] = $signal(() => ({
264
+ fn: e,
265
+ deps: t,
266
+ memoized: (...t) => e(...t),
267
+ }));
268
+ return (
269
+ $effect(() => {
270
+ const o = n();
271
+ t &&
272
+ ((o.deps &&
273
+ t.length === o.deps.length &&
274
+ !t.some((e, t) => e !== o.deps[t])) ||
275
+ r({ fn: e, deps: t, memoized: (...t) => e(...t) }));
276
+ }),
277
+ () => n().memoized
278
+ );
279
+ }
280
+ export {
281
+ $signal,
282
+ $effect,
283
+ $memo,
284
+ $ref,
285
+ $context,
286
+ $callback,
287
+ Component,
288
+ h,
289
+ Fragment,
290
+ };
291
+ export default Olova;