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
@@ -18,7 +18,7 @@
18
18
  import { Component, ComponentContent, ComponentEvents, ComponentProps, EvClick, EvContextMenu, EvDblClick, EvSelectionChange, componentFromDOM } from '../../core/component';
19
19
  import { GridColumn } from '../gridview/gridview'
20
20
 
21
- import { class_ns, isNumber, isString, setWaitCursor } from '../../core/core_tools';
21
+ import { class_ns, isNumber, isString, UnsafeHtml } from '../../core/core_tools';
22
22
  import { CoreEvent, EventCallback, EventMap } from '../../core/core_events';
23
23
  import { kbNav } from '../../core/core_tools';
24
24
 
@@ -31,15 +31,21 @@ import { SimpleText } from '../label/label';
31
31
 
32
32
  import check_icon from "../checkbox/check.svg";
33
33
  import "./spreadsheet.module.scss"
34
- import { CoreElement, EvViewChange } from '../../x4.js';
34
+ import { CoreElement } from '../../x4.js';
35
35
 
36
36
  interface CellRef {
37
37
  col: number;
38
38
  row: number;
39
39
  }
40
40
 
41
+ export type CellClassifier = ( row: number, col: number ) => string; // return the cell computed class
42
+ export type RowClassifier = (row: number ) => string; // return the row computed class
41
43
  export type CellRenderer = (row: number, col: number, content: any) => Component;
42
44
 
45
+ export interface SpreadsheetColumn extends Omit<GridColumn,"classifier"> {
46
+ cellClassifier?: CellClassifier;
47
+ }
48
+
43
49
 
44
50
  function mkid(row: number, col: number) {
45
51
  return ((row & 0xfffff) << 12) | (col & 0xfff);
@@ -85,6 +91,7 @@ export class Store extends CoreElement<StoreEvents> {
85
91
  n.set(k, v);
86
92
  }
87
93
  });
94
+ this._data = n;
88
95
  }
89
96
 
90
97
  this._maxrows = rows;
@@ -108,6 +115,10 @@ export class Store extends CoreElement<StoreEvents> {
108
115
  return this._data.get(mkid(row, col));
109
116
  }
110
117
 
118
+ hasData( row: number, col?: number ) {
119
+ return this._data.has( col===undefined ? row : mkid(row, col));
120
+ }
121
+
111
122
  lock() {
112
123
  this._lock++;
113
124
  }
@@ -121,6 +132,29 @@ export class Store extends CoreElement<StoreEvents> {
121
132
  }
122
133
  }
123
134
 
135
+ removeRow( row_num: number ) {
136
+
137
+ if( row_num>=this._maxrows ) {
138
+ return;
139
+ }
140
+
141
+ const n = new Map<number, any>();
142
+ this._data.forEach( (v, k) => {
143
+ const row = k >> 12;
144
+ if (row != row_num) {
145
+ if( row>row_num ) {
146
+ k = mkid(row-1,k&0xfff)
147
+ }
148
+
149
+ n.set(k, v);
150
+ }
151
+ } );
152
+ this._data = n;
153
+
154
+ this._maxrows--;
155
+ this._changed( );
156
+ }
157
+
124
158
  private _changed() {
125
159
  if (!this._lock) {
126
160
  this.fire("changed", {});
@@ -130,6 +164,12 @@ export class Store extends CoreElement<StoreEvents> {
130
164
  this._change = true;
131
165
  }
132
166
  }
167
+
168
+ clear( ) {
169
+ this._data = new Map();
170
+ this._maxrows = 0;
171
+ this._changed( );
172
+ }
133
173
  }
134
174
 
135
175
 
@@ -149,7 +189,9 @@ export interface SpreadsheetEvents extends ComponentEvents {
149
189
  export interface SpreadsheetProps extends ComponentProps {
150
190
  footer?: boolean;
151
191
  store: Store;
152
- columns: GridColumn[];
192
+ columns: SpreadsheetColumn[];
193
+ rowClassifier?: RowClassifier;
194
+
153
195
 
154
196
  click?: EventCallback<EvClick>;
155
197
  dblClick?: EventCallback<EvDblClick>;
@@ -169,7 +211,7 @@ export interface SpreadsheetProps extends ComponentProps {
169
211
  @class_ns("x4")
170
212
  export class Spreadsheet<P extends SpreadsheetProps = SpreadsheetProps, E extends SpreadsheetEvents = SpreadsheetEvents> extends Component<P, E> {
171
213
 
172
- private _columns: GridColumn[];
214
+ private _columns: SpreadsheetColumn[];
173
215
  private _store: Store;
174
216
 
175
217
  private _lock: number;
@@ -427,9 +469,17 @@ export class Spreadsheet<P extends SpreadsheetProps = SpreadsheetProps, E extend
427
469
  return;
428
470
  }
429
471
 
430
- //if (ev.change_type == 'change') {
431
- this._selection.clear();
432
- //}
472
+ // try to keep selection
473
+ if (ev.type == 'changed' && this._selection.size ) {
474
+ const nsel = new Set<number>();
475
+ this._selection.forEach(x => {
476
+ if( this._store.hasData( x ) ) {
477
+ nsel.add( x );
478
+ }
479
+ });
480
+
481
+ this._selection = nsel;
482
+ }
433
483
 
434
484
  this._updateFlexs();
435
485
  this._computeFullSize();
@@ -598,10 +648,10 @@ export class Spreadsheet<P extends SpreadsheetProps = SpreadsheetProps, E extend
598
648
  return header;
599
649
  }
600
650
  /**
601
- *
651
+ * extra_cls est input/output
602
652
  */
603
653
 
604
- private _renderCell(row: number, column: GridColumn, extra_cls: string[]): ComponentContent {
654
+ private _renderCell(row: number, column: SpreadsheetColumn, extra_cls: string[]): ComponentContent {
605
655
 
606
656
  const col = column.id;
607
657
  const type = column.type;
@@ -611,14 +661,14 @@ export class Spreadsheet<P extends SpreadsheetProps = SpreadsheetProps, E extend
611
661
  return null;
612
662
  }
613
663
 
614
- let cls = "";
615
- //if( column.classifier ) {
616
- // extra_cls.push( column.classifier( data, rec, col ) );
617
- //}
664
+ let cls = "";
665
+ if( column.cellClassifier ) {
666
+ extra_cls.push( column.cellClassifier( row, col ) );
667
+ }
618
668
 
619
- //if (data instanceof Function) {
620
- // return data(rec, col);
621
- //}
669
+ if( data instanceof UnsafeHtml ) {
670
+ return data;
671
+ }
622
672
 
623
673
  if (column.formatter) {
624
674
  return column.formatter(data);
@@ -661,7 +711,7 @@ export class Spreadsheet<P extends SpreadsheetProps = SpreadsheetProps, E extend
661
711
 
662
712
  case "percent": {
663
713
  return new Box({
664
- cls: "percent" + cls,
714
+ cls: "percent " + cls,
665
715
  content: new Component({ cls: "bar", width: data + "%" })
666
716
  });
667
717
  }
@@ -733,8 +783,16 @@ export class Spreadsheet<P extends SpreadsheetProps = SpreadsheetProps, E extend
733
783
 
734
784
  els.push(el);
735
785
  }
786
+
787
+ let row_cls = 'row';
788
+ if( this.props.rowClassifier ) {
789
+ const xtra = this.props.rowClassifier( rowid );
790
+ if( xtra ) {
791
+ row_cls += ' ' + xtra.trim();
792
+ }
793
+ }
736
794
 
737
- return new Box({ cls: "row", style: { top: top.toFixed(2) + "px" }, content: els });
795
+ return new Box({ cls: row_cls, style: { top: top.toFixed(2) + "px" }, content: els });
738
796
  }
739
797
 
740
798
  /**
@@ -968,11 +1026,7 @@ export class Spreadsheet<P extends SpreadsheetProps = SpreadsheetProps, E extend
968
1026
  this._addSelection(ref.ref,true);
969
1027
  }
970
1028
 
971
- this._on_dblclk(e, ref.row, ref.col);
972
-
973
- debugger;
974
- //const rec = this._dataview.getByIndex( row );
975
- //this.fire( "dblClick", { context: rec } );
1029
+ this.fire( "dblClick", { context: { row: ref.row, col: ref.col } } );
976
1030
  }
977
1031
  });
978
1032
 
@@ -986,9 +1040,10 @@ export class Spreadsheet<P extends SpreadsheetProps = SpreadsheetProps, E extend
986
1040
  this._addSelection(ref.ref, true );
987
1041
  }
988
1042
 
989
- debugger;
990
- //const rec = this._dataview.getByIndex( row );
991
- //this.fire( "contextMenu", { uievent: e, context: rec } );
1043
+ this.fire( "contextMenu", { uievent: e, context: { row: ref.row, col: ref.col } } );
1044
+ }
1045
+ else {
1046
+ this.fire( "contextMenu", { uievent: e, context: null } );
992
1047
  }
993
1048
 
994
1049
  e.preventDefault();
@@ -1017,14 +1072,6 @@ export class Spreadsheet<P extends SpreadsheetProps = SpreadsheetProps, E extend
1017
1072
  this._computeFullSize();
1018
1073
  }
1019
1074
 
1020
- /**
1021
- *
1022
- */
1023
-
1024
- protected _on_dblclk(e: UIEvent, row: number, col: number) {
1025
-
1026
- }
1027
-
1028
1075
  /**
1029
1076
  *
1030
1077
  */
@@ -40,6 +40,7 @@
40
40
  &> .body {
41
41
  padding: 8px;
42
42
  border: 1px solid var( --border );
43
+ min-height: 0;
43
44
  }
44
45
  }
45
46
 
@@ -32,6 +32,7 @@ interface TextAreaProps extends BaseProps {
32
32
  value?: string;
33
33
  resize?: boolean;
34
34
  readonly?: boolean;
35
+ trim?: boolean;
35
36
  }
36
37
 
37
38
 
@@ -39,7 +40,7 @@ interface TextAreaProps extends BaseProps {
39
40
  *
40
41
  */
41
42
 
42
- class SimpleTextArea extends Component {
43
+ class SimpleTextArea extends Component<TextAreaProps> {
43
44
 
44
45
  constructor( props: TextAreaProps ) {
45
46
  super( { ...props, tag: "textarea" } );
@@ -61,7 +62,12 @@ class SimpleTextArea extends Component {
61
62
  }
62
63
 
63
64
  getText( ) {
64
- return (this.dom as HTMLTextAreaElement).value;
65
+ let text = (this.dom as HTMLTextAreaElement).value;
66
+ if( this.props.trim!==false ) {
67
+ text = text.trim();
68
+ }
69
+
70
+ return text;
65
71
  }
66
72
 
67
73
  queryInterface<T>(name: string): T {
@@ -88,7 +88,14 @@ export class TextEdit extends HBox {
88
88
  }
89
89
 
90
90
  const gadgets = props.inputGadgets ?? [];
91
+ gadgets.forEach( g => {
92
+ g.addClass( "gadget" );
93
+ })
94
+
95
+
91
96
  const iprops: InputProps = { ...props, id: props.inputId, attrs: props.inputAttrs, width: props.inputWidth };
97
+ // no propagation...
98
+ delete iprops.cls;
92
99
 
93
100
  this.setContent( [
94
101
  props.label ? new HBox( { id: "label", width: props.labelWidth, content: [
@@ -33,6 +33,7 @@ $color--interval: 8.4%;
33
33
  --color-primary-a90: #{darken($color--base, $color--interval * 4)};
34
34
  --color-primary-a100: #000000;
35
35
 
36
+ --color-danger-a30: #{lighten(#c01010,30%)};
36
37
  --color-danger-a50: #c01010;
37
38
  --color-danger-a60: #{darken(#c01010,10%)};
38
39
 
@@ -46,6 +47,7 @@ $color--interval: 8.4%;
46
47
  // Backgrounds
47
48
  --background-primary: var(--color-primary-a0); // Fond principal
48
49
  --background-secondary: var(--color-primary-a10); // Fond secondaire
50
+ --background-ternary: #f4f4f4; // Fond secondaire
49
51
 
50
52
  // Texts
51
53
  --text-primary: var(--color-primary-a100); // Texte principal
@@ -28,6 +28,7 @@ import icon from "./comments-question.svg"
28
28
 
29
29
  let last_hit: HTMLElement = null;
30
30
  let tooltip: Tooltip = null;
31
+ let mouse_pos: Point = {x:0, y:0 };
31
32
 
32
33
  const timer = new Timer( );
33
34
 
@@ -53,15 +54,20 @@ export function initTooltips( ) {
53
54
 
54
55
  }, true );
55
56
 
56
- document.addEventListener( "mouseleave", ( ev: Event ) => {
57
+ document.addEventListener( "mouseleave", ( ev: MouseEvent ) => {
57
58
  //console.log( "leave", ev.target );
58
-
59
59
  if( last_hit && ev.target==last_hit ) {
60
60
  last_hit = null;
61
61
  closeTT( );
62
62
  }
63
63
 
64
64
  }, true );
65
+
66
+ document.addEventListener( "mousemove", ( ev: MouseEvent ) => {
67
+ if( last_hit ) {
68
+ mouse_pos = { x:ev.pageX, y:ev.pageY }
69
+ }
70
+ });
65
71
  }
66
72
 
67
73
  function showTT( text: string, rc: Rect, pt: Point ) {
@@ -71,8 +77,14 @@ function showTT( text: string, rc: Rect, pt: Point ) {
71
77
 
72
78
  timer.setTimeout( null, 300, ( ) => {
73
79
  tooltip.setText( unsafeHtml(text) );
80
+
81
+ let y = mouse_pos.y;
82
+ if( rc.contains(mouse_pos) ) {
83
+ y = rc.bottom;
84
+ }
85
+
74
86
  //tooltip.displayNear( rc, "top left", "bottom left", {x:0,y:4} );
75
- tooltip.displayAt( pt.x+17, pt.y+17 );
87
+ tooltip.displayAt( mouse_pos.x+17, y+5 );
76
88
  } );
77
89
  }
78
90