@daz4126/helium 0.3.0 → 0.4.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/README.md +104 -12
- package/helium.js +56 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
The ultra-light library that makes HTML interactive!
|
|
4
4
|
|
|
5
|
-
Here's a simple example of a button that counts
|
|
5
|
+
Here's a simple example of a button that counts the number of times it has been clicked and turns red after more than 3 clicks:
|
|
6
6
|
|
|
7
7
|
```html
|
|
8
|
-
<button @
|
|
9
|
-
clicked <
|
|
8
|
+
<button @click="count++" :style="count > 3 && 'background: red'">
|
|
9
|
+
clicked <b @text="count">0</b> times
|
|
10
10
|
</button>
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
It's really simple to use - just sprinkle the magic @attributes into your HTML and watch it come alive!
|
|
14
|
+
|
|
13
15
|
[See more examples here](https://codepen.io/daz4126/pen/YPwwdBK)
|
|
14
16
|
|
|
15
17
|
To use, just import from the CDN then call the `helium` funtion (no install or build step required!):
|
|
@@ -29,32 +31,36 @@ Then include it in your
|
|
|
29
31
|
|
|
30
32
|
```javascript
|
|
31
33
|
import helium from "@daz4126/helium"
|
|
32
|
-
helium
|
|
34
|
+
helium()
|
|
33
35
|
```
|
|
34
36
|
|
|
37
|
+
# Helium Attributes
|
|
38
|
+
|
|
39
|
+
Helium uses custom attributes to add interactivity to HTML elements. To identify them, they all start with `@`, although there are also `data` attribute aliases that can be used instead.
|
|
40
|
+
|
|
35
41
|
## `@helium`
|
|
36
42
|
|
|
37
43
|
This attribute sets the root element. Helium attributes can only be used on this element and its children. If not set then it defaults to `document`.
|
|
38
44
|
|
|
39
45
|
Alias: `data-helium`
|
|
40
46
|
|
|
41
|
-
## `@
|
|
47
|
+
## `@text`
|
|
42
48
|
|
|
43
49
|
Inserts the result of a JavaScript expression into the text-content of the element.
|
|
44
50
|
|
|
45
51
|
This will update the textContent of the element with the value of the `count` variable:
|
|
46
52
|
|
|
47
53
|
```html
|
|
48
|
-
<b @
|
|
54
|
+
<b @text="count">0</b>
|
|
49
55
|
```
|
|
50
56
|
|
|
51
57
|
You can also use expresions. This will update the textContent of the element with the value of the `name` variable but in uppercase:
|
|
52
58
|
|
|
53
59
|
```html
|
|
54
|
-
<span @
|
|
60
|
+
<span @text="name.toUpperCase()">0</span>
|
|
55
61
|
```
|
|
56
62
|
|
|
57
|
-
Alias: `data-he-
|
|
63
|
+
Alias: `data-he-text`
|
|
58
64
|
|
|
59
65
|
## `@bind`
|
|
60
66
|
|
|
@@ -73,7 +79,7 @@ Alias: `data-he-bind`
|
|
|
73
79
|
Makes the element hidden or visible depending on the result of a JavaScript expression.
|
|
74
80
|
|
|
75
81
|
```html
|
|
76
|
-
<div @
|
|
82
|
+
<div @visible="count > 3">Only visible if the count is greater than 3</div>
|
|
77
83
|
```
|
|
78
84
|
|
|
79
85
|
Alias: `data-he-hidden` & `data-he-visible`
|
|
@@ -132,16 +138,102 @@ You can add modifiers of `prevent` to prevent the default behaviour, `outside` t
|
|
|
132
138
|
|
|
133
139
|
Alias: prepend the event name with `data-he-on`, for example `data-he-onclick="count++"`
|
|
134
140
|
|
|
135
|
-
##
|
|
141
|
+
## Dynamic Attributes
|
|
142
|
+
|
|
143
|
+
It's possible to dynamically update the attributes of elements. To do this, just prepend a `:` in front of the attribute name and write a JavaScript expression that evaulates to the desired attribute value. This will update whenever any of the Helium variables change value.
|
|
144
|
+
|
|
145
|
+
In the following example, the `<div>` element has a dynamic class attribute that will be 'normal' if the count is less than 10, but 'danger' if the count is 10 or more:
|
|
146
|
+
|
|
147
|
+
```html
|
|
148
|
+
<div :class="count < 10 ? 'normal' : 'danger'>
|
|
149
|
+
The count is <b @text=count></b>
|
|
150
|
+
</div>
|
|
151
|
+
```
|
|
136
152
|
|
|
137
153
|
## Magic Attributes
|
|
138
154
|
|
|
139
155
|
`$` is an alias for `document.querySelector`
|
|
140
156
|
|
|
141
|
-
`$el` is an alias for the element
|
|
142
157
|
|
|
143
|
-
|
|
158
|
+
```html
|
|
159
|
+
<div @click="$('#header').classList.add('active')">Activate Header!</div>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`$el` is an alias for the element:
|
|
163
|
+
|
|
164
|
+
```html
|
|
165
|
+
<div @click="$el.remove()">Click to remove me!</div>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`$event` is an alias for the event object of an event handler:
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
```html
|
|
172
|
+
<div @click="console.log($event.timeStamp)">Log the timestamp</div>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`@data` gives you access to the data object that contains all the Helium variables:
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
```html
|
|
179
|
+
<div @click="console.log($data)">Log the data</div>
|
|
180
|
+
```
|
|
144
181
|
|
|
145
182
|
## Default Variables and Functions
|
|
146
183
|
|
|
147
184
|
The helium function accepts a single JavaScript object as an argument. This can include default variable values and functions that can then be called inside the JavaScript expressions.
|
|
185
|
+
|
|
186
|
+
For example, the following will set the `count` variable to an initial value of `29` and the `name` variable to "Helium":
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
helium({ count: 29, name: "Helium"})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The following example shows how a function can be added into Helium and then used by even listeners:
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
helium({
|
|
196
|
+
appendTo(element){
|
|
197
|
+
const li = document.createElement("li")
|
|
198
|
+
li.textContent = "New Item"
|
|
199
|
+
element.append(li)
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
This function can then be called from an event handler, such as `@click`:
|
|
205
|
+
|
|
206
|
+
```html
|
|
207
|
+
<ul @ref="list"></ul>
|
|
208
|
+
<button @click="appendTo($list)>Append item to list</button>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Note that magic attributes and Helium variables are not available inside these functions. However, you can pass them as arguments and they will then be available in the function. If you pass Helium variables then they will be passed as values and updating them inside the function will *not* trigger a reactive update. A solution is to pass the magic `$data` attribute as an argument, then updating the properties of this inside the function *will* trigger a reactive update.
|
|
212
|
+
|
|
213
|
+
So instead of this:
|
|
214
|
+
|
|
215
|
+
```html
|
|
216
|
+
<button @click="increment(count)">Increment Count</button>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
helium({
|
|
221
|
+
increment(count,n = 1){
|
|
222
|
+
count += n
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
You should do this instead:
|
|
228
|
+
|
|
229
|
+
```html
|
|
230
|
+
<button @click="increment($data)">Increment Count</button>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
helium({
|
|
235
|
+
increment(data,n = 1){
|
|
236
|
+
data.count += n
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
```
|
package/helium.js
CHANGED
|
@@ -33,12 +33,12 @@ export default function helium(data = {}) {
|
|
|
33
33
|
try {
|
|
34
34
|
return new Function(
|
|
35
35
|
"$",
|
|
36
|
-
"$
|
|
36
|
+
"$data",
|
|
37
37
|
"$event",
|
|
38
38
|
"$el",
|
|
39
39
|
...Object.keys(data),
|
|
40
40
|
...[...refs.keys()],
|
|
41
|
-
`with($
|
|
41
|
+
`with($data) { ${withReturn ? "return" : ""} (${expr.trim()}) }`,
|
|
42
42
|
);
|
|
43
43
|
} catch (err) {
|
|
44
44
|
return () => expr;
|
|
@@ -65,8 +65,6 @@ export default function helium(data = {}) {
|
|
|
65
65
|
heliumElements.forEach((el) => {
|
|
66
66
|
for (const { name, value } of el.attributes) {
|
|
67
67
|
if (
|
|
68
|
-
name == "@react" ||
|
|
69
|
-
name == "data-he-react" ||
|
|
70
68
|
name == "@text" ||
|
|
71
69
|
name == "data-he-text" ||
|
|
72
70
|
name == "@bind" ||
|
|
@@ -75,7 +73,7 @@ export default function helium(data = {}) {
|
|
|
75
73
|
try {
|
|
76
74
|
new Function(`let ${value} = 1`);
|
|
77
75
|
state[value] ||=
|
|
78
|
-
name == "@
|
|
76
|
+
name == "@text" || name == "data-he-text"
|
|
79
77
|
? el.textContent
|
|
80
78
|
: el.value;
|
|
81
79
|
} catch (e) {}
|
|
@@ -97,12 +95,7 @@ export default function helium(data = {}) {
|
|
|
97
95
|
),
|
|
98
96
|
);
|
|
99
97
|
if (name == "@ref" || name == "data-he-ref") refs.set("$" + value, el);
|
|
100
|
-
if (
|
|
101
|
-
name == "@react" ||
|
|
102
|
-
name == "data-he-react" ||
|
|
103
|
-
name == "@text" ||
|
|
104
|
-
name == "data-he-text"
|
|
105
|
-
)
|
|
98
|
+
if (name == "@text" || name == "data-he-text")
|
|
106
99
|
Object.keys(state)
|
|
107
100
|
.filter((key) => value.includes(key))
|
|
108
101
|
.forEach((val) =>
|
|
@@ -178,10 +171,50 @@ export default function helium(data = {}) {
|
|
|
178
171
|
const [eventName, ...modifiers] = name
|
|
179
172
|
.slice(name.startsWith("@") ? 1 : 10)
|
|
180
173
|
.split(".");
|
|
181
|
-
const receiver =
|
|
182
|
-
|
|
174
|
+
const receiver =
|
|
175
|
+
modifiers.includes("outside") || modifiers.includes("document")
|
|
176
|
+
? document
|
|
177
|
+
: el;
|
|
178
|
+
const debounce = (fn, delay) => {
|
|
179
|
+
let timeout;
|
|
180
|
+
return function (...args) {
|
|
181
|
+
clearTimeout(timeout);
|
|
182
|
+
timeout = setTimeout(() => fn.apply(this, args), delay);
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
let debounceDelay = 0;
|
|
187
|
+
const debounceModifier = modifiers.find((m) =>
|
|
188
|
+
m.startsWith("debounce"),
|
|
189
|
+
);
|
|
190
|
+
if (debounceModifier) {
|
|
191
|
+
const time = debounceModifier.split(":")[1];
|
|
192
|
+
if (time && !isNaN(time)) debounceDelay = Number(time);
|
|
193
|
+
else debounceDelay = 300;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function _handler(e) {
|
|
183
197
|
if (modifiers.includes("prevent")) e.preventDefault();
|
|
184
|
-
|
|
198
|
+
const keyModifiers = {
|
|
199
|
+
shift: "shiftKey",
|
|
200
|
+
ctrl: "ctrlKey",
|
|
201
|
+
alt: "altKey",
|
|
202
|
+
meta: "metaKey",
|
|
203
|
+
};
|
|
204
|
+
for (const [mod, prop] of Object.entries(keyModifiers)) {
|
|
205
|
+
if (modifiers.includes(mod) && !e[prop]) return;
|
|
206
|
+
}
|
|
207
|
+
if (["keydown", "keyup", "keypress"].includes(eventName)) {
|
|
208
|
+
const last = modifiers[modifiers.length - 1];
|
|
209
|
+
if (last) {
|
|
210
|
+
let keyName = e.key;
|
|
211
|
+
if (keyName === " ") keyName = "Space";
|
|
212
|
+
else if (keyName === "Escape") keyName = "Esc";
|
|
213
|
+
if (keyName.toLowerCase() !== last.toLowerCase()) return;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!modifiers.includes("outside") || !el.contains(e.target)) {
|
|
185
218
|
compileExpression(value, false)(
|
|
186
219
|
$,
|
|
187
220
|
state,
|
|
@@ -190,9 +223,15 @@ export default function helium(data = {}) {
|
|
|
190
223
|
...Object.values(data),
|
|
191
224
|
...[...refs.values()],
|
|
192
225
|
);
|
|
226
|
+
}
|
|
193
227
|
if (modifiers.includes("once"))
|
|
194
|
-
el.removeEventListener(eventName,
|
|
195
|
-
}
|
|
228
|
+
el.removeEventListener(eventName, debouncedHandler);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const debouncedHandler =
|
|
232
|
+
debounceDelay > 0 ? debounce(_handler, debounceDelay) : _handler;
|
|
233
|
+
|
|
234
|
+
receiver.addEventListener(eventName, debouncedHandler);
|
|
196
235
|
}
|
|
197
236
|
}
|
|
198
237
|
});
|
|
@@ -204,8 +243,7 @@ export default function helium(data = {}) {
|
|
|
204
243
|
}
|
|
205
244
|
});
|
|
206
245
|
observer.observe(element, { childList: true, subtree: true });
|
|
207
|
-
for (const [key, items] of bindings.entries())
|
|
208
|
-
items.forEach((binding) => applyBinding(binding));
|
|
246
|
+
for (const [key, items] of bindings.entries()) items.forEach(applyBinding);
|
|
209
247
|
}
|
|
210
248
|
processElements(root);
|
|
211
249
|
}
|