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.
- package/.vscode/launch.json +14 -0
- package/.vscode/settings.json +2 -0
- package/ai-comments.txt +97 -0
- package/demo/assets/house-light.svg +1 -0
- package/demo/assets/radio.svg +4 -0
- package/demo/index.html +12 -0
- package/demo/main.scss +23 -0
- package/demo/main.ts +324 -0
- package/demo/package.json +26 -0
- package/demo/scss.d.ts +4 -0
- package/demo/svg.d.ts +1 -0
- package/demo/tsconfig.json +14 -0
- package/lib/types/x4js.d.ts +0 -2374
- package/package.json +23 -47
- package/prepack.mjs +3 -0
- package/scripts/prepack.mjs +342 -0
- package/src/colors.scss +246 -0
- package/src/components/boxes/boxes.module.scss +1 -1
- package/src/components/boxes/boxes.ts +139 -28
- package/src/components/button/button.ts +80 -33
- package/src/components/combobox/combobox.ts +1 -1
- package/src/components/dialog/dialog.ts +4 -0
- package/src/components/gridview/gridview.ts +104 -6
- package/src/components/icon/icon.ts +42 -14
- package/src/components/input/input.ts +146 -74
- package/src/components/keyboard/keyboard.module.scss +1 -1
- package/src/components/keyboard/keyboard.ts +31 -9
- package/src/components/label/label.module.scss +9 -0
- package/src/components/label/label.ts +10 -6
- package/src/components/link/link.module.scss +44 -0
- package/src/components/link/link.ts +7 -1
- package/src/components/listbox/listbox.module.scss +18 -4
- package/src/components/listbox/listbox.ts +32 -12
- package/src/components/menu/menu.module.scss +14 -2
- package/src/components/menu/menu.ts +1 -1
- package/src/components/messages/messages.ts +13 -5
- package/src/components/panel/panel.module.scss +7 -0
- package/src/components/popup/popup.ts +14 -10
- package/src/components/propgrid/propgrid.ts +1 -1
- package/src/components/shared.scss +4 -0
- package/src/components/spreadsheet/spreadsheet.ts +81 -34
- package/src/components/tabs/tabs.module.scss +1 -0
- package/src/components/textarea/textarea.ts +8 -2
- package/src/components/textedit/textedit.ts +7 -0
- package/src/components/themes.scss +2 -0
- package/src/components/tooltips/tooltips.ts +15 -3
- package/src/core/component.ts +358 -162
- package/src/core/core_application.ts +129 -32
- package/src/core/core_colors.ts +382 -119
- package/src/core/core_data.ts +73 -86
- package/src/core/core_dom.ts +10 -0
- package/src/core/core_dragdrop.ts +32 -7
- package/src/core/core_element.ts +111 -4
- package/src/core/core_events.ts +48 -11
- package/src/core/core_i18n.ts +2 -0
- package/src/core/core_pdf.ts +454 -0
- package/src/core/core_router.ts +64 -5
- package/src/core/core_state.ts +1 -0
- package/src/core/core_styles.ts +11 -12
- package/src/core/core_svg.ts +346 -51
- package/src/core/core_tools.ts +105 -17
- package/src/x4.ts +1 -0
- package/src/x4tsx.d.ts +2 -1
- package/tsconfig.json +11 -0
- package/lib/README.txt +0 -20
- package/lib/cjs/x4.css +0 -1
- package/lib/cjs/x4.js +0 -2
- package/lib/esm/x4.css +0 -1
- package/lib/esm/x4.mjs +0 -2
- 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,
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
//
|
|
431
|
-
this._selection.
|
|
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:
|
|
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
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
664
|
+
let cls = "";
|
|
665
|
+
if( column.cellClassifier ) {
|
|
666
|
+
extra_cls.push( column.cellClassifier( row, col ) );
|
|
667
|
+
}
|
|
618
668
|
|
|
619
|
-
|
|
620
|
-
|
|
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:
|
|
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.
|
|
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
|
-
|
|
990
|
-
|
|
991
|
-
|
|
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
|
*/
|
|
@@ -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
|
-
|
|
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:
|
|
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(
|
|
87
|
+
tooltip.displayAt( mouse_pos.x+17, y+5 );
|
|
76
88
|
} );
|
|
77
89
|
}
|
|
78
90
|
|