Skip to content

Commit dd4ed14

Browse files
author
codegram01
committed
init
0 parents  commit dd4ed14

File tree

5 files changed

+283
-0
lines changed

5 files changed

+283
-0
lines changed

LISENCE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 codegram01
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# GramJs
2+
3+
Smallest Javascript framework. The only Javascript Framework you can understand.
4+
GramJs only have 100 line code and 3 function.
5+
6+
Check example at folder demo
7+
8+
[Video when i create]()
9+
10+
## Usage
11+
- Just copy file gram.js and add to your project
12+
- import { e, range, ref } from "gram.js"
13+
14+
## Docs
15+
Gramjs have 3 function
16+
17+
### function e(tag, ops, ...childs) {}
18+
function e create and return new html element.
19+
e just like wrap of document.createElement and add more feature
20+
21+
you can add element property in ops
22+
ops:
23+
- text : it will do elm.innerText = value
24+
- html : it will do elm.innerHTML = value
25+
- value : it will do elm.value = value
26+
- show : element will display none or show when value true or false
27+
- default html attribute : like src, href, width, ...
28+
29+
### function ref(value) {}
30+
ref create reactive value.
31+
32+
Create value: const myVal = ref("Hello World")
33+
Get value: myVal.value
34+
Change value: myVal.value = "Something"
35+
36+
you bind ref value to html element like this
37+
```javascript
38+
e("h1", {text: title})
39+
e("input", {value: title})
40+
```
41+
when value change html element will update
42+
or when html update value will update
43+
44+
### function range(arrItem, render) {}
45+
range to help you map array value to html
46+
47+
range recevive
48+
- arrItem : array item
49+
- render : function e , logic for render 1 element of array
50+
range return html element like function e
51+
52+
like when you have
53+
```javascript
54+
const fruits = ref(["apple", "banana", "orange"])
55+
```
56+
display array to html like this
57+
```javascript
58+
range(fruits, (fruit, index) => {
59+
return e("li", {text: `${index}: ${fruit}`})
60+
})
61+
```
62+
When you change array, you need call myArr.markChange() to update html
63+
64+
## TODO
65+
I keep Gramjs to a minimum so you can easy to understand.
66+
But if you want use it in real life, some feature need
67+
68+
What you can add to GramJs:
69+
- The syntax create element
70+
in gramjs we create element use e(), but it look different write in html syntax
71+
some people in react framework create jsx, and then jsx under the hood convert to e function, you can add jsx in your gramjs
72+
73+
- Reactive value
74+
GramJs can work good at basic data type like string, number, boolean
75+
But in Array and object reactive is hard to detect when value change and update html. I still haven't figured out how to do it effectively.
76+
77+
## Contribute
78+
- fork, update, merge, open issue is happy
79+
- [Subscribe my Youtube](https://www.youtube.com/@WingramOrg)

demo/index.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<html>
2+
<head>
3+
<title>Demo GramJs</title>
4+
</head>
5+
<body>
6+
<div id="app"></div>
7+
<script src="index.js" type="module"></script>
8+
</body>
9+
</html>

demo/index.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { e, range, ref } from "../gram.js"
2+
3+
const app = document.getElementById("app")
4+
5+
const title = ref("Fruits Manager")
6+
7+
const fruits = ref(["apple", "banana", "orange"])
8+
const fruitInp = ref("")
9+
function addFruit(){
10+
fruits.value.push(fruitInp.value);
11+
fruits.markChange();
12+
fruitInp.value = "";
13+
}
14+
function removeFruit(index) {
15+
fruits.value.splice(index, 1);
16+
fruits.markChange();
17+
}
18+
19+
const showFruit = ref(true)
20+
function toggleShowFruit() {
21+
showFruit.value = !showFruit.value
22+
}
23+
24+
const ctn = e("div", {},
25+
e("h1", {text: title}),
26+
e("input", {value: title}),
27+
e("hr"),
28+
29+
e("input", {type: "text", value: fruitInp, placeholder: "Enter fruit"}),
30+
e("button", {text: "add fruit", onclick: addFruit}),
31+
e("ul", { show: showFruit },
32+
range(fruits, (fruit, index) => {
33+
return e("li", {text: `${index}: ${fruit} - `},
34+
e("button", {text: "x", onclick: ()=>{removeFruit(index)}})
35+
)
36+
})
37+
),
38+
e("hr"),
39+
40+
e("div", {},
41+
e("button", {text: "toggle show fruits", onclick: toggleShowFruit}),
42+
e("span", {text: showFruit})
43+
),
44+
)
45+
46+
app.appendChild(ctn);

gram.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
export function e(tag, ops, ...childs) {
2+
const elm = document.createElement(tag);
3+
4+
if (ops) {
5+
for (const [key, op] of Object.entries(ops)) {
6+
if (key.startsWith("on")) {
7+
const event = key.slice(2);
8+
elm.addEventListener(event, op);
9+
continue;
10+
}
11+
if (op.isRef) {
12+
switch (key) {
13+
case "text":
14+
elm.innerText = op.value;
15+
op.subscribe(() => {
16+
elm.innerText = op.value;
17+
});
18+
break;
19+
case "html":
20+
elm.innerHTML = op.value;
21+
op.subscribe(() => {
22+
elm.innerHTML = op.value;
23+
});
24+
break;
25+
case "value":
26+
elm.value = op.value;
27+
elm.addEventListener("input", () => {
28+
op.value = elm.value;
29+
});
30+
op.subscribe(() => {
31+
elm.value = op.value;
32+
});
33+
break;
34+
case "show":
35+
elm.style.display = op.value ? "" : "none"
36+
op.subscribe(() => {
37+
elm.style.display = op.value ? "" : "none"
38+
});
39+
break;
40+
default:
41+
op.subscribe(() => {
42+
elm[key] = op.value;
43+
});
44+
}
45+
continue;
46+
}
47+
48+
switch (key) {
49+
case "text":
50+
elm.innerText = op;
51+
continue;
52+
case "html":
53+
elm.innerHTML = op;
54+
continue;
55+
default:
56+
elm[key] = op;
57+
continue;
58+
}
59+
}
60+
}
61+
62+
if (childs) {
63+
for (let i = 0; i < childs.length; i++) {
64+
if (Array.isArray(childs[i])) {
65+
for (const child of childs[i]) {
66+
elm.appendChild(child);
67+
}
68+
} else {
69+
elm.appendChild(childs[i]);
70+
}
71+
}
72+
}
73+
74+
return elm;
75+
}
76+
77+
export function ref(value) {
78+
const subscribes = [];
79+
const refObject = {
80+
isRef: true,
81+
82+
get value() {
83+
return value;
84+
},
85+
set value(newValue) {
86+
value = newValue;
87+
this.callSubscribe()
88+
},
89+
90+
91+
subscribe(func) {
92+
subscribes.push(func);
93+
},
94+
callSubscribe(){
95+
for (const func of subscribes) {
96+
func();
97+
}
98+
},
99+
markChange(){
100+
this.callSubscribe();
101+
}
102+
};
103+
return refObject;
104+
}
105+
106+
export function range(arrItem, render) {
107+
const ctn = e("div");
108+
109+
function callRender(){
110+
const arrItemWrap = arrItem.value ? arrItem.value : arrItem
111+
for(let i = 0; i < arrItemWrap.length; i++){
112+
const itemElm = render(arrItemWrap[i], i);
113+
114+
ctn.appendChild(itemElm)
115+
}
116+
117+
return ctn
118+
}
119+
120+
if(arrItem.isRef){
121+
arrItem.subscribe(()=> {
122+
ctn.innerHTML = "";
123+
callRender()
124+
})
125+
}
126+
127+
return callRender()
128+
}

0 commit comments

Comments
 (0)