x4js 2.2.51 → 2.2.53

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.51",
3
+ "version": "2.2.53",
4
4
  "type": "module",
5
5
  "main": "src/x4.ts",
6
6
  "module": "src/x4.ts",
@@ -24,6 +24,10 @@
24
24
  @extend %flex;
25
25
  }
26
26
 
27
+ .x4stretch {
28
+ align-self: stretch;
29
+ }
30
+
27
31
  .x4fit-h {
28
32
  width: stretch;
29
33
  }
@@ -28,7 +28,7 @@
28
28
  --combobox-btn-color-hover: var( --text-primary );
29
29
 
30
30
  --combo-tree-indent: 1em;
31
- }
31
+ }
32
32
 
33
33
  .x4dropdownlist {
34
34
  @extend %shadow-xl;
@@ -36,7 +36,7 @@
36
36
 
37
37
  max-height: 250px;
38
38
  max-width: 50vw;
39
-
39
+
40
40
  position: absolute;
41
41
  background-color: var( --dropdown-background );
42
42
  border: 1px solid var( --dropdown-border );
@@ -51,7 +51,7 @@
51
51
 
52
52
  .x4item {
53
53
  white-space: nowrap;
54
-
54
+
55
55
  &.level-1 { padding-left: calc(var(--combo-tree-indent) * 1 ); }
56
56
  &.level-2 { padding-left: calc(var(--combo-tree-indent) * 2 ); }
57
57
  &.level-3 { padding-left: calc(var(--combo-tree-indent) * 3 ); }
@@ -60,47 +60,48 @@
60
60
  &.level-6 { padding-left: calc(var(--combo-tree-indent) * 6 ); }
61
61
  &.level-7 { padding-left: calc(var(--combo-tree-indent) * 7 ); }
62
62
  &.level-8 { padding-left: calc(var(--combo-tree-indent) * 8 ); }
63
+ }
63
64
  }
64
- }
65
- }
66
-
65
+ }
66
+
67
67
  .x4combobox {
68
68
  @extend %hbox;
69
69
  margin: 5px;
70
70
  gap: 6px;
71
71
 
72
72
  &> #label {
73
-
73
+
74
74
  &> .x4label {
75
75
  padding: 0 6px 0 0;
76
76
  border-bottom: 1px solid transparent;
77
-
77
+
78
78
  height: 100%;
79
79
  font-weight: 500;
80
80
  gap: 0px;
81
-
81
+
82
82
  #text:not(.empty) {
83
83
  &::after {
84
84
  content: ":"
85
- }
85
+ }
86
+ }
86
87
  }
87
88
  }
88
- }
89
89
 
90
90
  &>#edit {
91
91
  @extend %flex;
92
92
  border-bottom: 1px solid var( --combobox-border );
93
+
93
94
  &:focus-within {
94
95
  border-bottom-color: var( --combobox-border-focus );
95
96
  }
96
-
97
+
97
98
  .x4input {
98
99
  @extend %flex;
99
-
100
- &[readonly] {
101
- cursor: pointer;
102
- }
103
- }
100
+ cursor: pointer;
101
+ // &[readonly] {
102
+ // cursor: pointer;
103
+ // }
104
+ }
104
105
 
105
106
  .x4button {
106
107
  margin: 0;
@@ -111,36 +112,39 @@
111
112
 
112
113
  #icon {
113
114
  color: var( --combobox-btn-color );
114
- }
115
+ }
115
116
 
116
117
  &:hover, &:hover #icon {
117
118
  color: var( --combobox-btn-color-hover );
118
- }
119
+ }
119
120
 
120
121
  //&:focus {
121
122
  //background-color: var( --color-30 );
122
123
  //color: var( --color-10 );
123
124
  //}
124
125
  }
125
- }
126
+ }
127
+
128
+ &[disabled],
129
+ &.readonly {
130
+ --label-color: var( --disabled-color-dark );
131
+ --input-color: var( --disabled-color-dark );
126
132
 
127
- &[disabled] {
128
133
  &, * {
129
134
  cursor: not-allowed;
130
- }
135
+ }
131
136
 
132
137
  #label .x4label {
133
- color: var( --disabled-color-dark );
134
138
  pointer-events: none;
135
- }
136
139
  }
137
-
140
+ }
141
+
138
142
  &[required] {
139
143
  & > #label > .x4label::before {
140
144
  content: "*";
141
145
  font-weight: bold;
142
146
  color: var( --textedit-required );
143
147
  margin-right: 2px;
144
- }
145
148
  }
149
+ }
146
150
  }
@@ -15,7 +15,7 @@
15
15
  **/
16
16
 
17
17
  import { Component, ComponentEvents, ComponentProps, EvClick, EvSelectionChange, makeUniqueComponentId } from '../../core/component';
18
- import { class_ns, IComponentInterface, IFormElement, kbNav, safeText, sanitizeHtml, UnsafeHtml } from '../../core/core_tools';
18
+ import { class_ns, IComponentInterface, IFormElement, kbNav } from '../../core/core_tools';
19
19
  import { EventCallback } from '../../core/core_events';
20
20
 
21
21
  import { Listbox, ListboxID, ListItem } from '../listbox/listbox';
@@ -46,7 +46,7 @@ export class DropdownList extends Popup<DropdownProps,DropdownEvents> {
46
46
 
47
47
  private _list: Listbox;
48
48
 
49
- constructor( props: DropdownProps, content?: ListItem[] ) {
49
+ constructor( props: DropdownProps ) {
50
50
  super( props );
51
51
 
52
52
  this._list = new Listbox( { items: props.items } );
@@ -147,7 +147,7 @@ export class Combobox extends Component<ComboboxProps,ComboboxEvents> {
147
147
  list.select( sel, false );
148
148
  }
149
149
 
150
- this._input.setValue( safeText(itm.text) );
150
+ this._input.setValue( itm.text as string );
151
151
 
152
152
  if( !this._prevent_close ) {
153
153
  this._popup.show( false );
@@ -248,7 +248,9 @@ export class Combobox extends Component<ComboboxProps,ComboboxEvents> {
248
248
  }
249
249
 
250
250
  setItems( items: ListItem[] ) {
251
- this._getList().setItems( items );
251
+ const list = this._getList( );
252
+ list.setItems( items );
253
+ this.setValue( "" );
252
254
  }
253
255
 
254
256
  getValue( ) {
@@ -260,7 +262,12 @@ export class Combobox extends Component<ComboboxProps,ComboboxEvents> {
260
262
  }
261
263
 
262
264
  selectItem( index: ListboxID ) {
263
- this._getList( ).select( index );
265
+ const list = this._getList( );
266
+ list.select( index );
267
+ const el = list.getItem( index );
268
+ if( el ) {
269
+ this.setValue( el.text as string );
270
+ }
264
271
  }
265
272
 
266
273
  getSelection( ) {
@@ -29,6 +29,7 @@
29
29
  background-color: white;
30
30
  border: 1px solid var( --border-dark );
31
31
  max-width: 99vw;
32
+ outline: none;
32
33
 
33
34
  &> .caption {
34
35
  padding: 8px;
@@ -39,6 +40,7 @@
39
40
  color: var(--color-dialog-caption-text);
40
41
  font-weight: bold;
41
42
  font-size: 120%;
43
+ pointer-events: none;
42
44
 
43
45
  #icon {
44
46
  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
  }),
@@ -23,6 +23,7 @@
23
23
  --input-placeholder: var( --disabled-background );
24
24
  --input-error: var( --alert-background );
25
25
 
26
+ --input-color-disabled: var( --disabled-color-dark );
26
27
  --input-checkbox-color: var( --accent-background );
27
28
  }
28
29
 
@@ -68,8 +69,10 @@ input.x4input {
68
69
  font-weight: bold;
69
70
  }
70
71
 
71
- &:disabled {
72
+ &:disabled,
73
+ &[disabled] {
72
74
  background-color: transparent;
75
+ color: var( --input-color-disabled );
73
76
  }
74
77
 
75
78
  &:invalid {
@@ -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); }
@@ -94,16 +94,11 @@ export interface ListboxProps extends Omit<ComponentProps,'content'> {
94
94
  @class_ns( "x4" )
95
95
  export class Listbox extends Component<ListboxProps,ListboxEvents> {
96
96
 
97
- private _view: Viewport;
98
- //private _selection: ListboxID;
99
- //private _selitem: Component;
100
-
97
+ private _view: Viewport;
101
98
  private _lastsel: ListboxID;
102
-
103
99
  private _multisel: Set<ListboxID>;
104
100
  private _items: ListItem[];
105
-
106
- preventFocus = false;
101
+ //<?? preventFocus = false;
107
102
 
108
103
  constructor( props: ListboxProps ) {
109
104
  super( { ...props } );
@@ -515,7 +510,7 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
515
510
  return new SimpleText( { cls: `column ref-c${index+2}`, text: c } )
516
511
  }
517
512
 
518
- const content = [
513
+ const content: Component[] = [
519
514
  new Label( { cls: `column ref-c1`, icon: item.iconId, text: item.text } ),
520
515
  ];
521
516
 
@@ -629,6 +624,11 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
629
624
  return Array.from( this._multisel );
630
625
  }
631
626
 
627
+ getFirstSel( ) : ListItem {
628
+ const [first] = this.getSelection( );
629
+ return first ? this.getItem( first ) : null;
630
+ }
631
+
632
632
  ensureSelectionVisible( ) {
633
633
  const sels = Array.from( this._multisel.values() );
634
634
  if( sels.length) {
@@ -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';
@@ -25,7 +25,7 @@
25
25
  --textedit-btn-color: var( --text-secondary );
26
26
  --textedit-btn-color-hover: var( --text-primary );
27
27
 
28
- --textedit-color-disabled: var( --disabled-background );
28
+ --textedit-color-disabled: var( --disabled-color-dark );
29
29
  }
30
30
 
31
31
  .x4textedit {
@@ -103,8 +103,8 @@
103
103
  }
104
104
 
105
105
  #label > .x4label #text,
106
- #label > .x4label::before,
107
106
  #label::after {
107
+ --label-color: var( --textedit-color-disabled );
108
108
  color: var( --textedit-color-disabled );
109
109
  }
110
110
 
@@ -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
 
@@ -109,6 +109,7 @@ export interface ComponentProps {
109
109
  hidden?: boolean,
110
110
  /** Enables flex layout (boolean) or sets flex-grow (number). */
111
111
  flex?: boolean | number;
112
+ stretch?: boolean;
112
113
  /** Tooltip text. */
113
114
  tooltip?: string;
114
115
  /** Existing DOM element to wrap. */
@@ -202,6 +203,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
202
203
  });
203
204
  }
204
205
  }
206
+
207
+ if( props.stretch ) {
208
+ this.addClass( "x4stretch" );
209
+ }
205
210
 
206
211
  if( props.id!==undefined ) {
207
212
  this.setAttribute( "id", props.id );
@@ -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