targetj 1.0.213 → 1.0.215
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 +107 -386
- package/build/$Dom.js +27 -9
- package/build/App.js +1 -0
- package/build/DomInit.js +5 -8
- package/build/EventListener.js +17 -14
- package/build/PageManager.js +78 -35
- package/build/TModelManager.js +4 -2
- package/build/TargetData.js +3 -1
- package/build/TargetUtil.js +24 -10
- package/dist/targetjs.js +1 -1
- package/dist/targetjs.js.gz +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,71 +1,72 @@
|
|
|
1
|
-
# TargetJS:
|
|
1
|
+
# TargetJS: UI Development as a Sequence
|
|
2
2
|
|
|
3
3
|
**[targetjs.io](https://targetjs.io)**
|
|
4
4
|
[](https://github.com/livetrails/targetjs/blob/main/LICENSE)
|
|
5
5
|
[](https://github.com/livetrails/targetjs/stargazers)
|
|
6
6
|
[](https://www.npmjs.com/package/targetj)
|
|
7
7
|
|
|
8
|
-
TargetJS is a
|
|
9
|
-
It can be used as a full-featured framework or as a lightweight library alongside other frameworks. It is also a highly performant web framework, as shown in the [framework benchmark](https://krausest.github.io/js-framework-benchmark/current.html).
|
|
10
|
-
|
|
11
|
-
## The Philosophy Behind TargetJS
|
|
8
|
+
TargetJS is a high-performance JavaScript UI framework with ultra-compact syntax. It replaces the "State → Render" model with a Code-Ordered Reactivity. It unifies UI, animations, APIs, event handling, and state into self-contained "Targets" that stack together like intelligent Lego pieces.
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
TargetJS adopts a new approach. First, it unifies class methods and fields into a single construct called targets. Each target is given state, lifecycles, timing, iterations, and the autonomy to execute mimicking the behavior of living cells. Targets are essentially self-contained, intelligent blocks of code.
|
|
16
|
-
|
|
17
|
-
The second challenge is making these targets fit and work together especially since UI operations are highly asynchronous. Instead of relying on traditional method calls and callbacks that don't address asynchronous nature well, TargetJS allows targets to react to the execution or completion of preceding targets. A subsequent target can run independently, execute whenever the previous one does, or wait until the previous target completes. Targets stack together like Lego pieces. It can address complex asynchronous workflow while remaining easy to understand.
|
|
10
|
+
It can be used as a full-featured framework or as a lightweight library alongside other frameworks. It is also a highly performant web framework, as shown in the [framework benchmark](https://krausest.github.io/js-framework-benchmark/current.html).
|
|
18
11
|
|
|
19
|
-
For example, setting a value can implicitly define an animation, where the current value iteratively progresses until it reaches the new value. When the animation completes, the next target might initiate a fetch API call. Once the data is received, it can trigger another target that creates 10 new elements, each with its own animation and API call. A subsequent target can then be set to run only after all 10 elements have completed their tasks. Targets simply react and chain together based on how the code is written.
|
|
20
12
|
|
|
21
|
-
|
|
13
|
+
## The Philosophy Behind TargetJS
|
|
22
14
|
|
|
23
|
-
|
|
15
|
+
Traditional frameworks model the UI as a function of state: change state, re-render the UI. When state changes from A to B, the UI immediately jumps to **B**. The framework doesn’t naturally represent the *journey* from A to B. But modern, rich user experiences are built on sequences that unfold over time. For example:
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
2. All-in-One solution: Offers a unified approach to UI rendering, API integration, state management, event handling, and animation.
|
|
27
|
-
3. Code-ordered execution, Rebol-like style: less code and more readable code.
|
|
17
|
+
> Click → Animate button → Chain secondary animation → Fetch data → Render list → Animate items → Pause → Animate an important item
|
|
28
18
|
|
|
29
|
-
|
|
19
|
+
TargetJS is built for this reality. Instead of managing complex flags, your code structure mirrors these sequences directly.
|
|
30
20
|
|
|
31
|
-
|
|
21
|
+
It achieves this through Targets. A Target is a self-contained unit that merges data (fields) and logic (methods) into a single reactive block. Each Target has its own internal state, timing, and lifecycle, acting like a living cell within your app. By simply ordering them in your code, you create complex asynchronous workflows without async/await or .then() chains.
|
|
32
22
|
|
|
33
|
-
|
|
23
|
+
By building animation directly into the logic of the framework and adopting a compact style, TargetJS makes the journey from A to B explicit and with significantly less code than traditional frameworks.
|
|
34
24
|
|
|
35
|
-
|
|
25
|
+
## ⚡ Quick Start (30 Seconds)
|
|
36
26
|
|
|
37
|
-
**
|
|
27
|
+
**1. Install**
|
|
38
28
|
|
|
39
|
-
|
|
29
|
+
```bash
|
|
30
|
+
npm install targetj
|
|
31
|
+
```
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
**2. The "Hello World" Sequence**
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
<div id="likeButton"></div>
|
|
45
|
-
```
|
|
35
|
+
This creates a blue box that grows, then turns red, and then logs "Hello World" in order.
|
|
46
36
|
|
|
47
37
|
```javascript
|
|
48
38
|
import { App } from "targetj";
|
|
49
39
|
|
|
50
40
|
App({
|
|
51
|
-
|
|
52
|
-
height:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
html: "♡ Like"
|
|
58
|
-
}).mount("#likeButton");
|
|
41
|
+
backgroundColor: 'blue',
|
|
42
|
+
height: 100,
|
|
43
|
+
width: { value: [100, 200], steps: 100 }, // 1. Animate width in 100 steps using the default 8 ms interval per step.
|
|
44
|
+
backgroundColor$$: { value: 'red', steps: 100 }, // 2. Wait ($$) then turn red in 100 steps
|
|
45
|
+
done$$() { console.log("Hello World!"); } // 3. Wait ($$) then log
|
|
46
|
+
}).mount("#app");
|
|
59
47
|
```
|
|
60
48
|
|
|
61
|
-
|
|
49
|
+
## Understanding TargetJS Syntax
|
|
50
|
+
|
|
51
|
+
These symbols tell the framework **when** a target should run.
|
|
52
|
+
|
|
53
|
+
| Symbol | Name | Behavior |
|
|
54
|
+
| -------- | -------- | -------------------------------------------------------------------------------------------------------------------------|
|
|
55
|
+
| `name` | Standard | Runs immediately in the order it appears. |
|
|
56
|
+
| `name$` | Reactive | Runs every time the previous sibling target executes. |
|
|
57
|
+
| `name$$` | Deferred | Executes only after the entire preceding target chain including children, animations, and API calls has fully completed. |
|
|
58
|
+
| `_name` | Inactive | Does not run automatically. Trigger it manually via `.activateTarget()`. |
|
|
59
|
+
|
|
62
60
|
|
|
61
|
+
## Examples: Like Button → Animated Like (in 3 Steps)
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
Let’s see how TargetJS handles a complex interaction that would usually require 50+ lines of React/CSS. The example demonstrates how to run four asynchronous operations in a strict sequential sequence, where each step waits for the previous ones to complete.
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
### 1) Like button
|
|
67
66
|
|
|
68
|
-
|
|
67
|
+
One object defines a UI element without separate HTML/CSS. Static targets map directly to DOM styles/attributes. You can still use CSS if wanted.
|
|
68
|
+
|
|
69
|
+
<img src="https://targetjs.io/img/likeButton6.gif" width="130" />
|
|
69
70
|
|
|
70
71
|
```html
|
|
71
72
|
<div id="likeButton"></div>
|
|
@@ -81,16 +82,17 @@ App({
|
|
|
81
82
|
textAlign: "center",
|
|
82
83
|
borderRadius: 10,
|
|
83
84
|
html: "♡ Like",
|
|
85
|
+
// Runs immediately on mount
|
|
84
86
|
scale: { value: [1.2, 1], steps: 12, interval: 12 },
|
|
85
87
|
backgroundColor: { value: ["#ffe8ec", "#f5f5f5"], steps: 12, interval: 12 }
|
|
86
88
|
}).mount("#likeButton");
|
|
87
89
|
```
|
|
88
90
|
|
|
89
|
-
###
|
|
91
|
+
### 2) Adding the Interaction
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
We move the animation into an `onClick` and add a deferred heart animation.
|
|
92
94
|
|
|
93
|
-
|
|
95
|
+
<img src="https://targetjs.io/img/likeButton-step2-2.gif" width="130" />
|
|
94
96
|
|
|
95
97
|
```html
|
|
96
98
|
<div id="likeButton"></div>
|
|
@@ -103,132 +105,31 @@ App({
|
|
|
103
105
|
borderRadius: 10, backgroundColor: "#f5f5f5",
|
|
104
106
|
cursor: "pointer", userSelect: "none",
|
|
105
107
|
html: "♡ Like",
|
|
106
|
-
|
|
107
|
-
onClick() {
|
|
108
|
-
this.setTarget('scale', { value: [1.2, 1], steps: 8, interval: 12 });
|
|
109
|
-
this.setTarget('backgroundColor', { value: [ '#ffe8ec', '#f5f5f5' ], steps: 12, interval: 12 });
|
|
110
|
-
}
|
|
111
|
-
}).mount("#likeButton");
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
### 4) Sequencing with `$$`: Adding a small heart after click animation (first async op)
|
|
117
|
-
|
|
118
|
-
**What this shows:** A `$$` target (deferred) runs only after all prior targets finish (including `onClick()` and its animations). Here it adds a new heart element and runs its fly motion only once the click sequence has completed. Repeated clicks will delay adding the heart.
|
|
119
|
-
|
|
120
|
-
<img src="https://targetjs.io/img/likeButton7.gif" width="130" />
|
|
121
|
-
|
|
122
|
-
```html
|
|
123
|
-
<div id="likeButton"></div>
|
|
124
|
-
```
|
|
125
|
-
```javascript
|
|
126
|
-
import { App } from "targetj";
|
|
127
|
-
|
|
128
|
-
App({
|
|
129
|
-
width: 220, height: 60, lineHeight: 60, textAlign: "center",
|
|
130
|
-
borderRadius: 10, backgroundColor: "#f5f5f5", cursor: "pointer", userSelect: "none",
|
|
131
|
-
html: "♡ Like",
|
|
132
108
|
onClick() {
|
|
133
109
|
this.setTarget('scale', { value: [1.2, 1], steps: 8, interval: 12 });
|
|
134
110
|
this.setTarget('backgroundColor', { value: [ '#ffe8ec', '#f5f5f5' ], steps: 12, interval: 12 });
|
|
135
111
|
},
|
|
136
|
-
heart$$: {
|
|
112
|
+
heart$$: { // Wait for the button animation to finish, THEN add and animate the heart.
|
|
137
113
|
html: "♥", color: "crimson", fontSize: 20,
|
|
138
114
|
fly() {
|
|
139
115
|
const cx = this.getCenterX(), cy = this.getCenterY();
|
|
140
116
|
this.setTarget({
|
|
141
|
-
opacity: {
|
|
142
|
-
scale: {
|
|
143
|
-
rotate: {
|
|
144
|
-
x: {
|
|
145
|
-
y: {
|
|
146
|
-
}
|
|
117
|
+
opacity: { value: [0, 1, 1, 0.8, 0.1], steps: 20 },
|
|
118
|
+
scale: { value: [0.8, 1.4, 1.1, 0.9, 0.8], steps: 20 },
|
|
119
|
+
rotate: { value: [0, 12, -8, 6, 0], steps: 20 },
|
|
120
|
+
x: { value: [cx, cx + 22, cx - 16, cx + 10, cx], steps: 30 },
|
|
121
|
+
y: { value: [cy - 8, cy - 70, cy - 90, cy - 120, cy - 150], steps: 30 }
|
|
122
|
+
});
|
|
147
123
|
}
|
|
148
|
-
}
|
|
149
|
-
}).mount("#likeButton");
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
### 5) Another `$$`: Adding a big heart (second async op)
|
|
155
|
-
|
|
156
|
-
**What this shows:** Deferred addition of a new element using $$. `bigHeart$$` waits for `heart$$` and the click sequence to complete their animation, then adds a larger heart and runs its own happy animation.
|
|
157
|
-
|
|
158
|
-
<img src="https://targetjs.io/img/likeButton8.gif" width="130" />
|
|
159
|
-
|
|
160
|
-
```html
|
|
161
|
-
<div id="likeButton"></div>
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
```javascript
|
|
165
|
-
import { App } from "targetj";
|
|
166
|
-
|
|
167
|
-
App({
|
|
168
|
-
width: 220, height: 60, lineHeight: 60, textAlign: "center",
|
|
169
|
-
borderRadius: 10, backgroundColor: "#f5f5f5", cursor: "pointer", userSelect: "none",
|
|
170
|
-
html: "♡ Like",
|
|
171
|
-
|
|
172
|
-
onClick() {
|
|
173
|
-
this.setTarget('scale', { value: [1.2, 1], steps: 8, interval: 12 });
|
|
174
|
-
this.setTarget('backgroundColor', { value: [ '#ffe8ec', '#f5f5f5' ], steps: 12, interval: 12 });
|
|
175
|
-
},
|
|
176
|
-
|
|
177
|
-
heart$$: {
|
|
178
|
-
html: "♥", color: "crimson", fontSize: 20,
|
|
179
|
-
fly() {
|
|
180
|
-
const cx = this.getCenterX(), cy = this.getCenterY();
|
|
181
|
-
this.setTarget({
|
|
182
|
-
opacity: { list: [0, 1, 1, 0.8, 0.1] },
|
|
183
|
-
scale: { list: [0.8, 1.4, 1.1, 0.9, 0.8] },
|
|
184
|
-
rotate: { list: [0, 12, -8, 6, 0] },
|
|
185
|
-
x: { list: [cx, cx + 22, cx - 16, cx + 10, cx] },
|
|
186
|
-
y: { list: [cy - 8, cy - 70, cy - 90, cy - 120, cy - 150] }
|
|
187
|
-
}, 20);
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
bigHeart$$: {
|
|
191
|
-
html: "♥", color: "blue", fontSize: 100,
|
|
192
|
-
happyFly() {
|
|
193
|
-
const cx = this.getCenterX(), cy = this.getCenterY();
|
|
194
|
-
this.setTarget({
|
|
195
|
-
opacity: { list: [0, 1, 1, 0.85, 0.6, 0.1] },
|
|
196
|
-
scale: { list: [0.4, 1.9, 1.2, 1.6, 1.0, 0.95] },
|
|
197
|
-
rotate: { list: [0, 4, -3, 4, -2, 0] },
|
|
198
|
-
x: { list: [cx, cx + 14, cx + 10, cx - 6, cx - 14, cx] },
|
|
199
|
-
y: { list: [cy, cy - 30, cy - 55, cy - 80, cy - 100, cy - 130] }
|
|
200
|
-
}, 30);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}).mount("#likeButton");
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
### 6) `fetch$$` (third async op)
|
|
209
|
-
|
|
210
|
-
**What this shows:** Networking is just another target. The POST happens **only after** all prior visual steps complete, since the target is postfixed with `$$`. Similarly, repeated clicks delay `fetch$$`.
|
|
211
|
-
|
|
212
|
-
```html
|
|
213
|
-
<div id="likeButton"></div>
|
|
214
|
-
```
|
|
215
|
-
```javascript
|
|
216
|
-
import { App } from "targetj";
|
|
217
|
-
|
|
218
|
-
App({
|
|
219
|
-
// …same as step 5…
|
|
220
|
-
|
|
221
|
-
fetch$$: { method: "POST", id: 123, url: "/api/like" }
|
|
124
|
+
}
|
|
222
125
|
}).mount("#likeButton");
|
|
223
126
|
```
|
|
224
127
|
|
|
225
|
-
|
|
128
|
+
### 3) The Full Async Workflow
|
|
226
129
|
|
|
227
|
-
|
|
130
|
+
We handle UI, two animations, a POST request, and a cleanup.
|
|
228
131
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
<img src="https://targetjs.io/img/likeButton9.gif" width="130" />
|
|
132
|
+
<img src="https://targetjs.io/img/likeButton-step3-4.gif" width="130" />
|
|
232
133
|
|
|
233
134
|
```html
|
|
234
135
|
<div id="likeButton"></div>
|
|
@@ -247,58 +148,40 @@ App({
|
|
|
247
148
|
this.setTarget('scale', { value: [1.2, 1], steps: 8, interval: 12 });
|
|
248
149
|
this.setTarget('backgroundColor', { value: [ '#ffe8ec', '#f5f5f5' ], steps: 12, interval: 12 });
|
|
249
150
|
},
|
|
250
|
-
|
|
251
151
|
heart$$: {
|
|
252
152
|
html: "♥", color: "crimson", fontSize: 20,
|
|
253
153
|
fly() {
|
|
254
154
|
const cx = this.getCenterX(), cy = this.getCenterY();
|
|
255
155
|
this.setTarget({
|
|
256
|
-
opacity: {
|
|
257
|
-
scale: {
|
|
258
|
-
rotate: {
|
|
259
|
-
x: {
|
|
260
|
-
y: {
|
|
261
|
-
}
|
|
156
|
+
opacity: { value: [0, 1, 1, 0.8, 0.1], steps: 20 },
|
|
157
|
+
scale: { value: [0.8, 1.4, 1.1, 0.9, 0.8], steps: 20 },
|
|
158
|
+
rotate: { value: [0, 12, -8, 6, 0], steps: 20 },
|
|
159
|
+
x: { value: [cx, cx + 22, cx - 16, cx + 10, cx], steps: 30 },
|
|
160
|
+
y: { value: [cy - 8, cy - 70, cy - 90, cy - 120, cy - 150], steps: 30 }
|
|
161
|
+
});
|
|
262
162
|
}
|
|
263
163
|
},
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
html: "♥", color: "blue", fontSize: 100,
|
|
267
|
-
happyFly() {
|
|
268
|
-
const cx = this.getCenterX(), cy = this.getCenterY();
|
|
269
|
-
this.setTarget({
|
|
270
|
-
opacity: { list: [0, 1, 1, 0.85, 0.6, 0.1] },
|
|
271
|
-
scale: { list: [0.4, 1.9, 1.2, 1.6, 1.0, 0.95] },
|
|
272
|
-
rotate: { list: [0, 4, -3, 4, -2, 0] },
|
|
273
|
-
x: { list: [cx, cx + 14, cx + 10, cx - 6, cx - 14, cx] },
|
|
274
|
-
y: { list: [cy, cy - 30, cy - 55, cy - 80, cy - 100, cy - 130] }
|
|
275
|
-
}, 30);
|
|
276
|
-
}
|
|
277
|
-
},
|
|
278
|
-
fetch$$: { method: "POST", id: 123, url: "/api/like" },
|
|
279
|
-
removeHearts$$() { this.removeChildren(); },
|
|
164
|
+
fetch$$: { method: "POST", id: 123, url: "/api/like" }, // Wait for hearts to finish, THEN fetch
|
|
165
|
+
removeHearts$$() { this.removeChildren(); }, // Wait for fetch to finish, THEN cleanup
|
|
280
166
|
onKey(e) { if (e.key === "Enter") this.activateTarget("onClick"); }
|
|
281
167
|
}
|
|
282
168
|
}).mount("#likeButton");
|
|
283
169
|
```
|
|
284
|
-
---
|
|
285
170
|
|
|
286
|
-
###
|
|
171
|
+
### Summary
|
|
172
|
+
|
|
173
|
+
Instead of wiring callbacks and effects, you write a sequence of targets. All targets execute automatically in the order they are written. `$$` defers execution until all prior sibling steps finish. Animations, API calls, event handling, and child creation are all treated as the same kind of thing: targets. Complex asynchronous flows are expressed by structuring parent and child targets. In addition, targets also provide built-in capabilities such as `onComplete` callback, enabledOn, looping with delays, and more as explained below.
|
|
174
|
+
|
|
175
|
+
---
|
|
287
176
|
|
|
288
|
-
- Instead of wiring callbacks and effects, you write a sequence of targets. `$$` defers until all prior steps finish. Animations, API calls, and child creation are all the same kind of thing: targets.
|
|
289
|
-
- Minimal plumbing yet full control to manage a flow of complex asynchronous operations.
|
|
290
|
-
|
|
291
177
|
## Table of Contents
|
|
292
178
|
|
|
293
|
-
1. [
|
|
294
|
-
1. [
|
|
295
|
-
1. [📦 Installation](#-installation)
|
|
296
|
-
1. [What Problems Does TargetJS Solve?](#what-problems-does-targetjs-solve)
|
|
179
|
+
1. [📦 Alternative Installation Via CDN](#-alternative-installation-via-cdn)
|
|
180
|
+
1. [🚀 Why TargetJS?](#-why-targetjs)
|
|
297
181
|
1. More Examples:
|
|
298
182
|
- [Loading Five Users Example](#loading-five-users-example)
|
|
299
183
|
- [Infinite Loading and Scrolling Example](#infinite-loading-and-scrolling-example)
|
|
300
184
|
1. [Target Methods](#target-methods)
|
|
301
|
-
1. [Target Variables](#target-variables)
|
|
302
185
|
1. [Special Target Names](#special-target-names)
|
|
303
186
|
1. [How to Debug in TargetJS](#how-to-debug-in-targetjs)
|
|
304
187
|
1. [Documentation](#documentation)
|
|
@@ -306,55 +189,7 @@ App({
|
|
|
306
189
|
1. [Contact](#contact)
|
|
307
190
|
1. [💖 Support TargetJS](#-support-targetjs)
|
|
308
191
|
|
|
309
|
-
##
|
|
310
|
-
|
|
311
|
-
Targets provide a unified interface for both class methods and fields. Each Target comes equipped with a built-in set of capabilities:
|
|
312
|
-
|
|
313
|
-
1. State Management: Targets are inherently stateful, enabling implicit state handling across your application.
|
|
314
|
-
2. Iterations: They can iterate towards defined values, making them perfect for creating animations.
|
|
315
|
-
3. Multiple or Conditional Execution: Targets can execute repeatedly or only under specific conditions.
|
|
316
|
-
4. Execution timing: Targets enable fine-grained control over when they execute.
|
|
317
|
-
5. Code-Ordered Execution: Targets execute sequentially and predictably in the order they are written within a JavaScript object, thanks to ES2015's guaranteed property order.
|
|
318
|
-
|
|
319
|
-
## Understanding TargetJS Syntax: Reactive Postfixes
|
|
320
|
-
|
|
321
|
-
All targets execute automatically in the order they are writte unless their names have a postfix or prefix. TargetJS defines reactive behavior using the $ and $$ postfixes, while the _ prefix marks a target as inactive so it runs only when explicitly activated imperatively by another target. Although this convention may seem a bit cryptic at first, it enables a compact syntax.
|
|
322
|
-
|
|
323
|
-
**`$` Postfix (Immediate Reactivity):**
|
|
324
|
-
|
|
325
|
-
A target name ending with a single `$` (e.g., `height$`) indicates that this target will execute every time its immediately preceding target runs or emits a new value. If the preceding target involves an asynchronous operation like an API call, the reactive target activates when the response is received. If there are multiple API calls made, `$` postfix ensures that the target reacts to the first API result when it becomes available, then the second, and so on, maintaining a strict, code-ordered sequence of operations.
|
|
326
|
-
|
|
327
|
-
**`$$` Postfix (Deferred Reactivity):**
|
|
328
|
-
|
|
329
|
-
A target name ending with a double `$$` (e.g., `fetch$$`) will activate only after all the preceding targets have fully and comprehensively completed all of their operations. This includes:
|
|
330
|
-
|
|
331
|
-
- The successful resolution of any timed sequences, such as animations.
|
|
332
|
-
- The completion and return of results from all associated API calls.
|
|
333
|
-
- The finalization of all tasks, animations, and API calls initiated by any dependent child targets that were themselves triggered by a preceding target.
|
|
334
|
-
|
|
335
|
-
**`_` Prefix (Inactive):**
|
|
336
|
-
|
|
337
|
-
A target name starting with `_` (e.g., `_height`) indicates that the target is inactive and does not execute automatically. It runs only when explicitly activated imperatively by another target using `.activateTarget(targetName)`.
|
|
338
|
-
|
|
339
|
-
---
|
|
340
|
-
|
|
341
|
-
## **📦 Installation**
|
|
342
|
-
|
|
343
|
-
**Via package manager**
|
|
344
|
-
|
|
345
|
-
Install TargetJS via npm (note: there's no "s" at the end):
|
|
346
|
-
|
|
347
|
-
```bash
|
|
348
|
-
npm install targetj
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
Then import it into your JavaScript code:
|
|
352
|
-
|
|
353
|
-
```javascript
|
|
354
|
-
import { App } from "targetj";
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
**Via CDN**
|
|
192
|
+
## 📦 Alternative Installation Via CDN
|
|
358
193
|
|
|
359
194
|
Add the following `<script>` tag to your HTML to load TargetJS from a CDN:
|
|
360
195
|
|
|
@@ -362,7 +197,9 @@ Add the following `<script>` tag to your HTML to load TargetJS from a CDN:
|
|
|
362
197
|
<script src="https://unpkg.com/targetj@latest/dist/targetjs.js"></script>
|
|
363
198
|
```
|
|
364
199
|
|
|
365
|
-
This exposes `TargetJS` on `window`, so you can initialize your app with `TargetJS.App(...)`.
|
|
200
|
+
This exposes `TargetJS` on `window`, so you can initialize your app with `TargetJS.App(...)`.
|
|
201
|
+
|
|
202
|
+
> Ensure your code runs after the DOM is ready (use `defer`, place your script at the bottom of the `<body>`, or wrap it in a `DOMContentLoaded` listener).
|
|
366
203
|
|
|
367
204
|
```html
|
|
368
205
|
<div id='redbox'></div>
|
|
@@ -375,7 +212,10 @@ This exposes `TargetJS` on `window`, so you can initialize your app with `Target
|
|
|
375
212
|
}).mount('#redbox');
|
|
376
213
|
</script>
|
|
377
214
|
```
|
|
378
|
-
|
|
215
|
+
|
|
216
|
+
### Zero-JS Declarative HTML
|
|
217
|
+
|
|
218
|
+
TargetJS can also be used as a "no-code" library. Elements with tg- attributes are discovered and activated automatically.
|
|
379
219
|
|
|
380
220
|
```html
|
|
381
221
|
<div
|
|
@@ -385,21 +225,13 @@ Or, directly in your HTML with `tg-` attributes. Elements with tg- attributes ar
|
|
|
385
225
|
</div>
|
|
386
226
|
```
|
|
387
227
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
## What Problems Does TargetJS Solve?
|
|
391
|
-
|
|
392
|
-
TargetJS addresses several common pain points in front-end development:
|
|
228
|
+
## 🚀 Why TargetJS?
|
|
393
229
|
|
|
394
|
-
1.
|
|
395
|
-
2.
|
|
396
|
-
3.
|
|
397
|
-
4.
|
|
398
|
-
5.
|
|
399
|
-
6. **Difficult Animation Control:** TargetJS makes animations first-class citizens with fine-grained control.
|
|
400
|
-
7. **Performance Bottlenecks with Large Lists:** TargetJS optimizes rendering for large lists by using a tree structure that renders only the visible branches.
|
|
401
|
-
|
|
402
|
-
---
|
|
230
|
+
1. Zero Boilerplate Async: The $$ postfix handles the "wait" for you.
|
|
231
|
+
2. Unified State: State isn't "elsewhere". It's built into every Target.
|
|
232
|
+
3. Animation by Default: High-performance animations are baked into the logic.
|
|
233
|
+
4. Ultra-Compact: Write 70% less code than standard frameworks.
|
|
234
|
+
5. Lower Cognitive Load: Code reads from top to bottom, exactly how the user experiences the interaction.
|
|
403
235
|
|
|
404
236
|
## More Examples
|
|
405
237
|
|
|
@@ -428,6 +260,8 @@ App({
|
|
|
428
260
|
'https://targetjs.io/api/randomUser?id=user4'
|
|
429
261
|
],
|
|
430
262
|
child$() {
|
|
263
|
+
// prevTargetValue Holds the previous target’s value. For fetch targets, this is each API result in code order,
|
|
264
|
+
// not the order in which responses arrive in the browser.
|
|
431
265
|
const user = this.prevTargetValue;
|
|
432
266
|
return {
|
|
433
267
|
width: 200,
|
|
@@ -481,8 +315,6 @@ App({
|
|
|
481
315
|
|
|
482
316
|
In this advanced example, we implement an infinite-scrolling application.
|
|
483
317
|
|
|
484
|
-
**Explanation:**
|
|
485
|
-
|
|
486
318
|
* `addChildren` is a special target that adds multiple items to the container’s children each time it executes. The `onVisibleChildrenChange` event detects changes in the visible children and activates `addChildren` to insert new items and fill any gaps.
|
|
487
319
|
|
|
488
320
|
* `photo` and `userName` each add a `div` element inside every item, serving as placeholders for the photo and user name.
|
|
@@ -565,163 +397,52 @@ App({
|
|
|
565
397
|
```
|
|
566
398
|
---
|
|
567
399
|
|
|
568
|
-
##
|
|
400
|
+
## Technical Reference
|
|
401
|
+
|
|
402
|
+
### Target Methods
|
|
569
403
|
|
|
570
|
-
|
|
404
|
+
Every target can be an object with these optional controls:
|
|
571
405
|
|
|
572
406
|
1. **value**
|
|
573
|
-
|
|
574
|
-
|
|
407
|
+
The data or function that determines the target's state.
|
|
408
|
+
|
|
409
|
+
1. **steps**
|
|
410
|
+
Turns a value change into an animation (e.g., steps: 20).
|
|
575
411
|
|
|
576
|
-
1. **
|
|
577
|
-
|
|
578
|
-
each time an API response is received, while ensuring the order of API calls is enforced. This means it will remain inactive until the first API result is received,
|
|
579
|
-
then the second, and so on.
|
|
580
|
-
|
|
581
|
-
1. **Postfix `$$` to the target name** (Deferred):
|
|
582
|
-
A target name ending with `$$` indicates that it will be activated only after all the preceding targets have completed, along with all its imperative targets,
|
|
583
|
-
and after all API results have been received.
|
|
412
|
+
1. **interval**
|
|
413
|
+
The delay (ms) between steps or executions.
|
|
584
414
|
|
|
585
|
-
1. **
|
|
586
|
-
|
|
415
|
+
1. **cycles**
|
|
416
|
+
How many times to repeat the target.
|
|
587
417
|
|
|
588
418
|
1. **onComplete**
|
|
589
|
-
|
|
419
|
+
Callback when this target (and its children) finishes.
|
|
590
420
|
|
|
591
421
|
1. **enabledOn**
|
|
592
|
-
Determines whether the target is
|
|
422
|
+
Determines whether the target is enabled for execution.
|
|
593
423
|
|
|
594
424
|
1. **loop**
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
1. **cycles**
|
|
598
|
-
It works similarly to `loop`, but it specifies an explicit number of repetitions. It can also be combined with `loop`, in which case, once the specified cycles complete, they will rerun as long as `loop` returns true. In other words, `loop` functions as an outer loop for `cycles`.
|
|
599
|
-
|
|
600
|
-
1. **interval**
|
|
601
|
-
It specifies the pause between each target execution or each actual value update when steps are defined.
|
|
602
|
-
|
|
603
|
-
1. **steps**
|
|
604
|
-
By default, the actual value is updated immediately after the target value. The steps option allows the actual value to be updated in iterations specified by the number of steps.
|
|
425
|
+
Managed the repetition of target execution. Similar to `cycles` but uses boolean instead.
|
|
605
426
|
|
|
606
427
|
1. **easing**
|
|
607
428
|
A string that defines a predefined easing function that controls how the actual value is updated in relation to the steps.
|
|
608
429
|
|
|
609
430
|
1. **onValueChange**
|
|
610
|
-
This callback is triggered
|
|
611
|
-
|
|
612
|
-
1. **onStepsEnd**
|
|
613
|
-
This method is invoked only after the final step of updating the actual value is completed, assuming the target has a defined steps value.
|
|
614
|
-
|
|
615
|
-
1. **onImperativeStep**
|
|
616
|
-
This callback tracks the progress of imperative targets defined within a declarative target. If there are multiple imperative targets, this method is called at each step,
|
|
617
|
-
identifiable by their target name. You can also use `on${targetName}Step` to track individual targets with their own callbacks. For example, `onWidthStep()` is called on each update of the `width` target.
|
|
618
|
-
|
|
619
|
-
1. **onImperativeEnd**
|
|
620
|
-
Similar to `onImperativeStep`, but it is triggered when an imperative target completes. If multiple targets are expected to complete, you can use `on${targetName}End` instead. For example, `onWidthEnd` is called when the `width` target gets completed.
|
|
431
|
+
This callback is triggered when `value` emits a new value.
|
|
621
432
|
|
|
622
|
-
|
|
623
|
-
This is only a property. It defines the initial value of the actual value.
|
|
433
|
+
### Special Target Names
|
|
624
434
|
|
|
625
|
-
|
|
626
|
-
This is only a property. It indicates whether the target is ready for execution. When set to false, it behaves similarly to a `_` prefix. By default, all targets are active, so setting it to true is unnecessary.
|
|
627
|
-
|
|
628
|
-
1. **onSuccess**
|
|
629
|
-
An optional callback for targets that make API calls. It will be invoked for each API response received.
|
|
435
|
+
TargetJS maps directly to the DOM for zero-friction styling. For example:
|
|
630
436
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
## Target Variables
|
|
635
|
-
In all the target methods above, you can access the following variables:
|
|
636
|
-
|
|
637
|
-
1. **this.prevTargetValue**
|
|
638
|
-
It holds the value of the preceding target. If the preceding target involves API calls, a single $ postfix means it will hold one API result at a time, as the target is
|
|
639
|
-
activated with each API response. If the target is postfixed with $$, it will have the results as an array, ordered by the sequence of API calls rather than the order in
|
|
640
|
-
which the responses are received.
|
|
641
|
-
|
|
642
|
-
2. **this.isPrevTargetUpdated()**
|
|
643
|
-
It returns `true` if the previous target has been updated. This method is useful when a target is activated externally, such as by a user event, rather than by the preceding target.
|
|
644
|
-
|
|
645
|
-
3. **this.key**
|
|
646
|
-
Represents the name of the current target.
|
|
647
|
-
|
|
648
|
-
4. **this.value**
|
|
649
|
-
Represents the current value of the target.
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
## Special Target Names
|
|
653
|
-
|
|
654
|
-
All HTML style names and attributes are treated as special target names. The most commonly used style names and attributes have already been added to the framework, with the possibility of adding more in the future.
|
|
655
|
-
|
|
656
|
-
Examples:
|
|
657
|
-
- `width`, `height`: Set the dimensions of the object.
|
|
658
|
-
- `opacity`, `scale`, `rotate`: Adjust the opacity, scale, and rotation of the object.
|
|
659
|
-
- `zIndex`: Sets the z-order of the object.
|
|
660
|
-
|
|
661
|
-
In addition to styles and attribute names, we have the following special names:
|
|
662
|
-
|
|
663
|
-
1. **html**: Sets the content of the object, interpreted as text by default.
|
|
664
|
-
2. **children**: Adds new items to the parent each time it executes. Items can be either plain objects or instances of TModel for greater control.
|
|
665
|
-
3. **Child**: Similar to `children` but adds only one item.
|
|
666
|
-
4. **css**: A string that sets the CSS of the object.
|
|
667
|
-
5. **element**: Sets the HTML tag of the object, defaulting to `div`.
|
|
668
|
-
6. **shouldBeBracketed**: A boolean flag that, when set to true (the default), enables the creation of an optimization tree for a container with more items than the `bracketThreshold` (another target with a default value of 10). This optimization ensures only the visible branch receives updates and get executed.
|
|
669
|
-
7. **x** and **y**: Sets the location of the object.
|
|
670
|
-
8. **scrollLeft** and **scrollTop**: Control the scrolling position of the object.
|
|
671
|
-
9. **leftMargin**, **rightMargin**, **topMargin**, **bottomMargin**: Set margins between objects.
|
|
672
|
-
10. **domHolder**: When set to true, indicates that the current object serves as the DOM holder for all of its descendant objects. It can also return a DOM element, in which case the current object and all descendants will be contained within that DOM element.
|
|
673
|
-
11. **domParent**: Set by the container or children to control which DOM container they are embedded in.
|
|
674
|
-
12. **isVisible**: An optional target to explicitly control the visibility of the object, bypassing TargetJS’s automatic calculation.
|
|
675
|
-
13. **canHaveDom**: A boolean flag that determines if the object can have a DOM element on the page.
|
|
676
|
-
14. **canDeleteDom**: When set to true (the default), indicates that the object's DOM element will be removed when the object becomes invisible.
|
|
677
|
-
16. **widthFromDom** and **heightFromDom**: Boolean flags to explicilty control if the width and height should be derived from the DOM element.
|
|
678
|
-
17. **textOnly**: A boolean flag that specifies the content type as either text or HTML. The default value is false, indicating text.
|
|
679
|
-
18. **isInFlow**: A boolean flag that determines if the object will contribute to the content height and width of its parent.
|
|
680
|
-
19. **style**: An object to set the HTML style of the object, especially for style names that aren’t built-in.
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
Lastly, we have the event targets which their values can be an array of targets to activate on specific events or may implement the event handler directly.
|
|
684
|
-
|
|
685
|
-
**Example with Target Array:**
|
|
686
|
-
```javascript
|
|
687
|
-
onResize: [ 'width', 'height' ] // Activates declarative 'width' and 'height' targets on screen resize.
|
|
688
|
-
```
|
|
689
|
-
|
|
690
|
-
**Example with Event handler:**
|
|
691
|
-
```javascript
|
|
692
|
-
onResize() {
|
|
693
|
-
this.setTarget('width', getScreenWidth());
|
|
694
|
-
this.setTarget('height', getScreenHeight());
|
|
695
|
-
}
|
|
696
|
-
```
|
|
697
|
-
|
|
698
|
-
Here are all the event targets:
|
|
699
|
-
1. **onResize**: Triggered on screen resize events.
|
|
700
|
-
2. **onParentResize**: Activated when the parent’s width or height is updated.
|
|
701
|
-
3. **onFocus**: Triggered on focus events.
|
|
702
|
-
4. **onBlur**: Triggered on blur events.
|
|
703
|
-
5. **onClick**: Activated on click events.
|
|
704
|
-
6. **onTouchStart**: Called when `touchstart` or `mousedown` events occur.
|
|
705
|
-
7. **onTouch**: Generic handler for all touch events.
|
|
706
|
-
8. **onTouchEnd**: Called when `touchend` or `mouseup` events occur.
|
|
707
|
-
9. **onSwipe**: Activated on swipe events.
|
|
708
|
-
10. **onEnter**: Triggered when the mouse cursor enters the object’s DOM.
|
|
709
|
-
11. **onLeave**: Triggered when the mouse cursor leaves the object’s DOM.
|
|
710
|
-
12. **onScrollTop**: Called on top scroll events.
|
|
711
|
-
13. **onScrollLeft**: Called on left scroll events.
|
|
712
|
-
14. **onScroll**: Called on both scroll events.
|
|
713
|
-
15. **onWindowScroll**: Called on window scroll events.
|
|
714
|
-
16. **onKey**: Triggered by key events.
|
|
715
|
-
17. **onVisible**: Activated when the object becomes visible.
|
|
716
|
-
18. **onChildrenChange**: Triggered when the children count changes.
|
|
717
|
-
19. **onVisibleChildrenChange**: Triggered when the count of visible children changes.
|
|
718
|
-
20. **onDomEvent**: It accepts an array of targets and activates them when their associated object acquires a DOM element.
|
|
437
|
+
- **Styles**: `width`, `height`, `opacity`, `x`, `y`, `rotate`, `scale`, `backgroundColor`.
|
|
438
|
+
- **Structure**: `html`, `children`, `element`, `domHolder`.
|
|
439
|
+
- **Events**: `onClick`, `onScroll`, `onKey`, `onVisibleChildrenChange`, `onResize`.
|
|
719
440
|
|
|
720
441
|
## How to Debug in TargetJS
|
|
721
442
|
|
|
722
443
|
TargetJS provides built-in debugging tools:
|
|
723
444
|
|
|
724
|
-
```
|
|
445
|
+
```js
|
|
725
446
|
TargetJS.tApp.stop(); // Stop the application.
|
|
726
447
|
TargetJS.tApp.start(); // Restart the application
|
|
727
448
|
TargetJS.tApp.throttle = 0; // Slow down execution (milliseconds between cycles)
|