x4js 2.1.1 → 2.2.2

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.
Files changed (36) hide show
  1. package/package.json +9 -13
  2. package/src/components/base.scss +66 -2
  3. package/src/components/boxes/boxes.module.scss +3 -3
  4. package/src/components/button/button.module.scss +1 -1
  5. package/src/components/button/button.ts +4 -4
  6. package/src/components/calendar/calendar.module.scss +3 -3
  7. package/src/components/checkbox/checkbox.module.scss +1 -1
  8. package/src/components/combobox/combobox.module.scss +6 -6
  9. package/src/components/dialog/dialog.module.scss +4 -2
  10. package/src/components/form/form.module.scss +2 -2
  11. package/src/components/gridview/folder-open.svg +1 -0
  12. package/src/components/gridview/gridview.module.scss +14 -0
  13. package/src/components/gridview/gridview.ts +55 -15
  14. package/src/components/icon/icon.module.scss +1 -1
  15. package/src/components/label/label.module.scss +3 -2
  16. package/src/components/listbox/listbox.module.scss +2 -2
  17. package/src/components/menu/menu.module.scss +3 -3
  18. package/src/components/messages/messages.module.scss +54 -0
  19. package/src/components/messages/messages.ts +69 -3
  20. package/src/components/messages/spinner.svg +1 -0
  21. package/src/components/notification/notification.module.scss +1 -1
  22. package/src/components/panel/panel.module.scss +6 -1
  23. package/src/components/shared.scss +12 -82
  24. package/src/components/sizers/sizer.module.scss +27 -1
  25. package/src/components/sizers/sizer.ts +36 -12
  26. package/src/components/tabs/tabs.module.scss +21 -0
  27. package/src/components/tabs/tabs.ts +10 -5
  28. package/src/components/textarea/textarea.module.scss +1 -1
  29. package/src/components/textedit/textedit.module.scss +5 -5
  30. package/src/components/tooltips/tooltips.scss +1 -1
  31. package/src/components/treeview/treeview.module.scss +1 -1
  32. package/src/components/viewport/viewport.module.scss +1 -1
  33. package/src/core/core_application.ts +1 -1
  34. package/src/core/core_data.ts +20 -7
  35. package/src/x4.d.ts +10 -0
  36. package/src/x4.scss +3 -3
package/package.json CHANGED
@@ -1,17 +1,15 @@
1
1
  {
2
2
  "name": "x4js",
3
- "version": "2.1.1",
4
- "description": "X4 framework",
5
- "author": "etienne cochard",
6
- "license": "MIT",
3
+ "version": "2.2.2",
7
4
  "type": "module",
8
- "sideEffects": true,
9
- "main": "./src/x4.ts",
10
- "module": "./src/x4.ts",
11
- "types": "./src/x4.ts",
5
+ "main": "src/x4.ts",
6
+ "module": "src/x4.ts",
7
+ "types": "src/x4.ts",
12
8
  "exports": {
13
- ".": "./src/x4.ts",
14
- "./*": "./src/*.ts"
9
+ ".": "./src/x4.ts"
10
+ },
11
+ "scripts": {
12
+ "build-publish": "tsx ./publish.ts"
15
13
  },
16
14
  "files": [
17
15
  "src",
@@ -32,8 +30,6 @@
32
30
  "application"
33
31
  ],
34
32
  "devDependencies": {
35
- "typescript": "^5.8.3",
36
- "x4build": "^1.6.8",
37
- "esbuild-sass-plugin": "^3.3"
33
+ "typescript": "^5.8.3"
38
34
  }
39
35
  }
@@ -17,9 +17,73 @@
17
17
  @use "./shared.scss";
18
18
 
19
19
  .x4box {
20
- @extend .box;
20
+ @extend %box;
21
21
  }
22
22
 
23
23
  .x4flex {
24
- @extend .flex;
24
+ @extend %flex;
25
25
  }
26
+
27
+ .fit {
28
+ @extend %fit;
29
+ }
30
+
31
+ @keyframes rotating {
32
+ from {
33
+ transform: rotate(0deg);
34
+ }
35
+ to {
36
+ transform: rotate(360deg);
37
+ }
38
+ }
39
+
40
+ @keyframes shaking {
41
+ 0% {
42
+ transform: rotate(-15deg)
43
+ }
44
+
45
+ 4% {
46
+ transform: rotate(15deg)
47
+ }
48
+
49
+ 8%,24% {
50
+ transform: rotate(-18deg)
51
+ }
52
+
53
+ 12%,28% {
54
+ transform: rotate(18deg)
55
+ }
56
+
57
+ 16% {
58
+ transform: rotate(-22deg)
59
+ }
60
+
61
+ 20% {
62
+ transform: rotate(22deg)
63
+ }
64
+
65
+ 32% {
66
+ transform: rotate(-12deg)
67
+ }
68
+
69
+ 36% {
70
+ transform: rotate(12deg)
71
+ }
72
+
73
+ 40% {
74
+ transform: rotate(0deg)
75
+ }
76
+ }
77
+
78
+
79
+ .x4rotate {
80
+ animation: rotating 2s linear infinite;
81
+ }
82
+
83
+ .x4shake {
84
+ animation-name: shaking;
85
+ animation-duration: 5s;
86
+ animation-iteration-count: infinite;
87
+ animation-timing-function: linear;
88
+ animation-direction: reverse;
89
+ }
@@ -17,21 +17,21 @@
17
17
  @use "../shared.scss";
18
18
 
19
19
  .x4hbox {
20
- @extend .hbox;
20
+ @extend %hbox;
21
21
  &.align-start {
22
22
  align-items: start;
23
23
  }
24
24
  }
25
25
 
26
26
  .x4vbox {
27
- @extend .vbox;
27
+ @extend %vbox;
28
28
  }
29
29
 
30
30
  .x4stackbox {
31
31
  display: flex;
32
32
 
33
33
  &>* {
34
- @extend .fit;
34
+ @extend %fit;
35
35
  position: relative !important;
36
36
  }
37
37
 
@@ -51,7 +51,7 @@
51
51
  }
52
52
 
53
53
  .x4button {
54
- @extend .hbox;
54
+ @extend %hbox;
55
55
 
56
56
  margin: 5px;
57
57
  gap: 4px;
@@ -14,11 +14,11 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
- import { Component, ComponentEvents, ComponentProps, EvClick } from "../../core/component.ts"
18
- import { EventCallback } from '../../core/core_events.ts';
19
- import { class_ns, UnsafeHtml } from '../../core/core_tools.ts';
17
+ import { Component, ComponentEvents, ComponentProps, EvClick } from "../../core/component"
18
+ import { EventCallback } from '../../core/core_events';
19
+ import { class_ns, UnsafeHtml } from '../../core/core_tools';
20
20
 
21
- import { Icon } from "../icon/icon.ts"
21
+ import { Icon } from "../icon/icon"
22
22
 
23
23
  import "./button.module.scss";
24
24
 
@@ -81,12 +81,12 @@
81
81
  }
82
82
 
83
83
  .week {
84
- @extend .flex;
84
+ @extend %flex;
85
85
  align-items: center;
86
86
  padding: 2px;
87
87
 
88
88
  .cell {
89
- @extend .flex;
89
+ @extend %flex;
90
90
  min-width: 28px;
91
91
  min-height: 28px;
92
92
 
@@ -94,7 +94,7 @@
94
94
  text-align: center;
95
95
 
96
96
  .text {
97
- @extend .hbox;
97
+ @extend %hbox;
98
98
 
99
99
  transition: background-color 0.3s, color 0.3s;
100
100
  justify-content: center;
@@ -27,7 +27,7 @@
27
27
  }
28
28
 
29
29
  .x4checkbox {
30
- @extend .hbox;
30
+ @extend %hbox;
31
31
 
32
32
  display: flex;
33
33
  flex-direction: row;
@@ -31,8 +31,8 @@
31
31
  }
32
32
 
33
33
  .x4dropdownlist {
34
- @extend .shadow-xl;
35
- @extend .hbox;
34
+ @extend %shadow-xl;
35
+ @extend %hbox;
36
36
 
37
37
  max-height: 250px;
38
38
  max-width: 50vw;
@@ -42,7 +42,7 @@
42
42
  border: 1px solid var( --dropdown-border );
43
43
 
44
44
  .x4listbox {
45
- @extend .flex;
45
+ @extend %flex;
46
46
 
47
47
  border: none;
48
48
  margin: 0;
@@ -65,7 +65,7 @@
65
65
  }
66
66
 
67
67
  .x4combobox {
68
- @extend .hbox;
68
+ @extend %hbox;
69
69
  margin: 5px;
70
70
  gap: 6px;
71
71
 
@@ -88,14 +88,14 @@
88
88
  }
89
89
 
90
90
  &>#edit {
91
- @extend .flex;
91
+ @extend %flex;
92
92
  border-bottom: 1px solid var( --combobox-border );
93
93
  &:focus-within {
94
94
  border-bottom-color: var( --combobox-border-focus );
95
95
  }
96
96
 
97
97
  .x4input {
98
- @extend .flex;
98
+ @extend %flex;
99
99
 
100
100
  &[readonly] {
101
101
  cursor: pointer;
@@ -22,18 +22,20 @@
22
22
  }
23
23
 
24
24
  .x4dialog {
25
- @extend .shadow-xl, .vbox;
25
+ @extend %shadow-xl;
26
+ @extend %vbox;
26
27
 
27
28
  position: absolute !important;
28
29
  background-color: white;
29
30
  border: 1px solid var( --border-dark );
31
+ max-width: 99vw;
30
32
 
31
33
  &> .caption {
32
34
  padding: 8px;
33
35
  background-color: var(--color-dialog-caption);
34
36
 
35
37
  & > #title {
36
- @extend .flex;
38
+ @extend %flex;
37
39
  color: var(--color-dialog-caption-text);
38
40
  font-weight: bold;
39
41
  font-size: 120%;
@@ -21,8 +21,8 @@
21
21
  }
22
22
 
23
23
  .x4form {
24
- @extend .vbox;
25
- @extend .flex;
24
+ @extend %vbox;
25
+ @extend %flex;
26
26
 
27
27
  padding: 16px;
28
28
  background-color: var( --color-form );
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--!Font Awesome Pro 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2026 Fonticons, Inc.--><path opacity=".4" d="M32 96l0 200.6 21.7-54.3C65.9 211.9 95.3 192 128 192l320 0 0-32c0-17.7-14.3-32-32-32l-117.5 0c-25.5 0-49.9-10.1-67.9-28.1L204.1 73.4c-6-6-14.1-9.4-22.6-9.4L64 64C46.3 64 32 78.3 32 96zM49.1 426.1c-2 4.9-1.4 10.5 1.6 14.9s7.9 7 13.2 7l320 0 80 0c6.5 0 12.4-4 14.9-10.1l64-160c2-4.9 1.4-10.5-1.6-14.9s-7.9-7-13.2-7l-400 0c-6.5 0-12.4 4-14.9 10.1l-64 160z"/><path d="M448 160l0 32 32 0 0-32c0-35.3-28.7-64-64-64L298.5 96c-17 0-33.3-6.7-45.3-18.7L226.7 50.7c-12-12-28.3-18.7-45.3-18.7L64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0 80 0c19.6 0 37.3-11.9 44.6-30.2l64-160c5.9-14.8 4.1-31.5-4.8-44.7S543.9 224 528 224l-400 0c-19.6 0-37.3 11.9-44.6 30.2L32 382.8 32 96c0-17.7 14.3-32 32-32l117.5 0c8.5 0 16.6 3.4 22.6 9.4l22.6-22.6L204.1 73.4l26.5 26.5c18 18 42.4 28.1 67.9 28.1L416 128c17.7 0 32 14.3 32 32zM384 448L64 448c-5.3 0-10.3-2.6-13.2-7s-3.6-10-1.6-14.9l64-160c2.4-6.1 8.3-10.1 14.9-10.1l400 0c5.3 0 10.3 2.6 13.2 7s3.6 10 1.6 14.9l-64 160C476.4 444 470.5 448 464 448l-80 0z"/></svg>
@@ -109,7 +109,21 @@
109
109
  bottom: var( --scrollbar-size );
110
110
  left: 0;
111
111
  top: 0;
112
+
113
+ .empty {
114
+ position: relative;
115
+ left: 50%;
116
+ top: 20%;
117
+ width: fit-content;
118
+
119
+ #icon {
120
+ height: 64px;
121
+ fill: var( --accent-background );
122
+ opacity: 50%;
123
+ }
124
+ }
112
125
  }
126
+
113
127
  .row {
114
128
  position: absolute;
115
129
  left: 0;
@@ -15,9 +15,9 @@
15
15
  **/
16
16
 
17
17
 
18
- import { Component, ComponentContent, ComponentEvents, ComponentProps, EvClick, EvContextMenu, EvDblClick, EvSelectionChange, componentFromDOM } from '../../core/component';
18
+ import { Component, ComponentContent, ComponentEvents, ComponentProps, EvClick, EvContextMenu, EvDblClick, EvSelectionChange } from '../../core/component';
19
19
  import { class_ns, isNumber, isString, setWaitCursor, UnsafeHtml } from '../../core/core_tools';
20
- import { DataModel, DataStore, DataView, DataRecord, EvViewChange } from '../../core/core_data';
20
+ import { DataModel, DataStore, DataView, DataRecord, EvViewChange, SortCallback } from '../../core/core_data';
21
21
  import { EventCallback } from '../../core/core_events';
22
22
  import { kbNav } from '../../core/core_tools';
23
23
 
@@ -26,9 +26,13 @@ import { Image } from '../image/image'
26
26
  import { Box } from '../boxes/boxes';
27
27
  import { CSizer } from '../sizers/sizer'
28
28
  import { Viewport } from '../viewport/viewport';
29
- import { SimpleText } from '../label/label';
29
+ import { Label, SimpleText } from '../label/label';
30
+
31
+ import { _tr } from '../../core/core_i18n';
30
32
 
31
33
  import check_icon from "../checkbox/check.svg";
34
+ import empty_icon from "./folder-open.svg";
35
+
32
36
  import "./gridview.module.scss"
33
37
 
34
38
  export type CellRenderer = (rec: DataRecord) => Component;
@@ -55,7 +59,7 @@ export interface GridColumn {
55
59
  formatter?: (input: any) => string; // for "custom" type
56
60
  type?: ColType;
57
61
  cls?: string;
58
- sortable?: boolean;
62
+ sortable?: boolean | SortCallback;
59
63
  footer_val?: string;
60
64
  classifier?: CellClassifier;
61
65
  }
@@ -75,11 +79,16 @@ export interface GridviewProps extends ComponentProps {
75
79
  footer?: boolean;
76
80
  store: DataStore;
77
81
  columns: GridColumn[];
82
+ emptyMsg?: string;
78
83
 
79
84
  click?: EventCallback<EvClick>;
80
85
  dblClick?: EventCallback<EvDblClick>;
81
86
  contextMenu?: EventCallback<EvContextMenu>;
82
87
  selectionChange?: EventCallback<EvSelectionChange>;
88
+ sort?: {
89
+ field_id: string;
90
+ asc?: boolean;
91
+ }
83
92
  }
84
93
 
85
94
  /**
@@ -121,6 +130,7 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
121
130
  private _end: number;
122
131
 
123
132
  private _selection: Set<number>;
133
+
124
134
 
125
135
  // TODO: that
126
136
  private _num_fmt = new Intl.NumberFormat('fr-FR');
@@ -172,8 +182,11 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
172
182
 
173
183
  if (props.store) {
174
184
  this.setStore(props.store);
175
- }
176
185
 
186
+ if( props.sort ) {
187
+ this.sortCol( props.sort.field_id, props.sort.asc===true );
188
+ }
189
+ }
177
190
  }
178
191
 
179
192
  /**
@@ -240,7 +253,7 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
240
253
 
241
254
  if( sens==kbNav.first || sens==kbNav.last ) {
242
255
  let nel = sens==kbNav.first ? 0 : this._dataview.getCount()-1;
243
- this._clearSelection();
256
+ this._clearSelection( false );
244
257
  this._addSelection( nel );
245
258
  this._scrollToIndex( nel );
246
259
  return true;
@@ -249,7 +262,7 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
249
262
  const fsel = this._selection.values().next().value;
250
263
  let nel = sens==kbNav.next ? fsel+1 : fsel-1;
251
264
  if( nel>=0 && nel<this._dataview.getCount() ) {
252
- this._clearSelection();
265
+ this._clearSelection( false );
253
266
  this._addSelection( nel );
254
267
  this._scrollToIndex( nel );
255
268
  return true;
@@ -271,7 +284,7 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
271
284
  }
272
285
 
273
286
  if( nel!=fsel ) {
274
- this._clearSelection();
287
+ this._clearSelection( false );
275
288
  this._addSelection( nel );
276
289
 
277
290
  if (this._dataview.getCount() < SCROLL_LIMIT) {
@@ -612,7 +625,8 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
612
625
  this._dataview.sort([{
613
626
  field: cdata.id,
614
627
  ascending: asc,
615
- numeric: num
628
+ numeric: num,
629
+ callback: cdata.sortable instanceof Function ? cdata.sortable : undefined,
616
630
  }]);
617
631
 
618
632
  this._update(true);
@@ -785,6 +799,13 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
785
799
  rowel.addClass("selected");
786
800
  }
787
801
 
802
+ if( rowid&1 ) {
803
+ rowel.addClass( "even" );
804
+ }
805
+ else {
806
+ rowel.addClass( "odd" );
807
+ }
808
+
788
809
  return rowel;
789
810
  }
790
811
 
@@ -922,7 +943,7 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
922
943
  }
923
944
 
924
945
  this.setStyleVariable("--fixed-width", maxfw + "px");
925
- this._body.setStyleValue("height", maxh + "px");
946
+ this._body.setStyleValue("height", maxh==0 ? "100%" : maxh + "px");
926
947
  this._body.setStyleValue("width", maxw + "px");
927
948
  this._vheader.setStyleValue("height", maxh + "px");
928
949
  }
@@ -998,10 +1019,13 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
998
1019
  if (row!==undefined ) {
999
1020
  //TODO: multiselection
1000
1021
  if( !this._selection.has(row) ) {
1001
- this._clearSelection();
1022
+ this._clearSelection( false );
1002
1023
  this._addSelection(row);
1003
1024
  }
1004
1025
  }
1026
+ else {
1027
+ this._clearSelection( true );
1028
+ }
1005
1029
  });
1006
1030
 
1007
1031
  // DBLCLICK
@@ -1010,7 +1034,7 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
1010
1034
  if (row!==undefined ) {
1011
1035
  //TODO: multiselection
1012
1036
  if( !this._selection.has(row) ) {
1013
- this._clearSelection();
1037
+ this._clearSelection( false );
1014
1038
  this._addSelection(row);
1015
1039
  }
1016
1040
 
@@ -1027,7 +1051,7 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
1027
1051
  if (row!==undefined ) {
1028
1052
  //TODO: multiselection
1029
1053
  if( !this._selection.has(row) ) {
1030
- this._clearSelection();
1054
+ this._clearSelection( false );
1031
1055
  this._addSelection(row);
1032
1056
  }
1033
1057
 
@@ -1114,6 +1138,14 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
1114
1138
 
1115
1139
  // rows
1116
1140
  const rowc = this._dataview ? this._dataview.getCount() : 0;
1141
+
1142
+ // empty ?
1143
+ if( rowc==0 ) {
1144
+ this._body.setContent( new Label( { cls: "empty vertical", icon: empty_icon, text: this.props.emptyMsg ?? _tr.global.empty_list } ) );
1145
+ return;
1146
+ }
1147
+
1148
+
1117
1149
  const mul = rowc < SCROLL_LIMIT ? this._row_height : 1;
1118
1150
 
1119
1151
  const start = Math.floor(this._top / mul);
@@ -1190,10 +1222,14 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
1190
1222
  */
1191
1223
 
1192
1224
  clearSelection( ) {
1193
- this._clearSelection( );
1225
+ this._clearSelection( false );
1194
1226
  }
1195
1227
 
1196
- private _clearSelection() {
1228
+ private _clearSelection( notify: boolean ) {
1229
+ if( !this._selection.size ) {
1230
+ return;
1231
+ }
1232
+
1197
1233
  for (const ref of this._selection.keys()) {
1198
1234
  const els = this.queryAll(`.row[data-row="${ref}"]`)
1199
1235
  els.forEach(el => {
@@ -1202,6 +1238,9 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
1202
1238
  }
1203
1239
 
1204
1240
  this._selection.clear();
1241
+ if( notify ) {
1242
+ this.fire("selectionChange", { selection: [], empty: true } );
1243
+ }
1205
1244
  }
1206
1245
 
1207
1246
  /**
@@ -1274,3 +1313,4 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
1274
1313
  }
1275
1314
  }
1276
1315
 
1316
+
@@ -17,7 +17,7 @@
17
17
  @use "../shared.scss";
18
18
 
19
19
  .x4icon {
20
- @extend .hbox;
20
+ @extend %hbox;
21
21
 
22
22
  flex-shrink: 0;
23
23
  min-width: 10px;
@@ -24,7 +24,7 @@
24
24
  }
25
25
 
26
26
  .x4label {
27
- @extend .hbox;
27
+ @extend %hbox;
28
28
 
29
29
  color: var( --label-color );
30
30
  background-color: var( --label-background );
@@ -72,11 +72,12 @@
72
72
  }
73
73
 
74
74
  &.vertical {
75
- @extend .vbox;
75
+ @extend %vbox;
76
76
  }
77
77
  }
78
78
 
79
79
  .x4simpletext {
80
+ color: var(--label-color);
80
81
  text-align: left;
81
82
  &.al-center { text-align: center; }
82
83
  &.al-right { text-align: right; }
@@ -33,7 +33,7 @@
33
33
  }
34
34
 
35
35
  .x4listbox {
36
- @extend .vbox;
36
+ @extend %vbox;
37
37
 
38
38
  margin: 5px;
39
39
  border: 1px solid var( --listbox-border );
@@ -66,7 +66,7 @@
66
66
  }
67
67
 
68
68
  .x4item {
69
- @extend .flex;
69
+ @extend %flex;
70
70
 
71
71
  padding: 4px;
72
72
  background-color: transparent;
@@ -28,7 +28,7 @@
28
28
  }
29
29
 
30
30
  .x4menu {
31
- @extend .shadow-xxl;
31
+ @extend %shadow-xxl;
32
32
 
33
33
  position: absolute;
34
34
  overflow-y: auto;
@@ -44,7 +44,7 @@
44
44
  max-height: calc( 100vh - 32px );
45
45
 
46
46
  .x4cmenuitem {
47
- @extend .hbox;
47
+ @extend %hbox;
48
48
 
49
49
  transition: background-color 0.3s, color 0.3s;
50
50
 
@@ -82,7 +82,7 @@
82
82
  }
83
83
 
84
84
  #text {
85
- @extend .flex;
85
+ @extend %flex;
86
86
  }
87
87
 
88
88
  &.title {
@@ -90,3 +90,57 @@
90
90
 
91
91
  }
92
92
 
93
+
94
+ .x4progressionbox {
95
+ min-height: 200px;
96
+ min-width: 500px;
97
+
98
+ &> .x4form {
99
+ min-height: unset;
100
+ }
101
+
102
+ & .x4form {
103
+ min-width: 400px;
104
+ gap: 8px;
105
+
106
+ &> .x4hbox {
107
+ flex-grow: 1;
108
+ align-items: stretch;
109
+ .right {
110
+ flex-grow: 1;
111
+ gap: 8px;
112
+ display: grid;
113
+ grid-template-rows: auto auto 1fr;
114
+ }
115
+ }
116
+
117
+ .x4icon {
118
+ height: 64px;
119
+ animation: rotating 3s linear infinite;
120
+ fill: var(--accent-background);
121
+ align-self: center;
122
+ }
123
+
124
+ #title {
125
+ padding: 4px 16px;
126
+ line-height: 1.8em;
127
+ }
128
+
129
+ .x4progress {
130
+ margin: 0 16px;
131
+ }
132
+
133
+ #sub-text {
134
+ flex-grow: 1;
135
+ max-height: 400px;
136
+ overflow: auto;
137
+ background-color: #f5f5f5;
138
+ padding: 4px 8px;
139
+ margin: 0 16px;
140
+
141
+ .x4simpletext {
142
+ white-space: nowrap;
143
+ }
144
+ }
145
+ }
146
+ }