x4js 2.3.17 → 2.3.19

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 (46) hide show
  1. package/aicli.md +3 -3
  2. package/aicontext.md +211 -47
  3. package/cli/config.mjs +14 -7
  4. package/cli/copy-plugin.mjs +8 -0
  5. package/cli/create.mjs +8 -2
  6. package/cli/dev.mjs +4 -1
  7. package/cli/less-plugin.mjs +5 -1
  8. package/cli/main.mjs +15 -5
  9. package/cli/rawfile-plugin.mjs +23 -3
  10. package/cli/templates.mjs +5 -1
  11. package/package.json +1 -1
  12. package/src/components/calendar/calendar.module.scss +16 -1
  13. package/src/components/calendar/calendar.ts +52 -9
  14. package/src/components/checkbox/checkbox.ts +1 -0
  15. package/src/components/combobox/combobox.ts +51 -23
  16. package/src/components/dialog/dialog.ts +4 -1
  17. package/src/components/form/form.ts +9 -5
  18. package/src/components/gridview/gridview.ts +352 -176
  19. package/src/components/input/input.ts +63 -38
  20. package/src/components/keyboard/keyboard.module.scss +35 -4
  21. package/src/components/keyboard/keyboard.ts +295 -80
  22. package/src/components/listbox/listbox.ts +6 -1
  23. package/src/components/messages/messages.ts +12 -3
  24. package/src/components/popup/popup.ts +19 -20
  25. package/src/components/radio/radio.ts +8 -4
  26. package/src/components/rating/rating.ts +38 -48
  27. package/src/components/slider/slider.ts +38 -8
  28. package/src/components/spreadsheet/spreadsheet.ts +167 -132
  29. package/src/components/switch/switch.ts +2 -1
  30. package/src/components/tag/tag.ts +1 -2
  31. package/src/components/textarea/textarea.module.scss +6 -2
  32. package/src/components/textarea/textarea.ts +50 -11
  33. package/src/components/textedit/textedit.ts +12 -2
  34. package/src/core/component.ts +16 -9
  35. package/src/core/core_application.ts +8 -4
  36. package/src/core/core_clipboard.ts +239 -0
  37. package/src/core/core_data.ts +118 -49
  38. package/src/core/core_dom.ts +36 -6
  39. package/src/core/core_dragdrop.ts +11 -5
  40. package/src/core/core_element.ts +1 -1
  41. package/src/core/core_pdf.ts +696 -46
  42. package/src/core/core_router.ts +42 -44
  43. package/src/core/core_shortcuts.ts +1 -1
  44. package/src/core/core_state.ts +22 -5
  45. package/src/x4.d.ts +1 -0
  46. package/src/x4.ts +1 -0
@@ -28,75 +28,226 @@ import icon_hide from "./eye-slash.svg";
28
28
 
29
29
 
30
30
 
31
- const kb_def: any = {
32
- 'fr-FR': {
33
- lines: {
34
- lower: [
35
- "1 2 3 4 5 6 7 8 9 0",
36
- "a z e r t y u i o p {2}",
37
- "q s d f g h j k l m {3}",
38
- "{4} w x c v b n , . {4}",
39
- "{5} {6} ' {7}"
40
- ],
41
- upper: [
42
- "! @ # $ % ^ & * ( ) _ +",
43
- "A Z E R T Y U I O P {2}",
44
- "Q S D F G H J K L M {3}",
45
- "{4} W X C V B N ? : {4}",
46
- "{5} {6} ' {7}",
47
- ],
48
- number: [
49
- "1 2 3 {2}",
50
- "4 5 6 {8}",
51
- "7 8 9 {9}",
52
- "0 . {3} {9}"
53
- ],
54
- date: [
55
- "1 2 3 {2}",
56
- "4 5 6 {8}",
57
- "7 8 9 {9}",
58
- "0 / {3} {9}"
59
- ]
60
- }
61
- },
62
- 'en-GB': {
63
- lines: {
64
- lower: [
65
- "1 2 3 4 5 6 7 8 9 0",
66
- "a z e r t y u i o p {2}",
67
- "q s d f g h j k l m {3}",
68
- "{4} w x c v b n , . {4}",
69
- "{5} {6} ' {7}"
70
- ],
71
- upper: [
72
- "! @ # $ % ^ & * ( ) _ +",
73
- "A Z E R T Y U I O P {2}",
74
- "Q S D F G H J K L M {3}",
75
- "{4} W X C V B N ? : {4}",
76
- "{5} {6} ' {7}",
77
- ],
78
- number: [
79
- "1 2 3 {2}",
80
- "4 5 6 {8}",
81
- "7 8 9 {9}",
82
- "0 . {3} {9}"
83
- ],
84
- date: [
85
- "1 2 3 {2}",
86
- "4 5 6 {8}",
87
- "7 8 9 {9}",
88
- "0 / {3} {9}"
89
- ]
90
- }
91
- },
92
- 'en-US': 'en-GB'
31
+ /**
32
+ * A layout is the place of the 26 letters (its base) and the letters that
33
+ * a language adds to them (its extra), shown on a page of their own,
34
+ * called by a key. The upper case is computed, the digits and the signs
35
+ * are the same for all.
36
+ *
37
+ * base: the countries where it is not QWERTY are those that
38
+ * https://en.wikipedia.org/wiki/QWERTZ and /AZERTY list.
39
+ * extra: the main letters of the language in the CLDR of Unicode
40
+ * (cldr-json, cldr-misc-full/main/<lang>/characters.json), without a..z.
41
+ */
42
+
43
+ type KbBase = "azerty" | "qwerty" | "qwertz";
44
+ type KbMode = "alpha" | "accents" | "symbols" | "number" | "date";
45
+
46
+ interface KbLayout {
47
+ base: KbBase;
48
+ extra: string;
49
+ }
50
+
51
+ const kb_bases: Record<KbBase,string[]> = {
52
+ azerty: [ "a z e r t y u i o p", "q s d f g h j k l m", "w x c v b n" ],
53
+ qwerty: [ "q w e r t y u i o p", "a s d f g h j k l", "z x c v b n m" ],
54
+ qwertz: [ "q w e r t z u i o p", "a s d f g h j k l", "y x c v b n m" ],
55
+ };
56
+
57
+ // by language
58
+ const kb_langs: Record<string,KbLayout> = {
59
+ cs: { base: "qwertz", extra: "á č ď é ě í ň ó ř š ť ú ů ý ž" },
60
+ da: { base: "qwerty", extra: "æ ø å" },
61
+ de: { base: "qwertz", extra: "ä ö ü ß" },
62
+ en: { base: "qwerty", extra: "" },
63
+ es: { base: "qwerty", extra: "á é í ñ ó ú ü" },
64
+ et: { base: "qwerty", extra: "õ ä ö ü š ž" },
65
+ fi: { base: "qwerty", extra: "å ä ö š ž" },
66
+ fr: { base: "azerty", extra: "é è ê ë à â æ ç î ï ô œ ù û ü ÿ" },
67
+ ga: { base: "qwerty", extra: "á é í ó ú" },
68
+ hr: { base: "qwertz", extra: "č ć đ š ž" },
69
+ hu: { base: "qwertz", extra: "á é í ó ö ő ú ü ű" },
70
+ it: { base: "qwerty", extra: "à è é ì ò ù" },
71
+ lt: { base: "qwerty", extra: "ą č ę ė į š ų ū ž" },
72
+ lv: { base: "qwerty", extra: "ā č ē ģ ī ķ ļ ņ š ū ž" },
73
+ mt: { base: "qwerty", extra: "à ċ è ġ ħ ì ò ù ż" },
74
+ nl: { base: "qwerty", extra: "á ä é ë í ï ó ö ú ü" },
75
+ pl: { base: "qwerty", extra: "ą ć ę ł ń ó ś ź ż" },
76
+ pt: { base: "qwerty", extra: "á à â ã ç é ê í ó ò ô õ ú" },
77
+ ro: { base: "qwerty", extra: "ă â î ș ț" },
78
+ sk: { base: "qwertz", extra: "á ä č ď é í ĺ ľ ň ó ô ŕ š ť ú ý ž" },
79
+ sl: { base: "qwertz", extra: "č š ž" },
80
+ sv: { base: "qwerty", extra: "å ä ö é à" },
81
+ };
82
+
83
+ // the countries that do not have the keyboard of their language
84
+ const kb_countries: Record<string,Partial<KbLayout>> = {
85
+ "de-CH": { extra: "ä ö ü" }, // no ß in Switzerland
86
+ "fr-CH": { base: "qwertz" },
87
+ "it-CH": { base: "qwertz" },
88
+ "fr-LU": { base: "qwertz" }, // the Swiss French keyboard
89
+ "nl-BE": { base: "azerty" },
90
+ };
91
+
92
+ const kb_digits = "1 2 3 4 5 6 7 8 9 0";
93
+ const kb_signs = "! @ # $ % ^ & * ( ) _ +";
94
+
95
+ // the page of the signs, that the letters do not have
96
+ const kb_symbols = [
97
+ "- / : ; ( ) € & @ \"",
98
+ "\\ | ~ _ ` § £ $ ^ %",
99
+ "[ ] { } < > = + * #",
100
+ ];
101
+
102
+ const kb_pads = {
103
+ number: [
104
+ "1 2 3 {2}",
105
+ "4 5 6 {8}",
106
+ "7 8 9 {9}",
107
+ "0 . {3} {9}"
108
+ ],
109
+ date: [
110
+ "1 2 3 {2}",
111
+ "4 5 6 {8}",
112
+ "7 8 9 {9}",
113
+ "0 / {3} {9}"
114
+ ]
115
+ };
116
+
117
+ const KB_MAX_EXTRA = 12; // keys on a row of extra letters, as many as there are signs
118
+
119
+ /**
120
+ * "de-CH", "de_ch", "de": the layout of the country, or else the one of
121
+ * its language. A language that is not known gets a QWERTY.
122
+ */
123
+
124
+ function findLayout( locale: string ): KbLayout {
125
+ const [lang, country] = locale.replace( "_", "-" ).split( "-" );
126
+
127
+ let layout = kb_langs[lang.toLowerCase( )];
128
+ if( !layout ) {
129
+ layout = kb_langs.en;
130
+ }
131
+
132
+ if( country ) {
133
+ const own = kb_countries[lang.toLowerCase( ) + "-" + country.toUpperCase( )];
134
+ if( own ) {
135
+ layout = { ...layout, ...own };
136
+ }
137
+ }
138
+
139
+ return layout;
140
+ }
141
+
142
+ function upperKeys( line: string ): string {
143
+ return line.split( " " ).map( key => {
144
+ const up = key.toUpperCase( );
145
+ return up.length===1 ? up : key; // ß has no upper case of one letter
146
+ } ).join( " " );
147
+ }
148
+
149
+ /**
150
+ * the extra letters, on rows of the same length
151
+ */
152
+
153
+ function extraLines( extra: string ): string[] {
154
+ if( !extra ) {
155
+ return [];
156
+ }
157
+
158
+ const keys = extra.split( " " );
159
+ const count = Math.ceil( keys.length / KB_MAX_EXTRA );
160
+ const size = Math.ceil( keys.length / count );
161
+
162
+ const lines: string[] = [];
163
+ for( let i=0; i<keys.length; i+=size ) {
164
+ lines.push( keys.slice( i, i+size ).join( " " ) );
165
+ }
166
+
167
+ return lines;
168
+ }
169
+
170
+ function letterLines( layout: KbLayout, upper: boolean ): string[] {
171
+ let [l1, l2, l3] = kb_bases[layout.base];
172
+
173
+ if( upper ) {
174
+ l1 = upperKeys( l1 );
175
+ l2 = upperKeys( l2 );
176
+ l3 = upperKeys( l3 );
177
+ }
178
+
179
+ return [
180
+ upper ? kb_signs : kb_digits,
181
+ l1 + " {2}",
182
+ l2 + " {3}",
183
+ "{4} " + l3 + ( upper ? " ? : {4}" : " , . {4}" ),
184
+ bottomLine( layout, "alpha" ),
185
+ ];
186
+ }
187
+
188
+ /**
189
+ * the page called by {10}: the extra letters
190
+ */
191
+
192
+ function accentLines( layout: KbLayout, upper: boolean ): string[] {
193
+ let extra = extraLines( layout.extra );
194
+ if( upper ) {
195
+ extra = extra.map( upperKeys );
196
+ }
197
+
198
+ return [
199
+ ...extra,
200
+ "{4} {2} {3}",
201
+ bottomLine( layout, "accents" ),
202
+ ];
203
+ }
204
+
205
+ /**
206
+ * the page called by {11}: the signs
207
+ */
208
+
209
+ function symbolLines( layout: KbLayout ): string[] {
210
+ const [s1, s2, s3] = kb_symbols;
211
+
212
+ return [
213
+ s1 + " {2}",
214
+ s2 + " {3}",
215
+ s3,
216
+ bottomLine( layout, "symbols" ),
217
+ ];
218
+ }
219
+
220
+ /**
221
+ * the last row of the pages of letters: the key of the page that is shown
222
+ * is replaced by {8} at its place, to come back to the letters.
223
+ * no key of the extra letters when the language has none
224
+ */
225
+
226
+ function bottomLine( layout: KbLayout, page: "alpha" | "accents" | "symbols" ): string {
227
+ const accents = !layout.extra ? "" : page=="accents" ? "{8} " : "{10} ";
228
+ const symbols = page=="symbols" ? "{8} " : "{11} ";
229
+
230
+ return "{5} " + accents + symbols + "{6} ' {7}";
231
+ }
232
+
233
+ /**
234
+ * the text of the key that calls the extra letters: the first two of them
235
+ */
236
+
237
+ function accentLabel( layout: KbLayout, upper: boolean ): string {
238
+ const label = layout.extra.split( " " ).slice( 0, 2 ).join( " " );
239
+ return ( upper ? upperKeys( label ) : label ).replace( " ", "" );
93
240
  }
94
241
 
95
242
 
96
243
  const RE_sel = /text|password|search|tel|url/i;
97
244
 
98
245
  interface KeyboardProps extends BoxProps {
99
-
246
+ /**
247
+ * the language of the keys, with or without its country: "fr-FR",
248
+ * "de-CH", "pl"... "fr-FR" when it is not given
249
+ */
250
+ locale?: string;
100
251
  }
101
252
 
102
253
  /**
@@ -104,13 +255,17 @@ interface KeyboardProps extends BoxProps {
104
255
  * ```
105
256
  * --keyboard-key-background
106
257
  * --keyboard-hilite-color
258
+ * --keyboard-key-color
259
+ * --keyboard-accents-color
260
+ * --keyboard-symbols-color
107
261
  * --keyboard-zoom
108
262
  * ```
109
263
  */
110
264
  @class_ns( "x4" )
111
265
  export class Keyboard extends HBox<KeyboardProps>
112
266
  {
113
- mode: "lower" | "upper" | "number" | "date";
267
+ mode: KbMode;
268
+ upper: boolean;
114
269
  locale: string;
115
270
  keyboard: Box;
116
271
  visible: boolean;
@@ -119,8 +274,9 @@ export class Keyboard extends HBox<KeyboardProps>
119
274
  constructor( props: KeyboardProps ) {
120
275
  super( { ...props, id: 'v-keyboard' } );
121
276
 
122
- this.mode = 'lower';
123
- this.locale = 'fr-FR';
277
+ this.mode = 'alpha';
278
+ this.upper = false;
279
+ this.locale = props.locale ?? 'fr-FR';
124
280
  this.visible = false;
125
281
 
126
282
  document.addEventListener( 'focusin', (e) => this.handleFocus(e.target as Element,true), false );
@@ -152,6 +308,29 @@ export class Keyboard extends HBox<KeyboardProps>
152
308
  this.setStyleVariable( '--keyboard-zoom', perc+'%' );
153
309
  }
154
310
 
311
+ /**
312
+ * Change the language of the keys.
313
+ * @param locale - "fr-FR", "de-CH", "pl"... A country that has no keyboard
314
+ * of its own gets the one of its language, a language that is not known a QWERTY.
315
+ *
316
+ * @example
317
+ * keyboard.setLocale( "de-CH" );
318
+ */
319
+
320
+ setLocale( locale: string ) {
321
+ this.locale = locale;
322
+
323
+ // a language without extra letters has no page for them
324
+ if( this.mode=="accents" && !findLayout( locale ).extra ) {
325
+ this.mode = "alpha";
326
+ }
327
+
328
+ // drawn at least once
329
+ if( this.keyboard ) {
330
+ this._redraw( );
331
+ }
332
+ }
333
+
155
334
  /**
156
335
  *
157
336
  */
@@ -192,15 +371,9 @@ export class Keyboard extends HBox<KeyboardProps>
192
371
 
193
372
  // shift
194
373
  case 4: {
195
- if( this.mode=='lower' ) {
196
- this.mode = 'upper';
197
- }
198
- else {
199
- this.mode = 'lower';
200
- }
201
-
374
+ this.upper = !this.upper;
202
375
  this._redraw( );
203
- break;
376
+ break;
204
377
  }
205
378
 
206
379
  // num + sym
@@ -222,7 +395,19 @@ export class Keyboard extends HBox<KeyboardProps>
222
395
  }
223
396
 
224
397
  case 8: {
225
- this._switchMode( "lower" );
398
+ this._switchMode( "alpha" );
399
+ break;
400
+ }
401
+
402
+ // extra letters
403
+ case 10: {
404
+ this._switchMode( "accents" );
405
+ break;
406
+ }
407
+
408
+ // signs
409
+ case 11: {
410
+ this._switchMode( "symbols" );
226
411
  break;
227
412
  }
228
413
 
@@ -245,7 +430,7 @@ export class Keyboard extends HBox<KeyboardProps>
245
430
  *
246
431
  */
247
432
 
248
- private _switchMode( m: "lower" | "upper" | "number" | "date" ) {
433
+ private _switchMode( m: KbMode ) {
249
434
  this.mode = m;
250
435
  this._redraw( );
251
436
  }
@@ -312,7 +497,8 @@ export class Keyboard extends HBox<KeyboardProps>
312
497
  this._switchMode( "date");
313
498
  }
314
499
  else {
315
- this._switchMode( "lower" );
500
+ this.upper = false;
501
+ this._switchMode( "alpha" );
316
502
  }
317
503
  }
318
504
  }
@@ -436,7 +622,22 @@ export class Keyboard extends HBox<KeyboardProps>
436
622
  */
437
623
 
438
624
  private _createContent( ) {
439
- let lines = kb_def[this.locale].lines[this.mode];
625
+ let lines: string[];
626
+ const layout = findLayout( this.locale );
627
+
628
+ if( this.mode=="number" || this.mode=="date" ) {
629
+ lines = kb_pads[this.mode];
630
+ }
631
+ else if( this.mode=="accents" ) {
632
+ lines = accentLines( layout, this.upper );
633
+ }
634
+ else if( this.mode=="symbols" ) {
635
+ lines = symbolLines( layout );
636
+ }
637
+ else {
638
+ lines = letterLines( layout, this.upper );
639
+ }
640
+
440
641
  let result: Box[] = [];
441
642
 
442
643
  for( let j=0; j<lines.length; j++ ) {
@@ -527,8 +728,22 @@ export class Keyboard extends HBox<KeyboardProps>
527
728
 
528
729
  case 9:
529
730
  {
530
- content = '';
531
- cls += ' cplace';
731
+ content = '';
732
+ cls += ' cplace';
733
+ break;
734
+ }
735
+
736
+ case 10:
737
+ {
738
+ content = accentLabel( layout, this.upper );
739
+ cls += ' caccents';
740
+ break;
741
+ }
742
+
743
+ case 11:
744
+ {
745
+ content = '#+=';
746
+ cls += ' csymbols';
532
747
  break;
533
748
  }
534
749
  }
@@ -181,7 +181,8 @@ private _view: Viewport;
181
181
 
182
182
  navigate( sens: kbNav ) {
183
183
 
184
- if( !this._lastsel ) {
184
+ // an item of id 0 is one
185
+ if( this._lastsel===undefined ) {
185
186
  if( sens==kbNav.next ) sens = kbNav.first;
186
187
  else sens = kbNav.last;
187
188
  }
@@ -395,6 +396,7 @@ private _view: Viewport;
395
396
  if( itm ) {
396
397
  this._multisel.add( id );
397
398
  itm.addClass( "selected" );
399
+ this._lastsel = id; // the arrows go on from it
398
400
  }
399
401
  });
400
402
 
@@ -434,6 +436,9 @@ private _view: Viewport;
434
436
  }
435
437
 
436
438
  clearSelection( fireEvent = true ) {
439
+ // nothing selected: the arrows start from the first item
440
+ this._lastsel = undefined;
441
+
437
442
  if( this._multisel.size ) {
438
443
  this._clearSelection( );
439
444
  if( fireEvent ) {
@@ -106,10 +106,13 @@ export class MessageBox extends Dialog<DialogProps>
106
106
  box.on( "btnclick", ( ev ) => {
107
107
  asap( ( ) => {
108
108
  resolve( ev.button );
109
- box.close()
109
+ box.close()
110
110
  });
111
111
  });
112
112
 
113
+ // closed without a button (Escape, the close box): nothing was chosen
114
+ box.on( "closed", ( ) => resolve( null ) );
115
+
113
116
  box.show();
114
117
  } );
115
118
 
@@ -175,10 +178,13 @@ export class InputBox extends Dialog<DialogProps>
175
178
  box.on( "btnclick", ( ev ) => {
176
179
  asap( ( ) => {
177
180
  resolve( ev.button=="ok" ? box.getValue( ) : null );
178
- box.close()
181
+ box.close()
179
182
  });
180
183
  });
181
184
 
185
+ // closed without a button (Escape, the close box): nothing was chosen
186
+ box.on( "closed", ( ) => resolve( null ) );
187
+
182
188
  box.show();
183
189
  } );
184
190
 
@@ -233,10 +239,13 @@ export class PromptBox extends Dialog<DialogProps>
233
239
  box.on( "btnclick", ( ev ) => {
234
240
  asap( ( ) => {
235
241
  resolve( ev.button );
236
- box.close()
242
+ box.close()
237
243
  });
238
244
  });
239
245
 
246
+ // closed without a button (Escape, the close box): nothing was chosen
247
+ box.on( "closed", ( ) => resolve( null ) );
248
+
240
249
  box.show();
241
250
  } );
242
251
  }
@@ -46,6 +46,22 @@ function getRoot( ) {
46
46
  return document.body;
47
47
  }
48
48
 
49
+ /**
50
+ * on the document while the event goes down (capture): a press outside
51
+ * every popup closes the group opened last, the others at the next presses.
52
+ * The event is left as it is, what is pressed handles it as usual.
53
+ * One function for all the popups: it is removed by the one that empties the list.
54
+ */
55
+
56
+ function dismissLast( e: UIEvent ) {
57
+ if( autoclose_list.some( x => x.dom.contains( e.target as Node ) ) ) {
58
+ return;
59
+ }
60
+
61
+ // the newest popup: dismiss( ) closes its whole group (a menu and its sub-menus)
62
+ autoclose_list[autoclose_list.length-1].dismiss( );
63
+ }
64
+
49
65
  /**
50
66
  * @cssvar
51
67
  * ```
@@ -233,7 +249,7 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
233
249
  if( idx>=0 ) {
234
250
  autoclose_list.splice( idx, 1 );
235
251
  if( autoclose_list.length==0 ) {
236
- document.removeEventListener( "pointerdown", this._dismiss, true );
252
+ document.removeEventListener( "pointerdown", dismissLast, true );
237
253
  }
238
254
  }
239
255
  }
@@ -263,7 +279,7 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
263
279
 
264
280
  if( this.props.autoClose ) {
265
281
  if( autoclose_list.length==0 ) {
266
- document.addEventListener( "pointerdown", this._dismiss, true );
282
+ document.addEventListener( "pointerdown", dismissLast, true );
267
283
  }
268
284
 
269
285
  autoclose_list.push( this );
@@ -320,23 +336,6 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
320
336
  this._do_hide( );
321
337
  }
322
338
 
323
- /**
324
- * binded
325
- *
326
- * listened on the document while the event goes down (capture): a press
327
- * closes the popups even when what is pressed stops its propagation.
328
- * the event is left as it is, what is pressed handles it as usual.
329
- */
330
-
331
- private _dismiss = ( e: UIEvent ) => {
332
- const onac = autoclose_list.some( x=> x.dom.contains(e.target as Node) )
333
- if( onac ) {
334
- return;
335
- }
336
-
337
- this.dismiss( );
338
- }
339
-
340
339
  /**
341
340
  * dismiss all popup belonging to the same group as 'this'
342
341
  */
@@ -369,7 +368,7 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
369
368
  const list = inc_group.reverse( );
370
369
  autoclose_list = excl_group;
371
370
  if( autoclose_list.length==0 ) {
372
- document.removeEventListener( "pointerdown", this._dismiss, true );
371
+ document.removeEventListener( "pointerdown", dismissLast, true );
373
372
  }
374
373
 
375
374
  list.forEach( x => x.close() );
@@ -19,7 +19,7 @@ import { class_ns } from '../../core/core_tools';
19
19
  import { EventCallback } from '../../core/core_events';
20
20
 
21
21
  import { Label } from '../label/label';
22
- import { Input } from '../input/input'
22
+ import { Input, getRadioOwner } from '../input/input'
23
23
  import { HBox } from '../boxes/boxes';
24
24
 
25
25
  import icons from "../assets/icons"
@@ -152,10 +152,14 @@ export class Radio extends Component<RadioProps,RadioEvents> {
152
152
  */
153
153
 
154
154
  checkValue( vname: string ) {
155
- const grp = this.props.name;
156
- const el = this.parentElement().query<Radio>( `input[name="${grp}"][value="${vname}"]` );
155
+ // the radios of the group: in the form that holds this one, else in
156
+ // its dialog, else in the document (as a Form reads them)
157
+ const owner = getRadioOwner( this.dom );
158
+ const selector = `input[name="${this.props.name}"][value="${vname}"]`;
159
+
160
+ const el = owner.querySelector( selector ) as HTMLInputElement;
157
161
  if( el ) {
158
- el.setCheck( true );
162
+ el.checked = true;
159
163
  }
160
164
  }
161
165
  }