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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x4js",
3
- "version": "2.2.63",
3
+ "version": "2.2.65",
4
4
  "type": "module",
5
5
  "main": "src/x4.ts",
6
6
  "module": "src/x4.ts",
@@ -100,6 +100,11 @@
100
100
  }
101
101
  }
102
102
 
103
+ &.with-menu> #label::after {
104
+ content: '\25be';
105
+ margin-left: 2px;
106
+ }
107
+
103
108
  &:focus {
104
109
  background-color: var( --button-background-focus );
105
110
  color: var( --button-color-focus );
@@ -136,6 +136,10 @@ export class Button extends Component<ButtonProps,ButtonEvents> {
136
136
  if( props.tabindex!==false ) {
137
137
  this.setAttribute( 'tabindex', props.tabindex );
138
138
  }
139
+
140
+ if( props.menu ) {
141
+ this.addClass( "with-menu" );
142
+ }
139
143
  }
140
144
 
141
145
  /**
@@ -70,11 +70,13 @@
70
70
 
71
71
  &> .x4button {
72
72
  min-width: 80px;
73
+ #label {
74
+ white-space: nowrap;
75
+ }
73
76
 
74
77
  .x-simple-label {
75
78
  text-align: center;
76
79
  }
77
-
78
80
  }
79
81
  }
80
82
  }
@@ -21,18 +21,18 @@
21
21
  }
22
22
 
23
23
  .x4form {
24
- @extend %vbox;
24
+ @extend %vbox;
25
25
  @extend %flex;
26
-
27
- padding: 16px;
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
 
@@ -304,6 +304,15 @@
304
304
  }
305
305
  }
306
306
 
307
+ .gadget-footer {
308
+ position: absolute;
309
+ bottom: 0;
310
+ left: 0;
311
+ right: 0;
312
+ margin: 0;
313
+ border-top: 1px solid var(--border);
314
+ }
315
+
307
316
  .row-header {
308
317
  position: absolute;
309
318
  left: 0;
@@ -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
- // row header
564
- const els: Component[] = [];
565
-
566
- const count = this._getColCount();
567
- for (let col = 0; col < count; col++) {
568
- const cdata = this._getCol(col);
569
- if ((!!cdata.fixed) != fixed) {
570
- continue;
571
- }
572
-
573
- const cell = new Component({
574
- cls: `cell`,
575
- attrs: { "data-col": col },
576
- style: { width: cdata.width ? cdata.width + "px" : undefined },
577
- content: [
578
- new SimpleText({ text: cdata.footer_val }),
579
- ]
580
- });
581
-
582
- cell.addDOMEvent("dblclick", () => {
583
- this._sortCol(col);
584
- });
585
-
586
- els.push(cell);
587
- }
588
-
589
- if (fixed && els.length == 0) {
590
- return null;
591
- }
592
-
593
- const header = new Box({ cls: "col-footer", content: els });
594
- header.setClass("fixed", fixed);
595
-
596
- return header;
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 = "start";
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
- if (this._has_footer) {
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 && (e.target as HTMLElement).tagName!=="DIV" ) {
435
- return;
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
- font-weight: bold;
47
- background-color: white;
48
- color: var(--color-primary-a50);
49
-
50
- .x4box > .desc {
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-left: 8px;
52
+ padding: 8px;
69
53
  gap: 8px;
70
54
 
71
- &>.x4box {
72
- flex-grow: 1;
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
- &>.x4icon {
76
- .fa-secondary,
77
- .fa-primary {
78
- fill: var( --color-primary-a50 );
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
- width: 1em;
82
- height: 1em;
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
- &>.x4button {
86
- background-color: transparent;
87
- color: var(--color-primary-a50);
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
- g.icon ? new Icon({ id: "icon", iconId: g.icon }) : null,
168
- new VBox( { content: [
169
- new SimpleText({ cls: "title", text: g.title }),
170
- g.desc ? new SimpleText({ cls: "desc", text: g.desc }) : null,
171
- ]}),
172
- g.collapsible? new Button({ icon: icons.updown, click: (e) => toggle(tr) }) : null,
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
 
@@ -44,6 +44,8 @@
44
44
 
45
45
  &> .x4simpletext {
46
46
  padding: 0;
47
+ white-space: nowrap;
48
+ text-overflow: ellipsis;
47
49
  }
48
50
 
49
51
  &.alert {
@@ -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 Component {
39
- constructor( props: ComponentProps ) {
39
+ export class ScrollView extends Box {
40
+ constructor( props: BoxProps ) {
40
41
  super( props );
41
42
  this.setContent( new Viewport( {} ) );
42
43
  }
@@ -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
 
@@ -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 => {