targetj 1.0.200 → 1.0.202

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 CHANGED
@@ -5,8 +5,8 @@
5
5
  [![Stars](https://img.shields.io/github/stars/livetrails/targetjs.svg)](https://github.com/livetrails/targetjs/stargazers)
6
6
  [![npm version](https://img.shields.io/npm/v/targetj.svg)](https://www.npmjs.com/package/targetj)
7
7
 
8
- TargetJS is a modern JavaScript UI framework that simplifies front-end development by introducing key concepts: unifying class methods and fields, autonomous and reactive methods, and execution flow that follows the written code. It provides a unified solution for key aspects like UI rendering, animations, APIs, state management, and event handling. This integrated approach leads to extreme compact code, introduces a new development paradigm, and prioritizes user experience. It can be used as a full-featured framework or as a lightweight library alongside other frameworks.
9
- Furthermore, it is also a highly performant web framework, as shown in the [framework benchmark](https://krausest.github.io/js-framework-benchmark/current.html).
8
+ TargetJS is a modern JavaScript UI framework that simplifies front-end development by introducing key concepts: unifying class methods and fields, autonomous and reactive methods, and execution flow that follows the written code. It provides a unified solution for key aspects like UI rendering, animations, APIs, state management, and event handling. This integrated approach leads to extreme compact code and an introduction of a new development paradigm.
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
10
 
11
11
  ## The Philosophy Behind TargetJS
12
12
 
@@ -14,9 +14,9 @@ Frameworks often promise simplicity, but frequently require extensive boilerplat
14
14
 
15
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
16
 
17
- The second challenge is making these targets to 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 snapping Lego pieces. It can address complex asynchronous workflow yet easy to understand.
17
+ The second challenge is making these targets to 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 yet easy to understand.
18
18
 
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 nodes, each with its own animation and API call. A subsequent target can then be set to run only after all nodes have completed their tasks. Throughout this sequence, no direct method calls are made. Targets simply react and chain together based on how the code is written.
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 elements have completed their tasks. Throughout this sequence, no direct method calls are made. Targets simply react and chain together based on how the code is written.
20
20
 
21
21
  Targets unlock a fundamentally new way of coding that simplifies everything from animation, UI updates, API calls, and state management. It also makes the code significantly more compact.
22
22
 
@@ -25,212 +25,306 @@ Targets unlock a fundamentally new way of coding that simplifies everything from
25
25
  1. Unifying Class Methods and Fields with Targets: A new construct called “targets” combines methods and fields, providing state, lifecycles, iteration, and timing mechanisms for both.
26
26
  2. Declarative Reactive Targets: Targets can explicitly declare reactive execution triggered by the run or completion of their immediately preceding targets, whether synchronous or asynchronous.
27
27
  3. All-in-One Solution: Offers a unified approach to UI rendering, API integration, state management, event handling, and animation.
28
- 4. Code-Ordered Execution: The execution flow generally follows the order in which the code is written.
29
- 5. Autonomous Methods: Methods in TargetJS are not directly callable. Instead, they are designed to execute themselves or react dynamically to the execution or completion of preedings "Targets." This paradigm shift enables a declarative programming style and inherently supports asynchronous operations without explicit async/await keywords.
28
+ 4. Code-Ordered Execution: Targets are chained top to bottom and the execution flow generally follows the order in which the code is written.
29
+ 5. Autonomous Methods: Methods in TargetJS are not directly callable. Instead, they are designed to execute themselves or react dynamically to the execution or completion of preedings targets. This enables declarative programming that inherently supports asynchronous operations without explicit plumbing like using async/await keywords.
30
30
  6. Compactness: TargetJS allows developers to achieve interactive UIs with significantly less code.
31
31
 
32
- ## Examples
33
32
 
34
- To demonstrate the power and simplicity of TargetJS, let's explore how it can manage asynchronous workflows. Our first asynchronous operation is a simple animation, then we expand it to demonstrate API integration, event handling, and dynamic UI updates.
33
+ ## Examples: From like button animated like + API (in 7 steps)
35
34
 
36
- ### Growing and Shrinking Box: Declarative Animation
35
+ ---
36
+
37
+ ## 1) Like button (view only)
38
+
39
+ **What this shows:** One object defines a UI element without separate HTML/CSS. Static targets map directly to DOM styles/attributes.
40
+
41
+ <img src="https://targetjs.io/img/likeButton.png" width="130" />
37
42
 
38
43
  ```javascript
39
- import { App } from 'targetj';
44
+ import { App } from "targetj";
40
45
 
41
46
  App({
42
- background: 'mediumpurple',
43
- width: [{ list: [100, 250, 100] }, 50, 10], // width animates through 100 → 250 → 100, over 50 steps with 10ms interval
44
- height$() { // `$` creates a reactive target: `height` executes each time `width` updates
45
- return this.prevTargetValue / 2;
46
- }
47
+ width: 220,
48
+ height: 60,
49
+ lineHeight: 60,
50
+ textAlign: "center",
51
+ borderRadius: 10,
52
+ background: "#f5f5f5",
53
+ html: "♡ Like"
47
54
  });
48
55
  ```
49
56
 
50
- ![first example](https://targetjs.io/img/git1.gif)
57
+ ---
51
58
 
52
- **Important Note**: As you can see, the entire UI and its behavior are defined directly within this single JavaScript file. There is no separate HTML or CSS. Targets named after HTML style properties or attributes will be mapped to the element’s styles and attributes.
53
59
 
54
- **Explanation**
60
+ ## 2) Animation
55
61
 
56
- Targets execute precisely in the order they are defined:
62
+ **What this shows:** A mount-time animation that scales and changes the background over 12 steps, with 12ms pauses between steps. Targets without (`$`, `$$`, `_`) execute immediately in the order they are defined.
57
63
 
58
- 1. `background`: This target runs first, setting the element's background color to `mediumpurple`. Once the assignment is complete, its lifecycle ends.
59
- 2. `width`: Next, the `width` target takes over. It's configured to animate through a list of values (100, 250, 100), performing 50 steps with a 10ms pause between each step, creating a grow-then-shrink effect.
60
- 3. `height$`: Finally, the `height$` target demonstrates TargetJS's reactivity. its name ends with a single `$` postfix, `height$` is explicitly declared to react whenever its immediately preceding target (`width`) executes on every step. As `width` animates and changes its value, `height$` automatically re-runs, setting its value to half of width's value.
64
+ <img src="https://targetjs.io/img/likeButton6.gif" width="130" />
61
65
 
62
- The example above can also be implemented directly in HTML, utilizing tg- attributes that mirror the object literal keys used in JavaScript:
63
-
64
- ```html
65
- <div
66
- tg-background="mediumpurple"
67
- tg-width="[{ list: [100, 250, 100] }, 50, 10]"
68
- tg-height$="return this.prevTargetValue / 2;">
69
- </div>
66
+ ```javascript
67
+ import { App } from "targetj";
68
+
69
+ App({
70
+ width: 220,
71
+ height: 60,
72
+ lineHeight: 60,
73
+ textAlign: "center",
74
+ borderRadius: 10,
75
+ html: "♡ Like",
76
+ scale: [ { list: [1.2, 1] }, 12, 12 ],
77
+ background: [ { list: ["#ffe8ec", "#f5f5f5"] }, 12, 12 ]
78
+ });
70
79
  ```
71
- Or a combination of JavaScript and HTML, linked together using the same HTML ID.
72
80
 
73
- Finally, here’s how the example looks in TypeScript:
81
+ ## 3) Click animation (imperative `setTarget`)
74
82
 
75
- ```TypeScript
76
- import { App, TModel } from 'targetj';
83
+ **What this shows:** Clicking plays the animations from the previous step using imperative `setTarget`.
77
84
 
78
- type TargetFunctionContext = TModel & {
79
- key: string;
80
- value: any;
81
- prevTargetValue: any;
82
- isPrevTargetUpdated: () => boolean;
83
- };
85
+ <img src="https://targetjs.io/img/likeButton4.gif" width="130" />
86
+
87
+ ```javascript
88
+ import { App } from "targetj";
84
89
 
85
90
  App({
86
- background: 'mediumpurple',
87
- width: [{ list: [100, 250, 100] }, 50, 10],
88
- height$(this: TargetFunctionContext): number {
89
- return this.prevTargetValue / 2;
90
- }
91
+ width: 220, height: 60, lineHeight: 60, textAlign: "center",
92
+ borderRadius: 10, background: "#f5f5f5",
93
+ cursor: "pointer", userSelect: "none",
94
+ html: "♡ Like",
95
+
96
+ onClick() {
97
+ this.setTarget("scale", { list: [1.2, 1] }, 12, 12);
98
+ this.setTarget("background", { list: ["#ffe8ec", "#f5f5f5"] }, 12, 12);
99
+ this.setTarget("html", "♥ Liked");
100
+ }
91
101
  });
92
102
  ```
93
103
 
94
- ### Adding an API Call
104
+ ---
95
105
 
96
- Let's extend our previous example to demonstrate how TargetJS handles asynchronous operations. We'll fetch user details from an API, but we also want this API call to initiate only after the box animation has fully completed.
106
+ ## 4) Sequencing with `$$`: Adding a small heart after click
107
+
108
+ **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.
109
+
110
+ <img src="https://targetjs.io/img/likeButton7.gif" width="130" />
97
111
 
98
112
  ```javascript
99
- import { App } from 'targetj';
113
+ import { App } from "targetj";
100
114
 
101
115
  App({
102
- background: 'mediumpurple',
103
- width: [{ list: [100, 250, 100] }, 50, 10],
104
- height$() { return this.prevTargetValue / 2; },
105
- fetch$$: 'https://targetjs.io/api/randomUser?id=user0', // `$$` ensures this runs only after width and height animation is complete
106
- html$() { // `$` ensures this runs when the API response is resolved
107
- return this.prevTargetValue.name; // `prevTargetValue` holds the result from the previous target (i.e., the API response)
116
+ width: 220, height: 60, lineHeight: 60, textAlign: "center",
117
+ borderRadius: 10, background: "#f5f5f5", cursor: "pointer", userSelect: "none",
118
+ html: "♡ Like",
119
+ onClick() {
120
+ this.setTarget("scale", { list: [1.2, 1] }, 12, 12);
121
+ this.setTarget("background", { list: ["#ffe8ec", "#f5f5f5"] }, 12, 12);
122
+ this.setTarget("html", "♥ Liked");
123
+ },
124
+ heart$$: {
125
+ html: "♥", color: "crimson", fontSize: 20,
126
+ fly() {
127
+ const cx = this.getCenterX(), cy = this.getCenterY();
128
+ this.setTarget({
129
+ opacity: { list: [0, 1, 1, 0.8, 0.1] },
130
+ scale: { list: [0.8, 1.4, 1.1, 0.9, 0.8] },
131
+ rotate: { list: [0, 12, -8, 6, 0] },
132
+ x: { list: [cx, cx + 22, cx - 16, cx + 10, cx] },
133
+ y: { list: [cy - 8, cy - 70, cy - 90, cy - 120, cy - 150] }
134
+ }, 20);
108
135
  }
136
+ }
109
137
  });
110
138
  ```
111
139
 
112
- ![second example](https://targetjs.io/img/git2.gif)
113
-
114
- **Explanation**
140
+ ---
115
141
 
116
- This example introduces two new targets:
142
+ ## 5) Another `$$`: big heart, different motion
117
143
 
118
- 1. `fetch$$`: `fetch` target is a specialized target designed to retrieve data when given a URL string. Since its name ends with a `$$` postfix, as previously discussed, this indicates that `fetch$$` will activate only after preceding targets fully completed all of its operations. This guarantees the API call is initiated just after the animation finishes.
144
+ **What this shows:** Deferred addition of a new element using $$. `bigHeart$$` waits for `heart$$` to complete its animation, then adds a larger heart and runs its own animation.
119
145
 
120
- 2. `html$`: Following `fetch$$`, the `html` target is responsible for setting the text content of the `div` element to the fetched user's name. The `$` postfix here signifies that `html$` is a reactive target that executes each time its immediately preceding target (`fetch$$`) provides a result. In this context, `this.prevTargetValue` will hold the resolved data from the API call, allowing `html$` to dynamically display the user's name as soon as it's available.
121
-
122
- Together, these targets orchestrate the flow: animation completes, then the API call happens, then the UI updates with the fetched data, all managed declaratively and in code order.
123
-
124
- ### Attaching a Click Handler
125
-
126
- Let's expand our box further by adding a click handler. The goal is to change the box's background color to orange when clicked, pause for two seconds, and then revert the background back to its original mediumpurple.
146
+ <img src="https://targetjs.io/img/likeButton8.gif" width="130" />
127
147
 
128
148
  ```javascript
129
- import { App } from 'targetj';
149
+ import { App } from "targetj";
130
150
 
131
151
  App({
132
- background: 'mediumpurple',
133
- width: [{ list: [100, 250, 100] }, 50, 10],
134
- height$() { return this.prevTargetValue / 2; },
135
- fetch$$: 'https://targetjs.io/api/randomUser?id=user0',
136
- html$() { return this.prevTargetValue.name; },
137
- onClick() { // Special target that runs when the element is clicked
138
- this.setTarget('background', 'orange', 30, 10); // Animates background to orange over 30 steps
139
- },
140
- pause$$: { interval: 2000 }, // `$$` ensures this runs only after the preceding 'onClick' animation is fully complete
141
- purpleAgain$$() { // `$$` ensures this runs only after `pause$$` completes (2-second interval)
142
- this.setTarget('background', 'mediumpurple', 30, 10); // Animates background back to mediumpurple
152
+ width: 220, height: 60, lineHeight: 60, textAlign: "center",
153
+ borderRadius: 10, background: "#f5f5f5", cursor: "pointer", userSelect: "none",
154
+ html: "♡ Like",
155
+
156
+ onClick() {
157
+ this.setTarget("scale", { list: [1.2, 1] }, 12, 12);
158
+ this.setTarget("background", { list: ["#ffe8ec", "#f5f5f5"] }, 12, 12);
159
+ this.setTarget("html", "♥ Liked");
160
+ },
161
+
162
+ heart$$: {
163
+ html: "♥", color: "crimson", fontSize: 20,
164
+ fly() {
165
+ const cx = this.getCenterX(), cy = this.getCenterY();
166
+ this.setTarget({
167
+ opacity: { list: [0, 1, 1, 0.8, 0.1] },
168
+ scale: { list: [0.8, 1.4, 1.1, 0.9, 0.8] },
169
+ rotate: { list: [0, 12, -8, 6, 0] },
170
+ x: { list: [cx, cx + 22, cx - 16, cx + 10, cx] },
171
+ y: { list: [cy - 8, cy - 70, cy - 90, cy - 120, cy - 150] }
172
+ }, 20);
173
+ }
174
+ },
175
+ bigHeart$$: {
176
+ html: "♥", color: "blue", fontSize: 100,
177
+ fly() {
178
+ const cx = this.getCenterX(), cy = this.getCenterY();
179
+ this.setTarget({
180
+ opacity: { list: [0, 1, 1, 0.85, 0.6, 0.1] },
181
+ scale: { list: [0.4, 1.9, 1.2, 1.6, 1.0, 0.95] },
182
+ rotate: { list: [0, 4, -3, 4, -2, 0] },
183
+ x: { list: [cx, cx + 14, cx + 10, cx - 6, cx - 14, cx] },
184
+ y: { list: [cy, cy - 30, cy - 55, cy - 80, cy - 100, cy - 130] }
185
+ }, 30);
143
186
  }
187
+ }
144
188
  });
145
189
  ```
146
190
 
147
- ![third example](https://targetjs.io/img/git3.gif)
148
-
149
- **Explanation:**
150
-
151
- 1. `onClick`: This is a special TargetJS function that automatically runs whenever the associated element is clicked. Inside, `this.setTarget('background', 'orange', 30, 10)` imperatively triggers a new animation, changing the background color to orange over 30 steps.
152
- 2. `pause$$`: Notice the `$$` postfix. This `pause$$` target is configured with an interval of 2000 milliseconds (2 seconds). Crucially, its `$$` postfix means it will only begin its 2-second pause after its immediately preceding target (onClick) has fully completed its animation of changing the background to orange.
153
- 3. `purpleAgain$$`: Also ending with `$$`, this target executes only after the `pause$$` target has finished its 2-second execution. It then uses this.setTarget again to animate the background color back to `mediumpurple`.
191
+ ---
154
192
 
155
- This sequence demonstrates how TargetJS allows you to define complex, timed flow with a guaranteeing execution order.
193
+ ## 6) `fetch$$`
156
194
 
157
- ### Let's Make it More Complicated :)
158
-
159
- Let’s expand the previous example by creating 10 boxes instead of just one. Each box will be added with a slight delay (100ms) and undergo its own task from the previous example. Once all these individual box processes (creation, animation, and API calls) are complete, we'll trigger a final collective action: changing all their backgrounds to green.
195
+ **What this shows:** Networking is just another target. The POST happens **only after** all prior visual steps complete, since the target is postfixed with `$$`.
160
196
 
161
197
  ```javascript
162
- import { App } from 'targetj';
163
-
164
198
  App({
165
- width: 500,
166
- children: { // A special target that adds a new list of childen each time it executes.
167
- cycles: 9, // Creates 10 children (from cycle 0 to 9)
168
- interval: 100, // Adds a new child every 100 milliseconds
169
- value(cycle) {
170
- return {
171
- baseWidth: 250,
172
- baseHeight: 125,
173
- background: 'mediumpurple',
174
- width: [{ list: [100, 250, 100] }, 50, 10],
175
- height$() { return this.prevTargetValue / 2; },
176
- fetch$$: `https://targetjs.io/api/randomUser?id=user${cycle}`,
177
- html$() { return this.prevTargetValue.name; },
178
- onClick() { this.setTarget('background', 'orange', 30, 10); },
179
- pause$$: { interval: 2000 },
180
- purpleAgain$$() { this.setTarget('background', 'mediumpurple', 30, 10); }
181
- };
182
- }
183
- },
184
- greenify$$() { // `$$` ensures this runs only after all children have completed all their tasks
185
- this.getChildren().forEach(child => child.setTarget("background", "green", 30, 10)); // Iterates and animates each child's background
186
- }
199
+ // …same as step 5…
200
+
201
+ fetch$$: { method: "POST", id: 123, url: "/api/like" }
187
202
  });
188
203
  ```
189
204
 
190
- ![first example](https://targetjs.io/img/git4_1.gif)
205
+ ---
191
206
 
192
- **Explanation:**
207
+ ## 7) Final version
193
208
 
194
- This advanced example demonstrates TargetJS's capability to manage complex, dynamic UI scenarios:
209
+ **What this shows:** A Like button that consolidates the previous steps into a single component. After the POST completes, a cleanup `removeHearts$$` target runs to remove the two heart elements. The button also includes basic accessibility (role, tabIndex, and Enter to activate).
195
210
 
196
- 1. `children`: A special target construct used to create a collection of child objects. Each time it executes, a new list objects is added to the parent. The `cycles` property specifies that the value function will run 10 times (from `cycle` 0 to 9), thus creating 10 individual box objects.
197
- The `interval` property ensures that each new box is created and added to the UI every 100 milliseconds.
198
- The `value(cycle)` function return the same object element from the previous example.
211
+ <img src="https://targetjs.io/img/likeButton9.gif" width="130" />
199
212
 
200
- 2. `greenify$$`: This target demonstrates the `$$` postfix's full completion reactivity at a higher level. The `greenify$$` target will execute only after the entire children target has comprehensively completed all of its work. This includes:
213
+ ```javascript
214
+ import { App } from "targetj";
201
215
 
202
- - The creation of all 10 child boxes.
203
- - The completion of each individual child's width animation.
204
- - The successful return of all 10 API calls (`fetch`) for each child.
205
- - The population of all user names (`html`) for each child.
216
+ App({
217
+ likeButton: {
218
+ width: 220, height: 60, lineHeight: 60, textAlign: "center",
219
+ borderRadius: 10, background: "#f5f5f5", cursor: "pointer", userSelect: "none",
220
+ role: "button", tabIndex: 0,
221
+ html: "♡ Like",
222
+ onClick() {
223
+ this.setTarget("scale", { list: [1.2, 1] }, 12, 12);
224
+ this.setTarget("background", { list: ["#ffe8ec", "#f5f5f5"] }, 12, 12);
225
+ this.setTarget("html", "♥ Liked");
226
+ },
227
+
228
+ heart$$: {
229
+ html: "♥", color: "crimson", fontSize: 20,
230
+ fly() {
231
+ const cx = this.getCenterX(), cy = this.getCenterY();
232
+ this.setTarget({
233
+ opacity: { list: [0, 1, 1, 0.8, 0.1] },
234
+ scale: { list: [0.8, 1.4, 1.1, 0.9, 0.8] },
235
+ rotate: { list: [0, 12, -8, 6, 0] },
236
+ x: { list: [cx, cx + 22, cx - 16, cx + 10, cx] },
237
+ y: { list: [cy - 8, cy - 70, cy - 90, cy - 120, cy - 150] }
238
+ }, 20);
239
+ }
240
+ },
241
+
242
+ bigHeart$$: {
243
+ html: "♥", color: "blue", fontSize: 100,
244
+ fly() {
245
+ const cx = this.getCenterX(), cy = this.getCenterY();
246
+ this.setTarget({
247
+ opacity: { list: [0, 1, 1, 0.85, 0.6, 0.1] },
248
+ scale: { list: [0.4, 1.9, 1.2, 1.6, 1.0, 0.95] },
249
+ rotate: { list: [0, 4, -3, 4, -2, 0] },
250
+ x: { list: [cx, cx + 14, cx + 10, cx - 6, cx - 14, cx] },
251
+ y: { list: [cy, cy - 30, cy - 55, cy - 80, cy - 100, cy - 130] }
252
+ }, 30);
253
+ }
254
+ },
255
+ fetch$$: { method: "POST", id: 123, url: "/api/like" },
256
+ removeHearts$$() { this.removeAll(); },
257
+ onKey(e) { if (e.key === "Enter") this.activateTarget("onClick"); }
258
+ }
259
+ });
260
+ ```
206
261
 
207
- Only when all tasks initiated by children are finished will `greenify$$` runs. It then uses `this.getChildren().forEach(child => child.setTarget("background", "green", 30, 10))` to iterate over all the created child boxes and animate their backgrounds to green.
262
+ Or in HTML (no JavaScript required), using tg- attributes that mirror object literal keys:
208
263
 
264
+ ```html
265
+ <div
266
+ id="likeButton"
267
+ tg-width="220"
268
+ tg-height="60"
269
+ tg-lineHeight="60"
270
+ tg-textAlign="center"
271
+ tg-borderRadius="10"
272
+ tg-background="#f5f5f5"
273
+ tg-cursor="pointer"
274
+ tg-userSelect="none"
275
+ tg-role="button"
276
+ tg-html="♡ Like"
277
+ tg-tabIndex="0"
278
+ tg-onClick="function() {
279
+ this.setTarget('scale', { list: [1.2, 1] }, 12, 12);
280
+ this.setTarget('background', { list: ['#ffe8ec', '#f5f5f5'] }, 12, 12);
281
+ this.setTarget('html', '♥ Liked');
282
+ }"
283
+ tg-heart$$="{
284
+ html: '♥',
285
+ color: 'crimson',
286
+ fontSize: 20,
287
+ fly() {
288
+ const cx = this.getCenterX(), cy = this.getCenterY();
289
+ this.setTarget({
290
+ opacity: { list: [0, 1, 1, 0.8, 0.1] },
291
+ scale: { list: [0.8, 1.4, 1.1, 0.9, 0.8] },
292
+ rotate: { list: [0, 12, -8, 6, 0] },
293
+ x: { list: [cx, cx + 22, cx - 16, cx + 10, cx] },
294
+ y: { list: [cy - 8, cy - 70, cy - 90, cy - 120, cy - 150] }
295
+ }, 20);
296
+ }
297
+ }"
298
+ tg-bigHeart$$="{
299
+ html: '♥',
300
+ color: 'blue',
301
+ fontSize: 100,
302
+ fly() {
303
+ const cx = this.getCenterX(), cy = this.getCenterY();
304
+ this.setTarget({
305
+ opacity: { list: [0, 1, 1, 0.85, 0.6, 0.1] },
306
+ scale: { list: [0.4, 1.9, 1.2, 1.6, 1.0, 0.95] },
307
+ rotate: { list: [0, 4, -3, 4, -2, 0] },
308
+ x: { list: [cx, cx + 14, cx + 10, cx - 6, cx - 14, cx] },
309
+ y: { list: [cy, cy - 30, cy - 55, cy - 80, cy - 100, cy - 130] }
310
+ }, 30);
311
+ }
312
+ }"
313
+ tg-fetch$$='{"method":"POST","id":123,"url":"/api/like"}'
314
+ tg-removeHearts$$="function() { this.removeAll(); }"
315
+ tg-onKey="function(e) { if (e.key === 'Enter') this.activateTarget('onClick'); }"
316
+ /></div>
317
+ ```
209
318
 
210
- The example above can also be implemented directly in HTML:
211
-
212
- ```html
319
+ ---
213
320
 
214
- <div
215
- tg-width="500"
216
- tg-children="{ cycles: 9, interval: 100 }"
217
- tg-greenify$$="function() { this.getChildren().forEach(child => child.setTarget('background', 'green', 30, 10)); }"
218
- >
219
- <div
220
- tg-baseWidth="250"
221
- tg-baseHeight="125"
222
- tg-background="mediumpurple"
223
- tg-width="[{ list: [100, 250, 100] }, 50, 10]"
224
- tg-height$="function() { return this.prevTargetValue / 2; }"
225
- tg-fetch$$="function(index) { return `https://targetjs.io/api/randomUser?id=user${index}`; }"
226
- tg-html$="function() { return this.prevTargetValue.name; }"
227
- tg-onClick="function() { this.setTarget('background', 'orange', 30, 10); }"
228
- tg-pause$$="{ interval: 2000 }"
229
- tg-purpleagain$$="function() { this.setTarget('background', 'mediumpurple', 30, 10); }">
230
- </div>
231
- </div>
232
- ```
321
+ ## Final takeaway
233
322
 
323
+ - TargetJS treats time as a first-class concept. Instead of wiring callbacks and effects, you write a sequence of targets.
324
+ $ reacts to the previous step; $$ defers until all prior steps finish. Animations, API calls, and child creation are all the same kind of thing: targets.
325
+ So complex flows read top-to-bottom.
326
+ - Minimal plumbing yet full control to manage a flow of complex asynchronous operations.
327
+
234
328
  ## Table of Contents
235
329
 
236
330
  1. [Targets: The Building Blocks of TargetJS](#targets-the-building-blocks-of-targetjs)
@@ -326,53 +420,75 @@ TargetJS addresses several common pain points in front-end development:
326
420
 
327
421
  ## More Examples
328
422
 
329
- ## Loading Two Users Example
423
+ ## Loading Five Users Example
330
424
 
331
- In this example, we load two separate users and display two purple boxes, each containing a user's name, based on our first example.
425
+ In this example, we load five separate users and display five boxes, each containing a user's name and email.
332
426
 
333
- - `fetch` calls two APIs to retrieve details for two users.
334
- - `children` is a special target that adds new items to the parent each time it executes. Because it ends with `$` in this example, it executes every time an API call returns a result.
335
- - TargetJS ensures that API results are processed in the same sequence as the API calls. For example, if the user1 API result arrives before user0, `children` will not execute until the result for user0 has been received.
336
-
337
- ![first example](https://targetjs.io/img/quick3_1.gif)
427
+ - `fetch` calls five APIs to retrieve details for five users.
428
+ - `child` is a special target that adds a new item to the parent each time it executes. Because it ends with `$` in this example, it executes every time an API call returns a result.
429
+ - TargetJS ensures that API results are processed in the same sequence as the API calls. For example, if the user1 API result arrives before user0, `child` will not execute until the result for user0 has been received.
430
+
431
+ <img src="https://targetjs.io/img/fetch-5-users.gif" width="130" />
338
432
 
339
433
  ```javascript
340
- import { App, fetch } from "targetj";
434
+ import { App } from "targetj";
341
435
 
342
436
  App({
437
+ gap: 10,
343
438
  fetch: ['https://targetjs.io/api/randomUser?id=user0',
344
- 'https://targetjs.io/api/randomUser?id=user1'],
345
- children$() {
346
- return {
347
- background: "mediumpurple",
348
- html: this.prevTargetValue.name,
349
- width: [{ list: [100, 250, 100] }, 50, 10],
350
- height$() { return this.prevTargetValue / 2; },
351
- };
439
+ 'https://targetjs.io/api/randomUser?id=user1',
440
+ 'https://targetjs.io/api/randomUser?id=user2',
441
+ 'https://targetjs.io/api/randomUser?id=user3',
442
+ 'https://targetjs.io/api/randomUser?id=user4'
443
+ ],
444
+ child$() {
445
+ const user = this.prevTargetValue;
446
+ return {
447
+ width: 200,
448
+ height: 65,
449
+ borderRadius: 10,
450
+ boxSizing: "border-box",
451
+ padding: 10,
452
+ fontSize: 14,
453
+ background: "#f0f0f0",
454
+ scale: [{ list: [0.8, 1] }, 14, 12],
455
+ html$() {
456
+ return `<div style="font-weight:600">${user.name}</div>
457
+ <div style="opacity:.65">${user.email}</div>`;
458
+ },
459
+ };
460
+ }
461
+ });
462
+ ```
463
+
464
+ It can also be written using a target’s `cycles` and `intervals` properties/methods to fetch users at intervals instead of in a single batch. In this example, we set interval to 1000, making the API call once every second.
465
+
466
+ <img src="https://targetjs.io/img/fetch-5-users2.gif" width="130" />
467
+
468
+
469
+ ```javascript
470
+ App({
471
+ gap: 10,
472
+ fetch: {
473
+ interval: 1000,
474
+ cycles: 4,
475
+ value(i) { return `https://targetjs.io/api/randomUser?id=user${i}`; }
476
+ },
477
+ child$() {
478
+ return {
479
+ // …same as the previous example…
480
+ };
352
481
  }
353
482
  });
354
483
  ```
355
- Or in HTML:
356
-
357
- ```html
358
- <div tg-fetch="['https://targetjs.io/api/randomUser?id=user0', 'https://targetjs.io/api/randomUser?id=user1']">
359
- <div
360
- tg-background="mediumpurple"
361
- tg-html="function(index) { return this.getParentValue('fetch')[index].name; }"
362
- tg-width="[{ list: [100, 250, 100] }, 50, 10]"
363
- tg-height$="return this.prevTargetValue / 2;"
364
- >
365
- </div>
366
- </div>
367
- ```
368
484
 
369
485
  ### Infinite Loading and Scrolling Example
370
486
 
371
487
  In this advanced example, we demonstrate an infinite scrolling application where each item is animated, and upon completing its animation, it dynamically triggers an API call to fetch and display its details.
372
488
 
373
- - children: `children` is a special target that adds items to the container's children each time it is executed. The `onVisibleChildrenChange` event function detects changes in the visible children and activates the `children` target to add new items that fill the gaps.
489
+ - children: `children` is a special target that adds several items to the container's children each time it is executed. The `onVisibleChildrenChange` event function detects changes in the visible children and activates the `children` target to add new items that fill the gaps.
374
490
 
375
- loadItems: Since the target name ends with `$$`, it executes only after the newly created children finish their animations. It then iterates over all visible children and fetches their details. The result is an array of users. TargetJS ensures that this array preserves the order in which the API calls were made, not the order in which responses were received.
491
+ - loadItems: Since the target name ends with `$$`, it executes only after the newly created children finish their animations. It then iterates over all visible children and fetches their details. The result is an array of users. TargetJS ensures that this array preserves the order in which the API calls were made, not the order in which responses were received.
376
492
 
377
493
  - populate: Since the target name ends with `$$`, it executes only after all API calls have completed. It updates the content of each scrollable item with the name returned by the API.
378
494
 
@@ -380,7 +496,7 @@ TargetJS employs a tree-like structure to track visible branches, optimizing the
380
496
 
381
497
  We use the TModel class instead of a plain object to demonstrate how it can provide additional functionality and control. A plain object would also have worked in this example.
382
498
 
383
- ![Single page app](https://targetjs.io/img/infiniteScrolling11.gif)
499
+ <img src="https://targetjs.io/img/infiniteScrolling.gif" width="130" />
384
500
 
385
501
  ```javascript
386
502
  import { App, TModel, getEvents, fetch, getScreenWidth, getScreenHeight } from "targetj";
@@ -581,7 +697,7 @@ In addition to styles and attribute names, we have the following special names:
581
697
  1. **html**: Sets the content of the object, interpreted as text by default.
582
698
  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.
583
699
  4. **css**: A string that sets the CSS of the object.
584
- 5. **baseElement**: Sets the HTML tag of the object, defaulting to `div`.
700
+ 5. **element**: Sets the HTML tag of the object, defaulting to `div`.
585
701
  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.
586
702
  7. **x** and **y**: Sets the location of the object.
587
703
  8. **scrollLeft** and **scrollTop**: Control the scrolling position of the object.
@@ -344,7 +344,7 @@ var BaseModel = exports.BaseModel = /*#__PURE__*/function () {
344
344
  var nextKey = keyIndex < this.originalTargetNames.length - 1 ? this.originalTargetNames[keyIndex + 1] : undefined;
345
345
  doesNextTargetUsePrevValue = nextKey && nextKey.endsWith('$') ? true : false;
346
346
  if (doesNextTargetUsePrevValue || isInactiveKey || isExternalEvent || isInternalEvent || targetType === 'object' || targetType === 'function') {
347
- if (!target.value && !_TargetParser.TargetParser.isChildObjectTarget(key, target) && !_TargetParser.TargetParser.isIntervalTarget(target)) {
347
+ if (!_TUtil.TUtil.isDefined(target.value) && !_TargetParser.TargetParser.isChildObjectTarget(key, target) && !_TargetParser.TargetParser.isIntervalTarget(target)) {
348
348
  needsTargetExecution = true;
349
349
  target = _TargetUtil.TargetUtil.wrapTarget(this, target, key);
350
350
  }
@@ -196,13 +196,15 @@ var TargetExecutor = exports.TargetExecutor = /*#__PURE__*/function () {
196
196
  var targetValue = tmodel.targetValues[key] || _TargetUtil.TargetUtil.emptyValue();
197
197
  tmodel.targetValues[key] = targetValue;
198
198
  var easing = _TUtil.TUtil.isDefined(tmodel.targets[key].easing) ? tmodel.targets[key].easing : undefined;
199
- if (_TargetParser.TargetParser.isChildrenTarget(key, newValue)) {
199
+ if (_TargetParser.TargetParser.isChildTarget(key, newValue)) {
200
+ tmodel.addChild(newValue);
201
+ TargetExecutor.assignSingleTarget(targetValue, newValue, undefined, 0, newCycles, newInterval);
202
+ } else if (_TargetParser.TargetParser.isChildrenTarget(key, newValue)) {
200
203
  var values = Array.isArray(newValue) ? newValue : newValue ? [newValue] : [];
201
- var tmodelChildren = values.map(function (child) {
204
+ values.forEach(function (child) {
202
205
  tmodel.addChild(child);
203
- return tmodel.addedChildren.at(-1).child;
204
206
  });
205
- TargetExecutor.assignSingleTarget(targetValue, Array.isArray(newValue) ? tmodelChildren : tmodelChildren[0], undefined, 0, newCycles, newInterval);
207
+ TargetExecutor.assignSingleTarget(targetValue, newValue, undefined, 0, newCycles, newInterval);
206
208
  } else if (_TargetParser.TargetParser.isChildObjectTarget(key, tmodel.targets[key])) {
207
209
  var child = new _TModel.TModel(key, tmodel.targets[key]);
208
210
  tmodel.addChild(child);
@@ -212,7 +214,7 @@ var TargetExecutor = exports.TargetExecutor = /*#__PURE__*/function () {
212
214
  return !_TargetData.TargetData.excludedTargetKeys.has(k);
213
215
  }));
214
216
  TargetExecutor.assignSingleTarget(targetValue, filteredValue, undefined, 0, newCycles, newInterval);
215
- } else if (_typeof(newValue) === 'object' && newValue.mount === 'child') {
217
+ } else if (_typeof(newValue) === 'object' && newValue.asChild === true) {
216
218
  var _child = new _TModel.TModel(key, newValue);
217
219
  tmodel.addChild(_child);
218
220
  TargetExecutor.assignSingleTarget(targetValue, newValue, undefined, 0, newCycles, newInterval);