x4js 2.2.52 → 2.2.54

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.52",
3
+ "version": "2.2.54",
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
  }
@@ -20,6 +20,7 @@
20
20
  min-width: 0;
21
21
  min-height: 0;
22
22
  flex-shrink: 0;
23
+ align-self: stretch;
23
24
  }
24
25
 
25
26
  .x4hbox {
@@ -26,19 +26,48 @@ export interface BoxProps extends ComponentProps {
26
26
  }
27
27
 
28
28
  /**
29
- * A generic container component for grouping and laying out child components.
30
- * The CSS class for this component is automatically generated as `x4box`.
29
+ * A generic container component for grouping and laying out child components.
30
+ *
31
+ * The `refs` object is a typed directory of the children you need to reach
32
+ * again later. Assign a child to `refs` as you build the content: the
33
+ * assignment expression evaluates to the component itself, so it can be
34
+ * inlined directly in the content array.
35
+ *
36
+ * @example
37
+ * using refs: in your code, you can type
38
+ *
39
+ * class MyBox extends Box {
40
+ * declare refs: {
41
+ * a: Combobox;
42
+ * b: Input;
43
+ * }
44
+ *
45
+ * constructor( props ) {
46
+ * super( props );
47
+ *
48
+ * this.setContent( [
49
+ * this.refs.a = new ComboBox( { ... } );
50
+ * this.refs.b = new Input( { ... } );
51
+ * ])
52
+ *
53
+ * onSomeEvent() {
54
+ * this.refs.a.getValue();
55
+ * }
56
+ * }
57
+ *
58
+ *
59
+ *
31
60
  */
32
61
 
33
62
  @class_ns( "x4" )
34
63
  export class Box<P extends BoxProps=BoxProps,E extends ComponentEvents=ComponentEvents> extends Component<P,E> {
64
+ protected refs: Record<string,Component> = {};
35
65
  }
36
66
 
37
67
 
38
68
  /**
39
69
  * A horizontal box layout component.
40
70
  * Arranges child components in a horizontal line.
41
- * The CSS class for this component is automatically generated as `x4hbox`.
42
71
  */
43
72
 
44
73
  @class_ns( "x4" )
@@ -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;
@@ -7,7 +7,7 @@ import { CSizer } from '../sizers/sizer';
7
7
  import "./header.module.scss"
8
8
 
9
9
  interface HeaderItem {
10
- name: string;
10
+ name?: string; // default to ref-cx
11
11
  title: string;
12
12
  iconId?: string;
13
13
  width?: number; // <0 for flex
@@ -15,7 +15,7 @@ interface HeaderItem {
15
15
 
16
16
  interface HeaderProps extends Omit<ComponentProps,"content"> {
17
17
  items: HeaderItem[]
18
- target?: Component; // target element to set header col variable width var( --hdr-item-{name}-width )
18
+ target?: Component; // target element to set header col variable width var( --{name}-width ) parent element if not set
19
19
  }
20
20
 
21
21
  /**
@@ -38,7 +38,12 @@ export class Header extends HBox<HeaderProps> {
38
38
  constructor( props: HeaderProps ) {
39
39
  super( props );
40
40
 
41
- this._els = props.items?.map( x => {
41
+ this._els = props.items?.map( (x,index) => {
42
+
43
+ if( !x.name ) {
44
+ x.name = `ref-c${index+1}`;
45
+ }
46
+
42
47
  const cell = new Label( { cls: "cell", text: x.title, icon: x.iconId } );
43
48
  const sizer = new CSizer( "right" );
44
49
 
@@ -126,7 +131,13 @@ export class Header extends HBox<HeaderProps> {
126
131
  c.setWidth( width );
127
132
 
128
133
  const item = c.getInternalData<HeaderItem>( 'data' );
134
+
135
+ if( !this.props.target ) {
136
+ this.parentElement().setStyleVariable( `--${item.name}-width`, width + "px");
137
+ }
138
+ else {
129
139
  this.props.target?.setStyleVariable( `--${item.name}-width`, width + "px");
140
+ }
130
141
 
131
142
  fullw += width;
132
143
  } );
@@ -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 {
@@ -53,6 +53,16 @@
53
53
  &:empty {
54
54
  display: none;
55
55
  }
56
+
57
+ code {
58
+ padding: 0.2em 0.4em;
59
+ margin: 0;
60
+ font-size: 95%;
61
+ white-space: break-spaces;
62
+ background-color: var(--background-ternary);
63
+ border-radius: 6px;
64
+ border: 1px solid var(--border);
65
+ }
56
66
  }
57
67
 
58
68
  #icon {
@@ -81,6 +91,16 @@
81
91
  text-align: left;
82
92
  &.al-center { text-align: center; }
83
93
  &.al-right { text-align: right; }
94
+
95
+ code {
96
+ padding: 0.2em 0.4em;
97
+ margin: 0;
98
+ font-size: 95%;
99
+ white-space: break-spaces;
100
+ background-color: var(--background-ternary);
101
+ border-radius: 6px;
102
+ border: 1px solid var(--border);
103
+ }
84
104
  }
85
105
 
86
106
  [disabled] .x4label,
@@ -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 } );
@@ -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) {
@@ -40,6 +40,8 @@
40
40
  }
41
41
 
42
42
  & > .body {
43
+ flex-grow: 1;
44
+
43
45
  position: relative;
44
46
  left: 0;
45
47
  top: 0;
@@ -12,6 +12,17 @@
12
12
  background-color: white;
13
13
  }
14
14
 
15
+ .x4select {
16
+ appearance: none;
17
+ -webkit-appearance: none;
18
+ -moz-appearance: none;
19
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%23333' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
20
+ background-repeat: no-repeat;
21
+ background-position: right 6px center;
22
+ background-size: 12px 8px;
23
+ padding-right: 23px;
24
+ }
25
+
15
26
  //-- global saddly
16
27
  option {
17
28
  padding: 5px;
@@ -112,6 +112,7 @@ export class CSizer extends Component<ComponentProps,CSizerEvent> {
112
112
 
113
113
  let nr: any = {};
114
114
  let horz = true;
115
+ let size = 0;
115
116
 
116
117
  //const center = this._ref.hasClass("center");
117
118
  //if( center ) {
@@ -124,38 +125,69 @@ export class CSizer extends Component<ComponentProps,CSizerEvent> {
124
125
 
125
126
  if( this._type.includes("top") ) {
126
127
  nr.top = pt.y,
127
- nr.height = (rc.top+rc.height)-pt.y;
128
+ size = nr.height = (rc.top+rc.height)-pt.y;
128
129
  horz = false;
129
130
  }
130
131
 
131
132
  if( this._type=="vsize-next" ) {
132
- nr.height = (rc.top+rc.height)-pt.y;
133
+ size = nr.height = (rc.top+rc.height)-pt.y;
133
134
  horz = false;
134
135
  }
135
136
 
136
137
  if( this._type.includes("bottom") || this._type=='vsize-prev' ) {
137
- nr.height = (pt.y-rc.top);
138
+ size = nr.height = (pt.y-rc.top);
138
139
  horz = false;
139
140
  }
140
141
 
141
142
  if( this._type.includes("left") ) {
142
143
  nr.left = pt.x;
143
- nr.width = ((rc.left+rc.width)-pt.x);
144
+ size = nr.width = ((rc.left+rc.width)-pt.x);
144
145
  }
145
146
 
146
147
  if( this._type=="hsize-next" ) {
147
- nr.width = ((rc.left+rc.width)-pt.x);
148
+ size = nr.width = ((rc.left+rc.width)-pt.x);
148
149
  }
149
150
 
150
151
  if( this._type.includes("right") || this._type=='hsize-prev' ) {
151
- nr.width = (pt.x-rc.left);
152
+ size = nr.width = (pt.x-rc.left);
152
153
  }
153
154
 
155
+ const isFlex = ( c : Component ) => {
156
+ if( !c ) {
157
+ return false;
158
+ }
159
+
160
+ if( c.hasClass( "x4flex" ) ) {
161
+ return true;
162
+ }
163
+
164
+ return c.getStyleValue( "flexGrow" )!==undefined;
165
+ }
166
+
167
+ if( this._type.includes("-prev") ) {
168
+ if( isFlex(this.prevElement() ) ) {
169
+ this._ref.setStyleValue( "flex", `0 0 ${size}px` );
170
+ }
171
+ else {
172
+ this._ref.setStyle( nr );
173
+ }
174
+ }
175
+ else if( this._type.includes("-next") ) {
176
+ if( isFlex(this.nextElement() ) ) {
177
+ this._ref.setStyleValue( "flex", `0 0 ${size}px` );
178
+ }
179
+ else {
180
+ this._ref.setStyle( nr );
181
+ }
182
+
183
+ return;
184
+ }
185
+ else {
154
186
  this._ref.setStyle( nr );
155
- //this._ref.setStyleValue( "flexGrow", 0 );
187
+ }
156
188
 
157
189
  const nrc = this._ref.getBoundingRect( );
158
- this.fire( "resize", { size: horz ? nrc.width : nrc.height, width: nrc.width, height: nrc.height })
190
+ this.fire( "resize", { size, width: nrc.width, height: nrc.height })
159
191
 
160
192
  e.preventDefault( );
161
193
  e.stopPropagation( );
@@ -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
 
@@ -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 );