x4js 2.3.8 → 2.3.10

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/aiguide.md ADDED
@@ -0,0 +1,589 @@
1
+ # x4js — AI Guide
2
+
3
+ This document explains how to write idiomatic x4 code.
4
+ This is not a suggestion but an imperative rule.
5
+
6
+ For exact classes, properties and method signatures, always use `aicontext.md` or inspect the current x4 TypeScript sources.
7
+
8
+ **Do not invent x4 APIs.**
9
+
10
+ ## 1. General rule
11
+
12
+ Use the simplest tool that fits.
13
+
14
+ x4 deliberately has a small application model. Do not introduce abstractions simply because they are common in other frameworks.
15
+
16
+ Prefer:
17
+
18
+ - TypeScript modules and imports
19
+ - classes when identity and lifecycle are useful
20
+ - plain objects for application data
21
+ - `State` for observable application state
22
+ - local events for things that happened locally
23
+ - `GlobalEvent` for application-wide or distributed messages
24
+ - `DataStore` for specialized tabular data
25
+ - persistent `Component` objects backed by the real DOM
26
+ - CSS and CSS variables for presentation and theming
27
+ - JSX only when it makes a complex component tree easier to read
28
+
29
+ Avoid introducing by default:
30
+
31
+ - dependency injection
32
+ - repositories
33
+ - controllers
34
+ - command buses
35
+ - binding frameworks
36
+ - multiple application stores
37
+ - wrapper layers around native browser APIs
38
+ - React-style component architecture
39
+
40
+ Before creating an abstraction, check whether TypeScript, JavaScript, the browser, or x4 already solves the problem directly.
41
+
42
+ ---
43
+
44
+ ## 2. Mental model
45
+
46
+ The main concepts are deliberately few.
47
+
48
+ ### Component
49
+
50
+ A `Component` is a persistent TypeScript object associated with a real DOM element.
51
+
52
+ Use a `Component` when something has UI, DOM, lifecycle or component events.
53
+
54
+ Components are not temporary render descriptions.
55
+
56
+ Do not reason in terms of virtual DOM, reconciliation or repeatedly rendering component functions.
57
+
58
+ Components are persistent objects. When the UI changes, use their public API to update the existing instances rather than recreating them as render descriptions.
59
+
60
+ ### State
61
+
62
+ `State` describes what currently **is**.
63
+
64
+ Use it for mutable observable application state.
65
+
66
+ ```ts id="5phd4r"
67
+ const state = makeState({
68
+ selectedDeviceId: "",
69
+ connected: false
70
+ });
71
+ ```
72
+
73
+ State remains ordinary property-oriented application data.
74
+
75
+ Do not create a specialized store abstraction around State unless the application has a demonstrated need for one.
76
+
77
+ ### Events
78
+
79
+ Events describe what **happened**.
80
+
81
+ Use component/local events for communication between nearby objects.
82
+
83
+ For a simple event payload, `context` can carry the relevant identity or value when appropriate.
84
+
85
+ Do not put transient actions into State merely to trigger behavior.
86
+
87
+ ### GlobalEvent
88
+
89
+ Use `GlobalEvent` for application-wide messages.
90
+
91
+ A GlobalEvent may also be transported between processes, clients or a server.
92
+
93
+ Views should not care how a GlobalEvent is transported.
94
+
95
+ In particular, do not expose WebSocket details to UI components merely because WebSocket is used as the transport.
96
+
97
+ ### DataStore
98
+
99
+ Use `DataStore` for structured tabular data, especially components such as `Gridview` and `Spreadsheet`.
100
+
101
+ Do not use a DataStore as the general application State.
102
+
103
+ ---
104
+
105
+ ## 3. Component construction
106
+
107
+ For an application component derived from an x4 component, prefer:
108
+
109
+ ```ts id="wx4z2p"
110
+ interface DeviceViewProps extends ComponentProps {
111
+ device: Device;
112
+ }
113
+
114
+ class DeviceView extends VBox<DeviceViewProps> {
115
+ constructor(props: DeviceViewProps) {
116
+ super(props);
117
+
118
+ this.setContent([
119
+ // ...
120
+ ]);
121
+ }
122
+ }
123
+ ```
124
+
125
+ Pass the component props to `super(props)`.
126
+
127
+ Do not automatically generate:
128
+
129
+ ```ts id="y7mgvi"
130
+ super();
131
+ ```
132
+
133
+ when the component expects props.
134
+
135
+ For derived application components, prefer building the component's main content explicitly after `super(props)`.
136
+
137
+ Ordinary nested x4 components may naturally use their `content` property where convenient.
138
+
139
+ ---
140
+
141
+ ## 4. References
142
+
143
+ Follow the existing x4 `refs` conventions.
144
+
145
+ Do not invent references that have not actually been assigned.
146
+
147
+ For example, do not generate code that later uses:
148
+
149
+ ```ts id="6k48vt"
150
+ this.refs.temperature
151
+ ```
152
+
153
+ unless that reference was actually created according to the component's ref convention.
154
+
155
+ When no later access is required, no reference is necessary.
156
+
157
+ ---
158
+
159
+ ## 5. DOM usage
160
+
161
+ x4 uses the real browser DOM internally.
162
+
163
+ Each `Component` is a persistent TypeScript object associated with a real DOM element.
164
+
165
+ Application code should normally work with `Component` objects and their APIs, not manipulate DOM elements directly.
166
+
167
+ Direct DOM access is possible, but should be rare.
168
+
169
+ Use it only when a browser API or a specific low-level operation cannot be expressed cleanly through the existing x4 API.
170
+
171
+ Do not generate direct DOM manipulation when an x4 `Component` method already provides the required operation.
172
+
173
+ In normal x4 application code, prefer:
174
+
175
+ ```ts id="2dkh09"
176
+ label.setText("Ready");
177
+ button.setDisabled(true);
178
+ container.setContent([...]);
179
+ ```
180
+
181
+ rather than manipulating the corresponding DOM elements.
182
+
183
+ The absence of a virtual DOM does **not** mean that application code is expected to manipulate the DOM manually.
184
+
185
+ The normal model is:
186
+
187
+ ```text id="fqepqp"
188
+ Application code
189
+ ↓
190
+ Component objects
191
+ ↓
192
+ Real DOM
193
+ ```
194
+
195
+ ---
196
+
197
+ ## 6. Objects vs JSX
198
+
199
+ Both are valid x4.
200
+
201
+ Object construction:
202
+
203
+ ```ts id="ubp2j6"
204
+ this.setContent([
205
+ new Label({ text: "Temperature" }),
206
+ new Gauge({ min: 0, max: 100 }),
207
+ new Button({ label: "Restart" })
208
+ ]);
209
+ ```
210
+
211
+ JSX may be preferable for a complicated tree.
212
+
213
+ JSX in x4 is construction syntax.
214
+
215
+ It does not imply a virtual DOM, reconciliation, functional rendering or a React-style application architecture.
216
+
217
+ Do not convert object-oriented x4 code to JSX merely because JSX is available.
218
+
219
+ Do not avoid JSX when it clearly improves readability.
220
+
221
+ The runtime model remains the same in both cases.
222
+
223
+ ---
224
+
225
+ ## 7. State usage
226
+
227
+ State is mutable.
228
+
229
+ Prefer direct, readable mutations:
230
+
231
+ ```ts id="8qpf2j"
232
+ state.selectedDeviceId = device.id;
233
+ state.connected = true;
234
+ ```
235
+
236
+ Do not introduce reducers, immutable update helpers or action objects merely to modify State.
237
+
238
+ Watch State when code genuinely needs to react to state changes.
239
+
240
+ Keep observation simple.
241
+
242
+ Do not create elaborate nested watcher abstractions merely to avoid observing a root State.
243
+
244
+ State answers:
245
+
246
+ > What is the current application state?
247
+
248
+ It should not become an event bus.
249
+
250
+ ---
251
+
252
+ ## 8. Events
253
+
254
+ Use events to report occurrences.
255
+
256
+ A child component can report that the user requested an operation, while its owner decides what the operation means.
257
+
258
+ Prefer explicit component ownership and events over introducing controllers or a command architecture.
259
+
260
+ Use typed event structures when the payload has meaningful structure.
261
+
262
+ For simple contextual information, use the existing `CoreEvent.context` mechanism when appropriate.
263
+
264
+ State and events have different roles:
265
+
266
+ ```text id="f4gvwo"
267
+ State → what is
268
+ Event → what happened
269
+ ```
270
+
271
+ Do not use State as a replacement for events.
272
+
273
+ Do not use events as a replacement for persistent application state.
274
+
275
+ ---
276
+
277
+ ## 9. GlobalEvent
278
+
279
+ Use `GlobalEvent` for messages whose scope is the application or distributed system rather than a local component relationship.
280
+
281
+ Global messages should normally use stable application-level names, for example:
282
+
283
+ ```text id="5msmgk"
284
+ device.created
285
+ device.updated
286
+ device.deleted
287
+ device.telemetry
288
+ ```
289
+
290
+ For CRUD-style notifications, sending identity can be sufficient:
291
+
292
+ ```ts id="wz34qs"
293
+ { id: deviceId }
294
+ ```
295
+
296
+ The receiver can obtain the authoritative object through the application's model/API.
297
+
298
+ For high-frequency realtime information such as telemetry, carrying the actual data can be appropriate.
299
+
300
+ Do not force every GlobalEvent into the same payload strategy.
301
+
302
+ Most importantly:
303
+
304
+ > GlobalEvent represents the message, not its transport.
305
+
306
+ A view should normally not contain WebSocket-specific logic.
307
+
308
+ Whether a message is local, server/client or client/client should not change the view architecture.
309
+
310
+ ---
311
+
312
+ ## 10. Application models and server access
313
+
314
+ x4 does not require dependency injection, repositories or controllers.
315
+
316
+ Normal TypeScript modules and singletons are acceptable.
317
+
318
+ For example:
319
+
320
+ ```ts id="fdjmdv"
321
+ class DeviceModel {
322
+ // application-specific server operations
323
+ }
324
+
325
+ export const deviceModel = new DeviceModel();
326
+ ```
327
+
328
+ A model may encapsulate server access directly.
329
+
330
+ Keep responsibilities simple:
331
+
332
+ ```text id="t39sbp"
333
+ Model obtains or modifies domain data
334
+ State represents current application state
335
+ Component presents that state
336
+ Events communicate local occurrences
337
+ GlobalEvent communicates application-wide occurrences
338
+ ```
339
+
340
+ Do not add additional layers unless they solve an actual problem.
341
+
342
+ ---
343
+
344
+ ## 11. Lists and trees
345
+
346
+ `ListItem.data` can contain the corresponding business object.
347
+
348
+ When the object naturally belongs to the item, prefer:
349
+
350
+ ```ts id="esvskx"
351
+ {
352
+ id: device.id,
353
+ text: device.name,
354
+ data: device
355
+ }
356
+ ```
357
+
358
+ over creating an additional `id -> object` map without need.
359
+
360
+ Remember that selection semantics can differ between components.
361
+
362
+ Do not assume `Treeview`, `Listbox`, `Gridview` and `Spreadsheet` return the same kind of selection.
363
+
364
+ Check the current API.
365
+
366
+ ---
367
+
368
+ ## 12. Gridview and DataStore
369
+
370
+ `Gridview` is backed by a `DataStore`.
371
+
372
+ Use the DataStore/DataView model for grid data rather than turning general application State into a tabular store.
373
+
374
+ A `GridColumn` has its own exact contract.
375
+
376
+ Do not guess column properties, renderer signatures or selection types.
377
+
378
+ Check `aicontext.md` or the current source before generating Gridview code.
379
+
380
+ `DataStore` is a specialized tool, not a mandatory application architecture.
381
+
382
+ For very large remote datasets, do not assume loading the complete dataset into a local DataStore is appropriate.
383
+
384
+ ---
385
+
386
+ ## 13. Forms
387
+
388
+ Use `Form` as a form container and field discovery/validation mechanism.
389
+
390
+ Do not build a second binding framework around it by default.
391
+
392
+ `TextEdit` is useful for normal labelled fields.
393
+
394
+ Use raw `Input` when the lower-level control is what is actually needed.
395
+
396
+ Keep server/domain models separate from form presentation.
397
+
398
+ ---
399
+
400
+ ## 14. Dialogs
401
+
402
+ Prefer composition over subclassing `Dialog` when composition is sufficient.
403
+
404
+ For normal forms, build a `Dialog` containing a `Form` and the appropriate controls.
405
+
406
+ Use the actual Dialog and Button APIs documented by x4.
407
+
408
+ Do not invent generic modal APIs learned from other frameworks.
409
+
410
+ When asynchronous validation or saving must decide whether a dialog closes, check the exact behavior of `show`, `showAsync` and `btnclick` before choosing the implementation.
411
+
412
+ ---
413
+
414
+ ## 15. Long operations
415
+
416
+ Before inventing a task/progress abstraction, check existing x4 components.
417
+
418
+ For operations requiring progress text, percentage and error reporting, `ProgressionBox` already provides application-level UI for that purpose.
419
+
420
+ Use native `Promise` and `async` mechanisms for asynchronous execution unless another abstraction is genuinely required.
421
+
422
+ ---
423
+
424
+ ## 16. Timers and cleanup
425
+
426
+ `CoreElement` already provides named timers.
427
+
428
+ Use the exact timer API:
429
+
430
+ ```ts id="paz1yj"
431
+ this.setTimeout("refresh", 500, () => {
432
+ // ...
433
+ });
434
+
435
+ this.clearTimeout("refresh");
436
+ ```
437
+
438
+ and similarly for named intervals.
439
+
440
+ Do not invent APIs such as `setTimer`.
441
+
442
+ Starting a timer with an existing name replaces the previous timer of that name.
443
+
444
+ Use the lifecycle and cleanup facilities already provided by `CoreElement` and `Component`.
445
+
446
+ ---
447
+
448
+ ## 17. Lifecycle
449
+
450
+ Component removal participates in the x4 lifecycle and cleanup system.
451
+
452
+ Do not assume that removing and later reinserting a component is equivalent to hiding and showing it.
453
+
454
+ For temporary visibility changes, use the component visibility mechanisms.
455
+
456
+ Use the existing lifecycle rather than manually reproducing cleanup behavior in application code.
457
+
458
+ ---
459
+
460
+ ## 18. CSS and themes
461
+
462
+ x4 components use CSS and CSS variables extensively.
463
+
464
+ Use the existing CSS/theming mechanisms.
465
+
466
+ Do not introduce a JavaScript theme abstraction simply to mirror CSS variables.
467
+
468
+ Presentation belongs in CSS when CSS already solves the problem.
469
+
470
+ ---
471
+
472
+ ## 19. Browser and TypeScript capabilities
473
+
474
+ Do not wrap native capabilities merely for architectural symmetry.
475
+
476
+ Examples include:
477
+
478
+ - TypeScript modules
479
+ - JavaScript objects and classes
480
+ - Promise
481
+ - async/await
482
+ - CSS
483
+ - browser APIs
484
+ - standard language mechanisms
485
+
486
+ An x4 abstraction is useful when it adds concrete application value, not simply because an abstraction layer could exist.
487
+
488
+ This does not mean application code should bypass x4 Components to manipulate DOM directly.
489
+
490
+ For UI, use the x4 Component API in normal application code.
491
+
492
+ ---
493
+
494
+ ## 20. Source inspection
495
+
496
+ The npm package distributes the x4 TypeScript sources.
497
+
498
+ When an API is unclear:
499
+
500
+ 1. check `aicontext.md`;
501
+ 2. inspect the installed x4 TypeScript source;
502
+ 3. only then generate code.
503
+
504
+ The installed source can normally be found under the `x4js` package in `node_modules`.
505
+
506
+ Never infer an x4 API from React, Vue, Angular or another framework.
507
+
508
+ Never invent a plausible-looking x4 method.
509
+
510
+ Exact source code is preferable to guessing.
511
+
512
+ ---
513
+
514
+ ## 21. AI error classification
515
+
516
+ When generated x4 code is wrong, determine why before proposing framework changes.
517
+
518
+ There are three main possibilities:
519
+
520
+ 1. documentation was insufficient;
521
+ 2. the x4 API was ambiguous;
522
+ 3. the AI made an error despite sufficient information.
523
+
524
+ Do not modify x4 architecture merely to accommodate habits learned from other frameworks.
525
+
526
+ Improve documentation when documentation is the actual problem.
527
+
528
+ Improve an API when the API itself is genuinely unclear.
529
+
530
+ Otherwise fix the generated code.
531
+
532
+ ---
533
+
534
+ ## 22. What good x4 code should look like
535
+
536
+ Good x4 application code should generally be:
537
+
538
+ - ordinary TypeScript
539
+ - explicit
540
+ - easy to follow
541
+ - directly connected to the application's domain
542
+ - light on framework ceremony
543
+ - unsurprising when read without specialized tooling
544
+
545
+ A typical application relationship may look like:
546
+
547
+ ```text id="9sj16n"
548
+ Domain data
549
+ ↓
550
+ Model
551
+ ↓
552
+ State
553
+ ↓
554
+ Components
555
+ ```
556
+
557
+ Interactions remain similarly direct:
558
+
559
+ ```text id="v1k1uv"
560
+ User interaction
561
+ ↓
562
+ Component event
563
+ ↓
564
+ Application operation
565
+ ↓
566
+ State change / GlobalEvent
567
+ ↓
568
+ Existing Components update
569
+ ```
570
+
571
+ These diagrams are guidelines, not mandatory layers.
572
+
573
+ Do not introduce an object merely to fill one of the boxes.
574
+
575
+ The goal is not to use every x4 feature.
576
+
577
+ The goal is to build the application with the smallest set of mechanisms that keeps the code clear.
578
+
579
+ ---
580
+
581
+ ## Final rule
582
+
583
+ When generating x4 code:
584
+
585
+ > Prefer the simplest valid x4 solution that can be understood by reading the TypeScript.
586
+
587
+ If the solution requires several new architectural concepts to solve a simple application problem, reconsider it.
588
+
589
+ If the exact x4 API is uncertain, check the documentation or source instead of guessing.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x4js",
3
- "version": "2.3.8",
3
+ "version": "2.3.10",
4
4
  "type": "module",
5
5
  "main": "src/x4.ts",
6
6
  "module": "src/x4.ts",
@@ -21,6 +21,8 @@
21
21
  "src",
22
22
  "bin",
23
23
  "cli",
24
+ "aicontext.md",
25
+ "aiguide.md",
24
26
  "README.md",
25
27
  "LICENSE"
26
28
  ],
@@ -50,7 +50,7 @@ export class SimpleTextArea extends Component<TextAreaProps> {
50
50
 
51
51
  this.setAttribute( "name", props.name );
52
52
  if( props.value ) {
53
- this.setAttribute( "value", props.value+'' );
53
+ this.setText( props.value+'' );
54
54
  }
55
55
 
56
56
  if( props.resize!==undefined ) {
@@ -119,7 +119,7 @@ export class TextArea extends VBox {
119
119
 
120
120
  this.setContent( [
121
121
  new Label( { text: props.label }),
122
- this._input = new SimpleTextArea( { label,value,resize,readonly,trim } )
122
+ this._input = new SimpleTextArea( { label,value,resize,readonly,trim,name } )
123
123
  ])
124
124
  }
125
125
 
@@ -130,6 +130,7 @@ export class Application<E extends ApplicationEvents = ApplicationEvents> extend
130
130
  const ev = document.querySelector( mountPoint );
131
131
  if( ev ) {
132
132
  ev.appendChild( this.mainview.dom );
133
+ this.mounted = true;
133
134
  }
134
135
  }
135
136
  }
@@ -163,7 +163,8 @@ export function addEvent( node: Node, name: string, handler: DOMEventHandler, pr
163
163
 
164
164
  if( !mutObserver ) {
165
165
  mutObserver = new MutationObserver( observeMutation )
166
- mutObserver.observe( document.body, {childList: true,subtree: true} );
166
+ //document.documentElement exists even when document.body is not present
167
+ mutObserver.observe( document.documentElement, {childList: true,subtree: true} );
167
168
  }
168
169
 
169
170
  if( name=="removed" || name=="created" ) {
package/src/x4tsx.d.ts CHANGED
@@ -14,6 +14,7 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
+ import { Box } from './components/boxes/boxes.js';
17
18
  export { }
18
19
 
19
20
  declare global {
@@ -23,7 +24,7 @@ declare global {
23
24
  }
24
25
 
25
26
  interface IntrinsicClassAttributes<T> {
26
- ref?: [ owner: object, name: string ];
27
+ ref?: [ owner: Box<any, any>, name: string ];
27
28
  }
28
29
  }
29
30
  }