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
@@ -14,18 +14,20 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
- import { asap, class_ns, isArray, isNumber, isString } from '../../core/core_tools';
18
- import { Component, ComponentContent, ComponentEvents, ComponentProps, EvSelectionChange } from "../../core/component"
17
+ import { asap, class_ns, isArray, isNumber } from '../../core/core_tools';
18
+ import { Component, ComponentEvents, ComponentProps, EvSelectionChange } from "../../core/component"
19
+ import { EventCallback } from '../../core/core_events';
19
20
 
20
21
  import "./boxes.module.scss";
21
- import { EventCallback } from '../../core/core_events';
22
22
 
23
23
  export interface BoxProps extends ComponentProps {
24
+ /** Optional HTML tag to use for the box. */
24
25
  tag?: string;
25
26
  }
26
27
 
27
28
  /**
28
- *
29
+ * A generic container component for grouping and laying out child components.
30
+ * The CSS class for this component is automatically generated as `x4box`.
29
31
  */
30
32
 
31
33
  @class_ns( "x4" )
@@ -34,7 +36,9 @@ export class Box<P extends BoxProps=BoxProps,E extends ComponentEvents=Component
34
36
 
35
37
 
36
38
  /**
37
- *
39
+ * A horizontal box layout component.
40
+ * Arranges child components in a horizontal line.
41
+ * The CSS class for this component is automatically generated as `x4hbox`.
38
42
  */
39
43
 
40
44
  @class_ns( "x4" )
@@ -42,7 +46,9 @@ export class HBox<P extends BoxProps=BoxProps,E extends ComponentEvents=Componen
42
46
  }
43
47
 
44
48
  /**
45
- *
49
+ * A vertical box layout component.
50
+ * Arranges child components in a vertical stack.
51
+ * The CSS class for this component is automatically generated as `x4vbox`.
46
52
  */
47
53
 
48
54
  @class_ns( "x4" )
@@ -53,42 +59,53 @@ export class VBox<P extends BoxProps=BoxProps,E extends ComponentEvents=Componen
53
59
  }
54
60
 
55
61
 
62
+ type ContentBuilder = ( ) => Component;
63
+
64
+
56
65
  /**
57
- * stack of widgets where only one widget is visible at a time
66
+ * Represents an item in a {@link StackBox}.
58
67
  */
59
68
 
60
- type ContentBuilder = ( ) => Component;
61
-
62
69
  interface StackItem {
70
+ /** Unique name for the stack item. */
63
71
  name: string;
72
+ /** Content of the stack item, either a component or a builder function. */
64
73
  content: Component | ContentBuilder;
65
74
  title?: string;
66
75
  }
67
76
 
68
77
  /**
69
- *
78
+ * Events specific to the {@link StackBox} component.
70
79
  */
71
80
 
72
81
  interface StackeBoxEvents extends ComponentEvents {
82
+ /** Fired when the current page changes. */
73
83
  pageChange?: EvSelectionChange;
74
84
  }
75
85
 
86
+ /**
87
+ * Properties for the {@link StackBox} component.
88
+ */
89
+
76
90
  export interface StackBoxProps extends Omit<ComponentProps,"content"> {
91
+ /** Name of the default page to display. */
77
92
  default: string;
93
+
94
+ /** List of stack items. */
78
95
  items: StackItem[];
96
+
97
+ /** Callback for page change events. */
79
98
  pageChange?: EventCallback<EvSelectionChange>;
80
99
  }
81
100
 
82
- /**
83
- *
84
- */
85
101
 
86
102
  interface StackItemEx extends StackItem {
87
103
  page: Component;
88
104
  }
89
105
 
90
106
  /**
91
- *
107
+ * A stack of widgets where only one widget is visible at a time.
108
+ * The CSS class for this component is automatically generated as `x4stackbox`.
92
109
  */
93
110
 
94
111
  @class_ns( "x4" )
@@ -114,6 +131,11 @@ export class StackBox<P extends StackBoxProps = StackBoxProps, E extends StackeB
114
131
  }
115
132
  }
116
133
 
134
+ /**
135
+ * Adds a new item to the stack.
136
+ * @param item - The item to add.
137
+ */
138
+
117
139
  addItem( item: StackItem ) {
118
140
  this._items.push( {
119
141
  name: item.name,
@@ -122,6 +144,11 @@ export class StackBox<P extends StackBoxProps = StackBoxProps, E extends StackeB
122
144
  });
123
145
  }
124
146
 
147
+ /**
148
+ * Removes an item from the stack by its name.
149
+ * @param name - The name of the item to remove.
150
+ */
151
+
125
152
  removeItem( name: string ) {
126
153
  const index = this._items.findIndex( x => x.name==name );
127
154
  if( index>=0 ) {
@@ -134,10 +161,17 @@ export class StackBox<P extends StackBoxProps = StackBoxProps, E extends StackeB
134
161
  }
135
162
  }
136
163
 
164
+ /**
165
+ * Selects a page by its name.
166
+ * @param name - The name of the page to select.
167
+ * @returns The selected page component, if any.
168
+ */
169
+
137
170
  select( name: string ) {
138
171
  let sel = this.query( `:scope > .selected` );
139
172
  if( sel ) {
140
173
  sel.setClass( "selected", false );
174
+ (sel as any).deactivate?.( );
141
175
  }
142
176
 
143
177
  this._cur = this._items.findIndex( x => x.name==name );
@@ -181,8 +215,10 @@ export class StackBox<P extends StackBoxProps = StackBoxProps, E extends StackeB
181
215
  }
182
216
 
183
217
  /**
184
- *
185
- */
218
+ * Retrieves a page by its name.
219
+ * @param name - The name of the page to retrieve.
220
+ * @returns The page content, if found.
221
+ */
186
222
 
187
223
  getPage( name: string ) {
188
224
  const pg = this._items.find( x => x.name==name );
@@ -190,24 +226,28 @@ export class StackBox<P extends StackBoxProps = StackBoxProps, E extends StackeB
190
226
  }
191
227
 
192
228
  /**
193
- *
194
- */
229
+ * Gets the total number of pages in the stack.
230
+ * @returns The number of pages.
231
+ */
195
232
 
196
233
  getPageCount( ) {
197
234
  return this._items.length;
198
235
  }
199
236
 
200
237
  /**
201
- *
202
- */
238
+ * Enumerates the names of all pages in the stack.
239
+ * @returns An array of page names.
240
+ */
203
241
 
204
242
  enumPageNames( ) {
205
243
  return this._items.map( x => x.name );
206
244
  }
207
245
 
208
246
  /**
209
- *
210
- */
247
+ * Retrieves a stack item by its name.
248
+ * @param name - The name of the item to retrieve.
249
+ * @returns The stack item, if found.
250
+ */
211
251
 
212
252
  getItem( name: string ) {
213
253
  const pg = this._items.find( x => x.name==name );
@@ -215,8 +255,9 @@ export class StackBox<P extends StackBoxProps = StackBoxProps, E extends StackeB
215
255
  }
216
256
 
217
257
  /**
218
- *
219
- */
258
+ * Gets the name of the currently selected page.
259
+ * @returns The name of the current page, if any.
260
+ */
220
261
 
221
262
  getCurPage( ) {
222
263
  const c = this._items[this._cur];
@@ -227,8 +268,19 @@ export class StackBox<P extends StackBoxProps = StackBoxProps, E extends StackeB
227
268
  // :: ASSIST BOX ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
228
269
 
229
270
 
271
+ /**
272
+ * A specialized stack box for assisted navigation, such as wizards or carousels.
273
+ * The CSS class for this component is automatically generated as `x4assistbox`.
274
+ */
275
+
230
276
  @class_ns( "x4" )
231
277
  export class AssistBox extends StackBox {
278
+
279
+ /**
280
+ * Selects the next or previous page in the stack.
281
+ * @param nxt - If `true`, selects the next page; otherwise, selects the previous page.
282
+ */
283
+
232
284
  selectNextPage( nxt = true ) {
233
285
  let p;
234
286
  if( nxt && this._cur<this._items.length-1 ) {
@@ -243,10 +295,20 @@ export class AssistBox extends StackBox {
243
295
  }
244
296
  }
245
297
 
298
+ /**
299
+ * Checks if the current page is the first page.
300
+ * @returns `true` if the current page is the first page.
301
+ */
302
+
246
303
  isFirstPage( ) {
247
304
  return this._cur==0;
248
305
  }
249
306
 
307
+ /**
308
+ * Checks if the current page is the last page.
309
+ * @returns `true` if the current page is the last page.
310
+ */
311
+
250
312
  isLastPage( ) {
251
313
  return this._cur==this._items.length-1;
252
314
  }
@@ -268,6 +330,11 @@ export interface GridBoxProps extends Omit<BoxProps,"content"> {
268
330
  items?: GridBoxItem[];
269
331
  }
270
332
 
333
+ /**
334
+ * Grid-based layout container.
335
+ * Auto-generates CSS class: `x4gridbox`.
336
+ */
337
+
271
338
  @class_ns("x4")
272
339
  export class GridBox<P extends GridBoxProps=GridBoxProps,E extends ComponentEvents=ComponentEvents> extends Box<P,E> {
273
340
 
@@ -287,6 +354,11 @@ export class GridBox<P extends GridBoxProps=GridBoxProps,E extends ComponentEven
287
354
  }
288
355
  }
289
356
 
357
+ /**
358
+ * Sets grid rows (e.g., `2`, `"1fr 2fr"`, `["1fr", "2fr"]`).
359
+ * @param r - Rows definition.
360
+ */
361
+
290
362
  setRows( r: number | string | string[] ) {
291
363
  if( isArray(r) ) {
292
364
  r = r.join( " " );
@@ -298,6 +370,11 @@ export class GridBox<P extends GridBoxProps=GridBoxProps,E extends ComponentEven
298
370
  this.setStyleValue( "gridTemplateRows", r );
299
371
  }
300
372
 
373
+ /**
374
+ * Sets grid columns (e.g., `3`, `"1fr 1fr"`, `["auto", "1fr"]`).
375
+ * @param r - Columns definition.
376
+ */
377
+
301
378
  setCols( r: number | string | string[] ) {
302
379
  if( isArray(r) ) {
303
380
  r = r.join( " " );
@@ -309,23 +386,38 @@ export class GridBox<P extends GridBoxProps=GridBoxProps,E extends ComponentEven
309
386
  this.setStyleValue( "gridTemplateColumns", r );
310
387
  }
311
388
 
389
+ /**
390
+ * Sets the number of rows.
391
+ * @param n - Row count.
392
+ */
393
+
312
394
  setRowCount( n: number ) {
313
395
  this.setStyleValue( "gridTemplateRows", `repeat(${n})` );
314
396
  }
315
397
 
398
+ /**
399
+ * Sets the number of columns.
400
+ * @param n - Column count.
401
+ */
402
+
316
403
  setColCount( n: number ) {
317
404
  this.setStyleValue( "gridTemplateColumns", `repeat(${n})` );
318
405
  }
319
406
 
320
407
  /**
321
- * @param t "a a a" "b c c" "b c c"
322
- * user item.setAttribute( "grid-area", "a" );
323
- */
408
+ * Sets grid template areas (e.g., `["a a", "b c"]`).
409
+ * @param t - Template strings.
410
+ */
324
411
 
325
412
  setTemplate( t: string[] ) {
326
413
  this.setAttribute( "grid-template-area", t.map( x => '"' + x + '"' ).join(" ") );
327
414
  }
328
415
 
416
+ /**
417
+ * Places items at specific grid positions.
418
+ * @param items - Array of `{row, col, item}`.
419
+ */
420
+
329
421
  setItems( items: GridBoxItem[] ) {
330
422
  items.forEach( x => {
331
423
  x.item.setStyle( {
@@ -348,6 +440,11 @@ interface MasonryProps extends Omit<BoxProps,"content"> {
348
440
  items: Component[];
349
441
  }
350
442
 
443
+ /**
444
+ * Masonry-style layout (Pinterest-like).
445
+ * Auto-generates CSS class: `x4masonrybox`.
446
+ */
447
+
351
448
  @class_ns("x4")
352
449
  export class MasonryBox extends Box<MasonryProps> {
353
450
 
@@ -363,6 +460,11 @@ export class MasonryBox extends Box<MasonryProps> {
363
460
  }
364
461
  }
365
462
 
463
+ /**
464
+ * Resizes a single masonry item.
465
+ * @param item - Item to resize.
466
+ */
467
+
366
468
  resizeItem(item: Component) {
367
469
  const style = this.getComputedStyle();
368
470
 
@@ -381,13 +483,22 @@ export class MasonryBox extends Box<MasonryProps> {
381
483
  }
382
484
  }
383
485
 
486
+ /**
487
+ * Resizes all items to fit the grid.
488
+ */
489
+
384
490
  resizeAllItems( ) {
385
491
  const els = this.queryAll( ".item" );
386
- els.forEach( itm => {;
492
+ els.forEach( itm => {
387
493
  this.resizeItem( itm );
388
494
  } );
389
495
  }
390
496
 
497
+ /**
498
+ * Sets masonry items.
499
+ * @param items - Array of components.
500
+ */
501
+
391
502
  setItems( items: Component[] ) {
392
503
  const els = items.map( x => {
393
504
  return new Box( {
@@ -14,11 +14,11 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
- import { Component, ComponentEvents, ComponentProps, EvClick } from "../../core/component"
18
- import { EventCallback } from '../../core/core_events';
19
- import { class_ns, UnsafeHtml } from '../../core/core_tools';
17
+ import { Component, ComponentEvents, ComponentProps, EvClick } from "../../core/component.ts"
18
+ import { EventCallback } from '../../core/core_events.ts';
19
+ import { class_ns, UnsafeHtml } from '../../core/core_tools.ts';
20
20
 
21
- import { Icon } from "../icon/icon"
21
+ import { Icon } from "../icon/icon.ts"
22
22
 
23
23
  import "./button.module.scss";
24
24
 
@@ -28,6 +28,11 @@ import "./button.module.scss";
28
28
  */
29
29
 
30
30
  interface ButtonEvents extends ComponentEvents {
31
+ /**
32
+ * Fired when the button is clicked
33
+ * ex: myButton.on( "click", ( e: EvClick ) => { console.log( "click") } );
34
+ */
35
+
31
36
  click: EvClick;
32
37
  }
33
38
 
@@ -36,29 +41,62 @@ interface ButtonEvents extends ComponentEvents {
36
41
  */
37
42
 
38
43
  export interface ButtonProps extends ComponentProps {
39
- label?: string;
44
+ /** Text or HTML content of the button */
45
+ label?: string | UnsafeHtml;
46
+
47
+ /** Icon identifier to display */
40
48
  icon?: string;
49
+
50
+ /**
51
+ * Tab index for keyboard navigation.
52
+ * - `false` to exclude from tab order
53
+ * - `number` to set specific tab index
54
+ */
41
55
  tabindex?: boolean | number;
56
+
57
+ /**
58
+ * Enable auto-repeat behavior when button is held down.
59
+ * - `true` uses default 200ms repeat interval
60
+ * - `number` specifies custom repeat interval in milliseconds
61
+ *
62
+ * First click triggers after 500ms, then repeats at specified interval.
63
+ */
42
64
  autorepeat?: number | boolean;
65
+
66
+ /**
67
+ * Callback function invoked when button is clicked
68
+ * cf. ButtonEvents
69
+ */
43
70
  click?: EventCallback<EvClick>;
44
71
  }
45
72
 
46
73
  /**
47
- * Button component.
74
+ * Represents a clickable button component.
75
+ *
76
+ * Generates the CSS class **x4button** based on the class name.
77
+ * The button can contain an optional icon and label, supports keyboard activation,
78
+ * and may trigger auto-repeated click events while pointer is held down.
79
+ *
48
80
  */
49
81
 
82
+
50
83
  @class_ns( "x4" )
51
84
  export class Button extends Component<ButtonProps,ButtonEvents> {
52
85
 
53
86
  #text: Component;
54
87
 
55
88
  /**
56
- * Creates an instance of Button.
57
- *
58
- * @param props - The properties for the button component, including label and icon.
59
- * @example
60
- * const button = new Button({ label: 'Submit', icon: 'check-icon' });
61
- */
89
+ * Create a new Button.
90
+ *
91
+ * @param {ButtonProps} props - Configuration options such as `label`, `icon`, `tabindex`, `autorepeat`, and `click`.
92
+ *
93
+ * @example
94
+ * const btn = new Button({
95
+ * label: "Save",
96
+ * icon: "check",
97
+ * click: () => console.log("clicked"),
98
+ * });
99
+ */
62
100
 
63
101
  constructor( props: ButtonProps ) {
64
102
  super( { ...props, tag: 'button', content: null } );
@@ -88,7 +126,7 @@ export class Button extends Component<ButtonProps,ButtonEvents> {
88
126
  }
89
127
 
90
128
  /**
91
- * called by the system on click event
129
+ * @internal
92
130
  */
93
131
 
94
132
  protected _on_click( ev: MouseEvent ) {
@@ -109,6 +147,10 @@ export class Button extends Component<ButtonProps,ButtonEvents> {
109
147
  ev.stopPropagation();
110
148
  }
111
149
 
150
+ /**
151
+ * @internal
152
+ */
153
+
112
154
  protected _on_mouse( e: PointerEvent ) {
113
155
 
114
156
  let count = 0;
@@ -119,11 +161,10 @@ export class Button extends Component<ButtonProps,ButtonEvents> {
119
161
  const rt = this.props.autorepeat===true ? 200 : this.props.autorepeat as number;
120
162
 
121
163
  this.setTimeout( 'repeat', 500, ( ) => {
122
- count++;
123
-
124
- this.fire('click', {} );
164
+ this.fire( "click", {} );
125
165
  this.setInterval( 'repeat', rt, ( ) => {
126
- this.fire('click', {} );
166
+ count++;
167
+ this.fire( "click", {repeat:count} );
127
168
  })
128
169
  } );
129
170
  }
@@ -131,13 +172,16 @@ export class Button extends Component<ButtonProps,ButtonEvents> {
131
172
  this.clearTimeout( 'repeat' );
132
173
 
133
174
  if( !count ) {
134
- this.fire('click', {} );
175
+ this.fire("click", {} );
135
176
  }
136
177
  }
137
178
  }
138
179
 
139
180
  /**
140
- * simulate a click
181
+ * Activate the button as if it was clicked by a user.
182
+ *
183
+ * @example
184
+ * button.click();
141
185
  */
142
186
 
143
187
  click( ) {
@@ -145,7 +189,7 @@ export class Button extends Component<ButtonProps,ButtonEvents> {
145
189
  }
146
190
 
147
191
  /**
148
- * called on key down
192
+ * @internal
149
193
  */
150
194
 
151
195
  protected _on_keydown( e: KeyboardEvent ) {
@@ -156,13 +200,15 @@ export class Button extends Component<ButtonProps,ButtonEvents> {
156
200
  }
157
201
 
158
202
  /**
159
- * Sets the text content of the button's label.
160
- *
161
- * @param text - The new text or HTML content for the label.
162
- * @example
163
- * button.setText('Click Me');
164
- * button.setText(new UnsafeHtml('<b>Bold Text</b>'));
165
- */
203
+ * Set or change the button label.
204
+ *
205
+ * @param {string | UnsafeHtml} text - Text content or unsafe HTML.
206
+ *
207
+ * @example
208
+ * button.setText("Confirm");
209
+ * button.setText(new UnsafeHtml("<strong>OK</strong>"));
210
+ * button.setText( unsafe`<strong>OK</strong>` );
211
+ */
166
212
 
167
213
  public setText( text: string | UnsafeHtml ) {
168
214
  this.#text.setContent( text );
@@ -170,12 +216,13 @@ export class Button extends Component<ButtonProps,ButtonEvents> {
170
216
  }
171
217
 
172
218
  /**
173
- * Sets the icon of the button.
174
- *
175
- * @param icon - The new icon ID to set on the button.
176
- * @example
177
- * button.setIcon('new-icon-id');
178
- */
219
+ * Set or change the icon displayed by the button.
220
+ *
221
+ * @param {string} icon - Icon identifier to associate with the button.
222
+ *
223
+ * @example
224
+ * button.setIcon("arrow-right");
225
+ */
179
226
 
180
227
  public setIcon( icon: string ) {
181
228
  this.query<Icon>( "#icon" ).setIcon( icon );
@@ -52,7 +52,6 @@ export class DropdownList extends Popup<DropdownProps,DropdownEvents> {
52
52
  this.setContent( this._list );
53
53
 
54
54
  this.addDOMEvent( "mousedown", ( ev: Event ) => {
55
- console.log( "trap" );
56
55
  ev.stopImmediatePropagation( );
57
56
  ev.stopPropagation( );
58
57
  ev.preventDefault( );
@@ -228,6 +227,7 @@ export class Combobox extends Component<ComboboxProps,ComboboxEvents> {
228
227
  const rc = this._edit.getBoundingRect( );
229
228
  this._popup.setStyleValue( "minWidth", rc.width+"px" );
230
229
  this._popup.displayNear( rc, "top left", "bottom left", {x:0,y:6} );
230
+ this._popup.getList().ensureSelectionVisible( );
231
231
  }
232
232
 
233
233
  setItems( items: ListItem[] ) {
@@ -183,6 +183,10 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogEvents
183
183
  return this.form.getValues();
184
184
  }
185
185
 
186
+ validate( ) {
187
+ return this.form.validate( );
188
+ }
189
+
186
190
  /**
187
191
  *
188
192
  */