x4js 2.3.22 → 2.3.24

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 (56) hide show
  1. package/aicontext.md +31 -1
  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/dialog/dialog.module.scss +4 -4
  14. package/src/components/dialog/dialog.ts +1 -0
  15. package/src/components/dockingview/dockingview.module.scss +9 -11
  16. package/src/components/dockingview/dockingview.ts +1 -0
  17. package/src/components/form/form.module.scss +2 -2
  18. package/src/components/form/form.ts +1 -1
  19. package/src/components/gauge/gauge.module.scss +2 -2
  20. package/src/components/gridview/gridview.module.scss +0 -1
  21. package/src/components/input/input.module.scss +2 -2
  22. package/src/components/input/input.ts +3 -0
  23. package/src/components/keyboard/keyboard.ts +11 -1
  24. package/src/components/label/label.module.scss +3 -3
  25. package/src/components/listbox/listbox.module.scss +6 -3
  26. package/src/components/listbox/listbox.ts +2 -0
  27. package/src/components/menu/menu.module.scss +1 -2
  28. package/src/components/messages/messages.module.scss +18 -17
  29. package/src/components/messages/messages.ts +70 -12
  30. package/src/components/messages/pen-field.svg +1 -1
  31. package/src/components/panel/panel.module.scss +4 -3
  32. package/src/components/panel/panel.ts +1 -0
  33. package/src/components/popup/popup.module.scss +2 -3
  34. package/src/components/popup/popup.ts +1 -0
  35. package/src/components/propgrid/progrid.module.scss +4 -4
  36. package/src/components/radio/radio.module.scss +9 -3
  37. package/src/components/radio/radio.ts +7 -1
  38. package/src/components/select/select.module.scss +17 -12
  39. package/src/components/select/select.ts +9 -0
  40. package/src/components/settingsview/settingsview.module.scss +1 -4
  41. package/src/components/spreadsheet/spreadsheet.module.scss +0 -1
  42. package/src/components/switch/switch.module.scss +3 -2
  43. package/src/components/switch/switch.ts +1 -0
  44. package/src/components/tabs/tabs.module.scss +6 -3
  45. package/src/components/tabs/tabs.ts +3 -0
  46. package/src/components/tag/tag.module.scss +1 -1
  47. package/src/components/textarea/textarea.module.scss +8 -1
  48. package/src/components/textarea/textarea.ts +3 -0
  49. package/src/components/themes.scss +79 -12
  50. package/src/components/tickline/tickline.module.scss +1 -1
  51. package/src/components/tooltips/tooltips.scss +4 -3
  52. package/src/components/tooltips/tooltips.ts +1 -0
  53. package/src/components/treeview/treeview.module.scss +6 -2
  54. package/src/components/treeview/treeview.ts +1 -0
  55. package/src/core/core_application.ts +47 -0
  56. package/src/core/core_colors.ts +112 -17
@@ -18,14 +18,15 @@
18
18
 
19
19
  :root {
20
20
  --tooltip-caption-background: var( --color-primary-a70 );
21
- --tooltip-caption-color: white;
21
+ --tooltip-caption-color: var( --accent-color );
22
22
 
23
- --tooltip-icon-background: white;
23
+ --tooltip-icon-background: var( --accent-color );
24
24
  --tooltip-icon-color: var( --color-primary-a70 );
25
25
 
26
26
  --tooltip-background: var( --color-primary-a10 ); //white;
27
27
  --tooltip-color: var( --color-primary-a90 );
28
28
  --tooltip-border: var( --color-primary-a20 );
29
+ --tooltip-image-background: var( --background-primary );
29
30
  }
30
31
 
31
32
  .x4tooltip {
@@ -67,7 +68,7 @@
67
68
  img {
68
69
  max-width: 100px;
69
70
  max-height: 50px;
70
- background-color: white;
71
+ background-color: var( --tooltip-image-background );
71
72
  margin: 4px;
72
73
  }
73
74
  }
@@ -104,6 +104,7 @@ function closeTT( ) {
104
104
  * --tooltip-background
105
105
  * --tooltip-color
106
106
  * --tooltip-border
107
+ * --tooltip-image-background
107
108
  * ```
108
109
  */
109
110
 
@@ -17,10 +17,12 @@
17
17
 
18
18
  :root {
19
19
 
20
- --treeview-background: white;
20
+ --treeview-background: var( --background-primary );
21
+
22
+ --treeitem-color: var( --text-primary );
21
23
 
22
24
  --treeitem-backgound-hover: var( --background-secondary );
23
- --treeitem-color-hover: var( );
25
+ --treeitem-color-hover: var( --text-primary );
24
26
 
25
27
  --treeitem-background-sel: var( --accent-background );
26
28
  --treeitem-color-sel: var( --accent-color );
@@ -97,6 +99,8 @@
97
99
 
98
100
  &:hover {
99
101
  background-color: var( --treeitem-backgound-hover );
102
+ --label-color: var( --treeitem-color-hover );
103
+ --label-icon-color: var( --treeitem-color-hover );
100
104
  }
101
105
 
102
106
  &.selected {
@@ -72,6 +72,7 @@ export interface TreeviewEvents extends ComponentEvents {
72
72
  * @cssvar
73
73
  * ```
74
74
  * --treeview-background
75
+ * --treeitem-color
75
76
  * --treeitem-backgound-hover
76
77
  * --treeitem-color-hover
77
78
  * --treeitem-background-sel
@@ -42,6 +42,9 @@ export interface ApplicationEvents extends EventMap {
42
42
  // singleton
43
43
  let main_app: Application = null;
44
44
 
45
+ // the class of a theme on <html>: x4theme-<name> (see Application.setTheme)
46
+ const THEME_PREFIX = "x4theme-";
47
+
45
48
  /**
46
49
  * Provides information about the user's device and browser capabilities.
47
50
  */
@@ -201,6 +204,50 @@ export class Application<E extends ApplicationEvents = ApplicationEvents> extend
201
204
  Application.instance().fire( "global", { msg, params } );
202
205
  }
203
206
 
207
+ /**
208
+ * Selects the theme of the page: the class `x4theme-<name>` on `<html>`, in place
209
+ * of the one of the theme before.
210
+ * - `""`: the light theme of x4, the one by default: no class.
211
+ * - `"dark"`: the dark theme of x4, like the theme Dark Modern of VS Code
212
+ * (`html.x4theme-dark` in themes.scss).
213
+ * - any other name: a theme of the application, defined in its own css under
214
+ * `html.x4theme-<name>`, with the variables of themes.scss it changes.
215
+ * @param name - the name of the theme; "" for the light theme.
216
+ * @example
217
+ * Application.setTheme( "dark" ); // the dark theme of x4
218
+ * Application.setTheme( "pink" ); // html.x4theme-pink { --color-primary-a0: ...; } in the css of the application
219
+ * Application.setTheme( "" ); // back to the light theme
220
+ */
221
+
222
+ static setTheme( name: string ) {
223
+ const classes = document.documentElement.classList;
224
+
225
+ const current = Application.getTheme( );
226
+ if( current ) {
227
+ classes.remove( THEME_PREFIX + current );
228
+ }
229
+
230
+ if( name ) {
231
+ classes.add( THEME_PREFIX + name );
232
+ }
233
+ }
234
+
235
+ /**
236
+ * The name of the theme of the page, as setTheme got it: `""` for the light theme
237
+ * of x4, `"dark"` for its dark theme, or the name of a theme of the application.
238
+ */
239
+
240
+ static getTheme( ): string {
241
+ const classes = document.documentElement.classList;
242
+ for( let i = 0; i < classes.length; i++ ) {
243
+ if( classes[i].startsWith( THEME_PREFIX ) ) {
244
+ return classes[i].replace( THEME_PREFIX, "" );
245
+ }
246
+ }
247
+
248
+ return "";
249
+ }
250
+
204
251
  /**
205
252
  *
206
253
  */
@@ -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