juxscript 1.1.28 → 1.1.30
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/index.d.ts +2 -1
- package/index.d.ts.map +1 -1
- package/index.js +2 -1
- package/lib/components/base/BaseComponent.d.ts +20 -7
- package/lib/components/base/BaseComponent.d.ts.map +1 -1
- package/lib/components/base/BaseComponent.js +64 -15
- package/lib/components/base/BaseComponent.ts +75 -15
- package/lib/components/history/StateHistory.d.ts +91 -0
- package/lib/components/history/StateHistory.d.ts.map +1 -0
- package/lib/components/history/StateHistory.js +154 -0
- package/lib/components/history/StateHistory.ts +200 -0
- package/lib/components/registry.d.ts +10 -36
- package/lib/components/registry.d.ts.map +1 -1
- package/lib/components/registry.js +122 -105
- package/lib/components/registry.ts +141 -112
- package/package.json +1 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State History Tracker
|
|
3
|
+
* Tracks all state mutations for time-travel debugging and undo/redo
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface StateSnapshot<T = any> {
|
|
7
|
+
timestamp: number;
|
|
8
|
+
componentId: string;
|
|
9
|
+
property: string;
|
|
10
|
+
oldValue: T;
|
|
11
|
+
newValue: T;
|
|
12
|
+
stackTrace?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface EventSnapshot {
|
|
16
|
+
timestamp: number;
|
|
17
|
+
componentId: string;
|
|
18
|
+
eventType: 'bind' | 'sync' | 'callback' | 'trigger';
|
|
19
|
+
eventName: string;
|
|
20
|
+
details: Record<string, any>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class StateHistory {
|
|
24
|
+
private stateSnapshots: StateSnapshot[] = [];
|
|
25
|
+
private eventSnapshots: EventSnapshot[] = [];
|
|
26
|
+
private maxHistory: number = 100;
|
|
27
|
+
private currentIndex: number = -1;
|
|
28
|
+
private isReplaying: boolean = false;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Record a state change
|
|
32
|
+
*/
|
|
33
|
+
recordStateChange<T>(
|
|
34
|
+
componentId: string,
|
|
35
|
+
property: string,
|
|
36
|
+
oldValue: T,
|
|
37
|
+
newValue: T
|
|
38
|
+
): void {
|
|
39
|
+
if (this.isReplaying) return; // Don't record during replay
|
|
40
|
+
|
|
41
|
+
const snapshot: StateSnapshot<T> = {
|
|
42
|
+
timestamp: Date.now(),
|
|
43
|
+
componentId,
|
|
44
|
+
property,
|
|
45
|
+
oldValue,
|
|
46
|
+
newValue,
|
|
47
|
+
stackTrace: new Error().stack
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Trim future history if we're not at the end
|
|
51
|
+
if (this.currentIndex < this.stateSnapshots.length - 1) {
|
|
52
|
+
this.stateSnapshots = this.stateSnapshots.slice(0, this.currentIndex + 1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.stateSnapshots.push(snapshot);
|
|
56
|
+
this.currentIndex = this.stateSnapshots.length - 1;
|
|
57
|
+
|
|
58
|
+
// Trim if exceeds max
|
|
59
|
+
if (this.stateSnapshots.length > this.maxHistory) {
|
|
60
|
+
this.stateSnapshots.shift();
|
|
61
|
+
this.currentIndex--;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Record an event (bind, sync, callback, trigger)
|
|
67
|
+
*/
|
|
68
|
+
recordEvent(
|
|
69
|
+
componentId: string,
|
|
70
|
+
eventType: 'bind' | 'sync' | 'callback' | 'trigger',
|
|
71
|
+
eventName: string,
|
|
72
|
+
details: Record<string, any> = {}
|
|
73
|
+
): void {
|
|
74
|
+
const snapshot: EventSnapshot = {
|
|
75
|
+
timestamp: Date.now(),
|
|
76
|
+
componentId,
|
|
77
|
+
eventType,
|
|
78
|
+
eventName,
|
|
79
|
+
details
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
this.eventSnapshots.push(snapshot);
|
|
83
|
+
|
|
84
|
+
// Trim if exceeds max
|
|
85
|
+
if (this.eventSnapshots.length > this.maxHistory) {
|
|
86
|
+
this.eventSnapshots.shift();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get timeline of all changes and events
|
|
92
|
+
*/
|
|
93
|
+
getTimeline(): Array<StateSnapshot | EventSnapshot> {
|
|
94
|
+
return [...this.stateSnapshots, ...this.eventSnapshots]
|
|
95
|
+
.sort((a, b) => a.timestamp - b.timestamp);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get state snapshots for a specific component
|
|
100
|
+
*/
|
|
101
|
+
getComponentHistory(componentId: string): StateSnapshot[] {
|
|
102
|
+
return this.stateSnapshots.filter(s => s.componentId === componentId);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get event snapshots for a specific component
|
|
107
|
+
*/
|
|
108
|
+
getComponentEvents(componentId: string): EventSnapshot[] {
|
|
109
|
+
return this.eventSnapshots.filter(s => s.componentId === componentId);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Check if we can roll back
|
|
114
|
+
*/
|
|
115
|
+
canRollback(): boolean {
|
|
116
|
+
return this.currentIndex > 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Check if we can roll forward
|
|
121
|
+
*/
|
|
122
|
+
canRollforward(): boolean {
|
|
123
|
+
return this.currentIndex < this.stateSnapshots.length - 1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get the current snapshot (for rollback)
|
|
128
|
+
*/
|
|
129
|
+
getCurrentSnapshot(): StateSnapshot | null {
|
|
130
|
+
if (this.currentIndex >= 0 && this.currentIndex < this.stateSnapshots.length) {
|
|
131
|
+
return this.stateSnapshots[this.currentIndex];
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Move index for rollback
|
|
138
|
+
*/
|
|
139
|
+
moveBack(): StateSnapshot | null {
|
|
140
|
+
if (this.canRollback()) {
|
|
141
|
+
this.currentIndex--;
|
|
142
|
+
return this.stateSnapshots[this.currentIndex];
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Move index for rollforward
|
|
149
|
+
*/
|
|
150
|
+
moveForward(): StateSnapshot | null {
|
|
151
|
+
if (this.canRollforward()) {
|
|
152
|
+
this.currentIndex++;
|
|
153
|
+
return this.stateSnapshots[this.currentIndex];
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Mark as replaying to prevent recursive recording
|
|
160
|
+
*/
|
|
161
|
+
startReplay(): void {
|
|
162
|
+
this.isReplaying = true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* End replay mode
|
|
167
|
+
*/
|
|
168
|
+
endReplay(): void {
|
|
169
|
+
this.isReplaying = false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Clear all history
|
|
174
|
+
*/
|
|
175
|
+
clear(): void {
|
|
176
|
+
this.stateSnapshots = [];
|
|
177
|
+
this.eventSnapshots = [];
|
|
178
|
+
this.currentIndex = -1;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get summary statistics
|
|
183
|
+
*/
|
|
184
|
+
getStats() {
|
|
185
|
+
return {
|
|
186
|
+
totalStateChanges: this.stateSnapshots.length,
|
|
187
|
+
totalEvents: this.eventSnapshots.length,
|
|
188
|
+
currentIndex: this.currentIndex,
|
|
189
|
+
canRollback: this.canRollback(),
|
|
190
|
+
canRollforward: this.canRollforward(),
|
|
191
|
+
components: new Set([
|
|
192
|
+
...this.stateSnapshots.map(s => s.componentId),
|
|
193
|
+
...this.eventSnapshots.map(s => s.componentId)
|
|
194
|
+
]).size
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Global singleton
|
|
200
|
+
export const stateHistory = new StateHistory();
|
|
@@ -1,59 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Usage in console:
|
|
6
|
-
* __jux.get('hero-1').state.title = 'New Title'
|
|
7
|
-
* __jux.list()
|
|
8
|
-
* __jux.find('hero')
|
|
9
|
-
* __jux.create('button', 'btn-1', { label: 'Click Me' }).render()
|
|
2
|
+
* Simplified JUX Component Registry
|
|
3
|
+
* Lean console debugging interface
|
|
10
4
|
*/
|
|
11
5
|
import { BaseComponent } from './base/BaseComponent.js';
|
|
12
6
|
declare class ComponentRegistry {
|
|
13
7
|
private components;
|
|
14
|
-
/**
|
|
15
|
-
* Register a component instance
|
|
16
|
-
*/
|
|
17
8
|
register(component: BaseComponent<any>): void;
|
|
18
|
-
/**
|
|
19
|
-
* Unregister a component
|
|
20
|
-
*/
|
|
21
9
|
unregister(id: string): void;
|
|
22
10
|
/**
|
|
23
|
-
* Get
|
|
24
|
-
*/
|
|
25
|
-
get<T extends BaseComponent<any>>(id: string): T | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* Check if component exists
|
|
11
|
+
* Get component by index or ID
|
|
28
12
|
*/
|
|
29
|
-
|
|
13
|
+
get(indexOrId: number | string): BaseComponent<any> | undefined;
|
|
30
14
|
/**
|
|
31
|
-
*
|
|
15
|
+
* Print indexed list to console
|
|
32
16
|
*/
|
|
33
|
-
list():
|
|
17
|
+
list(): void;
|
|
34
18
|
/**
|
|
35
|
-
*
|
|
19
|
+
* Show component tree with state, history, events
|
|
36
20
|
*/
|
|
37
|
-
|
|
21
|
+
tree(indexOrId?: number | string): void;
|
|
22
|
+
private _printTree;
|
|
38
23
|
/**
|
|
39
24
|
* Get all components
|
|
40
25
|
*/
|
|
41
26
|
all(): BaseComponent<any>[];
|
|
42
27
|
/**
|
|
43
|
-
*
|
|
44
|
-
*/
|
|
45
|
-
byType(typeName: string): BaseComponent<any>[];
|
|
46
|
-
/**
|
|
47
|
-
* Clear all registered components
|
|
28
|
+
* Clear registry
|
|
48
29
|
*/
|
|
49
30
|
clear(): void;
|
|
50
|
-
/**
|
|
51
|
-
* Get registry stats
|
|
52
|
-
*/
|
|
53
|
-
stats(): {
|
|
54
|
-
total: number;
|
|
55
|
-
types: Record<string, number>;
|
|
56
|
-
};
|
|
57
31
|
}
|
|
58
32
|
export declare const registry: ComponentRegistry;
|
|
59
33
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,cAAM,iBAAiB;IACnB,OAAO,CAAC,UAAU,CAA4B;IAE9C,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IAO7C,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI5B;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,SAAS;IAO/D;;OAEG;IACH,IAAI,IAAI,IAAI;IAaZ;;OAEG;IACH,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAkBvC,OAAO,CAAC,UAAU;IAkClB;;OAEG;IACH,GAAG,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE;IAI3B;;OAEG;IACH,KAAK,IAAI,IAAI;CAIhB;AAED,eAAO,MAAM,QAAQ,mBAA0B,CAAC"}
|
|
@@ -1,146 +1,163 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Usage in console:
|
|
6
|
-
* __jux.get('hero-1').state.title = 'New Title'
|
|
7
|
-
* __jux.list()
|
|
8
|
-
* __jux.find('hero')
|
|
9
|
-
* __jux.create('button', 'btn-1', { label: 'Click Me' }).render()
|
|
2
|
+
* Simplified JUX Component Registry
|
|
3
|
+
* Lean console debugging interface
|
|
10
4
|
*/
|
|
5
|
+
import { stateHistory } from './history/StateHistory.js';
|
|
11
6
|
class ComponentRegistry {
|
|
12
7
|
constructor() {
|
|
13
|
-
this.components =
|
|
8
|
+
this.components = [];
|
|
14
9
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Register a component instance
|
|
17
|
-
*/
|
|
18
10
|
register(component) {
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
// Avoid duplicates
|
|
12
|
+
if (!this.components.find(c => c._id === component._id)) {
|
|
13
|
+
this.components.push(component);
|
|
14
|
+
}
|
|
21
15
|
}
|
|
22
|
-
/**
|
|
23
|
-
* Unregister a component
|
|
24
|
-
*/
|
|
25
16
|
unregister(id) {
|
|
26
|
-
this.components.
|
|
27
|
-
console.debug(`[Jux Registry] Unregistered: ${id}`);
|
|
17
|
+
this.components = this.components.filter(c => c._id !== id);
|
|
28
18
|
}
|
|
29
19
|
/**
|
|
30
|
-
* Get
|
|
20
|
+
* Get component by index or ID
|
|
31
21
|
*/
|
|
32
|
-
get(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
*/
|
|
38
|
-
has(id) {
|
|
39
|
-
return this.components.has(id);
|
|
22
|
+
get(indexOrId) {
|
|
23
|
+
if (typeof indexOrId === 'number') {
|
|
24
|
+
return this.components[indexOrId];
|
|
25
|
+
}
|
|
26
|
+
return this.components.find(c => c._id === indexOrId);
|
|
40
27
|
}
|
|
41
28
|
/**
|
|
42
|
-
*
|
|
29
|
+
* Print indexed list to console
|
|
43
30
|
*/
|
|
44
31
|
list() {
|
|
45
|
-
|
|
32
|
+
if (this.components.length === 0) {
|
|
33
|
+
console.log('📭 No components registered');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log('\n📋 Registered Components:\n');
|
|
37
|
+
this.components.forEach((comp, idx) => {
|
|
38
|
+
console.log(` [${idx}] ${comp._id} → ${comp.constructor.name}`);
|
|
39
|
+
});
|
|
40
|
+
console.log(`\n💡 Access via: _jux.get(${0}) or _jux.get('${this.components[0]._id}')\n`);
|
|
46
41
|
}
|
|
47
42
|
/**
|
|
48
|
-
*
|
|
43
|
+
* Show component tree with state, history, events
|
|
49
44
|
*/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
tree(indexOrId) {
|
|
46
|
+
let comp;
|
|
47
|
+
if (indexOrId === undefined) {
|
|
48
|
+
// Show all components
|
|
49
|
+
this.components.forEach((c, idx) => this._printTree(c, idx));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
comp = this.get(indexOrId);
|
|
53
|
+
if (!comp) {
|
|
54
|
+
console.error(`❌ Component not found: ${indexOrId}`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this._printTree(comp, typeof indexOrId === 'number' ? indexOrId : undefined);
|
|
58
|
+
}
|
|
59
|
+
_printTree(comp, index) {
|
|
60
|
+
const idx = index !== undefined ? `[${index}]` : '';
|
|
61
|
+
const stateChanges = stateHistory.getComponentHistory(comp._id);
|
|
62
|
+
const events = stateHistory.getComponentEvents(comp._id);
|
|
63
|
+
const syncCount = comp._syncBindings?.length || 0;
|
|
64
|
+
const bindCount = comp._bindings?.length || 0;
|
|
65
|
+
console.group(`🌳 ${idx} ${comp._id} (${comp.constructor.name})`);
|
|
66
|
+
console.log('📊 State:', comp.state);
|
|
67
|
+
if (stateChanges.length > 0) {
|
|
68
|
+
console.log(`📜 History: ${stateChanges.length} changes`);
|
|
69
|
+
console.log(' Last 3:', stateChanges.slice(-3).map(s => `${s.property}: ${s.oldValue} → ${s.newValue}`));
|
|
70
|
+
}
|
|
71
|
+
if (syncCount > 0) {
|
|
72
|
+
console.log(`🔗 Syncs: ${syncCount} active`);
|
|
73
|
+
}
|
|
74
|
+
if (bindCount > 0 || events.length > 0) {
|
|
75
|
+
console.log(`⚡ Events: ${bindCount} binds, ${events.length} fired`);
|
|
76
|
+
}
|
|
77
|
+
console.log(`\n💡 Commands:`);
|
|
78
|
+
console.log(` _jux.get(${index ?? `'${comp._id}'`}).state.prop = value`);
|
|
79
|
+
console.log(` _jux.get(${index ?? `'${comp._id}'`}).rollback()`);
|
|
80
|
+
console.log(` _jux.get(${index ?? `'${comp._id}'`}).timeline()`);
|
|
81
|
+
console.groupEnd();
|
|
54
82
|
}
|
|
55
83
|
/**
|
|
56
84
|
* Get all components
|
|
57
85
|
*/
|
|
58
86
|
all() {
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Get components by type (constructor name)
|
|
63
|
-
*/
|
|
64
|
-
byType(typeName) {
|
|
65
|
-
return Array.from(this.components.values())
|
|
66
|
-
.filter(comp => comp.constructor.name === typeName);
|
|
87
|
+
return this.components;
|
|
67
88
|
}
|
|
68
89
|
/**
|
|
69
|
-
* Clear
|
|
90
|
+
* Clear registry
|
|
70
91
|
*/
|
|
71
92
|
clear() {
|
|
72
|
-
this.components
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Get registry stats
|
|
77
|
-
*/
|
|
78
|
-
stats() {
|
|
79
|
-
const types = {};
|
|
80
|
-
this.components.forEach(comp => {
|
|
81
|
-
const type = comp.constructor.name;
|
|
82
|
-
types[type] = (types[type] || 0) + 1;
|
|
83
|
-
});
|
|
84
|
-
return {
|
|
85
|
-
total: this.components.size,
|
|
86
|
-
types
|
|
87
|
-
};
|
|
93
|
+
this.components = [];
|
|
94
|
+
stateHistory.clear();
|
|
88
95
|
}
|
|
89
96
|
}
|
|
90
|
-
// Global singleton instance
|
|
91
97
|
export const registry = new ComponentRegistry();
|
|
92
|
-
// Expose
|
|
98
|
+
// ✅ Expose lean console interface
|
|
93
99
|
if (typeof window !== 'undefined') {
|
|
94
|
-
window.
|
|
95
|
-
|
|
100
|
+
window._jux = {
|
|
101
|
+
/**
|
|
102
|
+
* Get component by index or ID
|
|
103
|
+
* @example
|
|
104
|
+
* const h = _jux.get(0) // Get first component
|
|
105
|
+
* const h = _jux.get('hero-1') // Get by ID
|
|
106
|
+
* h.state.title = 'New Title' // Direct mutation
|
|
107
|
+
* h.rollback() // Undo last change
|
|
108
|
+
*/
|
|
109
|
+
get: (indexOrId) => registry.get(indexOrId),
|
|
110
|
+
/**
|
|
111
|
+
* List all components with indices
|
|
112
|
+
* @example
|
|
113
|
+
* _jux.list()
|
|
114
|
+
* // [0] hero-1 → Hero
|
|
115
|
+
* // [1] nav-main → Nav
|
|
116
|
+
*/
|
|
96
117
|
list: () => registry.list(),
|
|
97
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Show component tree (state, history, events, syncs)
|
|
120
|
+
* @example
|
|
121
|
+
* _jux.tree() // Show all
|
|
122
|
+
* _jux.tree(0) // Show first component
|
|
123
|
+
* _jux.tree('hero-1') // Show specific component
|
|
124
|
+
*/
|
|
125
|
+
tree: (indexOrId) => registry.tree(indexOrId),
|
|
126
|
+
/**
|
|
127
|
+
* Get all components
|
|
128
|
+
*/
|
|
98
129
|
all: () => registry.all(),
|
|
99
|
-
|
|
100
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Clear all components and history
|
|
132
|
+
*/
|
|
101
133
|
clear: () => registry.clear(),
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return jux[type](id, options);
|
|
110
|
-
},
|
|
111
|
-
// Debug helper
|
|
112
|
-
debug: (id) => {
|
|
113
|
-
const comp = registry.get(id);
|
|
114
|
-
if (!comp) {
|
|
115
|
-
console.error(`Component "${id}" not found`);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
console.group(`🔍 Component: ${id}`);
|
|
119
|
-
console.log('Type:', comp.constructor.name);
|
|
120
|
-
console.log('State:', comp.state);
|
|
121
|
-
console.log('Props:', comp.props);
|
|
122
|
-
console.log('Container:', comp.container);
|
|
123
|
-
console.log('Instance:', comp);
|
|
124
|
-
console.groupEnd();
|
|
134
|
+
/**
|
|
135
|
+
* Access global state history
|
|
136
|
+
*/
|
|
137
|
+
history: {
|
|
138
|
+
stats: () => stateHistory.getStats(),
|
|
139
|
+
timeline: () => stateHistory.getTimeline(),
|
|
140
|
+
clear: () => stateHistory.clear()
|
|
125
141
|
}
|
|
126
142
|
};
|
|
127
143
|
console.log(`
|
|
128
|
-
🎨
|
|
144
|
+
🎨 JUX DevTools Ready!
|
|
145
|
+
|
|
146
|
+
Quick Commands:
|
|
147
|
+
_jux.list() List all components with indices
|
|
148
|
+
_jux.tree() Show component tree (state, history, events)
|
|
149
|
+
_jux.get(0) Get first component
|
|
150
|
+
_jux.get('hero-1') Get component by ID
|
|
129
151
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
__jux.stats() Show registry statistics
|
|
137
|
-
__jux.debug('id') Debug component details
|
|
138
|
-
__jux.create('hero', 'h1', {...}) Create component from console
|
|
152
|
+
Direct Manipulation:
|
|
153
|
+
const h = _jux.get(0)
|
|
154
|
+
h.state.title = 'New!' Mutate state directly
|
|
155
|
+
h.rollback() Undo last change
|
|
156
|
+
h.rollforward() Redo change
|
|
157
|
+
h.timeline() View full history
|
|
139
158
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
h.hide()
|
|
144
|
-
h.show()
|
|
159
|
+
History:
|
|
160
|
+
_jux.history.stats() Global statistics
|
|
161
|
+
_jux.history.timeline() Complete timeline
|
|
145
162
|
`);
|
|
146
163
|
}
|