x4js 2.0.28 → 2.0.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.
Files changed (70) hide show
  1. package/.vscode/launch.json +14 -0
  2. package/.vscode/settings.json +2 -0
  3. package/ai-comments.txt +97 -0
  4. package/demo/assets/house-light.svg +1 -0
  5. package/demo/assets/radio.svg +4 -0
  6. package/demo/index.html +12 -0
  7. package/demo/main.scss +23 -0
  8. package/demo/main.ts +324 -0
  9. package/demo/package.json +26 -0
  10. package/demo/scss.d.ts +4 -0
  11. package/demo/svg.d.ts +1 -0
  12. package/demo/tsconfig.json +14 -0
  13. package/lib/types/x4js.d.ts +0 -2374
  14. package/package.json +23 -47
  15. package/prepack.mjs +3 -0
  16. package/scripts/prepack.mjs +342 -0
  17. package/src/colors.scss +246 -0
  18. package/src/components/boxes/boxes.module.scss +1 -1
  19. package/src/components/boxes/boxes.ts +139 -28
  20. package/src/components/button/button.ts +80 -33
  21. package/src/components/combobox/combobox.ts +1 -1
  22. package/src/components/dialog/dialog.ts +4 -0
  23. package/src/components/gridview/gridview.ts +104 -6
  24. package/src/components/icon/icon.ts +42 -14
  25. package/src/components/input/input.ts +146 -74
  26. package/src/components/keyboard/keyboard.module.scss +1 -1
  27. package/src/components/keyboard/keyboard.ts +31 -9
  28. package/src/components/label/label.module.scss +9 -0
  29. package/src/components/label/label.ts +10 -6
  30. package/src/components/link/link.module.scss +44 -0
  31. package/src/components/link/link.ts +7 -1
  32. package/src/components/listbox/listbox.module.scss +18 -4
  33. package/src/components/listbox/listbox.ts +32 -12
  34. package/src/components/menu/menu.module.scss +14 -2
  35. package/src/components/menu/menu.ts +1 -1
  36. package/src/components/messages/messages.ts +13 -5
  37. package/src/components/panel/panel.module.scss +7 -0
  38. package/src/components/popup/popup.ts +14 -10
  39. package/src/components/propgrid/propgrid.ts +1 -1
  40. package/src/components/shared.scss +4 -0
  41. package/src/components/spreadsheet/spreadsheet.ts +81 -34
  42. package/src/components/tabs/tabs.module.scss +1 -0
  43. package/src/components/textarea/textarea.ts +8 -2
  44. package/src/components/textedit/textedit.ts +7 -0
  45. package/src/components/themes.scss +2 -0
  46. package/src/components/tooltips/tooltips.ts +15 -3
  47. package/src/core/component.ts +358 -162
  48. package/src/core/core_application.ts +129 -32
  49. package/src/core/core_colors.ts +382 -119
  50. package/src/core/core_data.ts +73 -86
  51. package/src/core/core_dom.ts +10 -0
  52. package/src/core/core_dragdrop.ts +32 -7
  53. package/src/core/core_element.ts +111 -4
  54. package/src/core/core_events.ts +48 -11
  55. package/src/core/core_i18n.ts +2 -0
  56. package/src/core/core_pdf.ts +454 -0
  57. package/src/core/core_router.ts +64 -5
  58. package/src/core/core_state.ts +1 -0
  59. package/src/core/core_styles.ts +11 -12
  60. package/src/core/core_svg.ts +346 -51
  61. package/src/core/core_tools.ts +105 -17
  62. package/src/x4.ts +1 -0
  63. package/src/x4tsx.d.ts +2 -1
  64. package/tsconfig.json +11 -0
  65. package/lib/README.txt +0 -20
  66. package/lib/cjs/x4.css +0 -1
  67. package/lib/cjs/x4.js +0 -2
  68. package/lib/esm/x4.css +0 -1
  69. package/lib/esm/x4.mjs +0 -2
  70. package/lib/styles/x4.css +0 -1
@@ -17,7 +17,7 @@
17
17
 
18
18
  import { EvChange } from './component';
19
19
  import { CoreElement } from './core_element';
20
- import { CoreEvent, EventCallback, EventMap, EventSource } from './core_events';
20
+ import { CoreEvent, EventMap, EventSource } from './core_events';
21
21
  import { isArray, isString } from './core_tools';
22
22
 
23
23
  export type DataRecordID = any;
@@ -80,24 +80,26 @@ function _getMetas( obj: object, create = true ) : MetaInfos {
80
80
  let mfld = Object.prototype.hasOwnProperty.call(ctor,metaFields) ? ctor[metaFields] : undefined;
81
81
 
82
82
  if( mfld===undefined ) {
83
- if( !create ) {
83
+ if( !create && ctor!=DataModel ) {
84
84
  console.assert( mfld!==undefined );
85
85
  }
86
86
 
87
87
  // construct our metas
88
88
  mfld = new MetaInfos( ctor.name );
89
89
 
90
- // merge with parent class metas
91
- let pctor = Object.getPrototypeOf(ctor);
92
- if( pctor!=DataModel ) {
93
- let pmetas = pctor[metaFields];
94
- mfld.fields = [...pmetas.fields, ...mfld.fields ]
95
-
96
- console.assert( mfld.id===undefined, 'cannot define mutiple record id' );
97
- if( !mfld.id ) {
98
- mfld.id = pmetas.id;
99
- }
100
- }
90
+ if( ctor!=DataModel ) { //<eco: allow addFields on DataModel
91
+ // merge with parent class metas
92
+ let pctor = Object.getPrototypeOf(ctor);
93
+ if( pctor!=DataModel ) {
94
+ let pmetas = pctor[metaFields];
95
+ mfld.fields = [...pmetas.fields, ...mfld.fields ]
96
+
97
+ console.assert( mfld.id===undefined, 'cannot define mutiple record id' );
98
+ if( !mfld.id ) {
99
+ mfld.id = pmetas.id;
100
+ }
101
+ }
102
+ }
101
103
 
102
104
  (obj.constructor as any)[metaFields] = mfld;
103
105
  }
@@ -249,7 +251,24 @@ export namespace data {
249
251
  * record model
250
252
  */
251
253
 
252
- export class DataModel {
254
+ export class DataModel<T = any> {
255
+
256
+ /**
257
+ * dynamic DataModel
258
+ */
259
+
260
+ addField( ...fields: FieldInfo[] ) {
261
+ if( fields.length==0 ) {
262
+ return;
263
+ }
264
+
265
+ let metas = _getMetas( this, false );
266
+ if( metas.fields.length==0 ) {
267
+ metas.id = fields[0].name;
268
+ }
269
+
270
+ metas.fields.push( ...fields );
271
+ }
253
272
 
254
273
  /**
255
274
  * MUST IMPLEMENT
@@ -309,8 +328,6 @@ export class DataModel {
309
328
 
310
329
  return rec as T;
311
330
  }
312
-
313
-
314
331
 
315
332
  /**
316
333
  * default unserializer
@@ -318,10 +335,10 @@ export class DataModel {
318
335
  * @returns a new Record
319
336
  */
320
337
 
321
- unSerialize(data: any, id?: DataRecordID ) : DataRecord {
338
+ unSerialize(data: any, id?: DataRecordID ) : DataRecord<T> {
322
339
 
323
340
  const fields = this.getFields();
324
- const rec = new DataRecord( );
341
+ const rec: any = {};
325
342
 
326
343
  fields.forEach( (sf) => {
327
344
  let value = data[sf.name];
@@ -457,63 +474,9 @@ export class DataModel {
457
474
  *
458
475
  */
459
476
 
460
- export class DataRecord {
461
- [ key: string ]: DataFieldValue;
462
-
463
- /*
464
- / **
465
- * @returns fields descriptors
466
- * /
467
-
468
- getFields(): FieldInfo[] {
469
- let metas = _getMetas( this, false );
470
- return metas.fields;
471
- }
472
-
473
-
474
-
475
- / **
476
- *
477
- * @param name
478
- * @param data
479
- * /
480
-
481
- setRaw( name: string, data: string ) {
482
- this[name] = data;
483
- }
484
-
485
-
486
-
487
- / **
488
- * set field value
489
- * @param name - field name
490
- * @param value - value to set
491
- * @example
492
- * record.set( 'field1', 7 );
493
- * /
494
-
495
- setField(name: string, value: any) {
496
- let fields = this.getFields( );
497
- let idx = fields.findIndex( fi => fi.name == name );
498
-
499
- if( idx < 0 ) {
500
- console.assert( false, 'unknown field: '+name);
501
- return;
502
- }
503
-
504
- let fld = fields[idx];
505
- if( fld.calc!==undefined ) {
506
- console.assert( false, 'cannot set calc field: '+name);
507
- return;
508
- }
509
-
510
- this.setRaw( fld.name, value );
511
- }
512
- */
513
-
514
-
515
- }
516
-
477
+ export type DataRecord<T = any> = Partial<T> & {
478
+ [key: string]: any;
479
+ };
517
480
 
518
481
  /**
519
482
  *
@@ -591,11 +554,11 @@ interface DataStoreEventMap extends EventMap {
591
554
  *
592
555
  */
593
556
 
594
- export class DataStore extends EventSource<DataStoreEventMap> {
557
+ export class DataStore<T = any> extends EventSource<DataStoreEventMap> {
595
558
 
596
- protected m_model: DataModel;
559
+ protected m_model: DataModel<T>;
597
560
  protected m_fields: FieldInfo[];
598
- protected m_records: DataRecord[];
561
+ protected m_records: DataRecord<T>[];
599
562
 
600
563
  protected m_proxy: DataProxy;
601
564
  protected m_rec_index: DataIndex;
@@ -648,7 +611,7 @@ export class DataStore extends EventSource<DataStoreEventMap> {
648
611
 
649
612
  public setData( records: any[] ) {
650
613
 
651
- const realRecords: DataRecord[] = new Array( records.length );
614
+ const realRecords: DataRecord<T>[] = new Array( records.length );
652
615
 
653
616
  records.forEach( (rec,idx) => {
654
617
  realRecords[idx] = this.m_model.unSerialize(rec);
@@ -697,11 +660,11 @@ export class DataStore extends EventSource<DataStoreEventMap> {
697
660
  * @param data
698
661
  */
699
662
 
700
- public append( rec: DataRecord | any ) {
663
+ public appendRaw( rec: T ) {
664
+ return this.append( this.m_model.unSerialize( rec ) );
665
+ }
701
666
 
702
- if( !(rec instanceof DataRecord) ) {
703
- rec = this.m_model.unSerialize( rec );
704
- }
667
+ public append( rec: DataRecord ) {
705
668
 
706
669
  const id = this.m_model.getID(rec);
707
670
  console.assert( id!==undefined );
@@ -797,12 +760,13 @@ export class DataStore extends EventSource<DataStoreEventMap> {
797
760
  return -1;
798
761
  }
799
762
 
763
+
800
764
  /**
801
765
  * return the record by it's id
802
766
  * @returns record or null
803
767
  */
804
768
 
805
- public getById(id: DataRecordID): DataRecord {
769
+ public getById(id: DataRecordID): DataRecord<T> {
806
770
  let idx = this.indexOfId( id );
807
771
  if( idx<0 ) {
808
772
  return null;
@@ -817,12 +781,12 @@ export class DataStore extends EventSource<DataStoreEventMap> {
817
781
  * @returns record or null
818
782
  */
819
783
 
820
- public getByIndex( index: number ): DataRecord {
784
+ public getByIndex( index: number ): DataRecord<T> {
821
785
  let idx = this.m_rec_index[index];
822
786
  return this._getRecord( idx );
823
787
  }
824
788
 
825
- private _getRecord( index: number ) : DataRecord {
789
+ private _getRecord( index: number ) : DataRecord<T> {
826
790
  return this.m_records[index] ?? null;
827
791
  }
828
792
 
@@ -1065,6 +1029,29 @@ export class DataStore extends EventSource<DataStoreEventMap> {
1065
1029
  }
1066
1030
  }
1067
1031
 
1032
+ find( cb: ( rec: DataRecord ) => boolean ) {
1033
+ let result;
1034
+
1035
+ if( this.m_rec_index ) {
1036
+ result = this.m_rec_index.find( ri => {
1037
+ if( cb( this.m_records[ri] ) ) {
1038
+ return true;
1039
+ }
1040
+ });
1041
+ }
1042
+ else {
1043
+ result = this.m_records.findIndex( rec => {
1044
+ if( rec ) {
1045
+ if( cb( rec ) ) {
1046
+ return true;
1047
+ }
1048
+ }
1049
+ } );
1050
+ }
1051
+
1052
+ return result>=0 ? this.getByIndex(result) : null;
1053
+ }
1054
+
1068
1055
  export( ) {
1069
1056
  return this.m_records;
1070
1057
  }
@@ -93,7 +93,10 @@ function observeSize(entries: ResizeObserverEntry[]) {
93
93
  }
94
94
 
95
95
  /**
96
+ * Manually dispatches an event through the custom event system.
97
+ * Simulates bubbling unless the event type is in the unbubbleEvents list.
96
98
  *
99
+ * @param ev - The event to dispatch.
97
100
  */
98
101
 
99
102
  export function dispatchEvent(ev: Event) {
@@ -129,7 +132,14 @@ export function dispatchEvent(ev: Event) {
129
132
  }
130
133
 
131
134
  /**
135
+ * Registers an event handler for a specific node.
136
+ * Automatically initializes MutationObserver or ResizeObserver if special events
137
+ * ('created', 'removed', 'resized') are requested.
132
138
  *
139
+ * @param node - The target DOM node.
140
+ * @param name - The name of the event to listen for.
141
+ * @param handler - The function to call when the event occurs.
142
+ * @param prepend - Whether to prepend the handler to the list (default: false).
133
143
  */
134
144
 
135
145
  export function addEvent( node: Node, name: string, handler: DOMEventHandler, prepend = false ) {
@@ -27,8 +27,10 @@ interface DropInfo {
27
27
  type DropCallback = ( command: 'enter' | 'leave' | 'drag' | 'drop', el: Component, infos: DropInfo ) => void;
28
28
  type FilterCallback = ( el: Component, data: DataTransfer ) => boolean;
29
29
 
30
- /**
31
- *
30
+ /**
31
+ * Manages drag and drop operations within the application.
32
+ * This class handles the registration of draggable elements and drop targets,
33
+ * and orchestrates the visual feedback and event dispatching during drag operations.
32
34
  */
33
35
 
34
36
 
@@ -43,9 +45,13 @@ class DragManager {
43
45
  timer: any; // pb with name of settimeout return
44
46
 
45
47
  /**
46
- *
48
+ * Registers a component as a draggable element.
49
+ * This sets up DOM event listeners for `dragstart`, `drag`, and `dragend`
50
+ * to manage the drag operation, including creating a drag ghost and applying CSS classes.
51
+ *
52
+ * @param el - The component to make draggable.
47
53
  */
48
-
54
+ // TODO: Add support for custom drag data beyond 'text/string'.
49
55
  registerDraggableElement(el: Component) {
50
56
 
51
57
  el.addDOMEvent('dragstart', (ev: DragEvent) => {
@@ -78,7 +84,14 @@ class DragManager {
78
84
  }
79
85
 
80
86
  /**
81
- *
87
+ * Registers a component as a drop target.
88
+ * This sets up DOM event listeners for `dragenter`, `dragover`, `dragleave`, and `drop`.
89
+ * It uses a `DropCallback` to notify the component about drag events and an optional `FilterCallback`
90
+ * to determine if the target should accept the dragged item.
91
+ *
92
+ * @param el - The component to make a drop target.
93
+ * @param cb - The callback function to execute on drag events.
94
+ * @param filterCB - An optional callback to filter which draggable items can be dropped.
82
95
  */
83
96
 
84
97
  registerDropTarget(el: Component, cb: DropCallback, filterCB?: FilterCallback ) {
@@ -151,7 +164,11 @@ class DragManager {
151
164
  el.setInternalData( x_drag_cb, cb );
152
165
  }
153
166
 
154
- _startCheck() {
167
+ /**
168
+ * @internal
169
+ */
170
+
171
+ private _startCheck() {
155
172
 
156
173
  if (this.timer) {
157
174
  clearInterval(this.timer);
@@ -161,7 +178,11 @@ class DragManager {
161
178
  this.timer = setInterval( () => this._check(), 300 );
162
179
  }
163
180
 
164
- _check( ) {
181
+ /**
182
+ * @internal
183
+ */
184
+
185
+ private _check( ) {
165
186
 
166
187
  const leaving = ( x: Component ) => {
167
188
  x.removeClass('drop-over');
@@ -198,4 +219,8 @@ class DragManager {
198
219
  }
199
220
  }
200
221
 
222
+ /**
223
+ * Singleton instance of the DragManager for global access.
224
+ */
225
+
201
226
  export const dragManager = new DragManager();
@@ -16,10 +16,67 @@
16
16
 
17
17
  import { EventMap, EventSource } from './core_events';
18
18
 
19
+
19
20
  /**
20
- *
21
+ * CoreElement
22
+ *
23
+ * A lightweight base class that provides two orthogonal utilities commonly needed by UI
24
+ * or domain objects:
25
+ * 1) Named timers (wraps setTimeout / setInterval by name so they can be started, stopped,
26
+ * and cleared by string identifier), and
27
+ * 2) A typed eventing surface (lazy-initialised EventSource) for attaching, detaching and
28
+ * firing events.
29
+ *
30
+ * The class is generic over an EventMap `E` which maps event name keys to the payload
31
+ * type for that event. This enables compile-time type safety for listeners and fired events.
32
+ *
33
+ * Template parameters:
34
+ * @template E - An {@link EventMap}-shaped type that maps event keys to the event payload types.
35
+ *
36
+ * Timer semantics:
37
+ * - Timers are referenced by a string `name`. Each instance of CoreElement maintains its own
38
+ * map of timers.
39
+ * - Starting a timer with a name that is already present will stop the previous timer first.
40
+ * - setTimeout(name, ms, callback) creates a single-shot timer (uses global setTimeout).
41
+ * - setInterval(name, ms, callback) creates a repeating timer (uses global setInterval).
42
+ * - clearTimeout(name) and clearInterval(name) both stop and remove the timer with the given
43
+ * name (they are aliases for the same internal stop logic).
44
+ * - clearTimeouts() will stop and remove all timers currently tracked by the instance.
45
+ * - The underlying timer handles are encapsulated; callers only interact via the string name.
46
+ *
47
+ * Event semantics:
48
+ * - Event support is provided via a lazily-initialised EventSource instance internal to the
49
+ * CoreElement. The EventSource is created on first use (first call to on()).
50
+ * - on(name, listener) registers a listener for the given event name and returns a small
51
+ * subscription object exposing an off() method for convenience.
52
+ * - off(name, listener) removes a previously-registered listener (no-op if there is no
53
+ * EventSource or listener).
54
+ * - fire(name, ev) will dispatch the given payload to all listeners registered for that
55
+ * event name (no-op if there is no EventSource).
56
+ * - Listener and event payload types are enforced by the generic `E`.
57
+ *
58
+ * Threading / reentrancy / error handling:
59
+ * - Timer callbacks execute via the platform timer mechanisms (setTimeout/setInterval). Any
60
+ * exceptions thrown by callbacks will propagate according to the environment's timer
61
+ * semantics (typically uncaught unless handled by the callback).
62
+ * - The class uses console.assert to validate non-null listeners on public attach/detach
63
+ * methods; callers should avoid passing undefined/null listeners.
64
+ * Example:
65
+ * ```ts
66
+ * // Strongly-typed events
67
+ * interface MyEvents { loaded: { ok: boolean }, tick: number }
68
+ * class MyElement extends CoreElement<MyEvents> {}
69
+ *
70
+ * const el = new MyElement();
71
+ * const sub = el.on("loaded", e => console.log(e.ok));
72
+ * el.fire("loaded", { ok: true });
73
+ * sub.off(); // convenience to remove listener
74
+ *
75
+ * // Timers
76
+ * el.setInterval("poll", 1000, () => el.fire("tick", Date.now()));
77
+ * el.clearInterval("poll");
78
+ * ```
21
79
  */
22
-
23
80
  export class CoreElement<E extends EventMap = EventMap> {
24
81
 
25
82
  #events: EventSource<E>;
@@ -46,22 +103,55 @@ export class CoreElement<E extends EventMap = EventMap> {
46
103
  if (clear) { clear(); }
47
104
  }
48
105
 
106
+ /**
107
+ * Sets a timeout that executes a callback function after a specified delay.
108
+ * If a timeout with the same name already exists, it will be cleared before the new one is set.
109
+ * @param name - A unique string identifier for this timeout.
110
+ * @param ms - The delay in milliseconds before the callback is executed.
111
+ * @param callback - The function to execute after the delay.
112
+ */
113
+
49
114
  setTimeout( name: string, ms: number, callback: () => void ) {
50
115
  this.__startTimer( name, ms, false, callback );
51
116
  }
117
+
118
+ /**
119
+ * Clears a previously set timeout.
120
+ * @param name - The name of the timeout to clear.
121
+ * @link setTimeout
122
+ */
52
123
 
53
124
  clearTimeout( name: string ) {
54
125
  this.__stopTimer( name );
55
126
  }
56
127
 
128
+ /**
129
+ * Sets an interval that repeatedly executes a callback function after a specified delay.
130
+ * If a timeout with the same name already exists, it will be cleared before the new one is set.
131
+ * @param name - A unique string identifier for this timeout.
132
+ * @param ms - The delay in milliseconds before the callback is executed.
133
+ * @param callback - The function to execute after the delay.
134
+ */
135
+
57
136
  setInterval( name: string, ms: number, callback: ( ) => void ) {
58
137
  this.__startTimer( name, ms, true, callback );
59
138
  }
60
139
 
140
+ /**
141
+ * Clears a previously set interval.
142
+ * @param name - The name of the interval to clear.
143
+ * @link setInterval
144
+ */
145
+
61
146
  clearInterval( name: string ) {
62
147
  this.__stopTimer( name );
63
148
  }
64
149
 
150
+ /**
151
+ * Clears all timeouts and intervals currently managed by this instance.
152
+ * This stops all scheduled callbacks and removes their references.
153
+ * @link setTimeout
154
+ */
65
155
  clearTimeouts( ) {
66
156
  for( const [id,val] of this.#timers ) {
67
157
  val( );
@@ -73,6 +163,13 @@ export class CoreElement<E extends EventMap = EventMap> {
73
163
  // :: EVENTS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
74
164
 
75
165
  /**
166
+ * Registers an event listener for a specific event name.
167
+ * The listener will be invoked when an event with the given name is fired.
168
+ * Returns an object with an `off()` method, which can be used to conveniently remove this specific listener.
169
+ * @param name - The name of the event to listen for.
170
+ * @param listener - The callback function to execute when the event is fired.
171
+ * @returns An object containing an `off()` method to unsubscribe the listener.
172
+ * @link fire
76
173
  * attach to an event
77
174
  */
78
175
 
@@ -92,7 +189,12 @@ export class CoreElement<E extends EventMap = EventMap> {
92
189
  }
93
190
 
94
191
  /**
95
- * detach
192
+ * Removes a previously registered event listener.
193
+ * If the listener was not found or no events were registered, this method does nothing.
194
+ * @param name - The name of the event from which to remove the listener.
195
+ * @param listener - The specific listener function to remove.
196
+ * @link on
197
+ * @link fire
96
198
  */
97
199
 
98
200
  off<K extends keyof E>( name: K, listener: ( ev: E[K] ) => void ) {
@@ -104,7 +206,12 @@ export class CoreElement<E extends EventMap = EventMap> {
104
206
  }
105
207
 
106
208
  /**
107
- *
209
+ * Dispatches an event with a given name and payload to all registered listeners.
210
+ * If no listeners are registered for the event name, or if no EventSource has been initialized, this method does nothing.
211
+ * @param name - The name of the event to fire.
212
+ * @param ev - The payload (event object) to pass to the listeners.
213
+ * @link on
214
+ * @link off
108
215
  */
109
216
 
110
217
  fire<K extends keyof E>( name: K, ev: E[K] ) {
@@ -17,7 +17,9 @@
17
17
  import { CoreElement } from './core_element';
18
18
 
19
19
  /**
20
- *
20
+ * Represents a base event interface for the framework.
21
+ * All custom events should implement this interface to ensure consistent behavior
22
+ * regarding event propagation and default action prevention.
21
23
  */
22
24
 
23
25
  export interface CoreEvent {
@@ -28,7 +30,15 @@ export interface CoreEvent {
28
30
  propagationStopped?: boolean; // if true, do not propagate the event
29
31
  defaultPrevented?: boolean; // if true, do not call default handler (if any)
30
32
 
33
+ /**
34
+ * Stops the propagation of the event to further listeners.
35
+ * Subsequent listeners for the same event on the same EventSource will not be called.
36
+ */
31
37
  stopPropagation?(): void; // stop the propagation
38
+ /**
39
+ * Prevents the default action associated with the event.
40
+ * If a default handler exists, it will not be executed.
41
+ */
32
42
  preventDefault?(): void; // prevent the default handler
33
43
  }
34
44
 
@@ -44,20 +54,35 @@ const preventDefault = function ( this: CoreEvent ) {
44
54
 
45
55
 
46
56
  /**
47
- *
57
+ * A generic interface for mapping event names to their corresponding event payload types.
58
+ * This is used by `EventSource` and `CoreElement` to provide compile-time type safety
59
+ * for event listeners and fired events.
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * interface MyCustomEvents {
64
+ * 'dataLoaded': { data: any, timestamp: number };
65
+ * 'itemSelected': { itemId: string };
66
+ * }
67
+ * ```
48
68
  */
49
69
 
50
70
  export interface EventMap {
51
71
  }
52
72
 
53
73
  /**
54
- *
74
+ * Defines the signature for an event callback function.
75
+ * @template T - The specific type of `CoreEvent` that the callback handles.
55
76
  */
56
77
 
57
78
  export type EventCallback<T extends CoreEvent = CoreEvent> = (event: T) => any;
58
79
 
59
80
  /**
60
- *
81
+ * A base class for objects that can emit and listen to custom events.
82
+ * It provides a typed eventing mechanism, allowing for the registration and removal of listeners,
83
+ * and the firing of events with associated payloads.
84
+ *
85
+ * @template E - An `EventMap`-shaped type that defines the events supported by this source.
61
86
  */
62
87
 
63
88
  export class EventSource<E extends EventMap = EventMap > {
@@ -65,10 +90,21 @@ export class EventSource<E extends EventMap = EventMap > {
65
90
  private _source: unknown;
66
91
  private _registry: Map<string,EventCallback[]>;
67
92
 
93
+ /**
94
+ * Creates an instance of EventSource.
95
+ * @param source - The object that will be reported as the `source` of events fired by this instance.
96
+ * If `null` or `undefined`, the `EventSource` instance itself will be the source.
97
+ */
68
98
  constructor(source: unknown = null) {
69
99
  this._source = source ?? this;
70
100
  }
71
101
 
102
+ /**
103
+ * Registers an event listener for a specific event name.
104
+ * @param name - The name of the event to listen for (must be a key in `E`).
105
+ * @param callback - The function to be called when the event is fired.
106
+ * @param capturing - If `true`, the listener will be added to the beginning of the listener list (capturing phase).
107
+ */
72
108
  addListener<K extends keyof E>( name: K, callback: ( ev: E[K] ) => void, capturing = false ) {
73
109
 
74
110
  if (!this._registry) {
@@ -98,9 +134,9 @@ export class EventSource<E extends EventMap = EventMap > {
98
134
  }
99
135
 
100
136
  /**
101
- * stop listening to an event
102
- * @param eventName - event name
103
- * @param callback - callback to remove (must be the same as in on )
137
+ * Removes a previously registered event listener.
138
+ * @param name - The name of the event from which to remove the listener.
139
+ * @param callback - The specific callback function to remove. It must be the same function instance that was originally registered.
104
140
  */
105
141
 
106
142
  removeListener<K extends keyof E>(name: K, callback: (ev: E[K]) => any) {
@@ -121,6 +157,11 @@ export class EventSource<E extends EventMap = EventMap > {
121
157
  }
122
158
  }
123
159
 
160
+ /**
161
+ * Dispatches an event with a given name and payload to all registered listeners.
162
+ * @param name - The name of the event to fire (must be a key in `E`).
163
+ * @param evx - The event payload (event object) to pass to the listeners.
164
+ */
124
165
  fire<K extends keyof E>(name: K, evx: E[K]) {
125
166
 
126
167
  let listeners = this._registry?.get(name as string);
@@ -171,7 +212,3 @@ export class EventSource<E extends EventMap = EventMap > {
171
212
  //}
172
213
  }
173
214
  }
174
-
175
-
176
-
177
-
@@ -289,6 +289,7 @@ let fr = {
289
289
 
290
290
  date_input_formats: 'd/m/y|d.m.y|d m y|d-m-y|dmy',
291
291
  date_format: 'D/M/Y',
292
+ date_time_format: 'D/M/Y H:I:S',
292
293
 
293
294
  day_short: [ 'dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam' ],
294
295
  day_long: [ 'dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi' ],
@@ -353,6 +354,7 @@ let en = {
353
354
 
354
355
  date_input_formats: 'm/d/y|m.d.y|m d y|m-d-y|mdy',
355
356
  date_format: 'M/D/Y',
357
+ date_time_format: 'M/D/Y H:I:S',
356
358
 
357
359
  day_short: [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ],
358
360
  day_long: [ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' ],