x4js 2.2.50 → 2.2.52

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.50",
3
+ "version": "2.2.52",
4
4
  "type": "module",
5
5
  "main": "src/x4.ts",
6
6
  "module": "src/x4.ts",
@@ -14,7 +14,7 @@
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, EvSelectionChange, makeUniqueComponentId } from '../../core/component';
17
+ import { Component, ComponentEvents, ComponentProps, EvClick, EvSelectionChange, makeUniqueComponentId } from '../../core/component';
18
18
  import { class_ns, IComponentInterface, IFormElement, kbNav, safeText, sanitizeHtml, UnsafeHtml } from '../../core/core_tools';
19
19
  import { EventCallback } from '../../core/core_events';
20
20
 
@@ -31,7 +31,8 @@ import icon from "./updown.svg";
31
31
 
32
32
 
33
33
  interface DropdownEvents extends PopupEvents {
34
- selectionChange: EvSelectionChange;
34
+ //selectionChange: EvSelectionChange;
35
+ click: EvClick;
35
36
  }
36
37
 
37
38
 
@@ -57,8 +58,9 @@ export class DropdownList extends Popup<DropdownProps,DropdownEvents> {
57
58
  ev.preventDefault( );
58
59
  }, true );
59
60
 
60
- this._list.on( "selectionChange", ( ev ) => {
61
- this.fire( "selectionChange", ev );
61
+ this._list.on( "click", ( ev ) => {
62
+ //this.fire( "selectionChange", ev );
63
+ this.fire( "click", ev );
62
64
  })
63
65
  }
64
66
 
@@ -152,11 +154,11 @@ export class Combobox extends Component<ComboboxProps,ComboboxEvents> {
152
154
  }
153
155
  }
154
156
 
155
- this._popup.on( "selectionChange", ( ev ) => {
156
- const [sel] = ev.selection as ListboxID[];
157
+ this._popup.on( "click", ( ev ) => {
158
+ const sel = ev.context as ListboxID;
157
159
  if( sel!==undefined ) { // no empty sel
158
160
  _select( sel );
159
- this.fire( "selectionChange", ev );
161
+ this.fire( "selectionChange", { selection: [sel], empty: false } );
160
162
  }
161
163
  });
162
164
 
@@ -178,8 +180,11 @@ export class Combobox extends Component<ComboboxProps,ComboboxEvents> {
178
180
  switch( ev.key ) {
179
181
  case "Enter":
180
182
  case "Escape": {
181
- this._popup.show( false );
182
- break;
183
+ if( this._popup.isOpen( ) ) {
184
+ this._popup.show( false );
185
+ break;
186
+ }
187
+ return;
183
188
  }
184
189
 
185
190
  case "ArrowUp":
@@ -39,6 +39,7 @@
39
39
  color: var(--color-dialog-caption-text);
40
40
  font-weight: bold;
41
41
  font-size: 120%;
42
+ pointer-events: none;
42
43
 
43
44
  #icon {
44
45
  color: var(--color-dialog-caption-text);
@@ -72,11 +72,10 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogEvents
72
72
 
73
73
  this.appendContent([
74
74
  new HBox({
75
- cls: "caption",
75
+ cls: "caption caption-element",
76
76
  content: [
77
77
  this._title = new Label({
78
78
  id: "title",
79
- cls: "caption-element",
80
79
  icon: props.icon,
81
80
  text: props.title
82
81
  }),
@@ -89,7 +88,8 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogEvents
89
88
  this.fire("btnclick", { button: props.closable } );
90
89
  }
91
90
  else {
92
- this.fire("btnclick", { button: props.buttons[0] } );
91
+ //<no it's ok 99% ! this.fire("btnclick", { button: props.buttons[0] } );
92
+ this.close( );
93
93
  }
94
94
  }
95
95
  }) : null,
@@ -113,6 +113,14 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogEvents
113
113
  // todo cancel
114
114
  ev.preventDefault();
115
115
  ev.stopPropagation();
116
+
117
+ if( isString(props.closable) ) {
118
+ this.fire("btnclick", { button: props.closable } );
119
+ }
120
+ else {
121
+ //<no it's ok 99% ! this.fire("btnclick", { button: props.buttons[0] } );
122
+ this.close( );
123
+ }
116
124
  }
117
125
  else if (ev.key == 'Enter') {
118
126
  const def = this.query<Button>('button.default');
@@ -124,6 +132,10 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogEvents
124
132
  }
125
133
  }
126
134
  })
135
+
136
+ asap( ( ) => {
137
+ this.focusNext( true );
138
+ } );
127
139
  }
128
140
 
129
141
  private focusNext( next: boolean) : boolean {
@@ -126,7 +126,10 @@
126
126
  }
127
127
  }
128
128
 
129
- .column { background-color: var(--listbox-background); overflow: hidden; }
129
+ .column {
130
+ background-color: transparent;
131
+ overflow: hidden;
132
+ }
130
133
 
131
134
  .ref-c1 { width: var( --ref-c1-width); }
132
135
  .ref-c2 { width: var( --ref-c2-width); }
@@ -251,14 +251,14 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
251
251
  while( target && target!=this.dom ) {
252
252
  const c = componentFromDOM( target );
253
253
 
254
- // avoid trapping child ckick
255
- if( c.dom.tagName==='INPUT' ) {
254
+ // avoid trapping child click
255
+ if( c && c.dom.tagName==='INPUT' ) {
256
256
  return;
257
257
  }
258
258
 
259
259
  if( c && c.hasClass("x4item") ) {
260
260
  const id = c.getInternalData( "id" );
261
- const fev: ComponentEvent = { context:id };
261
+ const fev: EvClick = { context:id };
262
262
  if (ev.type == 'click') {
263
263
  this.fire('click', fev );
264
264
  }
@@ -276,6 +276,10 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
276
276
  target = target.parentElement;
277
277
  }
278
278
 
279
+ if (ev.type == 'click') {
280
+ this.fire('click', {} );
281
+ }
282
+
279
283
  this.clearSelection( );
280
284
 
281
285
  ev.stopImmediatePropagation();
@@ -511,7 +515,7 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
511
515
  return new SimpleText( { cls: `column ref-c${index+2}`, text: c } )
512
516
  }
513
517
 
514
- const content = [
518
+ const content: Component[] = [
515
519
  new Label( { cls: `column ref-c1`, icon: item.iconId, text: item.text } ),
516
520
  ];
517
521
 
@@ -432,7 +432,7 @@ class CMover {
432
432
  this.self = ref ? true : false;
433
433
 
434
434
  const mouseDown = ( e: PointerEvent ) => {
435
- if( this.self && e.target!=x.dom ) {
435
+ if( this.self && e.target && (e.target as HTMLElement).tagName!=="DIV" ) {
436
436
  return;
437
437
  }
438
438
 
@@ -8,15 +8,96 @@
8
8
  --propertygrid-background: white;
9
9
  --propertygrid-gadget-background: white;
10
10
  --propertygrid-gadget-color: black;
11
+
12
+ --propertygrid-odd-background: var(--color-primary-a5);
13
+ --propertygrid-even-background: transparent;
11
14
  }
12
15
 
13
16
  .x4propertygrid {
14
17
  background: var( --propertygrid-background );
15
18
  border: 1px solid var(--border);
16
- overflow-y: auto;
17
19
  flex-basis: 0;
18
20
  align-self: stretch;
19
-
21
+
22
+ & > .body {
23
+ width: 100%;
24
+ flex-basis: 0;
25
+ overflow-y: auto;
26
+ overflow-x: auto;
27
+ outline: none;
28
+ position: relative;
29
+ }
30
+
31
+ &> #footer {
32
+ border-top: 1px solid var(--border);
33
+ margin: 0;
34
+
35
+ &.x4btngroup {
36
+ gap: 0px;
37
+
38
+ .x4button {
39
+ background-color: var( --ol-button-background );
40
+ margin: 0;
41
+ color: var( --ol-button-color );
42
+
43
+ &:disabled {
44
+ color: var( --ol-button-color-disabled );
45
+ }
46
+
47
+ .x4icon {
48
+ height: 1.5em;
49
+ width: 1.5em;
50
+
51
+ .fa-primary, .fa-secondary {
52
+ fill: var( --accent-background );
53
+ }
54
+ }
55
+
56
+ &.icon-danger {
57
+ .x4icon {
58
+ .fa-secondary {
59
+ fill: var( --disabled-color-dark);
60
+ opacity: 0.7;
61
+ }
62
+
63
+ .fa-primary {
64
+ fill: var( --alert-background );
65
+ }
66
+ }
67
+ }
68
+
69
+ &.icon-success {
70
+ .x4icon {
71
+ .fa-primary {
72
+ fill: var( --success-background );
73
+ }
74
+ }
75
+ }
76
+
77
+ &:hover{
78
+ background-color: var( --ol-button-background-hover );
79
+ color: var( --ol-button-color-hover );
80
+ }
81
+
82
+ &:active{
83
+ background-color: var( --ol-button-background-active );
84
+ color: var( --ol-button-color-active );
85
+ #icon {
86
+ color: var( --button-icon-color );
87
+ }
88
+ }
89
+
90
+ &:focus {
91
+ background-color: var( --ol-button-background-hover );
92
+ }
93
+
94
+ &:disabled {
95
+ color: var( --disabled-color-dark );
96
+ }
97
+ }
98
+ }
99
+ }
100
+
20
101
  .root {
21
102
  display: grid;
22
103
  grid-template-columns: 1fr;
@@ -78,7 +159,10 @@
78
159
  //border-right: 1px solid var(--color-primary-a50);
79
160
 
80
161
  &.even {
81
- background-color: var(--color-primary-a5);
162
+ background-color: var(--propertygrid-even-background)
163
+ }
164
+ &.odd {
165
+ background-color: var(--propertygrid-odd-background)
82
166
  }
83
167
 
84
168
  &:has(:focus) {
@@ -22,7 +22,7 @@ import { Input } from "../input/input"
22
22
  import { ListboxID, ListItem } from "../listbox/listbox"
23
23
  import { Label, SimpleText } from "../label/label"
24
24
  import { asap, class_ns, isFunction, isNumber } from '../../core/core_tools';
25
- import { Icon } from '../components'
25
+ import { Icon, ScrollView } from '../components'
26
26
 
27
27
  import icons from "../assets/icons"
28
28
 
@@ -58,6 +58,7 @@ export interface PropertyGroup {
58
58
 
59
59
  export interface PropertyProps extends ComponentProps {
60
60
  groups: PropertyGroup[];
61
+ footer?: Component;
61
62
  }
62
63
 
63
64
  /**
@@ -76,8 +77,18 @@ export class PropertyGrid extends VBox {
76
77
  constructor(props: PropertyProps) {
77
78
  super(props);
78
79
 
79
- this.root = new Component({ cls: "root" });
80
- this.setContent( this.root );
80
+ if( props.footer ) {
81
+ props.footer.setAttribute( "id", "footer" );
82
+ }
83
+
84
+ const scroller = new ScrollView( { cls: "body" } );
85
+ this.root = scroller.getViewport( );
86
+
87
+ this.root.addClass( "root" );
88
+ this.setContent( [
89
+ scroller,
90
+ props.footer,
91
+ ] );
81
92
 
82
93
  if( props.groups ) {
83
94
  this.setItems( props.groups );
@@ -90,6 +101,11 @@ export class PropertyGrid extends VBox {
90
101
 
91
102
  setItems( _grps: PropertyGroup[] ) {
92
103
 
104
+ if( !_grps || _grps.length==0 ) {
105
+ this.root.clearContent( );
106
+ return;
107
+ }
108
+
93
109
  this.groups = _grps.filter( x => !!x );
94
110
  //this.groups.sort( (a,b) => {return a.title>b.title ? 1 : 0} );
95
111
 
@@ -100,10 +116,8 @@ export class PropertyGrid extends VBox {
100
116
  g.items.forEach( (i,idx) => {
101
117
  if( i ) {
102
118
  const row = this.makePropertyRow(i);
103
- if( idx&1 ) {
104
- row.addClass( "even" )
105
- }
106
-
119
+ row.addClass( idx&1 ? "even" : "odd" );
120
+
107
121
  items.push( row );
108
122
  }
109
123
  });
@@ -1,13 +1,24 @@
1
- /**
2
- * @file tag.module.scss
3
- * @author Etienne Cochard
4
- * @copyright (c) 2026 R-libre ingenierie, all rights reserved.
5
- **/
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|.2
7
+ *
8
+ * @file tag.module.scss
9
+ * @author Etienne Cochard
10
+ *
11
+ * @copyright (c) 2026 R-libre ingenierie
12
+ *
13
+ * Use of this source code is governed by an MIT-style license
14
+ * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
+ **/
16
+
6
17
 
7
18
  :root {
8
19
  --tag-border: var( --border );
9
20
  --tag-border-focus: var( --border-focus );
10
- --tag-selection: var( --accent-background );
21
+ --tag-background: var( --accent-background );
11
22
  --tag-color: black;
12
23
  --tag-icon-color: var( --tag-color );
13
24
  }
@@ -15,9 +26,11 @@
15
26
  .x4tag {
16
27
  border-radius: 16px;
17
28
  border: 1px solid var( --tag-border );
29
+ background-color: var( --tag-background );
18
30
  padding: 2px 8px;
19
31
  gap: 4px;
20
32
  font-weight: normal;
33
+
21
34
  --label-color: var( --tag-color );
22
35
 
23
36
  .x4icon:empty {
@@ -1,8 +1,19 @@
1
- /**
2
- * @file tag.ts
3
- * @author Etienne Cochard
4
- * @copyright (c) 2026 R-libre ingenierie, all rights reserved.
5
- **/
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|.2
7
+ *
8
+ * @file tag.ts
9
+ * @author Etienne Cochard
10
+ *
11
+ * @copyright (c) 2026 R-libre ingenierie
12
+ *
13
+ * Use of this source code is governed by an MIT-style license
14
+ * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
+ **/
16
+
6
17
 
7
18
  import { ComponentProps } from '../../core/component';
8
19
  import { class_ns, UnsafeHtml } from '../../core/core_tools';
@@ -74,10 +74,14 @@
74
74
 
75
75
  // child + subitems
76
76
  .x4ctreeviewitem {
77
+
77
78
  &>.label {
79
+ --label-color: var( --treeitem-color );
80
+ --label-icon-color: var( --treeitem-color );
81
+
78
82
  gap: 4px;
79
83
 
80
- .x4label, .x4icon, .x4label #icon {
84
+ .x4icon {
81
85
  color: inherit;
82
86
  }
83
87
 
@@ -98,11 +102,16 @@
98
102
  &.selected {
99
103
  background-color: var( --treeitem-background-sel );
100
104
  color: var( --treeitem-color-sel );
105
+
106
+ --label-color: var( --treeitem-color-sel );
107
+ --label-icon-color: var( --treeitem-color-sel );
101
108
  }
102
109
 
103
110
  &:active{
104
111
  background-color: var( --accent-background-active );
105
112
  color: var( --accent-color-active );
113
+ --label-color: var( --accent-color-active );
114
+ --label-icon-color: var( --accent-color-active );
106
115
  }
107
116
  }
108
117
 
@@ -1,8 +1,19 @@
1
- /**
2
- * @file core_state.ts
3
- * @author Etienne Cochard
4
- * @copyright (c) 2025 R-libre ingenierie, all rights reserved.
5
- **/
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|.2
7
+ *
8
+ * @file core_state.ts
9
+ * @author Etienne Cochard
10
+ *
11
+ * @copyright (c) 2026 R-libre ingenierie
12
+ *
13
+ * Use of this source code is governed by an MIT-style license
14
+ * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
+ **/
16
+
6
17
 
7
18
  import { CoreEvent, EventMap, EventSource } from './core_events.js';
8
19
  import { getMemberValue, isPlainObject } from './core_tools.js';
package/src/x4.d.ts CHANGED
@@ -1,8 +1,18 @@
1
- /**
2
- * @file x4.d.ts
3
- * @author Etienne Cochard
4
- * @copyright (c) 2026 R-libre ingenierie, all rights reserved.
5
- **/
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|.2
7
+ *
8
+ * @file x4.d.ts
9
+ * @author Etienne Cochard
10
+ *
11
+ * @copyright (c) 2026 R-libre ingenierie
12
+ *
13
+ * Use of this source code is governed by an MIT-style license
14
+ * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
+ **/
6
16
 
7
17
  declare module "*.svg" {
8
18
  const content: string;
package/src/x4.scss CHANGED
@@ -15,5 +15,6 @@
15
15
  **/
16
16
 
17
17
  @import "./components/normalize.scss";
18
+ @import "./components/colors.scss";
18
19
  @import "./components/themes.scss";
19
20
  @import "./components/base.scss";
File without changes