x4js 2.3.21 → 2.3.23

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 (58) hide show
  1. package/aicontext.md +91 -5
  2. package/package.json +1 -1
  3. package/src/components/btngroup/btngroup.module.scss +1 -1
  4. package/src/components/btngroup/btngroup.ts +6 -1
  5. package/src/components/button/button.module.scss +4 -4
  6. package/src/components/button/button.ts +20 -0
  7. package/src/components/calendar/calendar.module.scss +2 -1
  8. package/src/components/calendar/calendar.ts +2 -1
  9. package/src/components/chart/chart.module.scss +4 -4
  10. package/src/components/checkbox/checkbox.module.scss +2 -1
  11. package/src/components/checkbox/checkbox.ts +1 -0
  12. package/src/components/colorpicker/colorpicker.module.scss +0 -1
  13. package/src/components/components.ts +1 -0
  14. package/src/components/dialog/dialog.module.scss +2 -2
  15. package/src/components/dialog/dialog.ts +1 -0
  16. package/src/components/dockingview/dockingview.module.scss +9 -8
  17. package/src/components/dockingview/dockingview.ts +1 -0
  18. package/src/components/form/form.module.scss +2 -2
  19. package/src/components/form/form.ts +1 -1
  20. package/src/components/gauge/gauge.module.scss +2 -2
  21. package/src/components/gridview/gridview.module.scss +0 -1
  22. package/src/components/input/input.module.scss +2 -2
  23. package/src/components/input/input.ts +3 -0
  24. package/src/components/keyboard/keyboard.ts +25 -3
  25. package/src/components/label/label.module.scss +1 -1
  26. package/src/components/listbox/listbox.module.scss +6 -3
  27. package/src/components/listbox/listbox.ts +2 -0
  28. package/src/components/menu/menu.module.scss +1 -2
  29. package/src/components/messages/messages.module.scss +11 -11
  30. package/src/components/messages/messages.ts +7 -1
  31. package/src/components/messages/pen-field.svg +1 -1
  32. package/src/components/panel/panel.module.scss +4 -3
  33. package/src/components/panel/panel.ts +1 -0
  34. package/src/components/popup/popup.module.scss +2 -3
  35. package/src/components/popup/popup.ts +1 -0
  36. package/src/components/propgrid/progrid.module.scss +4 -4
  37. package/src/components/radio/radio.module.scss +9 -3
  38. package/src/components/radio/radio.ts +7 -1
  39. package/src/components/select/select.module.scss +17 -12
  40. package/src/components/select/select.ts +9 -0
  41. package/src/components/settingsview/settingsview.module.scss +178 -0
  42. package/src/components/settingsview/settingsview.ts +289 -0
  43. package/src/components/spreadsheet/spreadsheet.module.scss +0 -1
  44. package/src/components/switch/switch.module.scss +3 -2
  45. package/src/components/switch/switch.ts +1 -0
  46. package/src/components/tabs/tabs.module.scss +6 -3
  47. package/src/components/tabs/tabs.ts +3 -0
  48. package/src/components/tag/tag.module.scss +1 -1
  49. package/src/components/textarea/textarea.module.scss +8 -1
  50. package/src/components/textarea/textarea.ts +3 -0
  51. package/src/components/themes.scss +25 -12
  52. package/src/components/tickline/tickline.module.scss +1 -1
  53. package/src/components/tooltips/tooltips.scss +4 -3
  54. package/src/components/tooltips/tooltips.ts +1 -0
  55. package/src/components/treeview/treeview.module.scss +6 -2
  56. package/src/components/treeview/treeview.ts +1 -0
  57. package/src/core/core_colors.ts +112 -17
  58. package/src/core/core_i18n.ts +157 -0
@@ -26,6 +26,34 @@ function round(v: number) {
26
26
  return Math.round(v);
27
27
  }
28
28
 
29
+ let ctx2d: CanvasRenderingContext2D = null;
30
+
31
+ /**
32
+ * a colour of css as the browser paints it: [red, green, blue, alpha 0-1];
33
+ * null when the browser does not know it
34
+ */
35
+
36
+ function browserColor( value: string ) {
37
+ if( !ctx2d ) {
38
+ const canvas = document.createElement( "canvas" );
39
+ canvas.width = canvas.height = 1;
40
+ ctx2d = canvas.getContext( "2d", { willReadFrequently: true } );
41
+ }
42
+
43
+ // a value the canvas refuses leaves fillStyle as it was
44
+ ctx2d.fillStyle = "#010203";
45
+ ctx2d.fillStyle = value;
46
+ if( ctx2d.fillStyle=="#010203" ) {
47
+ return null;
48
+ }
49
+
50
+ // fillStyle keeps the colour as it was written (oklch, color(srgb ...)): the pixel is in rgb
51
+ ctx2d.clearRect( 0, 0, 1, 1 );
52
+ ctx2d.fillRect( 0, 0, 1, 1 );
53
+ const px = ctx2d.getImageData( 0, 0, 1, 1 ).data;
54
+ return [ px[0], px[1], px[2], px[3] / 255 ];
55
+ }
56
+
29
57
 
30
58
  export interface Rgb {
31
59
  red: number;
@@ -79,6 +107,7 @@ export class Color {
79
107
  * var( --color-5 )
80
108
  * cyan
81
109
  * transparent
110
+ * any other colour of css the browser knows: hsl( ), oklch( ), color-mix( )...
82
111
  */
83
112
 
84
113
  setValue(value: string): this {
@@ -137,6 +166,12 @@ export class Color {
137
166
  }
138
167
  }
139
168
 
169
+ // another colour the browser knows (color-mix, hsl, oklch...)
170
+ const known = browserColor( value );
171
+ if( known ) {
172
+ return this.setRgb( known[0], known[1], known[2], known[3] );
173
+ }
174
+
140
175
  // red, to be seen, and marked as invalid
141
176
  this.setRgb(255, 0, 0, 1);
142
177
  this.invalid = true;
@@ -343,32 +378,92 @@ export class Color {
343
378
  * @param percent - The percentage to lighten (0-100).
344
379
  * @returns The current Color instance.
345
380
  */
346
- lighten(percent: number) : this {
381
+ lighten(percent: number): this {
382
+ const factor = clamp(percent, 0, 100) / 100;
347
383
 
348
- if (percent < 0) {
349
- percent = 0;
350
- }
351
- else if (percent > 100) {
352
- percent = 100;
353
- }
384
+ const [r, g, b, a] = this.rgb;
385
+ this.rgb = [round(r + (255 - r) * factor), round(g + (255 - g) * factor), round(b + (255 - b) * factor), a];
354
386
 
355
- const factor = percent / 100;
387
+ return this;
388
+ }
356
389
 
357
- const adj = (value: number): number => {
358
- value = (value + (255 - value) * factor) | 0;
359
- if (value > 255) {
360
- value = 255;
361
- }
362
- return value;
363
- };
390
+ /**
391
+ * Darkens the color by a given percentage.
392
+ *
393
+ * @param percent - The percentage to darken (0-100).
394
+ * @returns The current Color instance.
395
+ */
396
+ darken(percent: number): this {
397
+ const factor = 1 - clamp(percent, 0, 100) / 100;
364
398
 
365
- const _ = this.rgb;
366
- this.rgb = [adj(_[0]), adj(_[1]), adj(_[2]), _[3]];
399
+ const [r, g, b, a] = this.rgb;
400
+ this.rgb = [round(r * factor), round(g * factor), round(b * factor), a];
367
401
 
368
402
  return this;
369
403
  }
404
+
405
+ /**
406
+ * Mixes the color with another one, alpha included.
407
+ *
408
+ * @param other - The other color.
409
+ * @param amount - The part of the other color (0-1): 0 keeps this color, 1 gives the other one.
410
+ * @returns The current Color instance.
411
+ */
412
+ mix(other: Color, amount: number): this {
413
+ const t = clamp(amount, 0, 1);
414
+
415
+ const [r, g, b, a] = this.rgb;
416
+ const [r2, g2, b2, a2] = other.rgb;
417
+ this.rgb = [round(r + (r2 - r) * t), round(g + (g2 - g) * t), round(b + (b2 - b) * t), a + (a2 - a) * t];
418
+
419
+ return this;
420
+ }
421
+
422
+ /**
423
+ * Gets the relative luminance of the color, as WCAG defines it. The alpha is not used.
424
+ *
425
+ * @returns The luminance (0 for black, 1 for white).
426
+ */
427
+ luminance(): number {
428
+ // the components in linear light
429
+ const lin = (v: number) => {
430
+ v /= 255;
431
+ return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
432
+ };
433
+
434
+ const [r, g, b] = this.rgb;
435
+ return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
436
+ }
437
+
438
+ /**
439
+ * Gets the contrast ratio between the color and another one, as WCAG defines it.
440
+ *
441
+ * @param other - The other color.
442
+ * @returns The ratio (1 for the same luminance, 21 for black and white).
443
+ */
444
+ contrast(other: Color): number {
445
+ const l1 = this.luminance();
446
+ const l2 = other.luminance();
447
+ return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
448
+ }
449
+
450
+ /**
451
+ * Gets, of two colors of text, the one that contrasts most with the color.
452
+ *
453
+ * @param light - The light text color (white by default).
454
+ * @param dark - The dark text color (black by default).
455
+ * @returns A copy of light or dark.
456
+ */
457
+ textColor(light = WHITE, dark = BLACK): Color {
458
+ const best = this.contrast(light) >= this.contrast(dark) ? light : dark;
459
+
460
+ const [r, g, b, a] = best.rgb;
461
+ return new Color(r, g, b, a);
462
+ }
370
463
  }
371
464
 
465
+ const WHITE = new Color(255, 255, 255);
466
+ const BLACK = new Color(0, 0, 0);
372
467
 
373
468
 
374
469
 
@@ -331,6 +331,11 @@ let fr = {
331
331
  numeric: '123',
332
332
  alpha: 'Abc'
333
333
  },
334
+
335
+ settings: {
336
+ search: 'Rechercher un paramètre',
337
+ nomatch: 'Aucun paramètre trouvé',
338
+ },
334
339
  }
335
340
  };
336
341
 
@@ -396,6 +401,151 @@ let en = {
396
401
  numeric: '123',
397
402
  alpha: 'Abc'
398
403
  },
404
+
405
+ settings: {
406
+ search: 'Search settings',
407
+ nomatch: 'No setting found',
408
+ },
409
+ }
410
+ };
411
+
412
+ /** @ignore */
413
+
414
+ let es = {
415
+ global: {
416
+ ok: 'Aceptar',
417
+ cancel: 'Cancelar',
418
+ ignore: 'Ignorar',
419
+ yes: 'Sí',
420
+ no: 'No',
421
+ abort: "Anular",
422
+ retry: "Reintentar",
423
+
424
+ error: "Error",
425
+ today: "Hoy",
426
+
427
+ open: 'Abrir',
428
+ new: 'Nuevo',
429
+ delete: 'Eliminar',
430
+ close: 'Cerrar',
431
+ save: 'Guardar',
432
+
433
+ search: 'Buscar',
434
+ search_tip: 'Escriba el texto que desea buscar. <b>Intro</b> para iniciar la búsqueda. <b>Esc</b> para cancelar.',
435
+
436
+ required_field: "dato obligatorio",
437
+ invalid_format: "formato no válido",
438
+ invalid_email: 'dirección de correo no válida',
439
+ invalid_number: 'valor numérico no válido',
440
+
441
+ diff_date_seconds: '{0} segundos',
442
+ diff_date_minutes: '{0} minutos',
443
+ diff_date_hours: '{0} horas {1} minutos',
444
+
445
+ invalid_date: 'Fecha no reconocida ({0})',
446
+ empty_list: 'Lista vacía',
447
+
448
+ date_input_formats: 'd/m/y|d.m.y|d m y|d-m-y|dmy',
449
+ date_format: 'D/M/Y',
450
+ date_time_format: 'D/M/Y H:I:S',
451
+
452
+ day_short: [ 'dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sáb' ],
453
+ day_long: [ 'domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado' ],
454
+
455
+ month_short: [ 'ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic' ],
456
+ month_long: [ 'enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre' ],
457
+
458
+ property: 'Propiedad',
459
+ value: 'Valor',
460
+
461
+ err_403: `No tiene permisos suficientes para realizar esta acción`,
462
+
463
+ copy: 'Copiar',
464
+ cut: 'Cortar',
465
+ paste: 'Pegar',
466
+
467
+ filedrop: 'Suelte un archivo',
468
+
469
+ keyboard: {
470
+ next: 'Siguiente',
471
+ numeric: '123',
472
+ alpha: 'Abc'
473
+ },
474
+
475
+ settings: {
476
+ search: 'Buscar un ajuste',
477
+ nomatch: 'Ningún ajuste encontrado',
478
+ },
479
+ }
480
+ };
481
+
482
+ /** @ignore */
483
+
484
+ let de = {
485
+ global: {
486
+ ok: 'OK',
487
+ cancel: 'Abbrechen',
488
+ ignore: 'Ignorieren',
489
+ yes: 'Ja',
490
+ no: 'Nein',
491
+ abort: "Abbrechen",
492
+ retry: "Wiederholen",
493
+
494
+ error: "Fehler",
495
+ today: "Heute",
496
+
497
+ open: 'Öffnen',
498
+ new: 'Neu',
499
+ delete: 'Löschen',
500
+ close: 'Schließen',
501
+ save: 'Speichern',
502
+
503
+ search: 'Suchen',
504
+ search_tip: 'Geben Sie den zu suchenden Text ein. <b>Enter</b> startet die Suche. <b>Esc</b> bricht ab.',
505
+
506
+ required_field: "Pflichtangabe",
507
+ invalid_format: "ungültiges Format",
508
+ invalid_email: 'ungültige E-Mail-Adresse',
509
+ invalid_number: 'ungültiger Zahlenwert',
510
+
511
+ diff_date_seconds: '{0} Sekunden',
512
+ diff_date_minutes: '{0} Minuten',
513
+ diff_date_hours: '{0} Stunden {1} Minuten',
514
+
515
+ invalid_date: 'Datum nicht erkannt ({0})',
516
+ empty_list: 'Leere Liste',
517
+
518
+ date_input_formats: 'd.m.y|d/m/y|d m y|d-m-y|dmy',
519
+ date_format: 'D.M.Y',
520
+ date_time_format: 'D.M.Y H:I:S',
521
+
522
+ day_short: [ 'So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa' ],
523
+ day_long: [ 'Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag' ],
524
+
525
+ month_short: [ 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez' ],
526
+ month_long: [ 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ],
527
+
528
+ property: 'Eigenschaft',
529
+ value: 'Wert',
530
+
531
+ err_403: `Sie haben nicht die erforderlichen Rechte für diese Aktion`,
532
+
533
+ copy: 'Kopieren',
534
+ cut: 'Ausschneiden',
535
+ paste: 'Einfügen',
536
+
537
+ filedrop: 'Datei hier ablegen',
538
+
539
+ keyboard: {
540
+ next: 'Weiter',
541
+ numeric: '123',
542
+ alpha: 'Abc'
543
+ },
544
+
545
+ settings: {
546
+ search: 'Einstellungen durchsuchen',
547
+ nomatch: 'Keine Einstellung gefunden',
548
+ },
399
549
  }
400
550
  };
401
551
 
@@ -405,6 +555,13 @@ addTranslation( 'fr', fr );
405
555
  createLanguage( 'en', 'fr' );
406
556
  addTranslation( 'en', en );
407
557
 
558
+ // a key they lack is taken in english
559
+ createLanguage( 'es', 'en' );
560
+ addTranslation( 'es', es );
561
+
562
+ createLanguage( 'de', 'en' );
563
+ addTranslation( 'de', de );
564
+
408
565
  selectLanguage( 'fr' ); // by default
409
566
 
410
567