x4js 1.4.35 → 1.4.39

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.
@@ -44,6 +44,43 @@ export interface ICaptureInfo {
44
44
  handler: EventHandler<UIEvent>;
45
45
  iframes: NodeListOf<HTMLIFrameElement>;
46
46
  }
47
+ /** @ignore properties without 'px' unit */
48
+ export declare const _x4_unitless: {
49
+ animationIterationCount: number;
50
+ borderImageOutset: number;
51
+ borderImageSlice: number;
52
+ borderImageWidth: number;
53
+ boxFlex: number;
54
+ boxFlexGroup: number;
55
+ boxOrdinalGroup: number;
56
+ columnCount: number;
57
+ flex: number;
58
+ flexGrow: number;
59
+ flexPositive: number;
60
+ flexShrink: number;
61
+ flexNegative: number;
62
+ flexOrder: number;
63
+ gridRow: number;
64
+ gridColumn: number;
65
+ fontWeight: number;
66
+ lineClamp: number;
67
+ lineHeight: number;
68
+ opacity: number;
69
+ order: number;
70
+ orphans: number;
71
+ tabSize: number;
72
+ widows: number;
73
+ zIndex: number;
74
+ zoom: number;
75
+ fillOpacity: number;
76
+ floodOpacity: number;
77
+ stopOpacity: number;
78
+ strokeDasharray: number;
79
+ strokeDashoffset: number;
80
+ strokeMiterlimit: number;
81
+ strokeOpacity: number;
82
+ strokeWidth: number;
83
+ };
47
84
  /**
48
85
  *
49
86
  */
package/lib/component.js CHANGED
@@ -28,7 +28,7 @@
28
28
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
29
  */
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.Container = exports.SizerOverlay = exports.EvOverlayResize = exports.Separator = exports.EvSize = exports.Space = exports.Flex = exports.flyWrap = exports.Component = exports.EvFocus = exports.EvDblClick = exports.html = exports.isHtmlString = exports.HtmlString = void 0;
31
+ exports.Container = exports.SizerOverlay = exports.EvOverlayResize = exports.Separator = exports.EvSize = exports.Space = exports.Flex = exports.flyWrap = exports.Component = exports.EvFocus = exports.EvDblClick = exports._x4_unitless = exports.html = exports.isHtmlString = exports.HtmlString = void 0;
32
32
  /**
33
33
  * @todo
34
34
  * create Container class
@@ -50,7 +50,7 @@ const _x4_el_store = Symbol();
50
50
  /** @ignore where Component is stored in dom */
51
51
  const _x4_el_sym = Symbol();
52
52
  /** @ignore properties without 'px' unit */
53
- const _x4_unitless = {
53
+ exports._x4_unitless = {
54
54
  animationIterationCount: 1, borderImageOutset: 1, borderImageSlice: 1, borderImageWidth: 1, boxFlex: 1, boxFlexGroup: 1,
55
55
  boxOrdinalGroup: 1, columnCount: 1, flex: 1, flexGrow: 1, flexPositive: 1, flexShrink: 1, flexNegative: 1, flexOrder: 1,
56
56
  gridRow: 1, gridColumn: 1, fontWeight: 1, lineClamp: 1, lineHeight: 1, opacity: 1, order: 1, orphans: 1, tabSize: 1, widows: 1,
@@ -273,7 +273,7 @@ class Component extends base_component_1.BaseComponent {
273
273
  if (value === undefined) {
274
274
  value = null;
275
275
  }
276
- else if (!_x4_unitless[name] && ((0, tools_1.isNumber)(value) || reNumber.test(value))) {
276
+ else if (!exports._x4_unitless[name] && ((0, tools_1.isNumber)(value) || reNumber.test(value))) {
277
277
  value = value + 'px';
278
278
  }
279
279
  this.m_dom.style[name] = value;
package/lib/dialog.js CHANGED
@@ -149,6 +149,7 @@ class Dialog extends popup_1.Popup {
149
149
  this.setStyleValue('height', this.m_props.dlgHeight + '%');
150
150
  }
151
151
  this.addClass('@resized');
152
+ this.m_el_title.setStyleValue("width", "auto");
152
153
  if (this.m_props.maximized) {
153
154
  this._maximize();
154
155
  this.emit('size', (0, component_1.EvSize)(null));
package/lib/formatters.js CHANGED
@@ -64,8 +64,9 @@ function money_formatter(input) {
64
64
  return '';
65
65
  }
66
66
  let val = (0, tools_1.roundTo)(typeof (input) == 'string' ? parseFloat(input) : input, 2);
67
- if (val === -0.00)
67
+ if (Object.is(val, -0.00)) {
68
68
  val = 0.00;
69
+ }
69
70
  let res = moneyFmt.format(val);
70
71
  return res;
71
72
  }
package/lib/gridview.js CHANGED
@@ -642,6 +642,10 @@ class GridView extends layout_1.VLayout {
642
642
  return;
643
643
  }
644
644
  const update = () => {
645
+ // element destroyed between updateScroll and now
646
+ if (!this.dom) {
647
+ return;
648
+ }
645
649
  let newTop = Math.floor(this.m_view_el.dom.scrollTop / (this.m_itemHeight || 1));
646
650
  if (newTop != this.m_topIndex || forceUpdate) {
647
651
  this.m_topIndex = newTop;
@@ -753,6 +753,7 @@ class Spreadsheet extends layout_1.VLayout {
753
753
  case 'Enter': {
754
754
  this.editCurCell();
755
755
  event.stopPropagation();
756
+ event.preventDefault();
756
757
  break;
757
758
  }
758
759
  case 'Delete': {
@@ -894,8 +895,8 @@ class Spreadsheet extends layout_1.VLayout {
894
895
  style: {
895
896
  left: rc.left - prc.left,
896
897
  top: rc.top - prc.top,
897
- width: rc.width,
898
- height: rc.height
898
+ width: rc.width - 1,
899
+ height: rc.height - 1
899
900
  },
900
901
  tabIndex: false,
901
902
  value: cellvalue,
@@ -931,10 +932,15 @@ class Spreadsheet extends layout_1.VLayout {
931
932
  this.killEditor(true);
932
933
  });
933
934
  input.setDomEvent('keydown', (e) => {
935
+ // prevented by edit...
936
+ if (e.defaultPrevented) {
937
+ return;
938
+ }
934
939
  switch (e.key) {
935
940
  case 'Escape': {
936
941
  this.killEditor(false);
937
942
  e.stopPropagation();
943
+ e.preventDefault();
938
944
  break;
939
945
  }
940
946
  case 'Enter':
@@ -945,18 +951,21 @@ class Spreadsheet extends layout_1.VLayout {
945
951
  }
946
952
  movesel(0, sens);
947
953
  e.stopPropagation();
954
+ e.preventDefault();
948
955
  break;
949
956
  }
950
957
  case 'ArrowUp':
951
958
  case 'Up': {
952
959
  movesel(-1, 0);
953
960
  e.stopPropagation();
961
+ e.preventDefault();
954
962
  break;
955
963
  }
956
964
  case 'ArrowDown':
957
965
  case 'Down': {
958
966
  movesel(1, 0);
959
967
  e.stopPropagation();
968
+ e.preventDefault();
960
969
  break;
961
970
  }
962
971
  }
@@ -972,6 +981,7 @@ class Spreadsheet extends layout_1.VLayout {
972
981
  case 'Escape': {
973
982
  this.killEditor(false);
974
983
  e.stopPropagation();
984
+ e.preventDefault();
975
985
  break;
976
986
  }
977
987
  case 'Enter':
@@ -982,6 +992,7 @@ class Spreadsheet extends layout_1.VLayout {
982
992
  }
983
993
  movesel(0, sens);
984
994
  e.stopPropagation();
995
+ e.preventDefault();
985
996
  break;
986
997
  }
987
998
  }
@@ -33,6 +33,7 @@ import { Component, CProps } from './component';
33
33
  declare abstract class SVGItem {
34
34
  private m_tag;
35
35
  private m_attrs;
36
+ private m_style;
36
37
  constructor(tag: string);
37
38
  /**
38
39
  * render the item
@@ -61,6 +62,7 @@ declare abstract class SVGItem {
61
62
  * @returns this
62
63
  */
63
64
  attr(name: string, value: string): this;
65
+ style(name: string, value: string | number): this;
64
66
  /**
65
67
  * add a class
66
68
  * @param name class name to add
@@ -70,6 +72,10 @@ declare abstract class SVGItem {
70
72
  *
71
73
  */
72
74
  renderAttrs(): string;
75
+ /**
76
+ *
77
+ */
78
+ renderStyle(): string;
73
79
  renderContent(): string;
74
80
  }
75
81
  /**
@@ -30,6 +30,8 @@
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
31
  exports.SVGComponent = exports.SVGPathBuilder = void 0;
32
32
  const component_1 = require("./component");
33
+ const tools_1 = require("./tools");
34
+ const reNumber = /^-?\d+(\.\d+)?$/;
33
35
  // degrees to radian
34
36
  function d2r(d) {
35
37
  return d * Math.PI / 180.0;
@@ -61,16 +63,18 @@ function clean(a, ...b) {
61
63
  class SVGItem {
62
64
  m_tag;
63
65
  m_attrs;
66
+ m_style;
64
67
  constructor(tag) {
65
68
  this.m_tag = tag;
66
69
  this.m_attrs = new Map();
70
+ this.m_style = new Map();
67
71
  }
68
72
  /**
69
73
  * render the item
70
74
  * @returns
71
75
  */
72
76
  render() {
73
- return `<${this.m_tag} ${this.renderAttrs()}>${this.renderContent()}</${this.m_tag}>`;
77
+ return `<${this.m_tag} ${this.renderAttrs()} ${this.renderStyle()}>${this.renderContent()}</${this.m_tag}>`;
74
78
  }
75
79
  /**
76
80
  * change the stroke color
@@ -109,6 +113,17 @@ class SVGItem {
109
113
  this.m_attrs.set(name, value);
110
114
  return this;
111
115
  }
116
+ style(name, value) {
117
+ if (value === undefined || value === '' || value === undefined) {
118
+ this.m_style.delete(name);
119
+ return;
120
+ }
121
+ if (!component_1._x4_unitless[name] && ((0, tools_1.isNumber)(value) || reNumber.test(value))) {
122
+ value = value + 'px';
123
+ }
124
+ this.m_style.set(name, '' + value);
125
+ return this;
126
+ }
112
127
  /**
113
128
  * add a class
114
129
  * @param name class name to add
@@ -122,12 +137,28 @@ class SVGItem {
122
137
  *
123
138
  */
124
139
  renderAttrs() {
140
+ if (!this.m_attrs.size) {
141
+ return "";
142
+ }
125
143
  let result = '';
126
144
  this.m_attrs.forEach((v, k) => {
127
145
  result += ` ${k} = "${v}"`;
128
146
  });
129
147
  return result;
130
148
  }
149
+ /**
150
+ *
151
+ */
152
+ renderStyle() {
153
+ if (!this.m_style.size) {
154
+ return "";
155
+ }
156
+ let result = 'style="';
157
+ this.m_style.forEach((v, k) => {
158
+ result += `${k}:${v};`;
159
+ });
160
+ return result + '"';
161
+ }
131
162
  renderContent() {
132
163
  return '';
133
164
  }
package/lib/x4.css CHANGED
@@ -840,6 +840,7 @@ textarea::selection {
840
840
  display: flex;
841
841
  align-items: center;
842
842
  background-color: var(--x4-selection-color);
843
+ width: 0;
843
844
  }
844
845
  .x-dialog > .title .x-icon {
845
846
  width: 2em;
@@ -858,6 +859,9 @@ textarea::selection {
858
859
  .x-dialog > .title .x-label {
859
860
  border-bottom: none;
860
861
  padding: 0;
862
+ overflow: hidden;
863
+ text-overflow: ellipsis;
864
+ white-space: nowrap;
861
865
  }
862
866
  .x-dialog > .title .res-btn {
863
867
  display: none;
@@ -1042,6 +1046,8 @@ textarea::selection {
1042
1046
  .x-message-box .x-form .icon,
1043
1047
  .x-important .x-form .icon {
1044
1048
  font-size: 48px;
1049
+ width: 48px;
1050
+ height: 48px;
1045
1051
  color: var(--x4-error-color);
1046
1052
  margin-right: 8px;
1047
1053
  }
@@ -1211,10 +1217,15 @@ textarea::selection {
1211
1217
  .x-spreadsheet .x-editor {
1212
1218
  position: absolute;
1213
1219
  min-height: 0;
1220
+ margin: 0;
1214
1221
  }
1215
1222
  .x-spreadsheet .x-editor input {
1216
1223
  margin: 0;
1217
1224
  min-height: 0;
1225
+ height: 100%;
1226
+ }
1227
+ .x-form .x-spreadsheet .x-editor {
1228
+ background-color: white;
1218
1229
  }
1219
1230
  .x-side-bar {
1220
1231
  min-width: 44px;
@@ -1291,9 +1302,13 @@ textarea::selection {
1291
1302
  background-color: white;
1292
1303
  padding: 2px 0;
1293
1304
  }
1294
- .x-popup-table tr:hover,
1295
1305
  .x-popup-table tr.x-selected {
1296
- background-color: #c8ffff;
1306
+ background-color: var(--x4-selection-color);
1307
+ color: var(--x4-selection-text);
1308
+ }
1309
+ .x-popup-table tr:hover {
1310
+ background-color: var(--x4-hover-color);
1311
+ color: var(--x4-hover-text);
1297
1312
  }
1298
1313
  .x-popup-table td {
1299
1314
  padding: 3px 8px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x4js",
3
- "version": "1.4.35",
3
+ "version": "1.4.39",
4
4
  "description": "X4js core files",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
package/src/component.ts CHANGED
@@ -67,7 +67,7 @@ const _x4_el_store = Symbol();
67
67
  const _x4_el_sym = Symbol();
68
68
 
69
69
  /** @ignore properties without 'px' unit */
70
- const _x4_unitless = {
70
+ export const _x4_unitless = {
71
71
  animationIterationCount: 1, borderImageOutset: 1, borderImageSlice: 1, borderImageWidth: 1, boxFlex: 1, boxFlexGroup: 1,
72
72
  boxOrdinalGroup: 1, columnCount: 1, flex: 1, flexGrow: 1, flexPositive: 1, flexShrink: 1, flexNegative: 1, flexOrder: 1,
73
73
  gridRow: 1, gridColumn: 1, fontWeight: 1, lineClamp: 1, lineHeight: 1, opacity: 1, order: 1, orphans: 1, tabSize: 1, widows: 1,
package/src/dialog.ts CHANGED
@@ -233,6 +233,7 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogBoxEven
233
233
  }
234
234
 
235
235
  this.addClass('@resized');
236
+ this.m_el_title.setStyleValue( "width", "auto" );
236
237
 
237
238
  if (this.m_props.maximized) {
238
239
  this._maximize();
package/src/formatters.ts CHANGED
@@ -74,7 +74,9 @@ export function money_formatter(input: any): string {
74
74
  }
75
75
 
76
76
  let val: number = roundTo(typeof (input) == 'string' ? parseFloat(input) : input, 2);
77
- if (val === -0.00) val = 0.00;
77
+ if (Object.is(val, -0.00)) {
78
+ val = 0.00;
79
+ }
78
80
 
79
81
  let res = moneyFmt.format(val);
80
82
  return res;
package/src/gridview.ts CHANGED
@@ -855,6 +855,12 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
855
855
  }
856
856
 
857
857
  const update = () => {
858
+
859
+ // element destroyed between updateScroll and now
860
+ if( !this.dom ) {
861
+ return;
862
+ }
863
+
858
864
  let newTop = Math.floor(this.m_view_el.dom.scrollTop / (this.m_itemHeight || 1));
859
865
 
860
866
  if (newTop != this.m_topIndex || forceUpdate) {
@@ -1015,6 +1015,7 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
1015
1015
  case 'Enter': {
1016
1016
  this.editCurCell();
1017
1017
  event.stopPropagation( );
1018
+ event.preventDefault( );
1018
1019
  break;
1019
1020
  }
1020
1021
 
@@ -1200,8 +1201,8 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
1200
1201
  style: {
1201
1202
  left: rc.left - prc.left,
1202
1203
  top: rc.top - prc.top,
1203
- width: rc.width,
1204
- height: rc.height
1204
+ width: rc.width - 1,
1205
+ height: rc.height - 1
1205
1206
  },
1206
1207
  tabIndex: false,
1207
1208
  value: cellvalue,
@@ -1247,11 +1248,16 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
1247
1248
  } );
1248
1249
 
1249
1250
  input.setDomEvent( 'keydown', (e: KeyboardEvent) => {
1250
-
1251
+ // prevented by edit...
1252
+ if( e.defaultPrevented ) {
1253
+ return;
1254
+ }
1255
+
1251
1256
  switch (e.key) {
1252
1257
  case 'Escape': {
1253
1258
  this.killEditor(false);
1254
1259
  e.stopPropagation();
1260
+ e.preventDefault( );
1255
1261
  break;
1256
1262
  }
1257
1263
 
@@ -1264,6 +1270,7 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
1264
1270
 
1265
1271
  movesel(0, sens);
1266
1272
  e.stopPropagation();
1273
+ e.preventDefault( );
1267
1274
  break;
1268
1275
  }
1269
1276
 
@@ -1271,6 +1278,7 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
1271
1278
  case 'Up': {
1272
1279
  movesel(-1, 0);
1273
1280
  e.stopPropagation();
1281
+ e.preventDefault( );
1274
1282
  break;
1275
1283
  }
1276
1284
 
@@ -1278,6 +1286,7 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
1278
1286
  case 'Down': {
1279
1287
  movesel(1, 0);
1280
1288
  e.stopPropagation();
1289
+ e.preventDefault( );
1281
1290
  break;
1282
1291
  }
1283
1292
  }
@@ -1296,6 +1305,7 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
1296
1305
  case 'Escape': {
1297
1306
  this.killEditor(false);
1298
1307
  e.stopPropagation();
1308
+ e.preventDefault( );
1299
1309
  break;
1300
1310
  }
1301
1311
 
@@ -1308,6 +1318,7 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
1308
1318
 
1309
1319
  movesel(0, sens);
1310
1320
  e.stopPropagation();
1321
+ e.preventDefault( );
1311
1322
  break;
1312
1323
  }
1313
1324
  }
@@ -27,8 +27,10 @@
27
27
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
28
  **/
29
29
 
30
- import { Component, CProps } from './component'
30
+ import { Component, CProps, _x4_unitless } from './component'
31
+ import { isNumber } from "./tools"
31
32
 
33
+ const reNumber = /^-?\d+(\.\d+)?$/;
32
34
 
33
35
  // degrees to radian
34
36
  function d2r( d: number ): number {
@@ -69,10 +71,12 @@ function clean( a, ...b ) {
69
71
  abstract class SVGItem {
70
72
  private m_tag: string
71
73
  private m_attrs: Map<string,string>;
74
+ private m_style: Map<string,string>;
72
75
 
73
76
  constructor( tag: string ) {
74
77
  this.m_tag = tag;
75
78
  this.m_attrs = new Map( );
79
+ this.m_style = new Map( );
76
80
  }
77
81
 
78
82
  /**
@@ -80,7 +84,7 @@ abstract class SVGItem {
80
84
  * @returns
81
85
  */
82
86
  render( ) : string {
83
- return `<${this.m_tag} ${this.renderAttrs()}>${this.renderContent( )}</${this.m_tag}>`;
87
+ return `<${this.m_tag} ${this.renderAttrs()} ${this.renderStyle()}>${this.renderContent( )}</${this.m_tag}>`;
84
88
  }
85
89
 
86
90
  /**
@@ -127,6 +131,21 @@ abstract class SVGItem {
127
131
  return this;
128
132
  }
129
133
 
134
+ style( name: string, value: string | number ) : this {
135
+
136
+ if (value === undefined || value==='' || value===undefined ) {
137
+ this.m_style.delete( name );
138
+ return;
139
+ }
140
+
141
+ if (!_x4_unitless[name] && (isNumber(value) || reNumber.test(value))) {
142
+ value = value + 'px';
143
+ }
144
+
145
+ this.m_style.set( name, ''+value );
146
+ return this;
147
+ }
148
+
130
149
  /**
131
150
  * add a class
132
151
  * @param name class name to add
@@ -142,13 +161,36 @@ abstract class SVGItem {
142
161
  *
143
162
  */
144
163
 
145
- renderAttrs( ) {
164
+ renderAttrs( ): string {
165
+ if( !this.m_attrs.size ) {
166
+ return "";
167
+ }
168
+
146
169
  let result = '';
147
170
  this.m_attrs.forEach( (v,k) => {
148
171
  result += ` ${k} = "${v}"`
149
172
  });
173
+
150
174
  return result;
151
175
  }
176
+
177
+ /**
178
+ *
179
+ */
180
+
181
+ renderStyle( ): string {
182
+
183
+ if( !this.m_style.size ) {
184
+ return "";
185
+ }
186
+
187
+ let result = 'style="';
188
+ this.m_style.forEach( (v,k) => {
189
+ result += `${k}:${v};`
190
+ });
191
+
192
+ return result+'"';
193
+ }
152
194
 
153
195
  renderContent( ): string {
154
196
  return '';
package/src/x4.less CHANGED
@@ -1052,6 +1052,7 @@ textarea {
1052
1052
  display: flex;
1053
1053
  align-items: center;
1054
1054
  background-color: var( --x4-selection-color );
1055
+ width: 0; // to avoid title changing dialog size when long
1055
1056
 
1056
1057
  .x-icon {
1057
1058
  width: 2em;
@@ -1074,6 +1075,9 @@ textarea {
1074
1075
  .x-label {
1075
1076
  border-bottom: none;
1076
1077
  padding: 0;
1078
+ overflow: hidden;
1079
+ text-overflow: ellipsis;
1080
+ white-space: nowrap;
1077
1081
  }
1078
1082
 
1079
1083
  .res-btn {
@@ -1295,6 +1299,8 @@ textarea {
1295
1299
 
1296
1300
  .icon {
1297
1301
  font-size: 48px;
1302
+ width: 48px;
1303
+ height: 48px;
1298
1304
  color: var( --x4-error-color );
1299
1305
  margin-right: 8px;
1300
1306
  }
@@ -1480,14 +1486,20 @@ textarea {
1480
1486
  .x-editor {
1481
1487
  position: absolute;
1482
1488
  min-height: 0;
1489
+ margin: 0;
1483
1490
 
1484
1491
  input {
1485
1492
  margin: 0;
1486
1493
  min-height: 0;
1494
+ height: 100%;
1487
1495
  }
1488
1496
  }
1489
1497
  }
1490
1498
 
1499
+ .x-form .x-spreadsheet .x-editor {
1500
+ background-color: white;
1501
+ }
1502
+
1491
1503
  .x-side-bar {
1492
1504
  min-width: 44px;
1493
1505
 
@@ -1592,9 +1604,15 @@ textarea {
1592
1604
  background-color: white;
1593
1605
  padding: 2px 0;
1594
1606
 
1595
- tr:hover,
1596
1607
  tr.x-selected {
1597
- background-color: rgba(200,255,255,1);
1608
+ //background-color: rgba(200,255,255,1);
1609
+ background-color: var(--x4-selection-color);
1610
+ color: var( --x4-selection-text);
1611
+ }
1612
+
1613
+ tr:hover {
1614
+ background-color: var(--x4-hover-color);
1615
+ color: var( --x4-hover-text);
1598
1616
  }
1599
1617
 
1600
1618
  td {