x4js 2.3.9 → 2.3.11
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/aicontext.md +70 -3
- package/aiguide.md +60 -0
- package/package.json +1 -1
- package/src/components/autocomplete/autocomplete.module.scss +28 -0
- package/src/components/autocomplete/autocomplete.ts +361 -0
- package/src/components/boxes/boxes.ts +66 -0
- package/src/components/button/button.ts +1 -1
- package/src/components/chart/chart.module.scss +126 -0
- package/src/components/chart/chart.ts +758 -0
- package/src/components/combobox/combobox.ts +5 -5
- package/src/components/components.ts +2 -0
- package/src/components/header/header.ts +38 -3
- package/src/components/listbox/listbox.module.scss +4 -5
- package/src/components/listbox/listbox.ts +1 -1
- package/src/components/select/select.module.scss +26 -17
- package/src/components/select/select.ts +60 -10
- package/src/components/spreadsheet/spreadsheet.module.scss +31 -0
- package/src/components/spreadsheet/spreadsheet.ts +522 -11
- package/src/components/textarea/textarea.ts +2 -2
- package/src/components/textedit/textedit.ts +4 -4
- package/src/core/core_application.ts +1 -0
- package/src/core/core_svg.ts +2 -2
- package/readme.npm.md +0 -248
|
@@ -38,6 +38,7 @@ interface DropdownEvents extends PopupEvents {
|
|
|
38
38
|
|
|
39
39
|
interface DropdownProps extends Omit<PopupProps,"content"> {
|
|
40
40
|
items: ListItem[];
|
|
41
|
+
renderer?: ( item: ListItem ) => Component;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
|
|
@@ -49,7 +50,7 @@ export class DropdownList extends Popup<DropdownProps,DropdownEvents> {
|
|
|
49
50
|
constructor( props: DropdownProps ) {
|
|
50
51
|
super( props );
|
|
51
52
|
|
|
52
|
-
this._list = new Listbox( { items: props.items } );
|
|
53
|
+
this._list = new Listbox( { items: props.items, renderer: props.renderer } );
|
|
53
54
|
this.setContent( this._list );
|
|
54
55
|
|
|
55
56
|
this.addDOMEvent( "mousedown", ( ev: Event ) => {
|
|
@@ -81,7 +82,7 @@ interface ComboboxEvents extends ComponentEvents {
|
|
|
81
82
|
interface ComboboxProps extends Omit<ComponentProps,"content"> {
|
|
82
83
|
label?: string;
|
|
83
84
|
name?: string;
|
|
84
|
-
value?:
|
|
85
|
+
value?: ListboxID;
|
|
85
86
|
labelWidth?: number | string;
|
|
86
87
|
readonly?: boolean;
|
|
87
88
|
required?: boolean;
|
|
@@ -145,10 +146,9 @@ export class Combobox extends Component<ComboboxProps,ComboboxEvents> {
|
|
|
145
146
|
const itm = list.getItem(sel);
|
|
146
147
|
if( itm ) {
|
|
147
148
|
list.select( sel, false );
|
|
149
|
+
this._input.setValue( itm.text as string );
|
|
148
150
|
}
|
|
149
151
|
|
|
150
|
-
this._input.setValue( itm.text as string );
|
|
151
|
-
|
|
152
152
|
if( !this._prevent_close ) {
|
|
153
153
|
this._popup.show( false );
|
|
154
154
|
}
|
|
@@ -162,7 +162,7 @@ export class Combobox extends Component<ComboboxProps,ComboboxEvents> {
|
|
|
162
162
|
}
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
-
if( props.value ) {
|
|
165
|
+
if( props.value!==undefined && props.value!==null ) {
|
|
166
166
|
_select( props.value );
|
|
167
167
|
}
|
|
168
168
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from "./autocomplete/autocomplete"
|
|
1
2
|
export * from "./boxes/boxes"
|
|
2
3
|
export * from "./breadcrumb/breadcrumb"
|
|
3
4
|
export * from "./btngroup/btngroup"
|
|
@@ -5,6 +6,7 @@ export * from "./button/button"
|
|
|
5
6
|
export * from "./calendar/calendar"
|
|
6
7
|
export * from "./canvas/canvas"
|
|
7
8
|
export * from "./canvas/canvas_ex"
|
|
9
|
+
export * from "./chart/chart"
|
|
8
10
|
export * from "./checkbox/checkbox"
|
|
9
11
|
export * from "./colorinput/colorinput"
|
|
10
12
|
export * from "./colorpicker/colorpicker"
|
|
@@ -19,10 +19,15 @@ interface HeaderProps extends Omit<ComponentProps,"content"> {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const CELL_MW = 8;
|
|
22
|
+
const MAX_COLS = 10; // columns with a default name (ref-c1...ref-c10) handled by the listbox css
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* by default when a header item is resized, the 'target' style '--{name}-width' is updated
|
|
25
|
-
*
|
|
26
|
+
*
|
|
27
|
+
* a Listbox handles 10 columns at most: the width of its cells is given by the
|
|
28
|
+
* css classes ref-c1 to ref-c10 (text of the item, then sub_cols).
|
|
29
|
+
* above, give a name to the header item and handle '--{name}-width' in your own css.
|
|
30
|
+
*
|
|
26
31
|
* @cssvar
|
|
27
32
|
* ```
|
|
28
33
|
* --header-background-hover
|
|
@@ -40,6 +45,10 @@ export class Header extends HBox<HeaderProps> {
|
|
|
40
45
|
constructor( props: HeaderProps ) {
|
|
41
46
|
super( props );
|
|
42
47
|
|
|
48
|
+
if( props.items?.some( ( x, index ) => !x.name && index>=MAX_COLS ) ) {
|
|
49
|
+
console.warn( `Header: ${props.items.length} columns, only the first ${MAX_COLS} get a width in a Listbox (ref-c1 to ref-c${MAX_COLS}).` );
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
this._els = props.items?.map( (x,index) => {
|
|
44
53
|
|
|
45
54
|
if( !x.name ) {
|
|
@@ -65,16 +74,42 @@ export class Header extends HBox<HeaderProps> {
|
|
|
65
74
|
this._calc_sizes( );
|
|
66
75
|
})
|
|
67
76
|
|
|
77
|
+
let resized = false;
|
|
78
|
+
|
|
68
79
|
sizer.on( "start", ( ) => {
|
|
69
|
-
//
|
|
80
|
+
// freeze the flex columns: if they keep taking the remaining space, the left side
|
|
81
|
+
// of the resized cell moves, and the sizer (which measures from it) runs away
|
|
82
|
+
resized = false;
|
|
83
|
+
|
|
84
|
+
this._els.forEach( c => {
|
|
85
|
+
const flex = c.getInternalData( "flex" );
|
|
86
|
+
if( flex ) {
|
|
87
|
+
c.setInternalData( "saved-flex", flex );
|
|
88
|
+
c.setInternalData( "flex", 0 );
|
|
89
|
+
c.setInternalData( "width", Math.round( c.getBoundingRect( ).width ) );
|
|
90
|
+
}
|
|
91
|
+
});
|
|
70
92
|
} );
|
|
71
93
|
|
|
72
94
|
sizer.on( "stop", ( ) => {
|
|
73
|
-
|
|
95
|
+
this._els.forEach( c => {
|
|
96
|
+
const flex = c.getInternalData( "saved-flex" );
|
|
97
|
+
if( flex ) {
|
|
98
|
+
c.setInternalData( "saved-flex", 0 );
|
|
99
|
+
|
|
100
|
+
// the resized column keeps its new width
|
|
101
|
+
if( c!==cell || !resized ) {
|
|
102
|
+
c.setInternalData( "flex", flex );
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
this._calc_sizes( );
|
|
74
108
|
} );
|
|
75
109
|
|
|
76
110
|
sizer.on( "resize", ( ev ) => {
|
|
77
111
|
//cell.setStyleValue( "flexGrow", "0" );
|
|
112
|
+
resized = true;
|
|
78
113
|
const sze = ev.size<CELL_MW ? CELL_MW : ev.size;
|
|
79
114
|
cell.setInternalData("flex",0);
|
|
80
115
|
cell.setInternalData("width",sze);
|
|
@@ -131,11 +131,10 @@
|
|
|
131
131
|
overflow: hidden;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
.ref-c5 { width: var( --ref-c5-width); }
|
|
134
|
+
// 10 columns max (see Header)
|
|
135
|
+
@for $i from 1 through 10 {
|
|
136
|
+
.ref-c#{$i} { width: var( --ref-c#{$i}-width ); }
|
|
137
|
+
}
|
|
139
138
|
|
|
140
139
|
//&:active{
|
|
141
140
|
//background-color: var( --color-80 );
|
|
@@ -35,7 +35,7 @@ export type ListboxID = number | string;
|
|
|
35
35
|
export interface ListItem {
|
|
36
36
|
id: ListboxID;
|
|
37
37
|
text: string | UnsafeHtml;
|
|
38
|
-
sub_cols?: (string | UnsafeHtml | Component)[]; // extra columns
|
|
38
|
+
sub_cols?: (string | UnsafeHtml | Component)[]; // extra columns (9 max: 10 columns with text), a null value creates no cell
|
|
39
39
|
|
|
40
40
|
iconId?: string;
|
|
41
41
|
data?: any;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
|
|
2
|
+
/**
|
|
3
|
+
* @cssvar
|
|
4
|
+
* --select-border
|
|
5
|
+
* --select-border-focus
|
|
6
|
+
* --select-background
|
|
7
|
+
*/
|
|
2
8
|
|
|
3
9
|
.x4select,
|
|
4
10
|
::picker(select) {
|
|
@@ -8,8 +14,8 @@
|
|
|
8
14
|
outline: none;
|
|
9
15
|
|
|
10
16
|
border-radius: 0;
|
|
11
|
-
border: 1px solid var( --border );
|
|
12
|
-
background-color: white;
|
|
17
|
+
border: 1px solid var( --select-border, var( --border ) );
|
|
18
|
+
background-color: var( --select-background, white );
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
.x4select {
|
|
@@ -21,23 +27,26 @@
|
|
|
21
27
|
background-position: right 6px center;
|
|
22
28
|
background-size: 12px 8px;
|
|
23
29
|
padding-right: 23px;
|
|
24
|
-
}
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
31
|
+
&:focus-visible {
|
|
32
|
+
border-color: var( --select-border-focus, var( --accent-background ) );
|
|
33
|
+
}
|
|
30
34
|
|
|
31
|
-
option
|
|
32
|
-
|
|
33
|
-
color: var( --accent-color );
|
|
34
|
-
}
|
|
35
|
+
.select-option {
|
|
36
|
+
padding: 5px;
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
38
|
+
&:checked {
|
|
39
|
+
background-color: var( --accent-background );
|
|
40
|
+
color: var( --accent-color );
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&:hover {
|
|
44
|
+
background-color: var( --accent-background-focus );
|
|
45
|
+
color: var( --accent-color );
|
|
46
|
+
}
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
&::checkmark {
|
|
49
|
+
display: none;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
43
52
|
}
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
import { EventCallback } from '../../core/core_events';
|
|
19
|
-
import { Component,
|
|
20
|
-
import { class_ns } from '../../core/core_tools';
|
|
19
|
+
import { Component, ComponentEvents, ComponentProps, EvChange, EvFocus } from '../../core/component';
|
|
20
|
+
import { class_ns, IComponentInterface, IFormElement, isArray } from '../../core/core_tools';
|
|
21
21
|
|
|
22
22
|
import { ListboxID, ListItem } from '../components';
|
|
23
23
|
|
|
@@ -29,14 +29,15 @@ import "./select.module.scss"
|
|
|
29
29
|
|
|
30
30
|
export interface SelectProps extends ComponentProps {
|
|
31
31
|
name?: string;
|
|
32
|
-
value
|
|
32
|
+
value?: ListboxID;
|
|
33
33
|
items: ListItem[];
|
|
34
34
|
multiple?: boolean;
|
|
35
|
+
required?: boolean;
|
|
35
36
|
change?: EventCallback<EvChange>;
|
|
36
37
|
focus?: EventCallback<EvFocus>;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
interface SelectEvents extends
|
|
40
|
+
interface SelectEvents extends ComponentEvents {
|
|
40
41
|
focus: EvFocus;
|
|
41
42
|
change: EvChange;
|
|
42
43
|
}
|
|
@@ -60,17 +61,21 @@ export class Select extends Component<SelectProps,SelectEvents> {
|
|
|
60
61
|
this.setAttribute( "name", props.name );
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
if( props.multiple ) {
|
|
65
|
+
this.setAttribute( "multiple", true );
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if( props.required ) {
|
|
69
|
+
this.setAttribute( "required", true );
|
|
70
|
+
}
|
|
71
|
+
|
|
63
72
|
this.setItems( props.items );
|
|
64
|
-
|
|
73
|
+
|
|
65
74
|
this.addDOMEvent( "blur", ( e ) => { this.on_focus(e,true);} );
|
|
66
75
|
this.addDOMEvent( "focus", ( e ) => { this.on_focus(e,false);} );
|
|
67
76
|
this.addDOMEvent( "input", ( e ) => { this.on_change(e as InputEvent); });
|
|
68
77
|
|
|
69
|
-
if( props.
|
|
70
|
-
this.setAttribute( "multiple", true );
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if( props.value ) {
|
|
78
|
+
if( props.value!==undefined ) {
|
|
74
79
|
this.setValue( props.value );
|
|
75
80
|
}
|
|
76
81
|
}
|
|
@@ -107,14 +112,21 @@ export class Select extends Component<SelectProps,SelectEvents> {
|
|
|
107
112
|
*/
|
|
108
113
|
|
|
109
114
|
setItems( items: ListItem[] ) {
|
|
115
|
+
const sel = this._items ? this.getSelValues( ) : [];
|
|
116
|
+
|
|
110
117
|
this._items = [...items];
|
|
111
118
|
this.setContent( items.map( x => {
|
|
112
119
|
return new Component( {
|
|
113
120
|
tag: "option",
|
|
121
|
+
cls: x.cls ? "select-option "+x.cls : "select-option",
|
|
114
122
|
attrs: { value: x.id },
|
|
115
123
|
content: x.text,
|
|
116
124
|
});
|
|
117
125
|
} ));
|
|
126
|
+
|
|
127
|
+
if( sel.length ) {
|
|
128
|
+
this.setSelValues( sel );
|
|
129
|
+
}
|
|
118
130
|
}
|
|
119
131
|
|
|
120
132
|
/**
|
|
@@ -136,6 +148,44 @@ export class Select extends Component<SelectProps,SelectEvents> {
|
|
|
136
148
|
const el = (this.dom as HTMLSelectElement);
|
|
137
149
|
el.selectedIndex = this._items.findIndex( x => x.id===value );
|
|
138
150
|
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @returns all selected ids (multiple)
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
public getSelValues( ) : ListboxID[] {
|
|
157
|
+
const el = (this.dom as HTMLSelectElement);
|
|
158
|
+
return Array.from( el.selectedOptions ).map( o => this._items[o.index].id );
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @param values ids to select (multiple)
|
|
163
|
+
*/
|
|
164
|
+
|
|
165
|
+
public setSelValues( values: ListboxID[] ) {
|
|
166
|
+
const el = (this.dom as HTMLSelectElement);
|
|
167
|
+
this._items.forEach( ( x, i ) => {
|
|
168
|
+
el.options[i].selected = values.includes( x.id );
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
*
|
|
174
|
+
*/
|
|
175
|
+
|
|
176
|
+
override queryInterface<T extends IComponentInterface>( name: string ): T {
|
|
177
|
+
if( name=="form-element" ) {
|
|
178
|
+
const i: IFormElement = {
|
|
179
|
+
getRawValue: ( ): any => { return this.props.multiple ? this.getSelValues() : this.getValue(); },
|
|
180
|
+
setRawValue: ( v: any ) => { isArray(v) ? this.setSelValues(v) : this.setValue(v); },
|
|
181
|
+
isValid: ( ) => { return (this.dom as HTMLSelectElement).checkValidity(); }
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
return i as unknown as T;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return super.queryInterface( name );
|
|
188
|
+
}
|
|
139
189
|
}
|
|
140
190
|
|
|
141
191
|
|
|
@@ -97,6 +97,37 @@
|
|
|
97
97
|
&.align-right {
|
|
98
98
|
justify-content: end;
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
&.editing {
|
|
102
|
+
position: relative;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// inline editor: cover the cell
|
|
106
|
+
.cell-editor {
|
|
107
|
+
position: absolute;
|
|
108
|
+
inset: 0;
|
|
109
|
+
width: 100%;
|
|
110
|
+
height: 100%;
|
|
111
|
+
box-sizing: border-box;
|
|
112
|
+
margin: 0;
|
|
113
|
+
padding: 0 4px;
|
|
114
|
+
|
|
115
|
+
font: inherit;
|
|
116
|
+
outline: none;
|
|
117
|
+
border: 2px solid var( --spreadsheet-row-background-sel );
|
|
118
|
+
border-radius: 0;
|
|
119
|
+
|
|
120
|
+
color: var( --spreadsheet-cell-color );
|
|
121
|
+
background-color: var( --spreadsheet-background );
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
&.align-center .cell-editor {
|
|
125
|
+
text-align: center;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
&.align-right .cell-editor {
|
|
129
|
+
text-align: right;
|
|
130
|
+
}
|
|
100
131
|
}
|
|
101
132
|
|
|
102
133
|
.x4viewport {
|