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.
@@ -1,164 +1,193 @@
1
1
  /**
2
- * Global component registry for debugging and console access
3
- * All rendered components are automatically registered here
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
 
12
6
  import { BaseComponent } from './base/BaseComponent.js';
7
+ import { stateHistory } from './history/StateHistory.js';
13
8
 
14
9
  class ComponentRegistry {
15
- private components: Map<string, BaseComponent<any>> = new Map();
10
+ private components: BaseComponent<any>[] = [];
16
11
 
17
- /**
18
- * Register a component instance
19
- */
20
12
  register(component: BaseComponent<any>): void {
21
- this.components.set(component._id, component);
22
- console.debug(`[Jux Registry] Registered: ${component._id}`);
13
+ // Avoid duplicates
14
+ if (!this.components.find(c => c._id === component._id)) {
15
+ this.components.push(component);
16
+ }
23
17
  }
24
18
 
25
- /**
26
- * Unregister a component
27
- */
28
19
  unregister(id: string): void {
29
- this.components.delete(id);
30
- console.debug(`[Jux Registry] Unregistered: ${id}`);
20
+ this.components = this.components.filter(c => c._id !== id);
31
21
  }
32
22
 
33
23
  /**
34
- * Get a component by ID
24
+ * Get component by index or ID
35
25
  */
36
- get<T extends BaseComponent<any>>(id: string): T | undefined {
37
- return this.components.get(id) as T;
26
+ get(indexOrId: number | string): BaseComponent<any> | undefined {
27
+ if (typeof indexOrId === 'number') {
28
+ return this.components[indexOrId];
29
+ }
30
+ return this.components.find(c => c._id === indexOrId);
38
31
  }
39
32
 
40
33
  /**
41
- * Check if component exists
34
+ * Print indexed list to console
42
35
  */
43
- has(id: string): boolean {
44
- return this.components.has(id);
36
+ list(): void {
37
+ if (this.components.length === 0) {
38
+ console.log('šŸ“­ No components registered');
39
+ return;
40
+ }
41
+
42
+ console.log('\nšŸ“‹ Registered Components:\n');
43
+ this.components.forEach((comp, idx) => {
44
+ console.log(` [${idx}] ${comp._id} → ${comp.constructor.name}`);
45
+ });
46
+ console.log(`\nšŸ’” Access via: _jux.get(${0}) or _jux.get('${this.components[0]._id}')\n`);
45
47
  }
46
48
 
47
49
  /**
48
- * List all registered component IDs
50
+ * Show component tree with state, history, events
49
51
  */
50
- list(): string[] {
51
- return Array.from(this.components.keys());
52
+ tree(indexOrId?: number | string): void {
53
+ let comp: BaseComponent<any> | undefined;
54
+
55
+ if (indexOrId === undefined) {
56
+ // Show all components
57
+ this.components.forEach((c, idx) => this._printTree(c, idx));
58
+ return;
59
+ }
60
+
61
+ comp = this.get(indexOrId);
62
+ if (!comp) {
63
+ console.error(`āŒ Component not found: ${indexOrId}`);
64
+ return;
65
+ }
66
+
67
+ this._printTree(comp, typeof indexOrId === 'number' ? indexOrId : undefined);
52
68
  }
53
69
 
54
- /**
55
- * Find components by partial ID match
56
- */
57
- find(pattern: string): BaseComponent<any>[] {
58
- const regex = new RegExp(pattern, 'i');
59
- return Array.from(this.components.values())
60
- .filter(comp => regex.test(comp._id));
70
+ private _printTree(comp: BaseComponent<any>, index?: number): void {
71
+ const idx = index !== undefined ? `[${index}]` : '';
72
+ const stateChanges = stateHistory.getComponentHistory(comp._id);
73
+ const events = stateHistory.getComponentEvents(comp._id);
74
+ const syncCount = (comp as any)._syncBindings?.length || 0;
75
+ const bindCount = (comp as any)._bindings?.length || 0;
76
+
77
+ console.group(`🌳 ${idx} ${comp._id} (${comp.constructor.name})`);
78
+
79
+ console.log('šŸ“Š State:', comp.state);
80
+
81
+ if (stateChanges.length > 0) {
82
+ console.log(`šŸ“œ History: ${stateChanges.length} changes`);
83
+ console.log(' Last 3:', stateChanges.slice(-3).map(s =>
84
+ `${s.property}: ${s.oldValue} → ${s.newValue}`
85
+ ));
86
+ }
87
+
88
+ if (syncCount > 0) {
89
+ console.log(`šŸ”— Syncs: ${syncCount} active`);
90
+ }
91
+
92
+ if (bindCount > 0 || events.length > 0) {
93
+ console.log(`⚔ Events: ${bindCount} binds, ${events.length} fired`);
94
+ }
95
+
96
+ console.log(`\nšŸ’” Commands:`);
97
+ console.log(` _jux.get(${index ?? `'${comp._id}'`}).state.prop = value`);
98
+ console.log(` _jux.get(${index ?? `'${comp._id}'`}).rollback()`);
99
+ console.log(` _jux.get(${index ?? `'${comp._id}'`}).timeline()`);
100
+
101
+ console.groupEnd();
61
102
  }
62
103
 
63
104
  /**
64
105
  * Get all components
65
106
  */
66
107
  all(): BaseComponent<any>[] {
67
- return Array.from(this.components.values());
68
- }
69
-
70
- /**
71
- * Get components by type (constructor name)
72
- */
73
- byType(typeName: string): BaseComponent<any>[] {
74
- return Array.from(this.components.values())
75
- .filter(comp => comp.constructor.name === typeName);
108
+ return this.components;
76
109
  }
77
110
 
78
111
  /**
79
- * Clear all registered components
112
+ * Clear registry
80
113
  */
81
114
  clear(): void {
82
- this.components.clear();
83
- console.debug('[Jux Registry] Cleared all components');
84
- }
85
-
86
- /**
87
- * Get registry stats
88
- */
89
- stats(): { total: number; types: Record<string, number> } {
90
- const types: Record<string, number> = {};
91
-
92
- this.components.forEach(comp => {
93
- const type = comp.constructor.name;
94
- types[type] = (types[type] || 0) + 1;
95
- });
96
-
97
- return {
98
- total: this.components.size,
99
- types
100
- };
115
+ this.components = [];
116
+ stateHistory.clear();
101
117
  }
102
118
  }
103
119
 
104
- // Global singleton instance
105
120
  export const registry = new ComponentRegistry();
106
121
 
107
- // Expose to window for console access
122
+ // āœ… Expose lean console interface
108
123
  if (typeof window !== 'undefined') {
109
- (window as any).__jux = {
110
- get: (id: string) => registry.get(id),
124
+ (window as any)._jux = {
125
+ /**
126
+ * Get component by index or ID
127
+ * @example
128
+ * const h = _jux.get(0) // Get first component
129
+ * const h = _jux.get('hero-1') // Get by ID
130
+ * h.state.title = 'New Title' // Direct mutation
131
+ * h.rollback() // Undo last change
132
+ */
133
+ get: (indexOrId: number | string) => registry.get(indexOrId),
134
+
135
+ /**
136
+ * List all components with indices
137
+ * @example
138
+ * _jux.list()
139
+ * // [0] hero-1 → Hero
140
+ * // [1] nav-main → Nav
141
+ */
111
142
  list: () => registry.list(),
112
- find: (pattern: string) => registry.find(pattern),
143
+
144
+ /**
145
+ * Show component tree (state, history, events, syncs)
146
+ * @example
147
+ * _jux.tree() // Show all
148
+ * _jux.tree(0) // Show first component
149
+ * _jux.tree('hero-1') // Show specific component
150
+ */
151
+ tree: (indexOrId?: number | string) => registry.tree(indexOrId),
152
+
153
+ /**
154
+ * Get all components
155
+ */
113
156
  all: () => registry.all(),
114
- byType: (type: string) => registry.byType(type),
115
- stats: () => registry.stats(),
157
+
158
+ /**
159
+ * Clear all components and history
160
+ */
116
161
  clear: () => registry.clear(),
117
162
 
118
- // Factory helpers for creating components from console
119
- create: (type: string, id: string, options?: any) => {
120
- const jux = (window as any).jux;
121
- if (!jux || !jux[type]) {
122
- console.error(`Component type "${type}" not found`);
123
- return null;
124
- }
125
- return jux[type](id, options);
126
- },
127
-
128
- // Debug helper
129
- debug: (id: string) => {
130
- const comp = registry.get(id);
131
- if (!comp) {
132
- console.error(`Component "${id}" not found`);
133
- return;
134
- }
135
- console.group(`šŸ” Component: ${id}`);
136
- console.log('Type:', comp.constructor.name);
137
- console.log('State:', comp.state);
138
- console.log('Props:', comp.props);
139
- console.log('Container:', comp.container);
140
- console.log('Instance:', comp);
141
- console.groupEnd();
163
+ /**
164
+ * Access global state history
165
+ */
166
+ history: {
167
+ stats: () => stateHistory.getStats(),
168
+ timeline: () => stateHistory.getTimeline(),
169
+ clear: () => stateHistory.clear()
142
170
  }
143
171
  };
144
172
 
145
173
  console.log(`
146
- šŸŽØ Jux DevTools Available!
147
-
148
- Available commands:
149
- __jux.get('id') Get component instance
150
- __jux.list() List all component IDs
151
- __jux.find('pattern') Search components by ID
152
- __jux.all() Get all components
153
- __jux.byType('Hero') Get components by type
154
- __jux.stats() Show registry statistics
155
- __jux.debug('id') Debug component details
156
- __jux.create('hero', 'h1', {...}) Create component from console
157
-
158
- Example:
159
- const h = __jux.get('hero-1')
160
- h.state.title = 'Changed from console!'
161
- h.hide()
162
- h.show()
174
+ šŸŽØ JUX DevTools Ready!
175
+
176
+ Quick Commands:
177
+ _jux.list() List all components with indices
178
+ _jux.tree() Show component tree (state, history, events)
179
+ _jux.get(0) Get first component
180
+ _jux.get('hero-1') Get component by ID
181
+
182
+ Direct Manipulation:
183
+ const h = _jux.get(0)
184
+ h.state.title = 'New!' Mutate state directly
185
+ h.rollback() Undo last change
186
+ h.rollforward() Redo change
187
+ h.timeline() View full history
188
+
189
+ History:
190
+ _jux.history.stats() Global statistics
191
+ _jux.history.timeline() Complete timeline
163
192
  `);
164
193
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.28",
3
+ "version": "1.1.30",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",