x4js 2.2.45 → 2.2.46

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.45",
3
+ "version": "2.2.46",
4
4
  "type": "module",
5
5
  "main": "src/x4.ts",
6
6
  "module": "src/x4.ts",
@@ -33,9 +33,7 @@
33
33
  "application"
34
34
  ],
35
35
  "devDependencies": {
36
- "typescript": "^5.8.3"
37
- },
38
- "dependencies": {
36
+ "typescript": "^5.8.3",
39
37
  "typedoc": "^0.28.19",
40
38
  "typedoc-plugin-markdown": "^4.12.0"
41
39
  }
@@ -136,6 +136,10 @@
136
136
  }
137
137
  }
138
138
 
139
+ &.empty .body .x4viewport {
140
+ height: 100%;
141
+ }
142
+
139
143
  &> #footer {
140
144
  border-top: 1px solid var(--border);
141
145
  margin: 0;
@@ -125,9 +125,7 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
125
125
  contextmenu: (e) => this._on_ctx_menu(e),
126
126
  } );
127
127
 
128
- asap( ( ) => {
129
128
  this.setItems( props.items, false );
130
- } );
131
129
  }
132
130
 
133
131
  /**
@@ -446,6 +444,7 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
446
444
  let update_sel = false;
447
445
 
448
446
  if( this._items.length ) {
447
+ this.removeClass( "empty" );
449
448
  const content = items.map( x => this.renderItem(x) );
450
449
  this._view.setContent( content );
451
450
 
@@ -454,6 +453,7 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
454
453
  }
455
454
  }
456
455
  else {
456
+ this.addClass( "empty" );
457
457
  update_sel = oldSel.length>0;
458
458
  this._view.setContent( new Label( { cls: "empty vertical", icon: icons.empty, text: this.props.emptyMsg ?? _tr.global.empty_list } ) );
459
459
  }
@@ -28,10 +28,12 @@
28
28
  .x4notification {
29
29
  @extend %shadow-xl;
30
30
 
31
- padding: 8px;
31
+ padding: 4px 8px;
32
32
  border: 1px solid var(--notification-border);
33
33
  border-left: 3px solid var( --accent-background );
34
34
  background-color: var( --notification-background );
35
+ min-width: 250px;
36
+ max-width: 30vw;
35
37
 
36
38
  &> .x4hbox {
37
39
  gap: 8px;
@@ -77,8 +79,8 @@
77
79
  color: var( --color-gray-7 );
78
80
  border: none;
79
81
 
80
- &:hover {
82
+ //&:hover {
81
83
  //background-color: var( -- );;
82
- }
84
+ //}
83
85
  }
84
86
  }
@@ -47,6 +47,8 @@ interface NotificationProps extends ComponentProps {
47
47
 
48
48
  @class_ns( "x4" )
49
49
  export class Notification extends Popup {
50
+ private static list = new Set<Notification>( );
51
+
50
52
  constructor( props: NotificationProps ) {
51
53
  super( { } );
52
54
 
@@ -85,19 +87,34 @@ export class Notification extends Popup {
85
87
  }
86
88
 
87
89
  close( ) {
90
+ Notification.list.delete( this );
88
91
  this.clearTimeout( "close" );
89
92
  super.close( );
90
93
  }
91
94
 
92
95
  display( time_in_s = 0 ) {
93
- const r = new Rect( 0, 0, window.innerWidth, window.innerHeight );
94
- this.displayNear( r, "bottom right", "bottom right", { x: -20, y: -10 } );
95
-
96
+ Notification.list.add( this );
96
97
  if( time_in_s ) {
97
98
  this.setTimeout( "close", time_in_s*1000, ( ) => {
98
99
  this.close()
99
100
  } );
100
101
  }
102
+
103
+ Notification.updatePositions( )
104
+ }
105
+
106
+ static updatePositions( ) {
107
+ const r = new Rect( 0, 0, window.innerWidth, window.innerHeight );
108
+
109
+ for( const n of this.list ) {
110
+ n.displayNear( r, "bottom right", "bottom right", { x: -20, y: -10 } );
111
+ const nr = n.getBoundingRect( );
112
+ r.height -= nr.height+10;
113
+ if( r.height<10 ) {
114
+ r.height = 10;
115
+ }
116
+ }
117
+
101
118
  }
102
119
  }
103
120
 
@@ -22,24 +22,7 @@
22
22
  --textarea-selection: var( --accent-background );
23
23
  }
24
24
 
25
- .x4textarea {
26
- margin: 5px;
27
-
28
- .x4label{
29
- gap: 0;
30
- padding: 4px 0;
31
-
32
- &::after {
33
- content: ":"
34
- }
35
- }
36
-
37
- .x4label:has(.empty) {
38
- display: none;
39
- }
40
-
41
- textarea {
42
- @extend %flex;
25
+ .x4simpletextarea {
43
26
 
44
27
  padding: 4px;
45
28
  outline: none;
@@ -60,4 +43,25 @@
60
43
  resize: none;
61
44
  }
62
45
  }
46
+
47
+ .x4textarea {
48
+ margin: 5px;
49
+
50
+ .x4label{
51
+ gap: 0;
52
+ padding: 4px 0;
53
+
54
+ &::after {
55
+ content: ":"
56
+ }
57
+ }
58
+
59
+ .x4label:has(.empty) {
60
+ display: none;
61
+ }
62
+
63
+ .x4simpletextarea {
64
+ @extend %flex;
65
+
66
+ }
63
67
  }
@@ -42,7 +42,8 @@ interface TextAreaProps extends BaseProps {
42
42
  *
43
43
  */
44
44
 
45
- class SimpleTextArea extends Component<TextAreaProps> {
45
+ @class_ns( "x4" )
46
+ export class SimpleTextArea extends Component<TextAreaProps> {
46
47
 
47
48
  constructor( props: TextAreaProps ) {
48
49
  super( { ...props, tag: "textarea" } );
@@ -72,6 +73,10 @@ class SimpleTextArea extends Component<TextAreaProps> {
72
73
  return text;
73
74
  }
74
75
 
76
+ scrollToBottom( ) {
77
+ this.dom.scrollTop = this.dom.scrollHeight;
78
+ }
79
+
75
80
  queryInterface<T>(name: string): T {
76
81
  if( name=="form-element" ) {
77
82
  const i: IFormElement = {
@@ -115,6 +120,10 @@ export class TextArea extends VBox {
115
120
  return this._input.getText( );
116
121
  }
117
122
 
123
+ scrollToBottom( ) {
124
+ this._input.scrollToBottom( );
125
+ }
126
+
118
127
  queryInterface<T>(name: string): T {
119
128
  if( name=="form-element" ) {
120
129
  const i: IFormElement = {
@@ -206,9 +206,7 @@ export class Treeview extends Component<TreeviewProps,TreeviewEvents> {
206
206
  keydown: ( ev ) => this._onkey( ev ),
207
207
  });
208
208
 
209
- asap( ( ) => {
210
209
  this.setItems( props.items );
211
- } );
212
210
  }
213
211
 
214
212
  /**
@@ -478,8 +476,8 @@ export class Treeview extends Component<TreeviewProps,TreeviewEvents> {
478
476
  this._selitem = undefined;
479
477
  }
480
478
 
481
- this._selection = undefined;
482
- this.fire( "selectionChange", { selection: [], empty: true } );
479
+ this._selection = undefined;
480
+ this.fire( "selectionChange", { selection: [], empty: true } );
483
481
  }
484
482
 
485
483
  /**
@@ -5,7 +5,7 @@
5
5
  **/
6
6
 
7
7
  import { CoreEvent, EventMap, EventSource } from './core_events.js';
8
- import { isPlainObject } from './core_tools.js';
8
+ import { getMemberValue, isPlainObject } from './core_tools.js';
9
9
 
10
10
  type StateData = boolean | number | string | Date | unknown;
11
11
  type State = Record<string, StateData>;
@@ -210,6 +210,11 @@ export class StateManager<T extends State> extends EventSource<StateEvents> {
210
210
  if( _path_matches( e.path, path ) ) {
211
211
  cb( e );
212
212
  }
213
+ else if( _path_matches( path, e.path ) ) {
214
+ const ee = { ...e };
215
+ ee.value = getMemberValue(this._proxy,path );
216
+ cb( ee );
217
+ }
213
218
  });
214
219
  }
215
220
  }
@@ -224,7 +229,7 @@ export class StateManager<T extends State> extends EventSource<StateEvents> {
224
229
  * state.items.push( 4 ); // "items.3 = 4"
225
230
  */
226
231
 
227
- export function makeState<T extends State>( initialState: T ): StateProxy<T> {
232
+ export function makeState<T extends Record<keyof T, StateData>>( initialState: T ): StateProxy<T> {
228
233
  return new StateManager( initialState ).proxify( );
229
234
  }
230
235