x4js 2.2.63 → 2.2.65
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/package.json +1 -1
- package/src/components/button/button.module.scss +5 -0
- package/src/components/button/button.ts +4 -0
- package/src/components/dialog/dialog.module.scss +3 -1
- package/src/components/form/form.module.scss +7 -7
- package/src/components/gridview/gridview.module.scss +9 -0
- package/src/components/gridview/gridview.ts +52 -41
- package/src/components/popup/popup.ts +5 -2
- package/src/components/propgrid/progrid.module.scss +53 -35
- package/src/components/propgrid/propgrid.ts +19 -6
- package/src/components/tag/tag.module.scss +2 -0
- package/src/components/viewport/viewport.ts +3 -2
- package/src/core/component.ts +3 -3
- package/src/core/core_tools.ts +8 -0
package/package.json
CHANGED
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
.x4form {
|
|
24
|
-
|
|
24
|
+
@extend %vbox;
|
|
25
25
|
@extend %flex;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
padding: 16px;
|
|
28
28
|
background-color: var( --color-form );
|
|
29
|
+
|
|
30
|
+
&.horizontal {
|
|
31
|
+
flex-direction: row;
|
|
32
|
+
}
|
|
29
33
|
|
|
30
34
|
&.no-flex {
|
|
31
35
|
flex-grow: 0;
|
|
32
36
|
}
|
|
33
|
-
|
|
34
|
-
&>.xcontainer {
|
|
35
|
-
|
|
36
|
-
}
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -74,7 +74,7 @@ export interface GridviewEvents extends ComponentEvents {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
export interface GridviewProps extends ComponentProps {
|
|
77
|
-
footer?: boolean;
|
|
77
|
+
footer?: boolean | Component;
|
|
78
78
|
store: DataStore;
|
|
79
79
|
columns: GridColumn[];
|
|
80
80
|
emptyMsg?: string;
|
|
@@ -180,7 +180,11 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
|
|
|
180
180
|
this._vis_rows = new Map();
|
|
181
181
|
this._selection = new Set();
|
|
182
182
|
this._has_fixed = false;
|
|
183
|
-
this._has_footer = props.footer;
|
|
183
|
+
this._has_footer = props.footer===true;
|
|
184
|
+
|
|
185
|
+
if( props.footer instanceof Component ) {
|
|
186
|
+
props.footer.addClass( "gadget-footer packed" );
|
|
187
|
+
}
|
|
184
188
|
|
|
185
189
|
this._columns = props.columns.map(x => x);
|
|
186
190
|
|
|
@@ -559,41 +563,45 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
|
|
|
559
563
|
*
|
|
560
564
|
*/
|
|
561
565
|
|
|
562
|
-
private _buildColFooter(fixed: boolean) {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
566
|
+
private _buildColFooter(fixed: boolean): Box {
|
|
567
|
+
|
|
568
|
+
if( !this.props.footer ) {
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// row footer
|
|
573
|
+
const els: Component[] = [];
|
|
574
|
+
|
|
575
|
+
const count = this._getColCount();
|
|
576
|
+
for (let col = 0; col < count; col++) {
|
|
577
|
+
const cdata = this._getCol(col);
|
|
578
|
+
if ((!!cdata.fixed) != fixed) {
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const cell = new Component({
|
|
583
|
+
cls: `cell`,
|
|
584
|
+
attrs: { "data-col": col },
|
|
585
|
+
style: { width: cdata.width ? cdata.width + "px" : undefined },
|
|
586
|
+
content: [
|
|
587
|
+
new SimpleText({ text: cdata.footer_val }),
|
|
588
|
+
]
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
cell.addDOMEvent("dblclick", () => {
|
|
592
|
+
this._sortCol(col);
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
els.push(cell);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (fixed && els.length == 0) {
|
|
599
|
+
return null;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const footer = new Box({ cls: "col-footer", content: els });
|
|
603
|
+
footer.setClass("fixed", fixed);
|
|
604
|
+
return footer;
|
|
597
605
|
}
|
|
598
606
|
|
|
599
607
|
/**
|
|
@@ -790,9 +798,8 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
|
|
|
790
798
|
const extra: string[] = []
|
|
791
799
|
const content = this._renderCell(rec, cdata, extra );
|
|
792
800
|
|
|
793
|
-
let align
|
|
801
|
+
let align: string;
|
|
794
802
|
switch (cdata.align) {
|
|
795
|
-
default: align = "start"; break;
|
|
796
803
|
case "center": align = "center"; break;
|
|
797
804
|
case "right": align = "end"; break;
|
|
798
805
|
}
|
|
@@ -1128,12 +1135,16 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
|
|
|
1128
1135
|
this._hheader = this._buildColHeader(false);
|
|
1129
1136
|
this._vheader = new Box({ cls: "row-header" })
|
|
1130
1137
|
|
|
1131
|
-
|
|
1138
|
+
let rfooter: Component = null;
|
|
1139
|
+
if (this._has_footer===true ) {
|
|
1132
1140
|
this._ffooter = this._buildColFooter(true);
|
|
1133
1141
|
this._footer = this._buildColFooter(false);
|
|
1134
1142
|
}
|
|
1143
|
+
else if( this.props.footer ) {
|
|
1144
|
+
rfooter = this.props.footer as Component
|
|
1145
|
+
}
|
|
1135
1146
|
|
|
1136
|
-
this.setContent([this._viewport, this._fheader, this._hheader, this._ffooter, this._footer, this._vheader]);
|
|
1147
|
+
this.setContent([this._viewport, this._fheader, this._hheader, this._ffooter, this._footer, rfooter, this._vheader]);
|
|
1137
1148
|
|
|
1138
1149
|
// compute misc variables
|
|
1139
1150
|
{
|
|
@@ -431,8 +431,11 @@ class CMover {
|
|
|
431
431
|
this.self = ref ? true : false;
|
|
432
432
|
|
|
433
433
|
const mouseDown = ( e: PointerEvent ) => {
|
|
434
|
-
if( this.self && e.target
|
|
435
|
-
|
|
434
|
+
if( this.self && e.target ) {
|
|
435
|
+
const clickable = (e.target as HTMLElement).closest('button, input, a, [role="button"]');
|
|
436
|
+
if( clickable ) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
436
439
|
}
|
|
437
440
|
|
|
438
441
|
x.setCapture( e.pointerId );
|
|
@@ -43,48 +43,66 @@
|
|
|
43
43
|
.group {
|
|
44
44
|
padding: 6px 4px 4px 4px;
|
|
45
45
|
min-height: 2em;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
font-style: italic;
|
|
52
|
-
font-weight: normal;
|
|
53
|
-
font-size: 90%;
|
|
54
|
-
color: var( --text-ternary );
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
&:not(:first-child ) {
|
|
58
|
-
border-top: 1px solid var(--color-primary-a50);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
&:not( :last-child ) {
|
|
62
|
-
border-bottom: 1px solid var(--color-primary-a50);
|
|
63
|
-
//box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.2);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
display: flex;
|
|
46
|
+
background-color: var( --background-secondary );
|
|
47
|
+
margin-bottom: 8px;
|
|
48
|
+
box-shadow: 4px 3px 8px rgba(0, 0, 0, 0.4);
|
|
49
|
+
color: var(--color-primary-a50);
|
|
50
|
+
display: flex;
|
|
67
51
|
align-items: center;
|
|
68
|
-
padding
|
|
52
|
+
padding: 8px;
|
|
69
53
|
gap: 8px;
|
|
70
54
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
55
|
+
&.sticky {
|
|
56
|
+
position: sticky;
|
|
57
|
+
top: 0;
|
|
58
|
+
z-index: 1;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.hdr {
|
|
62
|
+
&>.gadgets {
|
|
63
|
+
gap: 8px;
|
|
64
|
+
&> .x4 {
|
|
65
|
+
margin: 0;
|
|
66
|
+
padding: 0;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
74
69
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
70
|
+
.title {
|
|
71
|
+
font-weight: bold;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&>.x4button {
|
|
75
|
+
background-color: transparent;
|
|
76
|
+
color: var(--color-primary-a50);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&>.x4label {
|
|
80
|
+
.x4icon {
|
|
81
|
+
.fa-secondary,
|
|
82
|
+
.fa-primary {
|
|
83
|
+
fill: var( --color-primary-a50 );
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
width: 1em;
|
|
87
|
+
height: 1em;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
80
91
|
|
|
81
|
-
|
|
82
|
-
|
|
92
|
+
&>.desc {
|
|
93
|
+
font-style: italic;
|
|
94
|
+
font-weight: normal;
|
|
95
|
+
font-size: 90%;
|
|
96
|
+
color: var( --text-ternary );
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&:not(:first-child ) {
|
|
100
|
+
//border-top: 1px solid var(--color-primary-a50);
|
|
83
101
|
}
|
|
84
102
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
103
|
+
&:not( :last-child ) {
|
|
104
|
+
border-bottom: 1px solid var(--color-primary-a50);
|
|
105
|
+
//box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.2);
|
|
88
106
|
}
|
|
89
107
|
}
|
|
90
108
|
|
|
@@ -50,10 +50,12 @@ export interface PropertyValue {
|
|
|
50
50
|
export interface PropertyGroup {
|
|
51
51
|
title: string;
|
|
52
52
|
desc?: string;
|
|
53
|
+
name?: string;
|
|
53
54
|
icon?: string;
|
|
54
55
|
cls?: string;
|
|
55
56
|
collapsible?: boolean | number; // -1 for collapsible+collapsed
|
|
56
57
|
items: PropertyValue[];
|
|
58
|
+
gadgets?: Component[];
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
export interface PropertyProps extends ComponentProps {
|
|
@@ -118,6 +120,9 @@ export class PropertyGrid extends VBox {
|
|
|
118
120
|
if( i ) {
|
|
119
121
|
const row = this.makePropertyRow(i);
|
|
120
122
|
row.addClass( idx&1 ? "even" : "odd" );
|
|
123
|
+
if( g.name ) {
|
|
124
|
+
row.setData( "group", g.name );
|
|
125
|
+
}
|
|
121
126
|
|
|
122
127
|
items.push( row );
|
|
123
128
|
}
|
|
@@ -163,13 +168,16 @@ export class PropertyGrid extends VBox {
|
|
|
163
168
|
|
|
164
169
|
const tr = new HBox({
|
|
165
170
|
cls,
|
|
171
|
+
flex: 1,
|
|
166
172
|
content: [
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
new VBox( { flex: 1, content: [
|
|
174
|
+
new HBox( { cls: 'hdr', content: [
|
|
175
|
+
new Label({ flex:1, cls: "title", text: g.title, icon: g.icon }),
|
|
176
|
+
g.gadgets ? new HBox( { cls: 'gadgets', content: g.gadgets } ) : null,
|
|
177
|
+
g.collapsible? new Button({ icon: icons.updown, click: (e) => toggle(tr) }) : null,
|
|
178
|
+
]}),
|
|
179
|
+
g.desc ? new SimpleText({ cls: "desc", text: g.desc }) : null,
|
|
180
|
+
]}),
|
|
173
181
|
]
|
|
174
182
|
});
|
|
175
183
|
|
|
@@ -352,5 +360,10 @@ export class PropertyGrid extends VBox {
|
|
|
352
360
|
this.setPropValue( p, props[p] );
|
|
353
361
|
}
|
|
354
362
|
}
|
|
363
|
+
|
|
364
|
+
enableGroup( group_name: string, ena = true ) {
|
|
365
|
+
const els = this.queryAll( `.row[data-group="${group_name}"]` );
|
|
366
|
+
els.forEach( x => x.enable( ena ) );
|
|
367
|
+
}
|
|
355
368
|
}
|
|
356
369
|
|
|
@@ -18,6 +18,7 @@ import { class_ns } from '../../core/core_tools';
|
|
|
18
18
|
import { Component, ComponentProps } from "../../core/component"
|
|
19
19
|
|
|
20
20
|
import "./viewport.module.scss"
|
|
21
|
+
import { Box, BoxProps } from '../components';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
*
|
|
@@ -35,8 +36,8 @@ export class Viewport extends Component {
|
|
|
35
36
|
*/
|
|
36
37
|
|
|
37
38
|
@class_ns( "x4" )
|
|
38
|
-
export class ScrollView extends
|
|
39
|
-
constructor( props:
|
|
39
|
+
export class ScrollView extends Box {
|
|
40
|
+
constructor( props: BoxProps ) {
|
|
40
41
|
super( props );
|
|
41
42
|
this.setContent( new Viewport( {} ) );
|
|
42
43
|
}
|
package/src/core/component.ts
CHANGED
|
@@ -45,13 +45,12 @@ const RE_NUMBER = /^-?\d+(\.\d*)?$/;
|
|
|
45
45
|
|
|
46
46
|
function genClassNames( x: any ): string[] {
|
|
47
47
|
|
|
48
|
-
const classes = [];
|
|
49
48
|
let self = Object.getPrototypeOf(x);
|
|
50
|
-
|
|
51
49
|
if( self.constructor==Component ) {
|
|
52
|
-
return ["x4-comp"];
|
|
50
|
+
return ["x4-comp","x4"];
|
|
53
51
|
}
|
|
54
52
|
|
|
53
|
+
const classes = [];
|
|
55
54
|
while (self && self.constructor !== Component ) {
|
|
56
55
|
const clsname:string = self.constructor.name;
|
|
57
56
|
const clsns: string = Object.prototype.hasOwnProperty.call(self.constructor,x4_class_ns_sym) ? self.constructor[x4_class_ns_sym] : "";
|
|
@@ -59,6 +58,7 @@ function genClassNames( x: any ): string[] {
|
|
|
59
58
|
self = Object.getPrototypeOf(self);
|
|
60
59
|
}
|
|
61
60
|
|
|
61
|
+
classes.push( "x4" );
|
|
62
62
|
return classes;
|
|
63
63
|
}
|
|
64
64
|
|
package/src/core/core_tools.ts
CHANGED
|
@@ -113,6 +113,14 @@ export function unsafeHtml(x: string): UnsafeHtml {
|
|
|
113
113
|
return new UnsafeHtml(x);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* you can use it recursively
|
|
118
|
+
* const value = "hello";
|
|
119
|
+
* const t = unsafe`<b>${ value }</b>`; // direct text
|
|
120
|
+
* const result = unsafe`<i> ${ t } ${ [t,t,t] } </i>`
|
|
121
|
+
* const result2 = unsafe`<i> ${ [t,t,t,"world"] } </i>` // also mixes / array
|
|
122
|
+
*/
|
|
123
|
+
|
|
116
124
|
export function unsafe(strings: TemplateStringsArray, ...values: any[]): UnsafeHtml {
|
|
117
125
|
|
|
118
126
|
const resolve = ( value: any ) : string | UnsafeHtml => {
|