x4js 2.0.28 → 2.0.31

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 (69) 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/src/colors.scss +246 -0
  16. package/src/components/boxes/boxes.module.scss +1 -1
  17. package/src/components/boxes/boxes.ts +139 -28
  18. package/src/components/button/button.ts +76 -29
  19. package/src/components/combobox/combobox.ts +1 -1
  20. package/src/components/dialog/dialog.ts +4 -0
  21. package/src/components/gridview/gridview.ts +104 -6
  22. package/src/components/icon/icon.ts +42 -14
  23. package/src/components/input/input.ts +146 -74
  24. package/src/components/keyboard/keyboard.module.scss +1 -1
  25. package/src/components/keyboard/keyboard.ts +31 -9
  26. package/src/components/label/label.module.scss +9 -0
  27. package/src/components/label/label.ts +10 -6
  28. package/src/components/link/link.module.scss +44 -0
  29. package/src/components/link/link.ts +7 -1
  30. package/src/components/listbox/listbox.module.scss +18 -4
  31. package/src/components/listbox/listbox.ts +32 -12
  32. package/src/components/menu/menu.module.scss +14 -2
  33. package/src/components/menu/menu.ts +1 -1
  34. package/src/components/messages/messages.ts +13 -5
  35. package/src/components/panel/panel.module.scss +7 -0
  36. package/src/components/popup/popup.ts +14 -10
  37. package/src/components/propgrid/propgrid.ts +1 -1
  38. package/src/components/shared.scss +4 -0
  39. package/src/components/spreadsheet/spreadsheet.ts +81 -34
  40. package/src/components/tabs/tabs.module.scss +1 -0
  41. package/src/components/textarea/textarea.ts +8 -2
  42. package/src/components/textedit/textedit.ts +7 -0
  43. package/src/components/themes.scss +2 -0
  44. package/src/components/tooltips/tooltips.ts +15 -3
  45. package/src/core/component.ts +358 -162
  46. package/src/core/core_application.ts +129 -32
  47. package/src/core/core_colors.ts +382 -119
  48. package/src/core/core_data.ts +73 -86
  49. package/src/core/core_dom.ts +10 -0
  50. package/src/core/core_dragdrop.ts +32 -7
  51. package/src/core/core_element.ts +111 -4
  52. package/src/core/core_events.ts +48 -11
  53. package/src/core/core_i18n.ts +2 -0
  54. package/src/core/core_pdf.ts +454 -0
  55. package/src/core/core_router.ts +64 -5
  56. package/src/core/core_state.ts +1 -0
  57. package/src/core/core_styles.ts +11 -12
  58. package/src/core/core_svg.ts +346 -51
  59. package/src/core/core_tools.ts +105 -17
  60. package/src/x4.d.ts +10 -0
  61. package/src/x4.ts +1 -0
  62. package/src/x4tsx.d.ts +2 -1
  63. package/tsconfig.json +11 -0
  64. package/lib/README.txt +0 -20
  65. package/lib/cjs/x4.css +0 -1
  66. package/lib/cjs/x4.js +0 -2
  67. package/lib/esm/x4.css +0 -1
  68. package/lib/esm/x4.mjs +0 -2
  69. package/lib/styles/x4.css +0 -1
@@ -14,12 +14,12 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
- import { isArray, UnsafeHtml, isNumber, Rect, Constructor, class_ns, x4_class_ns_sym, IRect } from './core_tools';
18
- import { CoreElement } from './core_element';
19
- import { ariaValues, unitless } from './core_styles';
20
- import { CoreEvent, EventMap } from './core_events';
21
- import { addEvent, DOMEventHandler, GlobalDOMEvents } from './core_dom';
22
- import { Application, EvMessage } from './core_application';
17
+ import { isArray, UnsafeHtml, isNumber, Rect, Constructor, class_ns, x4_class_ns_sym, IRect } from './core_tools.ts';
18
+ import { CoreElement } from './core_element.ts';
19
+ import { ariaValues, unitless } from './core_styles.ts';
20
+ import { CoreEvent, EventMap } from './core_events.ts';
21
+ import { addEvent, DOMEventHandler, GlobalDOMEvents } from './core_dom.ts';
22
+ import { Application, EvMessage } from './core_application.ts';
23
23
 
24
24
  interface RefType<T extends Component> {
25
25
  dom: T;
@@ -75,31 +75,43 @@ export const makeUniqueComponentId = ( ) => {
75
75
  }
76
76
 
77
77
  /**
78
- *
78
+ * Base properties for all components.
79
79
  */
80
80
 
81
81
  export interface ComponentProps {
82
- tag?: string;
83
- ns?: string;
82
+ /** HTML tag name (default: `"div"`). */
83
+ tag?: string;
84
+ /** Namespace for SVG/MathML elements. */
85
+ ns?: string;
86
+ /** Inline CSS styles. */
87
+ style?: Partial<CSSStyleDeclaration>;
88
+ /** HTML attributes. */
89
+ attrs?: Record<string,string|number|boolean>;
90
+ /** Child content (components, strings, or HTML). */
91
+ content?: ComponentContent;
92
+ /** DOM event listeners. */
93
+ dom_events?: GlobalDOMEvents;
94
+ /** Additional CSS classes. */
95
+ cls?: string;
96
+ /** Element ID. */
97
+ id?: string;
98
+ /** Reference to the component instance. */
99
+ ref?: RefType<any>;
84
100
 
85
- style?: Partial<CSSStyleDeclaration>;
86
- attrs?: Record<string,string|number|boolean>;
87
- content?: ComponentContent;
88
- dom_events?: GlobalDOMEvents;
89
- cls?: string;
90
- id?: string;
91
- ref?: RefType<any>;
92
-
93
101
  // shortcuts
94
- width?: string | number;
102
+ /** Width (px or string like `"50%"` or `"3em"`). */
103
+ width?: string | number;
104
+ /** Height (px or string like `"50%"`). */
95
105
  height?: string | number;
106
+ /** Component is initialy disabled. */
96
107
  disabled?: boolean,
108
+ /** Component is initialy hidden. */
97
109
  hidden?: boolean,
110
+ /** Enables flex layout (boolean) or sets flex-grow (number). */
98
111
  flex?: boolean | number;
99
-
112
+ /** Tooltip text. */
100
113
  tooltip?: string;
101
-
102
- // wrapper
114
+ /** Existing DOM element to wrap. */
103
115
  existingDOM?: HTMLElement;
104
116
 
105
117
  // index signature
@@ -125,19 +137,35 @@ export interface ComponentEvents extends EventMap {
125
137
  }
126
138
 
127
139
  /**
128
- *
140
+ * Base component class with DOM integration and event handling.
141
+ * Auto-generates CSS class: `x4comp` + derived class names (e.g., `x4button`).
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * // Basic div
146
+ * const div = new Component({ tag: "div", content: "Hello" });
147
+ *
148
+ * // Custom element
149
+ * class MyComponent extends Component {}
150
+ * const inst = new MyComponent({ cls: "my-class" });
151
+ * ```
129
152
  */
130
153
 
131
154
  @class_ns( "x4" )
132
155
  export class Component<P extends ComponentProps = ComponentProps, E extends ComponentEvents = ComponentEvents>
133
156
  extends CoreElement<E> {
134
157
 
135
- readonly dom: Element;
136
- readonly props: P;
158
+ /** The underlying DOM element of the component. */
159
+ readonly dom: Element;
160
+
161
+ /** The properties passed to the component's constructor. */
162
+ readonly props: P;
163
+
137
164
  protected readonly clsprefix: string; // internal class name prefix (x4 internal)
138
165
 
139
166
  #store: Map<string|symbol,any>;
140
167
 
168
+
141
169
  constructor( props: P ) {
142
170
  super( );
143
171
 
@@ -219,6 +247,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
219
247
  (this.dom as any)[COMPONENT] = this;
220
248
  }
221
249
 
250
+ /**
251
+ * Attaches a listener for global messages dispatched by the application.
252
+ * The listener is automatically removed when the component's DOM element is removed.
253
+ * @param cb - The callback function to execute when a global message is received.
254
+ */
222
255
 
223
256
  onGlobalEvent( cb: ( ev: EvMessage ) => void ) {
224
257
 
@@ -233,24 +266,29 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
233
266
  // :: CLASSES ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
234
267
 
235
268
  /**
236
- *
237
- */
238
-
269
+ * Checks if the component's DOM element has a specific CSS class.
270
+ * @param cls - The CSS class name to check.
271
+ * @returns `true` if the class is present, `false` otherwise.
272
+ */
273
+
239
274
  hasClass( cls: string ) {
240
275
  return this.dom.classList.contains( cls );
241
276
  }
242
277
 
243
278
  /**
244
- *
245
- */
246
-
279
+ * Adds one or more CSS classes to the component's DOM element.
280
+ * Multiple classes can be provided as a space-separated string.
281
+ * @param cls - The CSS class(es) to add.
282
+ */
283
+
247
284
  addClass( cls: string ) {
248
285
  if( !cls ) return;
249
-
250
- if( cls.indexOf(' ')>=0 ) {
251
- cls = cls.trim( );
286
+
287
+ cls = cls.trim( );
288
+
289
+ if( cls.includes(' ') ) {
252
290
  const ccs = cls.split( " " );
253
- this.dom.classList.add(...ccs);
291
+ this.dom.classList.add( ...ccs.filter(x=>x) );
254
292
  }
255
293
  else {
256
294
  this.dom.classList.add(cls);
@@ -258,9 +296,12 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
258
296
  }
259
297
 
260
298
  /**
261
- * special case: '*' mean clear class list
262
- */
263
-
299
+ * Removes one or more CSS classes from the component's DOM element.
300
+ * If `*` is passed as the class name, all classes will be removed.
301
+ * Multiple classes can be provided as a space-separated string.
302
+ * @param cls - The CSS class(es) to remove, or `*` to clear all.
303
+ */
304
+
264
305
  removeClass( cls: string ) {
265
306
  if( !cls ) return;
266
307
 
@@ -279,9 +320,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
279
320
  }
280
321
 
281
322
  /**
282
- *
283
- */
284
-
323
+ * Removes all CSS classes from the component's DOM element that match a given regular expression.
324
+ * @param re - The regular expression to match against class names.
325
+ */
326
+
285
327
  removeClassEx( re: RegExp ) {
286
328
  const all = Array.from( this.dom.classList );
287
329
  all.forEach( x => {
@@ -292,9 +334,12 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
292
334
  }
293
335
 
294
336
  /**
295
- *
296
- */
297
-
337
+ * Toggles the presence of one or more CSS classes on the component's DOM element.
338
+ * If a class is present, it's removed; otherwise, it's added.
339
+ * Multiple classes can be provided as a space-separated string.
340
+ * @param cls - The CSS class(es) to toggle.
341
+ */
342
+
298
343
  toggleClass( cls: string ) {
299
344
  if( !cls ) return;
300
345
 
@@ -312,9 +357,12 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
312
357
  }
313
358
 
314
359
  /**
315
- *
316
- */
317
-
360
+ * Sets or removes a CSS class based on a boolean condition.
361
+ * @param cls - The CSS class to manage.
362
+ * @param set - If `true`, the class is added; if `false`, it's removed. Defaults to `true`.
363
+ * @returns The component instance for chaining.
364
+ */
365
+
318
366
  setClass( cls: string, set: boolean = true ) : this {
319
367
  if( set ) this.addClass(cls);
320
368
  else this.removeClass( cls );
@@ -324,9 +372,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
324
372
  // :: ATTRIBUTES ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
325
373
 
326
374
  /**
327
- * attributes
328
- */
329
-
375
+ * Sets multiple HTML attributes on the component's DOM element.
376
+ * @param attrs - An object where keys are attribute names and values are their corresponding values.
377
+ * @returns The component instance for chaining.
378
+ */
379
+
330
380
  setAttributes( attrs: ComponentAttributes ): this {
331
381
  for( const name in attrs ) {
332
382
  this.setAttribute( name, attrs[name] );
@@ -335,9 +385,12 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
335
385
  }
336
386
 
337
387
  /**
338
- *
339
- */
340
-
388
+ * Sets a single HTML attribute on the component's DOM element.
389
+ * If `value` is `null`, `undefined`, or `false`, the attribute will be removed.
390
+ * @param name - The name of the attribute.
391
+ * @param value - The value of the attribute.
392
+ */
393
+
341
394
  setAttribute( name: string, value: string | number | boolean ) {
342
395
  if( value===null || value===undefined || value===false ) {
343
396
  this.dom.removeAttribute( name );
@@ -348,24 +401,35 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
348
401
  }
349
402
 
350
403
  /**
351
- *
352
- */
353
-
404
+ * Retrieves the value of an HTML attribute from the component's DOM element.
405
+ * @param name - The name of the attribute.
406
+ * @returns The string value of the attribute, or `null` if not present.
407
+ */
408
+
354
409
  getAttribute( name: string ): string {
355
410
  return this.dom.getAttribute( name );
356
411
  }
357
412
 
358
413
  /**
414
+ * Retrieves the value of a `data-*` attribute from the component's DOM element.
415
+ * @param name - The suffix of the `data-` attribute (e.g., for `data-foo`, use `"foo"`).
416
+ * @returns The string value of the `data-*` attribute, or `null` if not present.
359
417
  *
360
- */
361
-
418
+ * @cf setIntData/getIntData (number)
419
+ * @cf setInternalData/getInternalData (typed data)
420
+ */
421
+
362
422
  getData( name: string ) : string {
363
423
  return this.getAttribute( "data-"+name );
364
424
  }
365
425
 
366
426
  /**
367
- * @returns undefined if not a number
368
- */
427
+ * Retrieves the integer value of a `data-*` attribute from the component's DOM element.
428
+ * Returns `undefined` if the attribute is not present or cannot be parsed as a number.
429
+ * @param name - The suffix of the `data-` attribute.
430
+ * @returns The integer value of the `data-*` attribute, or `undefined`.
431
+ */
432
+
369
433
  getIntData( name: string ) : number {
370
434
  const v = parseInt( this.getAttribute( "data-"+name ) );
371
435
  if( Number.isFinite(v) ) {
@@ -376,9 +440,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
376
440
  }
377
441
 
378
442
  /**
379
- *
380
- */
381
-
443
+ * Sets the value of a `data-*` attribute on the component's DOM element.
444
+ * @param name - The suffix of the `data-` attribute.
445
+ * @param value - The string value to set.
446
+ */
447
+
382
448
  setData( name: string, value: string ) {
383
449
  return this.setAttribute( "data-"+name, value );
384
450
  }
@@ -387,7 +453,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
387
453
  * idem as setData but onot on dom, you can store anything
388
454
  */
389
455
 
390
- setInternalData( name: string|symbol, value: any ): this {
456
+ setInternalData<T>( name: string|symbol, value: T ): this {
391
457
  if( !this.#store ) {
392
458
  this.#store = new Map( );
393
459
  }
@@ -404,16 +470,20 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
404
470
  // :: DOM EVENTS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
405
471
 
406
472
  /**
407
- *
408
- */
473
+ * Adds a DOM event listener to the component's DOM element.
474
+ * @param name - The name of the DOM event (e.g., `'click'`, `'mouseover'`).
475
+ * @param listener - The event handler function.
476
+ * @param prepend - If `true`, the listener is added to the beginning of the event listener list. Defaults to `false`.
477
+ */
409
478
 
410
479
  addDOMEvent<K extends keyof GlobalDOMEvents>( name: K, listener: GlobalDOMEvents[K], prepend = false ) {
411
480
  addEvent( this.dom, name, listener as DOMEventHandler, prepend );
412
481
  }
413
482
 
414
483
  /**
415
- *
416
- */
484
+ * Sets multiple DOM event listeners on the component's DOM element.
485
+ * @param events - An object where keys are event names and values are their corresponding handler functions.
486
+ */
417
487
 
418
488
  setDOMEvents( events: GlobalDOMEvents ) {
419
489
  for( const name in events ) {
@@ -440,8 +510,8 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
440
510
  // :: CONTENT ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
441
511
 
442
512
  /**
443
- * remove all content from component
444
- */
513
+ * Removes all child nodes from the component's DOM element.
514
+ */
445
515
 
446
516
  clearContent( ) {
447
517
  const d = this.dom;
@@ -451,10 +521,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
451
521
  }
452
522
 
453
523
  /**
454
- * change the whole content of the component
455
- * clear the content before
456
- * @param content new content
457
- */
524
+ * Replaces the entire content of the component's DOM element with new content.
525
+ * Any existing content will be cleared before the new content is added.
526
+ * @param content - The new content to set. Can be a single item or an array of items.
527
+ */
458
528
 
459
529
  setContent( content: ComponentContent ) {
460
530
  this.clearContent( );
@@ -462,9 +532,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
462
532
  }
463
533
 
464
534
  /**
465
- * cf. appendContent
466
- * @param content content to append
467
- */
535
+ * Appends content to the end of the component's DOM element.
536
+ * Content can be a single Component, an array of Components, a string, an array of strings,
537
+ * raw HTML, an array of raw HTML, a number, or a boolean.
538
+ * @param content - The content to append.
539
+ */
468
540
 
469
541
  appendContent( content: ComponentContent ) {
470
542
  const set = ( d: any, c: Component | string | UnsafeHtml | number | boolean ) => {
@@ -493,7 +565,16 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
493
565
  }
494
566
  }
495
567
  else {
496
- const fragment = document.createDocumentFragment( );
568
+ const fragment = document.createDocumentFragment( ) as any;
569
+
570
+ // polyfill
571
+ fragment.insertAdjacentHTML = ( position: string, html: string ) => {
572
+ const temp = document.createElement('div');
573
+ temp.innerHTML = html;
574
+ const nodes = Array.from(temp.childNodes);
575
+ fragment.append( ...nodes );
576
+ }
577
+
497
578
  for (const child of content ) {
498
579
  set( fragment, child );
499
580
  }
@@ -503,9 +584,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
503
584
  }
504
585
 
505
586
  /**
506
- * cf. appendContent
507
- * @param content content to append
508
- */
587
+ * Prepends content to the beginning of the component's DOM element.
588
+ * Content can be a single Component, an array of Components, a string, an array of strings,
589
+ * raw HTML, an array of raw HTML, a number, or a boolean.
590
+ * @param content - The content to prepend.
591
+ */
509
592
 
510
593
  prependContent( content: ComponentContent ) {
511
594
  const d = this.dom;
@@ -538,9 +621,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
538
621
  }
539
622
 
540
623
  /**
541
- * remove a single child
542
- * @see clearContent
543
- */
624
+ * Removes a specific child component from this component's DOM element.
625
+ * @param child - The child component instance to remove.
626
+ * @cf clearContent
627
+ */
544
628
 
545
629
  removeChild( child: Component ) {
546
630
  this.dom.removeChild( child.dom );
@@ -548,8 +632,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
548
632
 
549
633
 
550
634
  /**
551
- * query all elements by selector
552
- */
635
+ * Queries all descendant DOM elements matching a CSS selector and wraps them as Component instances.
636
+ * @param selector - The CSS selector string.
637
+ * @returns An array of Component instances.
638
+ */
553
639
 
554
640
  queryAll( selector: string ): Component[] {
555
641
  const all = this.dom.querySelectorAll( selector );
@@ -559,8 +645,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
559
645
  }
560
646
 
561
647
  /**
562
- *
563
- */
648
+ * Queries the first descendant DOM element matching a CSS selector and wraps it as a Component instance.
649
+ * @param selector - The CSS selector string.
650
+ * @returns The first matching Component instance, or `null` if no match is found.
651
+ */
564
652
 
565
653
  query<T extends Component = Component>( selector: string ): T {
566
654
  const r = this.dom.querySelector( selector );
@@ -572,8 +660,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
572
660
 
573
661
 
574
662
  /**
575
- *
576
- */
663
+ * Sets an ARIA attribute on the component's DOM element.
664
+ * @param name - The name of the ARIA attribute (e.g., `'aria-label'`).
665
+ * @param value - The value of the ARIA attribute.
666
+ * @returns The component instance for chaining.
667
+ */
577
668
 
578
669
  setAria( name: keyof ariaValues, value: string | number | boolean ): this {
579
670
  this.setAttribute( name, value );
@@ -582,8 +673,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
582
673
 
583
674
 
584
675
  /**
585
- *
586
- */
676
+ * Sets multiple inline CSS styles on the component's DOM element.
677
+ * Numeric values for properties like `width` or `height` will automatically append `"px"` unless they are unitless.
678
+ * @param style - An object where keys are CSS property names and values are their corresponding styles.
679
+ * @returns The component instance for chaining.
680
+ */
587
681
 
588
682
  setStyle( style: Partial<CSSStyleDeclaration> ): this {
589
683
  const _style = (this.dom as HTMLElement).style;
@@ -602,8 +696,12 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
602
696
  }
603
697
 
604
698
  /**
605
- *
606
- */
699
+ * Sets a single inline CSS style property on the component's DOM element.
700
+ * Numeric values for properties like `width` or `height` will automatically append `"px"` unless they are unitless.
701
+ * @param name - The name of the CSS property.
702
+ * @param value - The value of the CSS property.
703
+ * @returns The component instance for chaining.
704
+ */
607
705
 
608
706
  setStyleValue<K extends keyof CSSStyleDeclaration>( name: K, value: CSSStyleDeclaration[K] | number ): this {
609
707
 
@@ -625,35 +723,51 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
625
723
  }
626
724
 
627
725
  /**
628
- *
629
- * @param name
630
- * @returns
631
- */
726
+ * Retrieves the computed inline CSS style value for a specific property.
727
+ * This only returns styles explicitly set via `setStyle` or `setStyleValue`, not inherited or stylesheet-defined styles.
728
+ * @param name - The name of the CSS property.
729
+ * @returns The value of the inline CSS property.
730
+ */
632
731
 
633
732
  getStyleValue<K extends keyof CSSStyleDeclaration>( name: K ) {
634
733
  const _style = (this.dom as HTMLElement).style;
635
734
  return _style[name];
636
735
  }
637
736
 
737
+ /**
738
+ * Sets the width of the component.
739
+ * @param w - The width value. Can be a number (interpreted as pixels) or a string (e.g., `"100px"`, `"50%"`).
740
+ */
741
+
638
742
  setWidth( w: number | string ) {
639
743
  this.setStyleValue( "width", isNumber(w) ? w+"px" : w );
640
744
  }
641
745
 
746
+ /**
747
+ * Sets the height of the component.
748
+ * @param h - The height value. Can be a number (interpreted as pixels) or a string (e.g., `"100px"`, `"50%"`).
749
+ */
750
+
642
751
  setHeight( h: number | string ) {
643
752
  this.setStyleValue( "height", isNumber(h) ? h+"px" : h );
644
753
  }
645
754
 
646
755
  /**
647
- *
648
- */
756
+ * Sets a CSS custom property (CSS variable) on the component's DOM element.
757
+ * @param name - The name of the CSS variable (e.g., `'--my-color'`).
758
+ * @param value - The value to set for the CSS variable.
759
+ */
649
760
 
650
761
  setStyleVariable( name: string, value: string ) {
651
762
  (this.dom as HTMLElement).style.setProperty( name, value );
652
763
  }
653
764
 
654
765
  /**
655
- *
656
- */
766
+ * Retrieves the value of a CSS custom property (CSS variable) for the component.
767
+ * The computed style of the element is used.
768
+ * @param name - The name of the CSS variable.
769
+ * @returns The string value of the CSS variable.
770
+ */
657
771
 
658
772
  getStyleVariable( name: string ) {
659
773
  const style = this.getComputedStyle( );
@@ -661,33 +775,42 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
661
775
  }
662
776
 
663
777
  /**
664
- *
665
- * @returns
666
- */
778
+ * Retrieves the computed style for the component's DOM element.
779
+ * @returns A `CSSStyleDeclaration` object representing the computed styles.
780
+ */
667
781
 
668
782
  getComputedStyle( ) {
669
783
  return getComputedStyle( this.dom );
670
784
  }
671
785
 
672
786
  /**
673
- *
674
- */
787
+ * Sets pointer capture on the component's DOM element for a specific pointer.
788
+ * @param pointerId - The unique ID of the pointer.
789
+ *
790
+ * @ex
791
+ * control.on("pointerdown", (ev) => {
792
+ * ev.preventDefault(); // Prevent default browser actions
793
+ * control.setCapture(ev.pointerId);
794
+ * }
795
+ */
675
796
 
676
797
  setCapture( pointerId: number ) {
677
798
  this.dom.setPointerCapture( pointerId );
678
799
  }
679
800
 
680
801
  /**
681
- *
682
- */
802
+ * Releases pointer capture on the component's DOM element for a specific pointer.
803
+ * @param pointerId - The unique ID of the pointer.
804
+ */
683
805
 
684
806
  releaseCapture( pointerId: number ) {
685
807
  this.dom.releasePointerCapture( pointerId );
686
808
  }
687
809
 
688
810
  /**
689
- *
690
- */
811
+ * Returns the size and position of the component's DOM element relative to the viewport.
812
+ * @returns A `Rect` object containing the bounding rectangle.
813
+ */
691
814
 
692
815
  getBoundingRect( ): Rect {
693
816
  const rc = this.dom.getBoundingClientRect( );
@@ -697,37 +820,48 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
697
820
  // :: MISC ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
698
821
 
699
822
  /**
700
- *
701
- */
823
+ * Gives focus to the component's DOM element.
824
+ * @returns The component instance for chaining.
825
+ */
702
826
 
703
827
  focus( ): this {
704
828
  (this.dom as HTMLElement).focus( );
705
829
  return this;
706
830
  }
707
831
 
832
+ /**
833
+ * Checks if the component's DOM element currently has focus.
834
+ * @returns `true` if the component is focused, `false` otherwise.
835
+ */
836
+
708
837
  hasFocus( ) {
709
838
  return document.activeElement==this.dom;
710
839
  }
711
840
 
712
841
  /**
713
- *
714
- */
842
+ * Scrolls the component's DOM element into the visible area of the browser window.
843
+ * @param arg - Optional. A boolean (`true` for smooth scroll) or an object specifying scroll options.
844
+ */
715
845
 
716
846
  scrollIntoView(arg?: boolean | ScrollIntoViewOptions) {
717
847
  this.dom.scrollIntoView(arg);
718
848
  }
719
849
 
720
850
  /**
721
- *
722
- */
851
+ * Checks if the component's DOM element is currently visible (i.e., not hidden by `display: none`).
852
+ * @returns `true` if the component is visible, `false` otherwise.
853
+ */
723
854
 
724
855
  isVisible( ) {
725
856
  return (this.dom as HTMLElement).offsetParent !== null;
726
857
  }
727
858
 
728
859
  /**
729
- *
730
- */
860
+ * Shows or hides the component.
861
+ * It toggles the `x4hidden` CSS class.
862
+ * @param vis - If `true`, the component is shown; if `false`, it's hidden. Defaults to `true`.
863
+ * @returns The component instance for chaining.
864
+ */
731
865
 
732
866
  show( vis = true ): this {
733
867
  this.setClass( 'x4hidden', !vis );
@@ -735,8 +869,9 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
735
869
  }
736
870
 
737
871
  /**
738
- *
739
- */
872
+ * Hides the component by applying the `x4hidden` CSS class.
873
+ * @returns The component instance for chaining.
874
+ */
740
875
 
741
876
  hide( ): this {
742
877
  this.show( false );
@@ -744,8 +879,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
744
879
  }
745
880
 
746
881
  /**
747
- * enable or disable a component (all sub HTMLElement will be also disabled)
748
- */
882
+ * Enables or disables the component.
883
+ * This sets the `disabled` attribute and also propagates the disabled state to child input elements.
884
+ * @param ena - If `true`, the component is enabled; if `false`, it's disabled. Defaults to `true`.
885
+ * @returns The component instance for chaining.
886
+ */
749
887
 
750
888
  enable( ena = true ): this {
751
889
  this.setAttribute( "disabled", !ena ? 'true' : null );
@@ -766,8 +904,9 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
766
904
  }
767
905
 
768
906
  /**
769
- *
770
- */
907
+ * Disables the component.
908
+ * @returns The component instance for chaining.
909
+ */
771
910
 
772
911
  disable( ): this {
773
912
  this.enable( false );
@@ -775,16 +914,19 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
775
914
  }
776
915
 
777
916
  /**
778
- * check if element is marked disabled
779
- */
917
+ * Checks if the component is marked as disabled.
918
+ * This checks for the presence of the `disabled` attribute.
919
+ * @returns The string value of the `disabled` attribute, or `null` if not present.
920
+ */
780
921
 
781
922
  isDisabled( ) {
782
923
  return this.getAttribute('disabled');
783
924
  }
784
925
 
785
926
  /**
786
- *
787
- */
927
+ * Returns the next sibling element as a Component instance.
928
+ * @returns The next sibling component, or `null` if none exists.
929
+ */
788
930
 
789
931
  nextElement<T extends Component = Component>( ): T {
790
932
  const nxt = this.dom.nextElementSibling;
@@ -792,9 +934,9 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
792
934
  }
793
935
 
794
936
  /**
795
- *
796
- * @returns
797
- */
937
+ * Returns the previous sibling element as a Component instance.
938
+ * @returns The previous sibling component, or `null` if none exists.
939
+ */
798
940
 
799
941
  prevElement<T extends Component = Component>( ): T {
800
942
  const nxt = this.dom.previousElementSibling;
@@ -802,16 +944,30 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
802
944
  }
803
945
 
804
946
  /**
805
- * search for parent that match the given contructor
806
- */
947
+ * Searches up the DOM tree for a parent element that is a Component and optionally matches a specific constructor.
948
+ * @param cls - Optional. The constructor of the Component type to match.
949
+ * @returns The matching parent Component instance, or `null` if not found.
950
+ */
807
951
 
808
952
  parentElement<T extends Component>( cls?: Constructor<T> ): T {
809
953
  return Component.parentElement<T>( this.dom, cls );
810
954
  }
811
955
 
812
956
  /**
813
- * search for parent that match the given contructor
957
+ *
814
958
  */
959
+
960
+ childCount( ) {
961
+ return this.dom.childElementCount;
962
+ }
963
+
964
+ /**
965
+ * Static method to search up the DOM tree for a parent element that is a Component and optionally matches a specific constructor.
966
+ * @param dom - The starting DOM node from which to search upwards.
967
+ * @param cls - Optional. The constructor of the Component type to match.
968
+ * @returns The matching parent Component instance, or `null` if not found.
969
+ */
970
+
815
971
 
816
972
  static parentElement<T extends Component>( dom: Node, cls?: Constructor<T> ): T {
817
973
 
@@ -832,9 +988,9 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
832
988
  }
833
989
 
834
990
  /**
835
- *
836
- * @returns
837
- */
991
+ * Returns the first child element as a Component instance.
992
+ * @returns The first child component, or `null` if none exists.
993
+ */
838
994
 
839
995
  firstChild<T extends Component = Component>( ) : T {
840
996
  const nxt = this.dom.firstElementChild;
@@ -842,9 +998,9 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
842
998
  }
843
999
 
844
1000
  /**
845
- *
846
- * @returns
847
- */
1001
+ * Returns the last child element as a Component instance.
1002
+ * @returns The last child component, or `null` if none exists.
1003
+ */
848
1004
 
849
1005
  lastChild<T extends Component = Component>( ) : T {
850
1006
  const nxt = this.dom.lastElementChild;
@@ -852,8 +1008,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
852
1008
  }
853
1009
 
854
1010
  /**
855
- * renvoie la liste des Composants enfants
856
- */
1011
+ * Enumerates all child components of this component.
1012
+ * @param recursive - If `true`, searches all descendants; otherwise, only direct children.
1013
+ * @returns An array of child Component instances.
1014
+ */
857
1015
 
858
1016
  enumChildComponents( recursive: boolean ) {
859
1017
 
@@ -871,8 +1029,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
871
1029
  }
872
1030
 
873
1031
  /**
874
- * return children list of node (not all should be components)
875
- */
1032
+ * Enumerates all child DOM nodes of this component.
1033
+ * Not all nodes may be components.
1034
+ * @param recursive - If `true`, searches all descendant nodes; otherwise, only direct children.
1035
+ * @returns An array of child DOM nodes.
1036
+ */
876
1037
 
877
1038
  enumChildNodes( recursive: boolean ) {
878
1039
  const children: Node[] = Array.from( recursive ? this.dom.querySelectorAll( '*' ) : this.dom.children );
@@ -880,8 +1041,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
880
1041
  }
881
1042
 
882
1043
  /**
883
- *
884
- */
1044
+ * Visits all descendant components of this component, executing a callback function for each.
1045
+ * The traversal stops if the callback returns `true`.
1046
+ * @param cb - The callback function to execute for each component.
1047
+ */
885
1048
 
886
1049
  visitChildren( cb: ( el: Component ) => boolean ) {
887
1050
 
@@ -907,8 +1070,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
907
1070
  }
908
1071
 
909
1072
  /**
910
- *
911
- */
1073
+ * Animates the component's DOM element using the Web Animations API.
1074
+ * @param keyframes - An array of keyframe objects or a `Keyframe` object.
1075
+ * @param duration - The duration of the animation in milliseconds, or a `KeyframeAnimationOptions` object.
1076
+ */
912
1077
 
913
1078
  animate( keyframes: Keyframe[], duration: number ) {
914
1079
  this.dom.animate(keyframes,duration);
@@ -918,8 +1083,13 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
918
1083
  // :: TSX/REACT ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
919
1084
 
920
1085
  /**
921
- * called by the compiler when a jsx element is seen
922
- */
1086
+ * Creates a new Component or an array of Components from JSX elements.
1087
+ * This method is typically called by the TypeScript/JavaScript compiler when JSX is transpiled.
1088
+ * @param clsOrTag - The class constructor of the component, an HTML tag name string, a symbol for fragments, or a callback.
1089
+ * @param attrs - An object containing attributes and properties for the component.
1090
+ * @param children - Any child components or content passed within the JSX.
1091
+ * @returns A Component instance or an array of Components.
1092
+ */
923
1093
 
924
1094
  static createElement( clsOrTag: string | ComponentConstructor | symbol | CreateComponentCallBack, attrs: any, ...children: Component[] ): Component | Component[] {
925
1095
 
@@ -956,8 +1126,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
956
1126
  }
957
1127
 
958
1128
  /**
959
- *
960
- */
1129
+ * Creates a fragment, which is an array of components without a parent DOM element.
1130
+ * Used for grouping multiple children in JSX without introducing an extra DOM node.
1131
+ * @returns An array of components.
1132
+ */
961
1133
 
962
1134
  static createFragment( ): Component[] {
963
1135
  return this.createElement( FRAGMENT, null ) as Component[];
@@ -966,11 +1138,14 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
966
1138
  // :: SPECIALS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
967
1139
 
968
1140
  /**
969
- * system interfaces:
970
- * "form-element"
971
- * "tab-handler"
1141
+ * Queries for a specific system or application-defined interface on the component.
1142
+ * Common system interfaces include "form-element" and "tab-handler".
1143
+ * @param name - The name of the interface to query.
1144
+ * @returns An object conforming to the requested interface, or `null` if not supported.
972
1145
  *
973
- * each app can create it's own interface
1146
+ * system interfaces:
1147
+ * "form-element"
1148
+ * "tab-handler"
974
1149
  */
975
1150
 
976
1151
  queryInterface<T>( name: string ): T {
@@ -980,7 +1155,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
980
1155
 
981
1156
 
982
1157
  /**
983
- *
1158
+ * Type definition for a constructor that creates a Component instance.
984
1159
  */
985
1160
 
986
1161
  type ComponentConstructor = {
@@ -988,7 +1163,10 @@ type ComponentConstructor = {
988
1163
  };
989
1164
 
990
1165
  /**
991
- * get a component element from it's DOM counterpart
1166
+ * Retrieves a Component instance associated with a given DOM element.
1167
+ * Components created by this library internally store a reference to their instance on their `dom` property.
1168
+ * @param node - The DOM element to check.
1169
+ * @returns The Component instance if found, otherwise `null`.
992
1170
  */
993
1171
 
994
1172
  export function componentFromDOM<T extends Component = Component>( node: Element ) {
@@ -996,7 +1174,11 @@ export function componentFromDOM<T extends Component = Component>( node: Element
996
1174
  }
997
1175
 
998
1176
  /**
999
- * create a component from an existing DOM
1177
+ * Wraps an existing HTMLElement with a new Component instance.
1178
+ * If the HTMLElement already has an associated Component, that instance is returned.
1179
+ * Otherwise, a new `Component` is created to manage the existing DOM element.
1180
+ * @param el - The HTMLElement to wrap.
1181
+ * @returns A Component instance managing the provided HTMLElement.
1000
1182
  */
1001
1183
 
1002
1184
  export function wrapDOM( el: HTMLElement ): Component {
@@ -1011,14 +1193,27 @@ export function wrapDOM( el: HTMLElement ): Component {
1011
1193
 
1012
1194
  // :: Special components ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1013
1195
 
1014
- // just a flexible element that push other
1196
+ /**
1197
+ * A basic component class that provides flexible sizing, typically used in flex layouts.
1198
+ * Automatically generates CSS class: `x4flex`.
1199
+ */
1200
+
1015
1201
  export class Flex extends Component {
1016
1202
  constructor( ) {
1017
1203
  super({})
1018
1204
  }
1019
1205
  }
1020
1206
 
1021
- // just a spacer element that push other
1207
+ /**
1208
+ * A simple spacer component used for creating empty space, often in flex containers.
1209
+ * @example
1210
+ * ```ts
1211
+ * new Space(); // default spacer
1212
+ * new Space(10); // 10px wide spacer
1213
+ * new Space("1em", "my-spacer-class");
1214
+ * ```
1215
+ */
1216
+
1022
1217
  export class Space extends Component {
1023
1218
  constructor( width?: number|string, cls?: string ) {
1024
1219
  super( { width, cls } )
@@ -1036,6 +1231,7 @@ export class Space extends Component {
1036
1231
  */
1037
1232
 
1038
1233
  export interface EvClick extends ComponentEvent {
1234
+ repeat?: number;
1039
1235
  }
1040
1236
 
1041
1237
  /**
@@ -1073,7 +1269,7 @@ export interface EvSelectionChange extends ComponentEvent {
1073
1269
  */
1074
1270
 
1075
1271
  export interface EvContextMenu extends ComponentEvent {
1076
- uievent: UIEvent; // UI event that fire this event
1272
+ uievent: MouseEvent; // UI event that fire this event
1077
1273
  }
1078
1274
 
1079
1275
  /**