x4js 2.0.14 → 2.0.17
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/lib/cjs/x4.css +1 -1
- package/lib/cjs/x4.js +2 -2
- package/lib/esm/x4.css +1 -1
- package/lib/esm/x4.mjs +2 -2
- package/lib/src/components/boxes/boxes.ts +101 -9
- package/lib/src/components/canvas/canvas_ex.ts +13 -6
- package/lib/src/components/components.ts +2 -1
- package/lib/src/components/dialog/dialog.module.scss +3 -4
- package/lib/src/components/dialog/dialog.ts +19 -2
- package/lib/src/components/form/form.ts +1 -1
- package/lib/src/components/icon/icon.module.scss +1 -0
- package/lib/src/components/icon/icon.ts +0 -2
- package/lib/src/components/input/input.ts +46 -22
- package/lib/src/components/keyboard/keyboard.ts +29 -28
- package/lib/src/components/menu/menu.ts +2 -2
- package/lib/src/components/popup/popup.module.scss +6 -0
- package/lib/src/components/popup/popup.ts +5 -3
- package/lib/src/components/propgrid/progrid.module.scss +4 -0
- package/lib/src/components/propgrid/propgrid.ts +22 -5
- package/lib/src/components/sizers/sizer.ts +2 -1
- package/lib/src/components/tabs/tabs.ts +6 -0
- package/lib/src/components/textedit/textedit.ts +26 -21
- package/lib/src/core/component.ts +15 -21
- package/lib/src/core/core_application.ts +2 -1
- package/lib/src/core/core_data.ts +9 -8
- package/lib/src/core/core_element.ts +5 -0
- package/lib/src/core/core_i18n.ts +1 -1
- package/lib/src/core/core_router.ts +2 -2
- package/lib/src/core/core_state.ts +62 -0
- package/lib/src/core/core_svg.ts +1 -0
- package/lib/src/x4.ts +4 -0
- package/lib/styles/x4.css +1 -1
- package/lib/types/x4js.d.ts +369 -234
- package/package.json +18 -28
- package/src/components/boxes/boxes.ts +101 -9
- package/src/components/canvas/canvas.ts +1 -1
- package/src/components/canvas/canvas_ex.ts +13 -6
- package/src/components/components.ts +2 -1
- package/src/components/dialog/dialog.module.scss +3 -4
- package/src/components/dialog/dialog.ts +19 -2
- package/src/components/form/form.ts +1 -1
- package/src/components/icon/icon.module.scss +1 -0
- package/src/components/icon/icon.ts +0 -2
- package/src/components/input/input.ts +46 -22
- package/src/components/keyboard/keyboard.ts +29 -28
- package/src/components/menu/menu.ts +2 -2
- package/src/components/popup/popup.module.scss +6 -0
- package/src/components/popup/popup.ts +5 -3
- package/src/components/propgrid/progrid.module.scss +4 -0
- package/src/components/propgrid/propgrid.ts +22 -5
- package/src/components/sizers/sizer.ts +2 -1
- package/src/components/tabs/tabs.ts +6 -0
- package/src/components/textedit/textedit.ts +26 -21
- package/src/core/component.ts +15 -21
- package/src/core/core_application.ts +2 -1
- package/src/core/core_data.ts +9 -8
- package/src/core/core_element.ts +5 -0
- package/src/core/core_i18n.ts +1 -1
- package/src/core/core_router.ts +2 -2
- package/src/core/core_state.ts +62 -0
- package/src/core/core_svg.ts +1 -0
- package/src/x4.ts +4 -0
- package/.vscode/launch.json +0 -14
- package/demo/assets/house-light.svg +0 -1
- package/demo/assets/radio.svg +0 -4
- package/demo/index.html +0 -12
- package/demo/main.scss +0 -23
- package/demo/main.ts +0 -324
- package/demo/package.json +0 -26
- package/demo/scss.d.ts +0 -4
- package/demo/svg.d.ts +0 -1
- package/demo/tsconfig.json +0 -14
- package/scripts/build.mjs +0 -378
- package/scripts/prepack.mjs +0 -346
- package/tsconfig.json +0 -14
|
@@ -120,30 +120,24 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
120
120
|
|
|
121
121
|
this.hide( );
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
//e.preventDefault( );
|
|
123
|
+
this.addDOMEvent( "mousedown", (e) => {
|
|
124
|
+
this.handleKey( e );
|
|
125
|
+
e.preventDefault( );
|
|
127
126
|
e.stopPropagation( );
|
|
128
|
-
|
|
129
|
-
this.last_ev = e;
|
|
130
|
-
clearInterval( this.autorepeat );
|
|
131
|
-
this.autorepeat = setInterval( () => {
|
|
132
|
-
this.handleKey( this.last_ev );
|
|
133
|
-
}, 250 );
|
|
134
|
-
},
|
|
135
|
-
touchend: ( e ) => {
|
|
136
|
-
console.log( 'touch end' );
|
|
137
|
-
clearInterval( this.autorepeat );
|
|
138
|
-
this.last_ev = null;
|
|
139
|
-
},
|
|
140
|
-
*/
|
|
127
|
+
});
|
|
141
128
|
|
|
142
|
-
|
|
129
|
+
// for rapid people
|
|
130
|
+
this.addDOMEvent( "dblclick", (e) => {
|
|
143
131
|
this.handleKey( e );
|
|
144
132
|
e.preventDefault( );
|
|
145
133
|
e.stopPropagation( );
|
|
146
134
|
});
|
|
135
|
+
|
|
136
|
+
// for slow people
|
|
137
|
+
this.addDOMEvent( "contextmenu", (e) => {
|
|
138
|
+
e.preventDefault( );
|
|
139
|
+
e.stopPropagation( );
|
|
140
|
+
});
|
|
147
141
|
}
|
|
148
142
|
|
|
149
143
|
/**
|
|
@@ -285,20 +279,27 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
285
279
|
|
|
286
280
|
if( this.visible ) {
|
|
287
281
|
if( this.input ) {
|
|
288
|
-
this.show( );
|
|
289
|
-
this._scrollIntoView( this.input );
|
|
290
|
-
|
|
291
282
|
const type = this.input.type;
|
|
292
|
-
const dtype = this.input.getAttribute( "data-type" );
|
|
293
283
|
|
|
294
|
-
if( type
|
|
295
|
-
this.
|
|
284
|
+
if( type=='check' || type=="radio" ) {
|
|
285
|
+
this.hide( );
|
|
286
|
+
this.input = null;
|
|
296
287
|
}
|
|
297
|
-
else if( type==='date' || dtype==='date' ) {
|
|
298
|
-
this._switchMode( "date");
|
|
299
|
-
}
|
|
300
288
|
else {
|
|
301
|
-
this.
|
|
289
|
+
this.show( );
|
|
290
|
+
this._scrollIntoView( this.input );
|
|
291
|
+
|
|
292
|
+
const dtype = this.input.getAttribute( "data-type" );
|
|
293
|
+
|
|
294
|
+
if( type==='number' || dtype==='number' ) {
|
|
295
|
+
this._switchMode( "number" )
|
|
296
|
+
}
|
|
297
|
+
else if( type==='date' || dtype==='date' ) {
|
|
298
|
+
this._switchMode( "date");
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
this._switchMode( "lower" );
|
|
302
|
+
}
|
|
302
303
|
}
|
|
303
304
|
}
|
|
304
305
|
}
|
|
@@ -38,7 +38,7 @@ export interface MenuItem {
|
|
|
38
38
|
click?: DOMEventHandler;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
type MenuElement = MenuItem | Component | string;
|
|
41
|
+
export type MenuElement = MenuItem | Component | string;
|
|
42
42
|
|
|
43
43
|
export interface MenuProps extends Omit<PopupProps,"content"> {
|
|
44
44
|
items: MenuElement[];
|
|
@@ -149,7 +149,7 @@ class CMenuItem extends Component {
|
|
|
149
149
|
export class Menu extends Popup {
|
|
150
150
|
|
|
151
151
|
constructor( props: MenuProps ) {
|
|
152
|
-
super( { ...props, autoClose: "menu"
|
|
152
|
+
super( { ...props, autoClose: "menu" } );
|
|
153
153
|
|
|
154
154
|
this.addClass( "x4vbox" );
|
|
155
155
|
|
|
@@ -129,11 +129,13 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
*
|
|
132
|
+
* s
|
|
133
133
|
*/
|
|
134
134
|
|
|
135
|
-
displayCenter( ) {
|
|
136
|
-
this.displayNear( new Rect( window.innerWidth/2, window.innerHeight/2, 0, 0 ), "center middle" );
|
|
135
|
+
displayCenter( center = true ) {
|
|
136
|
+
//this.displayNear( new Rect( window.innerWidth/2, window.innerHeight/2, 0, 0 ), "center middle" );
|
|
137
|
+
this.setClass( 'center', center );
|
|
138
|
+
this._do_show( ); // to compute size
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
/**
|
|
@@ -20,7 +20,7 @@ import { Component, ComponentProps, EvChange, EvFocus } from "../../core/compone
|
|
|
20
20
|
import { HBox, VBox } from "../boxes/boxes"
|
|
21
21
|
import { Input, InputProps } from "../input/input"
|
|
22
22
|
import { ListItem } from "../listbox/listbox"
|
|
23
|
-
import { SimpleText } from "../label/label"
|
|
23
|
+
import { Label, SimpleText } from "../label/label"
|
|
24
24
|
import { class_ns, isFunction } from '../../core/core_tools';
|
|
25
25
|
import { Icon } from '../components.js'
|
|
26
26
|
|
|
@@ -32,7 +32,7 @@ type IValue = boolean | number | string;
|
|
|
32
32
|
type IValueCB = ( name: string) => IValue;
|
|
33
33
|
|
|
34
34
|
export interface PropertyValue {
|
|
35
|
-
type: 'boolean' | 'number' | 'string' | 'password' | 'options';
|
|
35
|
+
type: 'boolean' | 'number' | 'string' | 'password' | 'options' | 'label' | 'button';
|
|
36
36
|
title?: string;
|
|
37
37
|
desc?: string;
|
|
38
38
|
name?: string;
|
|
@@ -82,7 +82,7 @@ export class PropertyGrid extends VBox {
|
|
|
82
82
|
setItems( _grps: PropertyGroup[] ) {
|
|
83
83
|
|
|
84
84
|
this.groups = _grps;
|
|
85
|
-
this.groups.sort( (a,b) => {return a.title>b.title ? 1 : 0} );
|
|
85
|
+
//this.groups.sort( (a,b) => {return a.title>b.title ? 1 : 0} );
|
|
86
86
|
|
|
87
87
|
let items: Component[] = [];
|
|
88
88
|
|
|
@@ -145,6 +145,8 @@ export class PropertyGrid extends VBox {
|
|
|
145
145
|
|
|
146
146
|
makePropertyRow( item: PropertyValue ) {
|
|
147
147
|
|
|
148
|
+
let use_hdr = true;
|
|
149
|
+
|
|
148
150
|
// If boolean create checkbox
|
|
149
151
|
let editor: Component;
|
|
150
152
|
let value = isFunction(item.value) ? item.value( item.name ) : item.value;
|
|
@@ -171,7 +173,6 @@ export class PropertyGrid extends VBox {
|
|
|
171
173
|
items: item.options,
|
|
172
174
|
name: item.name,
|
|
173
175
|
change: ( e: EvChange ) => {
|
|
174
|
-
debugger;
|
|
175
176
|
item.callback?.( item.name, e.value );
|
|
176
177
|
}
|
|
177
178
|
});
|
|
@@ -208,6 +209,22 @@ export class PropertyGrid extends VBox {
|
|
|
208
209
|
}
|
|
209
210
|
});
|
|
210
211
|
}
|
|
212
|
+
else if (item.type === 'label') {
|
|
213
|
+
editor = new Label({
|
|
214
|
+
id: item.name,
|
|
215
|
+
text: value as string,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
else if (item.type === 'button') {
|
|
219
|
+
use_hdr = false;
|
|
220
|
+
editor = new Button({
|
|
221
|
+
id: item.name,
|
|
222
|
+
label: value as string,
|
|
223
|
+
click: ( ) => {
|
|
224
|
+
item.callback?.( item.name, '' );
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
211
228
|
else {
|
|
212
229
|
editor = new Input({
|
|
213
230
|
type: 'text',
|
|
@@ -225,7 +242,7 @@ export class PropertyGrid extends VBox {
|
|
|
225
242
|
return new HBox({
|
|
226
243
|
cls: 'row',
|
|
227
244
|
content: [
|
|
228
|
-
new Component({ cls: 'cell hdr', content: item.title ?? item.name, tooltip: item.desc }),
|
|
245
|
+
use_hdr ? new Component({ cls: 'cell hdr', content: item.title ?? item.name, tooltip: item.desc }) : null,
|
|
229
246
|
new Component({ cls: 'cell', tag: "label", attrs: { "labelFor": item.name }, content: editor })
|
|
230
247
|
]
|
|
231
248
|
});
|
|
@@ -33,12 +33,13 @@ interface CSizerEvent extends ComponentEvents {
|
|
|
33
33
|
stop: ComponentEvent;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
type SizerType = "left" | "top" | "right" | "bottom";
|
|
36
|
+
type SizerType = "left" | "top" | "right" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
*
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
|
+
|
|
42
43
|
@class_ns( "x4" )
|
|
43
44
|
export class CSizer extends Component<ComponentProps,CSizerEvent> {
|
|
44
45
|
|
|
@@ -138,6 +138,7 @@ export class Tabs extends VBox<TabsProps> {
|
|
|
138
138
|
|
|
139
139
|
private _list: CTabList;
|
|
140
140
|
private _stack: StackBox;
|
|
141
|
+
private _current: string;
|
|
141
142
|
|
|
142
143
|
constructor( props: TabsProps ) {
|
|
143
144
|
super( props );
|
|
@@ -169,6 +170,7 @@ export class Tabs extends VBox<TabsProps> {
|
|
|
169
170
|
selectTab( name: string ) {
|
|
170
171
|
this._list.select( name );
|
|
171
172
|
this._stack.select( name );
|
|
173
|
+
this._current = name;
|
|
172
174
|
}
|
|
173
175
|
|
|
174
176
|
private _onclick( ev: TablistClickEvent ) {
|
|
@@ -183,6 +185,10 @@ export class Tabs extends VBox<TabsProps> {
|
|
|
183
185
|
return this._stack.getPage( name );
|
|
184
186
|
}
|
|
185
187
|
|
|
188
|
+
getCurTab( ) {
|
|
189
|
+
return this._current;
|
|
190
|
+
}
|
|
191
|
+
|
|
186
192
|
/**
|
|
187
193
|
*
|
|
188
194
|
*/
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
* that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
|
-
import { EventCallback } from '@core/core_events.js';
|
|
18
|
-
import { Component,
|
|
17
|
+
//import { EventCallback } from '@core/core_events.js';
|
|
18
|
+
import { Component, makeUniqueComponentId } from '../../core/component';
|
|
19
19
|
import { class_ns, UnsafeHtml } from '../../core/core_tools';
|
|
20
20
|
|
|
21
21
|
import { HBox } from '../boxes/boxes';
|
|
22
|
-
import { Input, TextInputProps } from "../input/input"
|
|
22
|
+
import { DateProps, Input, InputProps, NumberProps, TextInputProps, TimeProps } from "../input/input"
|
|
23
23
|
import { Label } from '../label/label';
|
|
24
24
|
|
|
25
25
|
import "./textedit.module.scss";
|
|
@@ -30,12 +30,28 @@ import "./textedit.module.scss";
|
|
|
30
30
|
*
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
type TextEditInputs = TextInputProps | NumberProps | DateProps | TimeProps;
|
|
34
|
+
|
|
35
|
+
interface TextEditBase {
|
|
36
|
+
label: string | UnsafeHtml;
|
|
37
|
+
labelWidth?: number;
|
|
38
|
+
inputWidth?: number;
|
|
39
|
+
inputId?: string;
|
|
40
|
+
inputGadgets?: Component[];
|
|
41
|
+
inputAttrs?: any;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type TextEditProps = TextEditInputs & TextEditBase;
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
not enougth precise
|
|
48
|
+
interface TextEditProps extends InputProps {
|
|
34
49
|
label: string | UnsafeHtml;
|
|
35
50
|
labelWidth?: number;
|
|
51
|
+
editWidth?: number;
|
|
36
52
|
inputId?: string;
|
|
37
53
|
|
|
38
|
-
type?: "text" | "email" | "password" | "date" | "number";
|
|
54
|
+
type?: "text" | "email" | "password" | "date" | "number" | "time";
|
|
39
55
|
name?: string;
|
|
40
56
|
readonly?: boolean;
|
|
41
57
|
required?: boolean;
|
|
@@ -49,6 +65,7 @@ interface TextEditProps extends ComponentProps {
|
|
|
49
65
|
focus?: EventCallback<EvFocus>;
|
|
50
66
|
change?: EventCallback<EvChange>;
|
|
51
67
|
}
|
|
68
|
+
*/
|
|
52
69
|
|
|
53
70
|
/**
|
|
54
71
|
*
|
|
@@ -71,26 +88,14 @@ export class TextEdit extends HBox {
|
|
|
71
88
|
}
|
|
72
89
|
|
|
73
90
|
const gadgets = props.inputGadgets ?? [];
|
|
91
|
+
const iprops: InputProps = { ...props, id: props.inputId, attrs: props.inputAttrs, width: props.inputWidth };
|
|
74
92
|
|
|
75
93
|
this.setContent( [
|
|
76
|
-
new HBox( { id: "label", width: props.labelWidth, content: [
|
|
94
|
+
props.label ? new HBox( { id: "label", width: props.labelWidth, content: [
|
|
77
95
|
new Label( { tag: "label", text: props.label, labelFor: props.inputId } ),
|
|
78
|
-
]}),
|
|
96
|
+
]}) : null,
|
|
79
97
|
new HBox( { id: "edit", content: [
|
|
80
|
-
this.input = new Input(
|
|
81
|
-
type: props.type ?? "text",
|
|
82
|
-
readonly: props.readonly,
|
|
83
|
-
value: props.value,
|
|
84
|
-
name: props.name,
|
|
85
|
-
id: props.inputId,
|
|
86
|
-
required: props.required,
|
|
87
|
-
disabled: props.disabled,
|
|
88
|
-
placeholder: props.placeholder,
|
|
89
|
-
autofocus: props.autofocus,
|
|
90
|
-
attrs: props.inputAttrs,
|
|
91
|
-
focus: props.focus,
|
|
92
|
-
change: props.change,
|
|
93
|
-
} ),
|
|
98
|
+
this.input = new Input( iprops ),
|
|
94
99
|
...gadgets,
|
|
95
100
|
]})
|
|
96
101
|
])
|
package/src/core/component.ts
CHANGED
|
@@ -25,6 +25,7 @@ interface RefType<T extends Component> {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
type ComponentAttributes = Record<string,string|number|boolean>;
|
|
28
|
+
type CreateComponentCallBack = ( attrs: Record<string,string> ) => ComponentContent;
|
|
28
29
|
|
|
29
30
|
const FRAGMENT = Symbol( "fragment" );
|
|
30
31
|
const COMPONENT = Symbol( "component" );
|
|
@@ -43,7 +44,7 @@ const RE_NUMBER = /^-?\d+(\.\d*)?$/;
|
|
|
43
44
|
|
|
44
45
|
function genClassNames( x: any ): string[] {
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
const classes = [];
|
|
47
48
|
let self = Object.getPrototypeOf(x);
|
|
48
49
|
|
|
49
50
|
if( self.constructor==Component ) {
|
|
@@ -52,7 +53,7 @@ function genClassNames( x: any ): string[] {
|
|
|
52
53
|
|
|
53
54
|
while (self && self.constructor !== Component ) {
|
|
54
55
|
const clsname:string = self.constructor.name;
|
|
55
|
-
const clsns: string =
|
|
56
|
+
const clsns: string = Object.prototype.hasOwnProperty.call(self.constructor,x4_class_ns_sym) ? self.constructor[x4_class_ns_sym] : "";
|
|
56
57
|
classes.push( clsns+clsname.toLowerCase() );
|
|
57
58
|
self = Object.getPrototypeOf(self);
|
|
58
59
|
}
|
|
@@ -134,7 +135,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
134
135
|
readonly props: P;
|
|
135
136
|
protected readonly clsprefix: string; // internal class name prefix (x4 internal)
|
|
136
137
|
|
|
137
|
-
#store: Map<string|
|
|
138
|
+
#store: Map<string|symbol,any>;
|
|
138
139
|
|
|
139
140
|
constructor( props: P ) {
|
|
140
141
|
super( );
|
|
@@ -303,9 +304,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
303
304
|
*
|
|
304
305
|
*/
|
|
305
306
|
|
|
306
|
-
setClass( cls: string, set: boolean = true ) {
|
|
307
|
+
setClass( cls: string, set: boolean = true ) : this {
|
|
307
308
|
if( set ) this.addClass(cls);
|
|
308
309
|
else this.removeClass( cls );
|
|
310
|
+
return this;
|
|
309
311
|
}
|
|
310
312
|
|
|
311
313
|
// :: ATTRIBUTES ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
@@ -314,10 +316,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
314
316
|
* attributes
|
|
315
317
|
*/
|
|
316
318
|
|
|
317
|
-
setAttributes( attrs: ComponentAttributes ) {
|
|
319
|
+
setAttributes( attrs: ComponentAttributes ): this {
|
|
318
320
|
for( const name in attrs ) {
|
|
319
321
|
this.setAttribute( name, attrs[name] );
|
|
320
322
|
}
|
|
323
|
+
return this;
|
|
321
324
|
}
|
|
322
325
|
|
|
323
326
|
/**
|
|
@@ -373,7 +376,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
373
376
|
* idem as setData but onot on dom, you can store anything
|
|
374
377
|
*/
|
|
375
378
|
|
|
376
|
-
setInternalData( name: string|
|
|
379
|
+
setInternalData( name: string|symbol, value: any ): this {
|
|
377
380
|
if( !this.#store ) {
|
|
378
381
|
this.#store = new Map( );
|
|
379
382
|
}
|
|
@@ -382,7 +385,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
382
385
|
return this;
|
|
383
386
|
}
|
|
384
387
|
|
|
385
|
-
getInternalData( name: string|
|
|
388
|
+
getInternalData( name: string|symbol ): any {
|
|
386
389
|
return this.#store?.get(name);
|
|
387
390
|
}
|
|
388
391
|
|
|
@@ -417,7 +420,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
417
420
|
protected mapPropEvents<N extends keyof E>(props: P, ...elements: N[] ) {
|
|
418
421
|
const p = props as any;
|
|
419
422
|
elements.forEach( n => {
|
|
420
|
-
if (
|
|
423
|
+
if (Object.prototype.hasOwnProperty.call(p,n) && p[n]) {
|
|
421
424
|
this.on( n, p[n] );
|
|
422
425
|
}
|
|
423
426
|
});
|
|
@@ -675,7 +678,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
675
678
|
*
|
|
676
679
|
*/
|
|
677
680
|
|
|
678
|
-
getBoundingRect( ):
|
|
681
|
+
getBoundingRect( ): Rect {
|
|
679
682
|
const rc = this.dom.getBoundingClientRect( );
|
|
680
683
|
return new Rect( rc.x, rc.y, rc.width, rc.height );
|
|
681
684
|
}
|
|
@@ -843,7 +846,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
843
846
|
|
|
844
847
|
enumChildComponents( recursive: boolean ) {
|
|
845
848
|
|
|
846
|
-
|
|
849
|
+
const children: Component[] = [];
|
|
847
850
|
|
|
848
851
|
const nodes = this.enumChildNodes( recursive );
|
|
849
852
|
nodes.forEach( ( c: Node ) => {
|
|
@@ -861,7 +864,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
861
864
|
*/
|
|
862
865
|
|
|
863
866
|
enumChildNodes( recursive: boolean ) {
|
|
864
|
-
|
|
867
|
+
const children: Node[] = Array.from( recursive ? this.dom.querySelectorAll( '*' ) : this.dom.children );
|
|
865
868
|
return children;
|
|
866
869
|
}
|
|
867
870
|
|
|
@@ -880,7 +883,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
880
883
|
* called by the compiler when a jsx element is seen
|
|
881
884
|
*/
|
|
882
885
|
|
|
883
|
-
static createElement( clsOrTag: string | ComponentConstructor |
|
|
886
|
+
static createElement( clsOrTag: string | ComponentConstructor | symbol | CreateComponentCallBack, attrs: any, ...children: Component[] ): Component | Component[] {
|
|
884
887
|
|
|
885
888
|
let comp: Component;
|
|
886
889
|
|
|
@@ -1036,15 +1039,6 @@ export interface EvContextMenu extends ComponentEvent {
|
|
|
1036
1039
|
uievent: UIEvent; // UI event that fire this event
|
|
1037
1040
|
}
|
|
1038
1041
|
|
|
1039
|
-
/**
|
|
1040
|
-
* Simple message
|
|
1041
|
-
*/
|
|
1042
|
-
|
|
1043
|
-
export interface EvMessage extends ComponentEvent {
|
|
1044
|
-
readonly msg: string;
|
|
1045
|
-
readonly params?: any;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
1042
|
/**
|
|
1049
1043
|
* Drag/Drop event
|
|
1050
1044
|
*/
|
|
@@ -62,6 +62,7 @@ export class Application<E extends ApplicationEvents = ApplicationEvents> extend
|
|
|
62
62
|
super( );
|
|
63
63
|
|
|
64
64
|
console.assert( main_app==null, "Application must be a singleton." );
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
65
66
|
main_app = this;
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -185,7 +186,7 @@ export class Application<E extends ApplicationEvents = ApplicationEvents> extend
|
|
|
185
186
|
// then we send them on websocket
|
|
186
187
|
|
|
187
188
|
this.on( 'global', ( e: EvMessage ) => {
|
|
188
|
-
if(
|
|
189
|
+
if( Object.prototype.hasOwnProperty.call( e, socket_sent) ) {
|
|
189
190
|
return;
|
|
190
191
|
}
|
|
191
192
|
|
package/src/core/core_data.ts
CHANGED
|
@@ -77,7 +77,7 @@ const metaFields = Symbol( 'metaField' );
|
|
|
77
77
|
function _getMetas( obj: object, create = true ) : MetaInfos {
|
|
78
78
|
|
|
79
79
|
let ctor = obj.constructor as any;
|
|
80
|
-
let mfld =
|
|
80
|
+
let mfld = Object.prototype.hasOwnProperty.call(ctor,metaFields) ? ctor[metaFields] : undefined;
|
|
81
81
|
|
|
82
82
|
if( mfld===undefined ) {
|
|
83
83
|
if( !create ) {
|
|
@@ -105,6 +105,7 @@ function _getMetas( obj: object, create = true ) : MetaInfos {
|
|
|
105
105
|
return mfld;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
108
109
|
export namespace data {
|
|
109
110
|
|
|
110
111
|
/**
|
|
@@ -297,7 +298,7 @@ export class DataModel {
|
|
|
297
298
|
* @returns an object with known record values
|
|
298
299
|
*/
|
|
299
300
|
|
|
300
|
-
serialize( input: DataRecord ):
|
|
301
|
+
serialize<T = any>( input: DataRecord ): T {
|
|
301
302
|
let rec: any = {};
|
|
302
303
|
|
|
303
304
|
this.getFields().forEach((f) => {
|
|
@@ -306,8 +307,10 @@ export class DataModel {
|
|
|
306
307
|
}
|
|
307
308
|
});
|
|
308
309
|
|
|
309
|
-
return rec;
|
|
310
|
+
return rec as T;
|
|
310
311
|
}
|
|
312
|
+
|
|
313
|
+
|
|
311
314
|
|
|
312
315
|
/**
|
|
313
316
|
* default unserializer
|
|
@@ -454,11 +457,7 @@ export class DataModel {
|
|
|
454
457
|
*
|
|
455
458
|
*/
|
|
456
459
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const $model = Symbol( "model" )
|
|
460
|
-
|
|
461
|
-
export class DataRecord {
|
|
460
|
+
export class DataRecord {
|
|
462
461
|
[ key: string ]: DataFieldValue;
|
|
463
462
|
|
|
464
463
|
/*
|
|
@@ -511,6 +510,8 @@ export class DataRecord {
|
|
|
511
510
|
this.setRaw( fld.name, value );
|
|
512
511
|
}
|
|
513
512
|
*/
|
|
513
|
+
|
|
514
|
+
|
|
514
515
|
}
|
|
515
516
|
|
|
516
517
|
|
package/src/core/core_element.ts
CHANGED
package/src/core/core_i18n.ts
CHANGED
package/src/core/core_router.ts
CHANGED
|
@@ -60,7 +60,7 @@ export function parseRoute(str: string | RegExp, loose = false): Segment {
|
|
|
60
60
|
const ext = tmp.indexOf('.', 1);
|
|
61
61
|
|
|
62
62
|
keys.push(tmp.substring(1, o >= 0 ? o : ext >= 0 ? ext : tmp.length));
|
|
63
|
-
pattern += o >= 0 && ext < 0 ? '(?:/([
|
|
63
|
+
pattern += o >= 0 && ext < 0 ? '(?:/([^/]+?))?' : '/([^/]+?)';
|
|
64
64
|
if (ext >= 0) {
|
|
65
65
|
pattern += (o >= 0 ? '?' : '') + '\\' + tmp.substring(ext);
|
|
66
66
|
}
|
|
@@ -72,7 +72,7 @@ export function parseRoute(str: string | RegExp, loose = false): Segment {
|
|
|
72
72
|
|
|
73
73
|
return {
|
|
74
74
|
keys,
|
|
75
|
-
pattern: new RegExp( `^${pattern}${loose ? '(
|
|
75
|
+
pattern: new RegExp( `^${pattern}${loose ? '(?=$|/)' : '/?$'}`, 'i' )
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file core_state.ts
|
|
3
|
+
* @author Etienne Cochard
|
|
4
|
+
* @copyright (c) 2025 R-libre ingenierie, all rights reserved.
|
|
5
|
+
**/
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
type StateData = boolean | number | string | Date | any;
|
|
9
|
+
type State = Record<string,StateData>;
|
|
10
|
+
|
|
11
|
+
export class StateManager {
|
|
12
|
+
|
|
13
|
+
private _state: StateData;
|
|
14
|
+
private _subscribers: Map<string,any>;
|
|
15
|
+
private _currentTracking: Set<string>;
|
|
16
|
+
|
|
17
|
+
constructor(initialState: StateData ) {
|
|
18
|
+
this._state = initialState ? { ...initialState } : {};
|
|
19
|
+
this._subscribers = new Map();
|
|
20
|
+
this._currentTracking = new Set( );
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getState( path: string, defaultValue: StateData = null) {
|
|
24
|
+
// Optional tracking for reactivity
|
|
25
|
+
if (this._currentTracking) {
|
|
26
|
+
this._currentTracking.add(path);
|
|
27
|
+
}
|
|
28
|
+
// Fast path-based access
|
|
29
|
+
const parts = path.split('.');
|
|
30
|
+
let current = this._state;
|
|
31
|
+
|
|
32
|
+
for (const part of parts) {
|
|
33
|
+
if (current?.[part] === undefined) {
|
|
34
|
+
return defaultValue;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
current = current[part];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return current;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setState(path: string, value: StateData, context: any = {} ) {
|
|
44
|
+
// Update state
|
|
45
|
+
const parts = path.split('.');
|
|
46
|
+
let current = this._state;
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
49
|
+
const part = parts[i];
|
|
50
|
+
if (!current[part] || typeof current[part] !== 'object') {
|
|
51
|
+
current[part] = {};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
current = current[part];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
current[parts[parts.length - 1]] = value;
|
|
58
|
+
|
|
59
|
+
// Notify subscribers
|
|
60
|
+
this._notifySubscribers(path, value);
|
|
61
|
+
}
|
|
62
|
+
}
|
package/src/core/core_svg.ts
CHANGED
package/src/x4.ts
CHANGED
|
@@ -15,13 +15,17 @@
|
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
17
|
export * from "./core/component"
|
|
18
|
+
export * from "./core/core_application"
|
|
18
19
|
export * from "./core/core_colors"
|
|
20
|
+
export * from "./core/core_data"
|
|
19
21
|
export * from "./core/core_dom"
|
|
20
22
|
export * from "./core/core_dragdrop"
|
|
21
23
|
export * from "./core/core_element"
|
|
22
24
|
export * from "./core/core_events"
|
|
23
25
|
export * from "./core/core_i18n"
|
|
26
|
+
export * from "./core/core_react"
|
|
24
27
|
export * from "./core/core_router"
|
|
28
|
+
export * from "./core/core_state"
|
|
25
29
|
export * from "./core/core_styles"
|
|
26
30
|
export * from "./core/core_svg"
|
|
27
31
|
export * from "./core/core_tools"
|