targetj 1.0.225 → 1.0.226
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 +77 -48
- package/build/LoadingManager.js +9 -14
- package/build/TModel.js +6 -0
- package/build/TModelManager.js +1 -1
- package/build/TUtil.js +5 -0
- package/build/TargetUtil.js +3 -0
- package/dist/targetjs.js +1 -1
- package/dist/targetjs.js.gz +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# TargetJS: UI
|
|
1
|
+
# TargetJS: State as Destination, UI as Sequence
|
|
2
2
|
|
|
3
3
|
**[targetjs.io](https://targetjs.io)**
|
|
4
4
|
[](https://github.com/livetrails/targetjs/blob/main/LICENSE)
|
|
@@ -10,19 +10,31 @@ TargetJS is a high-performance JavaScript UI framework with ultra-compact syntax
|
|
|
10
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).
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## What problems TargetJS solves
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
**UI frameworks model the final result, not transition**
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Traditional frameworks model the UI as a function of state: change state, re-render the UI. When state changes from A → B, the UI immediately jumps to B. The framework doesn’t naturally represent the journey from A → B. But modern, rich user experiences are more like: A → transition → B.
|
|
18
18
|
|
|
19
|
-
TargetJS
|
|
19
|
+
TargetJS treats state as a destination. Values are not only assigned. They can be approached over time through configurable steps. This makes transitions a native part of state change rather than an afterthought. TargetJS also delivers CSS-level transition efficiency.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
**Fragmentation across multiple mental models**
|
|
22
22
|
|
|
23
|
-
In
|
|
23
|
+
In many applications, state, animation, events, loading, timing, and callbacks are all handled through separate concepts or APIs. This creates glue code and a mental split between them.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
TargetJS unifies them under one concept and one model. Methods and fields are unified and both become reactive units with their own state, lifecycle, timing, execution conditions, looping, and callbacks. This shifts fields from passive values to active participants, reducing boilerplate and keeping application logic consolidated.
|
|
26
|
+
|
|
27
|
+
**UI sequences are difficult to trace in code**
|
|
28
|
+
|
|
29
|
+
UIs often follow sequences like this:
|
|
30
|
+
|
|
31
|
+
Click → animate button → fetch data → render results → animate items → highlight one item
|
|
32
|
+
|
|
33
|
+
In traditional code, that sequence is often scattered across different places such as event handlers, effects, promises, and callbacks.
|
|
34
|
+
|
|
35
|
+
TargetJS code order and target reactivity allow the implementation to more closely mirror the actual UI sequence.
|
|
36
|
+
|
|
37
|
+
With its compact style, TargetJS makes the journey from A → B efficient and explicit, with significantly less code than traditional frameworks.
|
|
26
38
|
|
|
27
39
|
## ⚡ Quick Start (30 Seconds)
|
|
28
40
|
|
|
@@ -48,17 +60,39 @@ App({
|
|
|
48
60
|
}).mount("#app");
|
|
49
61
|
```
|
|
50
62
|
|
|
51
|
-
##
|
|
63
|
+
## Targets
|
|
64
|
+
|
|
65
|
+
In TargetJS, targets are the fundamental unit of behavior.
|
|
66
|
+
Methods, properties, and objects are internally transformed into targets that the framework schedules and executes.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
### Execution Syntax
|
|
52
70
|
|
|
53
|
-
|
|
71
|
+
Target names can include special symbols that determine **when they execute**.
|
|
54
72
|
|
|
55
|
-
| Symbol
|
|
56
|
-
|
|
57
|
-
| `name`
|
|
58
|
-
| `name$`
|
|
59
|
-
| `name$$` | Deferred | Runs only after the entire preceding target chain including children, animations, and API calls
|
|
60
|
-
| `_name`
|
|
61
|
-
|
|
73
|
+
| Symbol | Name | Behavior |
|
|
74
|
+
|------|------|------|
|
|
75
|
+
| `name` | Standard | Runs immediately in the order it appears. |
|
|
76
|
+
| `name$` | Reactive | Runs every time the previous sibling target runs. |
|
|
77
|
+
| `name$$` | Deferred | Runs only after the entire preceding target chain (including children, animations, and API calls) completes. |
|
|
78
|
+
| `_name` | Inactive | Does not run automatically. Trigger it manually via `.activateTarget()`. |
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
### Target Controls
|
|
82
|
+
|
|
83
|
+
A target can also be defined as an object with optional controls that manage its lifecycle and execution.
|
|
84
|
+
|
|
85
|
+
| Property | Description |
|
|
86
|
+
|------|------|
|
|
87
|
+
| `value` | The data or function that determines the target's state. |
|
|
88
|
+
| `steps` | Turns a value change into an animation. |
|
|
89
|
+
| `interval` | Delay (ms) between steps or executions. |
|
|
90
|
+
| `cycles` | Number of times the target repeats. |
|
|
91
|
+
| `loop` | Boolean form of repetition for continuous execution. |
|
|
92
|
+
| `enabledOn` | Determines whether the target is enabled for execution. |
|
|
93
|
+
| `easing` | Predefined easing function controlling how values update over steps. |
|
|
94
|
+
| `onComplete` | Callback triggered when this target (and its children) finishes. |
|
|
95
|
+
| `onValueChange` | Callback triggered when the target emits a new value. |
|
|
62
96
|
|
|
63
97
|
## Examples: Like Button → Animated Like (in 3 Steps)
|
|
64
98
|
|
|
@@ -112,7 +146,7 @@ App({
|
|
|
112
146
|
this.setTarget('backgroundColor', { value: [ '#ffe8ec', '#f5f5f5' ], steps: 12, interval: 12 });
|
|
113
147
|
},
|
|
114
148
|
heart$$: { // Wait for the button animation to finish, THEN add and animate the heart.
|
|
115
|
-
html: "♥", color: "crimson", fontSize: 20
|
|
149
|
+
html: "♥", color: "crimson", fontSize: 20,
|
|
116
150
|
fly() {
|
|
117
151
|
const cx = (this.parent.getWidth() - this.getWidth()) / 2;
|
|
118
152
|
this.setTarget('x', { value: [cx, cx + 22, cx - 16, cx + 10, cx ], steps: 50, cycles: 2 }); // Repeat it twice
|
|
@@ -172,7 +206,6 @@ Each target has its own state and lifecycle. Targets execute automatically in th
|
|
|
172
206
|
1. Deeper Examples:
|
|
173
207
|
- [Loading Five Users Example](#loading-five-users-example)
|
|
174
208
|
- [Infinite Loading and Scrolling Example](#infinite-loading-and-scrolling-example)
|
|
175
|
-
1. [Target Methods](#target-methods)
|
|
176
209
|
1. [Special Target Names](#special-target-names)
|
|
177
210
|
1. [How to Debug in TargetJS](#how-to-debug-in-targetjs)
|
|
178
211
|
1. [Documentation](#documentation)
|
|
@@ -421,46 +454,42 @@ App({
|
|
|
421
454
|
```
|
|
422
455
|
---
|
|
423
456
|
|
|
424
|
-
##
|
|
425
|
-
|
|
426
|
-
### Target Methods
|
|
427
|
-
|
|
428
|
-
Every target can be an object with these optional controls:
|
|
429
|
-
|
|
430
|
-
1. **value**
|
|
431
|
-
The data or function that determines the target's state.
|
|
457
|
+
## Special Target Names
|
|
432
458
|
|
|
433
|
-
|
|
434
|
-
|
|
459
|
+
Some target names have built-in meaning and interact directly with the DOM, layout system, or browser events.
|
|
460
|
+
Because these behaviors are expressed as targets, they still participate in the same execution system and dependency flows as any other target.
|
|
435
461
|
|
|
436
|
-
|
|
437
|
-
The delay (ms) between steps or executions.
|
|
462
|
+
**Styles**
|
|
438
463
|
|
|
439
|
-
|
|
440
|
-
How many times to repeat the target.
|
|
464
|
+
These targets update CSS properties and transforms:
|
|
441
465
|
|
|
442
|
-
|
|
443
|
-
|
|
466
|
+
- `width`, `height`
|
|
467
|
+
- `opacity`
|
|
468
|
+
- `x`, `y`, `z`
|
|
469
|
+
- `rotate`, `rotateX`, `rotateY`, `rotateZ`
|
|
470
|
+
- `scale`
|
|
471
|
+
- `backgroundColor`, `color`
|
|
444
472
|
|
|
445
|
-
|
|
446
|
-
Determines whether the target is enabled for execution.
|
|
473
|
+
These can be animated simply by adding `steps`.
|
|
447
474
|
|
|
448
|
-
|
|
449
|
-
Managed the repetition of target execution. Similar to `cycles` but uses boolean instead.
|
|
475
|
+
**Structure**
|
|
450
476
|
|
|
451
|
-
|
|
452
|
-
A string that defines a predefined easing function that controls how the actual value is updated in relation to the steps.
|
|
477
|
+
These targets define the structure of the interface:
|
|
453
478
|
|
|
454
|
-
|
|
455
|
-
|
|
479
|
+
- `children` or `addChildren` – adds new children each time the target executes
|
|
480
|
+
- `html` – inner HTML content, often simple text
|
|
481
|
+
- `element` – specify the DOM element type (e.g., `div`, `canvas`)
|
|
456
482
|
|
|
457
|
-
|
|
483
|
+
**Events**
|
|
458
484
|
|
|
459
|
-
|
|
485
|
+
These targets respond to browser events:
|
|
460
486
|
|
|
461
|
-
-
|
|
462
|
-
-
|
|
463
|
-
-
|
|
487
|
+
- `onClick`
|
|
488
|
+
- `onScroll`
|
|
489
|
+
- `onKey`
|
|
490
|
+
- `onResize`
|
|
491
|
+
- `onEnter` / `onLeave`
|
|
492
|
+
- `onVisibleChildrenChange`
|
|
464
493
|
|
|
465
494
|
## How to Debug in TargetJS
|
|
466
495
|
|
package/build/LoadingManager.js
CHANGED
|
@@ -124,16 +124,11 @@ var LoadingManager = exports.LoadingManager = /*#__PURE__*/function () {
|
|
|
124
124
|
value: function getTModelKey(tmodel, targetName) {
|
|
125
125
|
return "".concat(document.URL, "_").concat(tmodel.oid, "_").concat(targetName);
|
|
126
126
|
}
|
|
127
|
-
}, {
|
|
128
|
-
key: "getLoadTargetName",
|
|
129
|
-
value: function getLoadTargetName(targetName) {
|
|
130
|
-
return "load-".concat(targetName);
|
|
131
|
-
}
|
|
132
127
|
}, {
|
|
133
128
|
key: "addToTModelKeyMap",
|
|
134
129
|
value: function addToTModelKeyMap(tmodel, targetName, fetchId, cacheId) {
|
|
135
130
|
var key = this.getTModelKey(tmodel, targetName);
|
|
136
|
-
var loadTargetName =
|
|
131
|
+
var loadTargetName = _TUtil.TUtil.getLoadTargetName(targetName);
|
|
137
132
|
var loadingComplete = this.isLoadingComplete(tmodel, targetName);
|
|
138
133
|
if (loadingComplete || !this.tmodelKeyMap[key]) {
|
|
139
134
|
var _this$tmodelKeyMap, _this$tmodelKeyMap$ke;
|
|
@@ -215,7 +210,7 @@ var LoadingManager = exports.LoadingManager = /*#__PURE__*/function () {
|
|
|
215
210
|
if (!modelEntry) {
|
|
216
211
|
return false;
|
|
217
212
|
}
|
|
218
|
-
var loadTargetName =
|
|
213
|
+
var loadTargetName = _TUtil.TUtil.getLoadTargetName(targetName);
|
|
219
214
|
var targetValue = tmodel.val(loadTargetName);
|
|
220
215
|
return Array.isArray(targetValue) && _TUtil.TUtil.isDefined(targetValue[modelEntry.activeIndex]);
|
|
221
216
|
}
|
|
@@ -227,7 +222,7 @@ var LoadingManager = exports.LoadingManager = /*#__PURE__*/function () {
|
|
|
227
222
|
if (!tmodelEntry || tmodelEntry.accessIndex >= tmodelEntry.resultCount) {
|
|
228
223
|
return undefined;
|
|
229
224
|
}
|
|
230
|
-
var loadTargetName =
|
|
225
|
+
var loadTargetName = _TUtil.TUtil.getLoadTargetName(prevTargetName);
|
|
231
226
|
var targetValue = tmodel.val(loadTargetName);
|
|
232
227
|
var result;
|
|
233
228
|
if (targetValue) {
|
|
@@ -290,7 +285,7 @@ var LoadingManager = exports.LoadingManager = /*#__PURE__*/function () {
|
|
|
290
285
|
targetName = _ref.targetName;
|
|
291
286
|
var key = _this4.getTModelKey(tmodel, targetName);
|
|
292
287
|
var tmodelEntry = _this4.tmodelKeyMap[key];
|
|
293
|
-
var loadTargetName =
|
|
288
|
+
var loadTargetName = _TUtil.TUtil.getLoadTargetName(targetName);
|
|
294
289
|
if (!tmodelEntry || !tmodelEntry.fetchMap[fetchId]) {
|
|
295
290
|
return;
|
|
296
291
|
}
|
|
@@ -300,12 +295,12 @@ var LoadingManager = exports.LoadingManager = /*#__PURE__*/function () {
|
|
|
300
295
|
}));
|
|
301
296
|
var targetResults = tmodel.val(loadTargetName);
|
|
302
297
|
if (targetResults) {
|
|
303
|
-
if (!targetResults[fetchEntry.order]) {
|
|
298
|
+
if (!_TUtil.TUtil.isDefined(targetResults[fetchEntry.order])) {
|
|
304
299
|
tmodelEntry.resultCount++;
|
|
305
300
|
}
|
|
306
301
|
targetResults[fetchEntry.order] = res.result;
|
|
307
302
|
}
|
|
308
|
-
tmodel.val(targetName,
|
|
303
|
+
tmodel.val(targetName, res.result);
|
|
309
304
|
var newStatus = _this4.calculateTargetStatus(tmodel, targetName);
|
|
310
305
|
tmodel.setTargetStatus(targetName, newStatus);
|
|
311
306
|
tmodel.setLastUpdate(targetName);
|
|
@@ -332,7 +327,7 @@ var LoadingManager = exports.LoadingManager = /*#__PURE__*/function () {
|
|
|
332
327
|
targetName = _ref2.targetName;
|
|
333
328
|
var key = _this5.getTModelKey(tmodel, targetName);
|
|
334
329
|
var tmodelEntry = _this5.tmodelKeyMap[key];
|
|
335
|
-
var loadTargetName =
|
|
330
|
+
var loadTargetName = _TUtil.TUtil.getLoadTargetName(targetName);
|
|
336
331
|
if (!tmodelEntry || !tmodelEntry.fetchMap[fetchId]) {
|
|
337
332
|
return;
|
|
338
333
|
}
|
|
@@ -345,12 +340,12 @@ var LoadingManager = exports.LoadingManager = /*#__PURE__*/function () {
|
|
|
345
340
|
};
|
|
346
341
|
var targetResults = tmodel.val(loadTargetName);
|
|
347
342
|
if (targetResults) {
|
|
348
|
-
if (!targetResults[fetchEntry.order]) {
|
|
343
|
+
if (!_TUtil.TUtil.isDefined(targetResults[fetchEntry.order])) {
|
|
349
344
|
tmodelEntry.resultCount++;
|
|
350
345
|
}
|
|
351
346
|
targetResults[fetchEntry.order] = res;
|
|
352
347
|
}
|
|
353
|
-
tmodel.val(targetName,
|
|
348
|
+
tmodel.val(targetName, res);
|
|
354
349
|
tmodelEntry.errorCount++;
|
|
355
350
|
_this5.callOnErrorHandler(tmodel, targetName);
|
|
356
351
|
var newStatus = _this5.calculateTargetStatus(tmodel, targetName);
|
package/build/TModel.js
CHANGED
|
@@ -134,6 +134,7 @@ var TModel = exports.TModel = /*#__PURE__*/function (_BaseModel) {
|
|
|
134
134
|
this.deletedChildren.push(child);
|
|
135
135
|
this.removeFromUpdatingChildren(child);
|
|
136
136
|
this.removeFromActiveChildren(child);
|
|
137
|
+
this.removeFromAnimatingChildren(child);
|
|
137
138
|
this.childrenUpdateFlag = true;
|
|
138
139
|
(0, _App.getLocationManager)().calcChildren(this);
|
|
139
140
|
this.markLayoutDirty('removeChild');
|
|
@@ -501,6 +502,11 @@ var TModel = exports.TModel = /*#__PURE__*/function (_BaseModel) {
|
|
|
501
502
|
}
|
|
502
503
|
return parentValue;
|
|
503
504
|
}
|
|
505
|
+
}, {
|
|
506
|
+
key: "getLoadedItems",
|
|
507
|
+
value: function getLoadedItems(targetName) {
|
|
508
|
+
return this.val(_TUtil.TUtil.getLoadTargetName(targetName));
|
|
509
|
+
}
|
|
504
510
|
}, {
|
|
505
511
|
key: "delVal",
|
|
506
512
|
value: function delVal(key) {
|
package/build/TModelManager.js
CHANGED
|
@@ -226,7 +226,7 @@ var TModelManager = exports.TModelManager = /*#__PURE__*/function () {
|
|
|
226
226
|
}, {
|
|
227
227
|
key: "needsRerender",
|
|
228
228
|
value: function needsRerender(tmodel) {
|
|
229
|
-
if (tmodel.hasDom() && _TUtil.TUtil.isDefined(tmodel.getHtml()) && (tmodel.$dom.
|
|
229
|
+
if (tmodel.hasDom() && _TUtil.TUtil.isDefined(tmodel.getHtml()) && (tmodel.$dom.innerHTML() !== tmodel.getHtml() || tmodel.$dom.textOnly !== tmodel.isTextOnly())) {
|
|
230
230
|
return true;
|
|
231
231
|
}
|
|
232
232
|
return false;
|
package/build/TUtil.js
CHANGED
|
@@ -165,6 +165,11 @@ var TUtil = exports.TUtil = /*#__PURE__*/function () {
|
|
|
165
165
|
value: function capitalizeFirstLetter(val) {
|
|
166
166
|
return val.charAt(0).toUpperCase() + val.slice(1);
|
|
167
167
|
}
|
|
168
|
+
}, {
|
|
169
|
+
key: "getLoadTargetName",
|
|
170
|
+
value: function getLoadTargetName(targetName) {
|
|
171
|
+
return "load-".concat(targetName);
|
|
172
|
+
}
|
|
168
173
|
}, {
|
|
169
174
|
key: "formatNum",
|
|
170
175
|
value: function formatNum(num, precision) {
|
package/build/TargetUtil.js
CHANGED
|
@@ -405,6 +405,9 @@ var TargetUtil = exports.TargetUtil = /*#__PURE__*/function () {
|
|
|
405
405
|
if (tmodel.isTargetImperative(targetName)) {
|
|
406
406
|
continue;
|
|
407
407
|
}
|
|
408
|
+
if (tmodel.activatedTargets.indexOf(targetName) >= 0) {
|
|
409
|
+
return "activated targets";
|
|
410
|
+
}
|
|
408
411
|
if (tmodel.hasUpdatingImperativeTargets(targetName)) {
|
|
409
412
|
return tmodel.oid + "." + targetName + ": " + tmodel.getUpdatingImperativeTargets(targetName);
|
|
410
413
|
}
|