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/aicontext.md +1403 -0
- package/aiguide.md +589 -0
- package/package.json +3 -1
- package/src/components/textarea/textarea.ts +2 -2
- package/src/core/core_application.ts +1 -0
- package/src/core/core_dom.ts +2 -1
- package/src/x4tsx.d.ts +2 -1
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.
|
|
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.
|
|
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
|
|
package/src/core/core_dom.ts
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
27
|
+
ref?: [ owner: Box<any, any>, name: string ];
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
}
|