targetj 1.0.259 → 1.1.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/Export.js CHANGED
@@ -19,6 +19,11 @@ export * from "./build/AnimationUtil.js";
19
19
  export * from "./build/VisibilityUtil.js";
20
20
  export * from "./build/ScheduleUtil.js";
21
21
  export * from "./build/StateUtil.js";
22
+ export * from "./build/ParticleTModel.js";
23
+ export * from "./build/ParticleChild.js";
24
+ export * from "./build/ParticleRenderer.js";
25
+ export * from "./build/ParticleRuntime.js";
26
+ export * from "./build/ParticleUtil.js";
22
27
 
23
28
  import * as AppModule from "./build/App.js";
24
29
  import * as TModelModule from "./build/TModel.js";
@@ -41,6 +46,11 @@ import * as AnimationUtilModule from "./build/AnimationUtil.js";
41
46
  import * as VisibilityUtilModule from "./build/VisibilityUtil.js";
42
47
  import * as ScheduleUtilModule from "./build/ScheduleUtil.js";
43
48
  import * as StateUtilModule from "./build/StateUtil.js";
49
+ import * as ParticleTModelModule from "./build/ParticleTModel.js";
50
+ import * as ParticleChildModule from "./build/ParticleChild.js";
51
+ import * as ParticleRendererModule from "./build/ParticleRenderer.js";
52
+ import * as ParticleRuntimeModule from "./build/ParticleRuntime.js";
53
+ import * as ParticleUtilModule from "./build/ParticleUtil.js";
44
54
 
45
55
  const TargetJS = {
46
56
  ...AppModule,
@@ -63,7 +73,12 @@ const TargetJS = {
63
73
  ...AnimationUtilModule,
64
74
  ...VisibilityUtilModule,
65
75
  ...ScheduleUtilModule,
66
- ...StateUtilModule
76
+ ...StateUtilModule,
77
+ ...ParticleTModelModule,
78
+ ...ParticleChildModule,
79
+ ...ParticleRendererModule,
80
+ ...ParticleRuntimeModule,
81
+ ...ParticleUtilModule
67
82
  };
68
83
 
69
84
  if (typeof window !== "undefined") {
package/README.md CHANGED
@@ -1,17 +1,13 @@
1
- # TargetJS: State Includes the Journey
1
+ # TargetJS: The "State → Transition → Render" Framework
2
2
 
3
3
  **Code order defines the UI sequence.**
4
4
 
5
- Most frameworks are great at rendering state. TargetJS is designed for the journey between states.
6
-
7
5
  **[targetjs.io](https://targetjs.io)**
8
6
  [![MIT LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/livetrails/targetjs/blob/main/LICENSE)
9
7
  [![Stars](https://img.shields.io/github/stars/livetrails/targetjs.svg)](https://github.com/livetrails/targetjs/stargazers)
10
8
  [![npm version](https://img.shields.io/npm/v/targetj.svg)](https://www.npmjs.com/package/targetj)
11
9
 
12
- TargetJS is a JavaScript UI framework that replaces the "State → Render" model with "State → Transition → Render".
13
-
14
- Transitions are part of the state itself. This allows the entire UI, including an animation in progress, to be captured and later restored from the exact point at which it was saved.
10
+ TargetJS is a JavaScript UI framework that transforms how applications handle state and execution flow. Instead of treating state merely as data for rendering, TargetJS integrates the active UI runtime including in-progress animation and execution flow directly into the state itself. This unified state approach allows developers to capture and restore the exact state of an interface at any millisecond.
15
11
 
16
12
  TargetJS also lets code order directly define the UI sequence. UI, transitions, API calls, event handling, and state are unified into self-contained Targets that chain together through Code-Ordered Reactivity.
17
13
 
@@ -22,13 +18,9 @@ It can be used as a full-featured framework or as a lightweight library alongsid
22
18
 
23
19
  **UI frameworks model the final result, not the transition**
24
20
 
25
- 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.
26
-
27
- TargetJS makes that transition part of the state change itself. Values are not limited to being assigned immediately. They can move toward their destination over configurable steps, intervals, and easing. Transitions therefore become a native part of the UI model rather than effects added after rendering. TargetJS also delivers CSS-level transition efficiency.
28
-
29
- Because each Target has its own lifecycle, transitions can also adapt dynamically. For example, pausing when an element leaves the screen or changing speed on scroll.
21
+ Traditional frameworks model the UI as a function of data: change data, re-render the UI. When data changes from A → B, the UI immediately jumps to render B. The framework doesn’t naturally represent the journey from A → B. But modern, rich user experiences are more like: A → transition → B.
30
22
 
31
- Since the transition belongs to the runtime state, the UI can be captured while a transition is in progress. That state can later be restored, allowing the transition to resume from the point at which it was saved.
23
+ TargetJS redefines state to include both the transition and the active UI runtime. This allows transitions to adapt dynamically on the fly, for example, pausing when an element leaves the screen or changing speed on scroll. It also allows the entire UI to be captured mid-animation and restored later, resuming exactly where it left off.
32
24
 
33
25
  **Fragmentation across multiple mental models**
34
26
 
@@ -46,14 +38,12 @@ In traditional code, that sequence is often scattered across different places su
46
38
 
47
39
  TargetJS code order and target reactivity allow the implementation to more closely mirror the actual UI sequence.
48
40
 
49
- With its compact style, TargetJS makes the journey from A → B explicit and efficient, with significantly less code than traditional frameworks.
50
-
51
41
  ## 🚀 Why TargetJS?
52
42
 
53
- 1. Unified State: One single state. Transitions are state too.
54
- 1. Adaptive Transitions: Transitions can pause, resume, change speed, and respond to input.
55
- 1. Restorable UI: Capture the UI during a transition and later resume the complete state including the transition from the saved point.
43
+ 1. Unified State: UI values, transitions, and runtime execution are part of the same state.
44
+ 1. Restorable UI and Runtime: UI and runtime state can be captured and later the complete state can be restored including transitions and execution flow from the saved point.
56
45
  1. UI as Sequence: Code describes the UI story from top to bottom, just like the user experiences the interaction: "When this finishes, do that."
46
+ 1. Adaptive Transitions: Transitions can pause, resume, change speed, and respond to input.
57
47
  1. Ultra-Compact: Minimal code, with no coordination variables.
58
48
  1. Zero Boilerplate Async: Targets handle waiting for nested asynchronous operations automatically.
59
49
  1. Animation by Default: Turn value into high-performance animations simply by adding `steps`.
@@ -76,7 +66,9 @@ bounce → move → turn red → log
76
66
 
77
67
  Notice how the code reads in the same order as the UI sequence. The `$$` suffix makes each target wait for all preceding targets to complete.
78
68
 
79
- There is only one state, and the transitions are part of that state. Click the square while it is animating to save its current state. Click it again to restore the state and resume the animation from the exact point at which it was saved.
69
+ Click the square while it is animating to capture its current state. Click it again to restore that state and resume the animation from the exact point at which it was saved.
70
+
71
+ The checkpoint captures more than the square's visual state. It captures the runtime behind it including transition progress and pending targets. Restoring it resumes the whole sequence from that exact point, not just what was on screen. You can try the example at https://targetjs.io/examples/firstExample.html
80
72
 
81
73
  ```javascript
82
74
  import { App, state } from "targetj";
@@ -91,19 +83,18 @@ App({
91
83
  scale: { value: [0.5, 1.2, 1], steps: 100 },
92
84
 
93
85
  // $$ waits for the previous target to finish.
94
- x$$: { value: [0, 180], steps: 100 },
86
+ x$$: { value: [0, 180], steps: 200 },
95
87
 
96
88
  backgroundColor$$: {
97
89
  value: "crimson",
98
- steps: 100
90
+ steps: 200
99
91
  },
100
92
 
101
93
  done$$() {
102
94
  console.log("Sequence complete");
103
95
  },
104
96
 
105
- // Click once to save the state.
106
- // Click again to restore it including animation progress.
97
+ // 1st click: save a checkpoint. 2nd click: restore it and resume.
107
98
  onClick() {
108
99
  state().toggle();
109
100
  }
@@ -159,7 +150,7 @@ Target names can include special suffixes that determine when they execute. This
159
150
  | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
160
151
  | `name` | Standard | Runs immediately in code order unless `active` is `false`. |
161
152
  | `name$` | Reactive | Runs whenever the preceding sibling Target updates. Similar to activating the next Target from `onValueChange()` or `on<PropertyName>Step()`. |
162
- | `name$$` | Deferred | Runs after the entire preceding Target chain—including children, animations, and API calls—has completed. Similar to activating the next Target from `onComplete()`. |
153
+ | `name$$` | Deferred | Runs after the entire preceding Target chain including children, animations, and API calls has completed. Similar to activating the next Target from `onComplete()`. |
163
154
 
164
155
  To prevent a Target from running automatically, set `active: false` and activate it later with `.activateTarget()`.
165
156
 
@@ -255,8 +246,10 @@ App({
255
246
  this.setTarget('y', { value: [0, -120], steps: 400 });
256
247
  }
257
248
  },
258
- fetch$$: { method: "POST", id: 123, url: "/api/like" }, // Wait for the heart to finish, THEN fetch
259
- removeHearts$$() { this.removeChildren(); }, // Wait for fetch to finish, THEN cleanup
249
+ // Wait for the nested animation in heart$$ to finish , then fetch
250
+ fetch$$: { method: "POST", id: 123, url: "/api/like" },
251
+ // Wait for fetch to finish, then cleanup
252
+ removeHearts$$() { this.removeChildren(); },
260
253
  onKey(e) { if (e.key === "Enter") this.activateTarget("onClick"); }
261
254
  }).mount("#likeButton");
262
255
  ```
@@ -341,7 +341,7 @@ var AnimationManager = /*#__PURE__*/function () {
341
341
  if (targetValue) {
342
342
  var _targetValue$valueLis;
343
343
  targetValue.step = tmodel.getTargetSteps(originalKey);
344
- targetValue.valuePointer = (_targetValue$valueLis = targetValue.valueList) !== null && _targetValue$valueLis !== void 0 && _targetValue$valueLis.length ? targetValue.valueList.length - 1 : 0;
344
+ targetValue.valuePointer = (_targetValue$valueLis = targetValue.valueList) !== null && _targetValue$valueLis !== void 0 && _targetValue$valueLis.length ? targetValue.valueList.length : 0;
345
345
  tmodel.setActual(originalKey, value);
346
346
  if (tmodel.isTargetImperative(originalKey)) {
347
347
  targetValue.cycle = targetValue.cycles;
@@ -239,17 +239,10 @@ var AnimationUtil = /*#__PURE__*/function () {
239
239
  } finally {
240
240
  _iterator2.f();
241
241
  }
242
- var now = TUtil.now();
243
242
  for (var _i4 = 0, _records2 = records; _i4 < _records2.length; _i4++) {
244
243
  var record = _records2[_i4];
245
244
  var originalKey = record.originalKey;
246
- var targetValue = tmodel.targetValues[originalKey];
247
- if (!targetValue) {
248
- continue;
249
- }
250
- targetValue.catchupAt = now;
251
- tmodel.removeFromAnimatingMap(originalKey);
252
- (tmodel.noDomUpdatingTargets || (tmodel.noDomUpdatingTargets = new Set())).add(originalKey);
245
+ tmodel.addToNoDomUpdatingTargets(originalKey);
253
246
  }
254
247
  }
255
248
  }, {
package/build/App.js CHANGED
@@ -25,6 +25,7 @@ import { TUtil } from "./TUtil.js";
25
25
  import { DomInit } from "./DomInit.js";
26
26
  import { SearchUtil } from "./SearchUtil.js";
27
27
  import { TModelUtil } from "./TModelUtil.js";
28
+ import "./ParticleTModel.js";
28
29
  var tApp;
29
30
  var queuedAppCalls = [];
30
31
  var AppFn = function AppFn() {
@@ -85,7 +86,7 @@ var AppFn = function AppFn() {
85
86
  if (t.val('sourceDom')) {
86
87
  return;
87
88
  }
88
- var child = new TModel(t.type, t.targets);
89
+ var child = TargetExecutor.createTModel(t.type, t.targets);
89
90
  tmodel.addChild(child);
90
91
  });
91
92
  }
@@ -105,7 +106,9 @@ var AppFn = function AppFn() {
105
106
  my.events.detachWindowEvents();
106
107
  my.events.attachWindowEvents();
107
108
  my.events.clearAll();
108
- my.events.attachEvents(my.manager.getVisibles());
109
+ my.events.attachEvents(Object.values(App.tmodelIdMap).filter(function (tmodel) {
110
+ return tmodel.hasDom() && tmodel.$dom.element.isConnected;
111
+ }));
109
112
  _context.next = 10;
110
113
  return my.runScheduler.resetRuns();
111
114
  case 10:
@@ -143,6 +146,7 @@ var AppFn = function AppFn() {
143
146
  }, _callee2);
144
147
  }));
145
148
  my.reset = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3() {
149
+ var _i, _Object$values, _tmodel$particleRunti, _tmodel$particleRende, tmodel;
146
150
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
147
151
  while (1) switch (_context3.prev = _context3.next) {
148
152
  case 0:
@@ -169,11 +173,16 @@ var AppFn = function AppFn() {
169
173
  _context3.next = 3;
170
174
  return my.runScheduler.resetRuns();
171
175
  case 3:
176
+ for (_i = 0, _Object$values = Object.values(App.tmodelIdMap); _i < _Object$values.length; _i++) {
177
+ tmodel = _Object$values[_i];
178
+ (_tmodel$particleRunti = tmodel.particleRuntime) === null || _tmodel$particleRunti === void 0 || _tmodel$particleRunti.dispose();
179
+ (_tmodel$particleRende = tmodel.particleRenderer) === null || _tmodel$particleRende === void 0 || _tmodel$particleRende.destroy();
180
+ }
172
181
  my.manager.clearAll();
173
182
  my.locationManager.clear();
174
183
  my.loader.clear();
175
184
  SearchUtil.clear();
176
- case 7:
185
+ case 8:
177
186
  case "end":
178
187
  return _context3.stop();
179
188
  }
@@ -199,7 +208,7 @@ var App = function App(firstChild) {
199
208
  if (!firstChild) {
200
209
  return;
201
210
  }
202
- var tmodel = firstChild instanceof TModel ? firstChild : new TModel("App", firstChild);
211
+ var tmodel = firstChild instanceof TModel ? firstChild : TargetExecutor.createTModel("App", firstChild);
203
212
  if (!((_tApp2 = tApp) !== null && _tApp2 !== void 0 && _tApp2.tRoot)) {
204
213
  if (document.readyState === "loading") {
205
214
  queuedAppCalls.push(tmodel);
@@ -668,12 +668,16 @@ var BaseModel = /*#__PURE__*/function () {
668
668
  }, {
669
669
  key: "getTargetValue",
670
670
  value: function getTargetValue(key) {
671
- var _target$value;
672
- var target = this.targetValues[key] || this.targets[key];
673
- if (!target) {
671
+ var targetValue = this.targetValues[key];
672
+ if (targetValue !== undefined) {
673
+ var _value = targetValue.value;
674
+ return typeof _value === 'function' ? _value.call(this) : _value;
675
+ }
676
+ var target = this.targets[key];
677
+ if (target === undefined) {
674
678
  return undefined;
675
679
  }
676
- var value = (_target$value = target.value) !== null && _target$value !== void 0 ? _target$value : target;
680
+ var value = target && _typeof(target) === 'object' && Object.prototype.hasOwnProperty.call(target, 'value') ? target.value : target;
677
681
  return typeof value === 'function' ? value.call(this) : value;
678
682
  }
679
683
  }, {
@@ -1027,6 +1031,27 @@ var BaseModel = /*#__PURE__*/function () {
1027
1031
  (_this$getParent4 = this.getParent()) === null || _this$getParent4 === void 0 || _this$getParent4.addToUpdatingChildren(this);
1028
1032
  }
1029
1033
  }
1034
+ }, {
1035
+ key: "addToNoDomUpdatingTargets",
1036
+ value: function addToNoDomUpdatingTargets(key) {
1037
+ var _this$getParent5;
1038
+ var targetValue = this.targetValues[key];
1039
+ if (!targetValue) {
1040
+ return false;
1041
+ }
1042
+ var noDomTargets = this.noDomUpdatingTargets || (this.noDomUpdatingTargets = new Set());
1043
+ if (noDomTargets.has(key)) {
1044
+ return false;
1045
+ }
1046
+ targetValue.catchupAt = TUtil.now();
1047
+ noDomTargets.add(key);
1048
+ this.removeFromAnimatingMap(key);
1049
+ this.removeFromUpdatingTargets(key);
1050
+ this.resetScheduleTimeStamp(key);
1051
+ this.resetScheduleRemainingTime(key);
1052
+ (_this$getParent5 = this.getParent()) === null || _this$getParent5 === void 0 || _this$getParent5.addToUpdatingChildren(this);
1053
+ return true;
1054
+ }
1030
1055
  }, {
1031
1056
  key: "removeFromUpdatingTargets",
1032
1057
  value: function removeFromUpdatingTargets(key) {
@@ -1038,8 +1063,8 @@ var BaseModel = /*#__PURE__*/function () {
1038
1063
  }
1039
1064
  }
1040
1065
  if (this.updatingTargetList.length === 0) {
1041
- var _this$getParent5;
1042
- (_this$getParent5 = this.getParent()) === null || _this$getParent5 === void 0 || _this$getParent5.removeFromUpdatingChildren(this);
1066
+ var _this$getParent6;
1067
+ (_this$getParent6 = this.getParent()) === null || _this$getParent6 === void 0 || _this$getParent6.removeFromUpdatingChildren(this);
1043
1068
  }
1044
1069
  }
1045
1070
  }, {
@@ -1096,8 +1121,8 @@ var BaseModel = /*#__PURE__*/function () {
1096
1121
  }, {
1097
1122
  key: "hasAnyUpdates",
1098
1123
  value: function hasAnyUpdates() {
1099
- var _this$animatingMap$si, _this$animatingMap3;
1100
- return this.updatingTargetList.length !== 0 || this.activeTargetList.length !== 0 || ((_this$animatingMap$si = (_this$animatingMap3 = this.animatingMap) === null || _this$animatingMap3 === void 0 ? void 0 : _this$animatingMap3.size) !== null && _this$animatingMap$si !== void 0 ? _this$animatingMap$si : 0) !== 0;
1124
+ var _this$animatingMap$si, _this$animatingMap3, _this$noDomUpdatingTa, _this$noDomUpdatingTa2;
1125
+ return this.updatingTargetList.length !== 0 || this.activeTargetList.length !== 0 || ((_this$animatingMap$si = (_this$animatingMap3 = this.animatingMap) === null || _this$animatingMap3 === void 0 ? void 0 : _this$animatingMap3.size) !== null && _this$animatingMap$si !== void 0 ? _this$animatingMap$si : 0) !== 0 || ((_this$noDomUpdatingTa = (_this$noDomUpdatingTa2 = this.noDomUpdatingTargets) === null || _this$noDomUpdatingTa2 === void 0 ? void 0 : _this$noDomUpdatingTa2.size) !== null && _this$noDomUpdatingTa !== void 0 ? _this$noDomUpdatingTa : 0) !== 0;
1101
1126
  }
1102
1127
  }, {
1103
1128
  key: "removeFromAnimatingMap",
@@ -1106,28 +1131,28 @@ var BaseModel = /*#__PURE__*/function () {
1106
1131
  if ((_this$animatingMap4 = this.animatingMap) !== null && _this$animatingMap4 !== void 0 && _this$animatingMap4.has(key)) {
1107
1132
  this.animatingMap.delete(key);
1108
1133
  if (this.animatingMap.size === 0) {
1109
- var _this$getParent6;
1110
- (_this$getParent6 = this.getParent()) === null || _this$getParent6 === void 0 || _this$getParent6.removeFromAnimatingChildren(this);
1134
+ var _this$getParent7;
1135
+ (_this$getParent7 = this.getParent()) === null || _this$getParent7 === void 0 || _this$getParent7.removeFromAnimatingChildren(this);
1111
1136
  }
1112
1137
  }
1113
1138
  }
1114
1139
  }, {
1115
1140
  key: "clearAnimatingMap",
1116
1141
  value: function clearAnimatingMap() {
1117
- var _this$animatingMap5, _this$getParent7;
1142
+ var _this$animatingMap5, _this$getParent8;
1118
1143
  (_this$animatingMap5 = this.animatingMap) === null || _this$animatingMap5 === void 0 || _this$animatingMap5.clear();
1119
- (_this$getParent7 = this.getParent()) === null || _this$getParent7 === void 0 || _this$getParent7.removeFromAnimatingChildren(this);
1144
+ (_this$getParent8 = this.getParent()) === null || _this$getParent8 === void 0 || _this$getParent8.removeFromAnimatingChildren(this);
1120
1145
  }
1121
1146
  }, {
1122
1147
  key: "addToAnimatingMap",
1123
1148
  value: function addToAnimatingMap(key) {
1124
- var _this$targetValues$ke24, _this$getParent8;
1149
+ var _this$targetValues$ke24, _this$getParent9;
1125
1150
  if ((_this$targetValues$ke24 = this.targetValues[key]) !== null && _this$targetValues$ke24 !== void 0 && _this$targetValues$ke24.snapAnimation) {
1126
1151
  return;
1127
1152
  }
1128
1153
  this.animatingMap || (this.animatingMap = new Map());
1129
1154
  this.animatingMap.set(key, true);
1130
- (_this$getParent8 = this.getParent()) === null || _this$getParent8 === void 0 || _this$getParent8.addToAnimatingChildren(this);
1155
+ (_this$getParent9 = this.getParent()) === null || _this$getParent9 === void 0 || _this$getParent9.addToAnimatingChildren(this);
1131
1156
  }
1132
1157
  }, {
1133
1158
  key: "getAnimatingTargets",
package/build/Bracket.js CHANGED
@@ -96,7 +96,7 @@ var Bracket = /*#__PURE__*/function (_TModel) {
96
96
  }, {
97
97
  key: "isVisible",
98
98
  value: function isVisible() {
99
- return this.visibilityStatus ? this.visibilityStatus.top && this.visibilityStatus.bottom : false;
99
+ return this.visibilityStatus ? this.visibilityStatus.isVisible : false;
100
100
  }
101
101
  }, {
102
102
  key: "getBracketThreshold",
@@ -145,10 +145,16 @@ var Bracket = /*#__PURE__*/function (_TModel) {
145
145
  if (hasEventDirty) {
146
146
  return true;
147
147
  }
148
+ if (this.visibilityDirty) {
149
+ return true;
150
+ }
148
151
  if (this.currentBracketStatus >= 1 || this.isNowVisible || this.isNowInvisible) {
149
152
  this.currentBracketStatus = Math.max(0, this.currentBracketStatus - 1);
150
153
  return true;
151
154
  }
155
+ if (this.dirtyLayout !== false) {
156
+ return true;
157
+ }
152
158
  if (nowVisible) {
153
159
  this.currentBracketStatus = Math.min(2, this.currentBracketStatus + 1);
154
160
  }