x4js 2.0.26 → 2.0.30
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/.vscode/launch.json +14 -0
- package/.vscode/settings.json +2 -0
- package/ai-comments.txt +97 -0
- package/demo/assets/house-light.svg +1 -0
- package/demo/assets/radio.svg +4 -0
- package/demo/index.html +12 -0
- package/demo/main.scss +23 -0
- package/demo/main.ts +324 -0
- package/demo/package.json +26 -0
- package/demo/scss.d.ts +4 -0
- package/demo/svg.d.ts +1 -0
- package/demo/tsconfig.json +14 -0
- package/lib/types/x4js.d.ts +0 -2374
- package/package.json +23 -47
- package/prepack.mjs +3 -0
- package/scripts/prepack.mjs +342 -0
- package/src/colors.scss +246 -0
- package/src/components/boxes/boxes.module.scss +1 -1
- package/src/components/boxes/boxes.ts +139 -28
- package/src/components/button/button.ts +80 -33
- package/src/components/combobox/combobox.ts +1 -1
- package/src/components/dialog/dialog.ts +4 -0
- package/src/components/gauge/gauge.module.scss +3 -0
- package/src/components/gauge/gauge.ts +1 -1
- package/src/components/gridview/gridview.ts +106 -8
- package/src/components/icon/icon.ts +42 -14
- package/src/components/input/input.ts +155 -76
- package/src/components/keyboard/keyboard.module.scss +1 -1
- package/src/components/keyboard/keyboard.ts +31 -9
- package/src/components/label/label.module.scss +9 -0
- package/src/components/label/label.ts +10 -6
- package/src/components/link/link.module.scss +44 -0
- package/src/components/link/link.ts +7 -1
- package/src/components/listbox/listbox.module.scss +18 -4
- package/src/components/listbox/listbox.ts +34 -15
- package/src/components/menu/menu.module.scss +14 -2
- package/src/components/menu/menu.ts +1 -1
- package/src/components/messages/messages.ts +13 -5
- package/src/components/panel/panel.module.scss +7 -0
- package/src/components/popup/popup.ts +14 -10
- package/src/components/propgrid/propgrid.ts +13 -3
- package/src/components/shared.scss +4 -0
- package/src/components/spreadsheet/spreadsheet.module.scss +308 -0
- package/src/components/spreadsheet/spreadsheet.ts +1223 -0
- package/src/components/tabs/tabs.module.scss +1 -0
- package/src/components/textarea/textarea.ts +8 -2
- package/src/components/textedit/textedit.ts +7 -0
- package/src/components/themes.scss +2 -0
- package/src/components/tooltips/tooltips.ts +15 -3
- package/src/core/component.ts +358 -162
- package/src/core/core_application.ts +129 -32
- package/src/core/core_colors.ts +382 -119
- package/src/core/core_data.ts +73 -86
- package/src/core/core_dom.ts +10 -0
- package/src/core/core_dragdrop.ts +32 -7
- package/src/core/core_element.ts +111 -4
- package/src/core/core_events.ts +48 -11
- package/src/core/core_i18n.ts +2 -0
- package/src/core/core_pdf.ts +454 -0
- package/src/core/core_router.ts +64 -5
- package/src/core/core_state.ts +1 -0
- package/src/core/core_styles.ts +11 -12
- package/src/core/core_svg.ts +348 -51
- package/src/core/core_tools.ts +105 -17
- package/src/x4.ts +1 -0
- package/src/x4tsx.d.ts +2 -1
- package/tsconfig.json +11 -0
- package/lib/README.txt +0 -20
- package/lib/cjs/x4.css +0 -1
- package/lib/cjs/x4.js +0 -2
- package/lib/esm/x4.css +0 -1
- package/lib/esm/x4.mjs +0 -2
- package/lib/styles/x4.css +0 -1
|
@@ -121,14 +121,14 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
121
121
|
this.hide( );
|
|
122
122
|
|
|
123
123
|
this.addDOMEvent( "mousedown", (e) => {
|
|
124
|
-
this.
|
|
124
|
+
this.handleKeyEvent( e );
|
|
125
125
|
e.preventDefault( );
|
|
126
126
|
e.stopPropagation( );
|
|
127
127
|
});
|
|
128
128
|
|
|
129
129
|
// for rapid people
|
|
130
130
|
this.addDOMEvent( "dblclick", (e) => {
|
|
131
|
-
this.
|
|
131
|
+
this.handleKeyEvent( e );
|
|
132
132
|
e.preventDefault( );
|
|
133
133
|
e.stopPropagation( );
|
|
134
134
|
});
|
|
@@ -148,7 +148,7 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
148
148
|
*
|
|
149
149
|
*/
|
|
150
150
|
|
|
151
|
-
private
|
|
151
|
+
private handleKeyEvent( e: UIEvent ) {
|
|
152
152
|
let target = e.target as HTMLElement;
|
|
153
153
|
let key;
|
|
154
154
|
|
|
@@ -165,6 +165,10 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
165
165
|
return;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
this._handleKey( key );
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private _handleKey( key: number ) {
|
|
168
172
|
switch( key ) {
|
|
169
173
|
// bk space
|
|
170
174
|
case 2: {
|
|
@@ -326,11 +330,16 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
326
330
|
private handleFocus( target: Element, enter: boolean ) {
|
|
327
331
|
|
|
328
332
|
if( enter ) {
|
|
329
|
-
if( target.tagName=='INPUT'
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
333
|
+
if( target.tagName=='INPUT' ) {
|
|
334
|
+
const input = target as HTMLInputElement;
|
|
335
|
+
if( !input.readOnly &&
|
|
336
|
+
input.type!='checkbox' && input.type!='radio' &&
|
|
337
|
+
input.type!='range' && input.type!='file' ) {
|
|
338
|
+
this.input = input;
|
|
339
|
+
this.visible = true;
|
|
340
|
+
this.setTimeout( "vis", 200, this._updateVis );
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
334
343
|
}
|
|
335
344
|
}
|
|
336
345
|
|
|
@@ -430,6 +439,7 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
430
439
|
let content = line[i];
|
|
431
440
|
let key;
|
|
432
441
|
let icon = null;
|
|
442
|
+
let repeat = false;
|
|
433
443
|
|
|
434
444
|
if( content.length>2 && content[0]=='{' && content[content.length-1]=='}') {
|
|
435
445
|
|
|
@@ -452,6 +462,7 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
452
462
|
|
|
453
463
|
case 2:
|
|
454
464
|
{
|
|
465
|
+
repeat = true;
|
|
455
466
|
content = undefined;
|
|
456
467
|
icon = icon_bksp;
|
|
457
468
|
cls += ' cdel';
|
|
@@ -516,7 +527,18 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
516
527
|
key = line[i].charCodeAt(0);
|
|
517
528
|
}
|
|
518
529
|
|
|
519
|
-
let el = new Button( {
|
|
530
|
+
let el = new Button( {
|
|
531
|
+
cls,
|
|
532
|
+
label: content,
|
|
533
|
+
attrs: {'data-key': key},
|
|
534
|
+
icon,
|
|
535
|
+
autorepeat: repeat,
|
|
536
|
+
click: ( e ) => {
|
|
537
|
+
if( e.repeat ) {
|
|
538
|
+
this._handleKey( key )
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
} );
|
|
520
542
|
tl.push( el );
|
|
521
543
|
}
|
|
522
544
|
|
|
@@ -30,16 +30,25 @@
|
|
|
30
30
|
background-color: var( --label-background );
|
|
31
31
|
gap: 0.2em;
|
|
32
32
|
|
|
33
|
+
&.al-right
|
|
33
34
|
&.right {
|
|
34
35
|
text-align: right;
|
|
35
36
|
justify-content: end;
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
&.al-center,
|
|
38
40
|
&.center {
|
|
39
41
|
text-align: center;
|
|
40
42
|
justify-content: center;
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
&.al-right {
|
|
46
|
+
padding-left: 8px;
|
|
47
|
+
#icon {
|
|
48
|
+
order: 2;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
#text {
|
|
44
53
|
&:empty {
|
|
45
54
|
display: none;
|
|
@@ -24,6 +24,7 @@ export interface LabelProps extends ComponentProps {
|
|
|
24
24
|
text?: string | UnsafeHtml;
|
|
25
25
|
icon?: string;
|
|
26
26
|
labelFor?: string;
|
|
27
|
+
align?: "left" | "center" | "right";
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -32,29 +33,32 @@ export interface LabelProps extends ComponentProps {
|
|
|
32
33
|
|
|
33
34
|
@class_ns( "x4" )
|
|
34
35
|
export class Label extends Component<LabelProps> {
|
|
35
|
-
#text: Component;
|
|
36
36
|
|
|
37
37
|
constructor( p: LabelProps ) {
|
|
38
38
|
super( { ...p, content: null } );
|
|
39
39
|
|
|
40
40
|
this.setContent( [
|
|
41
41
|
new Icon( { id:"icon", iconId: this.props.icon } ),
|
|
42
|
-
|
|
42
|
+
new Component( { tag: 'span', id: 'text' } )
|
|
43
43
|
] );
|
|
44
44
|
|
|
45
45
|
// small hack for react:
|
|
46
46
|
// p.content may be the text
|
|
47
|
-
|
|
48
|
-
this.setText( text );
|
|
47
|
+
this.setText( this.props.text );
|
|
49
48
|
|
|
50
49
|
if( p.labelFor ) {
|
|
51
50
|
this.setAttribute( "for", p.labelFor );
|
|
52
51
|
}
|
|
52
|
+
|
|
53
|
+
if( p.align ) {
|
|
54
|
+
this.addClass( "al-"+p.align );
|
|
55
|
+
}
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
setText( text: string | UnsafeHtml ) {
|
|
56
|
-
this
|
|
57
|
-
|
|
59
|
+
const lab = this.query<Icon>( "#text" );
|
|
60
|
+
lab.setContent( text );
|
|
61
|
+
lab.setClass( "empty", !text );
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
setIcon( icon: string ) {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ___ ___ __
|
|
3
|
+
* \ \/ / / _
|
|
4
|
+
* \ / /_| |_
|
|
5
|
+
* / \____ _|
|
|
6
|
+
* /__/\__\ |_|
|
|
7
|
+
*
|
|
8
|
+
* @file link.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
|
+
|
|
17
|
+
.x4link {
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
|
|
20
|
+
#text {
|
|
21
|
+
text-decoration: underline;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&[disabled] {
|
|
25
|
+
cursor: not-allowed;
|
|
26
|
+
border-color: var( --border );
|
|
27
|
+
color: var( --listbox-item-color-disabled );
|
|
28
|
+
|
|
29
|
+
&>.body {
|
|
30
|
+
.x4viewport {
|
|
31
|
+
pointer-events: none;
|
|
32
|
+
.x4item {
|
|
33
|
+
&.selected {
|
|
34
|
+
background-color: var( --listbox-item-color-sel-disabled );
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&:focus-within {
|
|
42
|
+
border-color: var( --listbox-border-focus );
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -19,6 +19,7 @@ import { EventCallback } from '../../core/core_events';
|
|
|
19
19
|
import { class_ns, UnsafeHtml } from '../../core/core_tools';
|
|
20
20
|
import { Label } from '../label/label';
|
|
21
21
|
|
|
22
|
+
import "./link.module.scss"
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Link events
|
|
@@ -36,6 +37,7 @@ interface LinkProps extends ComponentProps {
|
|
|
36
37
|
href: string;
|
|
37
38
|
text?: string | UnsafeHtml; // you can also use content for complexe content
|
|
38
39
|
icon?: string;
|
|
40
|
+
align?: "left" | "center" | "right";
|
|
39
41
|
click?: EventCallback<EvClick>;
|
|
40
42
|
}
|
|
41
43
|
|
|
@@ -44,12 +46,16 @@ export class Link extends Component<LinkProps,LinkEvents> {
|
|
|
44
46
|
constructor( props: LinkProps ) {
|
|
45
47
|
super( { tag: "a", ...props} );
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
if( props.href ) {
|
|
50
|
+
this.setAttribute( "href", props.href );
|
|
51
|
+
}
|
|
52
|
+
|
|
48
53
|
this.mapPropEvents( props, "click" );
|
|
49
54
|
|
|
50
55
|
this.setContent( new Label( {
|
|
51
56
|
text: props.text,
|
|
52
57
|
icon: props.icon,
|
|
58
|
+
align: props.align,
|
|
53
59
|
} ) );
|
|
54
60
|
|
|
55
61
|
this.addDOMEvent('click', (e) => this._on_click(e));
|
|
@@ -39,16 +39,20 @@
|
|
|
39
39
|
border: 1px solid var( --listbox-border );
|
|
40
40
|
background-color: var( --listbox-background );
|
|
41
41
|
|
|
42
|
-
&:focus-within {
|
|
43
|
-
border-color: var( --listbox-border-focus );
|
|
44
|
-
}
|
|
45
|
-
|
|
46
42
|
outline: none;
|
|
47
43
|
|
|
48
44
|
&>.x4header {
|
|
49
45
|
border-bottom: 1px solid var( --border );
|
|
50
46
|
}
|
|
51
47
|
|
|
48
|
+
&>.title {
|
|
49
|
+
background: white;
|
|
50
|
+
padding: 4px;
|
|
51
|
+
font-weight: bold;
|
|
52
|
+
color: black;
|
|
53
|
+
border-bottom: 1px solid var(--border);
|
|
54
|
+
}
|
|
55
|
+
|
|
52
56
|
&>.body {
|
|
53
57
|
width: 100%;
|
|
54
58
|
flex-basis: 0;
|
|
@@ -94,6 +98,12 @@
|
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
|
|
101
|
+
.ref-c1 { width: var( --ref-c1-width); }
|
|
102
|
+
.ref-c2 { width: var( --ref-c2-width); }
|
|
103
|
+
.ref-c3 { width: var( --ref-c3-width); }
|
|
104
|
+
.ref-c4 { width: var( --ref-c4-width); }
|
|
105
|
+
.ref-c5 { width: var( --ref-c5-width); }
|
|
106
|
+
|
|
97
107
|
//&:active{
|
|
98
108
|
//background-color: var( --color-80 );
|
|
99
109
|
//color: var(--color-0);
|
|
@@ -162,4 +172,8 @@
|
|
|
162
172
|
}
|
|
163
173
|
}
|
|
164
174
|
}
|
|
175
|
+
|
|
176
|
+
&:focus-within {
|
|
177
|
+
border-color: var( --listbox-border-focus );
|
|
178
|
+
}
|
|
165
179
|
}
|
|
@@ -42,8 +42,7 @@ export interface ListItem {
|
|
|
42
42
|
*
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
|
-
interface ListboxEvents extends ComponentEvents {
|
|
46
|
-
//change: EvChange;
|
|
45
|
+
export interface ListboxEvents extends ComponentEvents {
|
|
47
46
|
click?: EvClick;
|
|
48
47
|
dblClick?: EvDblClick;
|
|
49
48
|
contextMenu?: EvContextMenu;
|
|
@@ -54,9 +53,11 @@ interface ListboxEvents extends ComponentEvents {
|
|
|
54
53
|
*
|
|
55
54
|
*/
|
|
56
55
|
|
|
57
|
-
interface ListboxProps extends Omit<ComponentProps,'content'> {
|
|
56
|
+
export interface ListboxProps extends Omit<ComponentProps,'content'> {
|
|
58
57
|
items?: ListItem[];
|
|
59
58
|
renderer?: ( item: ListItem ) => Component;
|
|
59
|
+
title?: string;
|
|
60
|
+
icon?: string;
|
|
60
61
|
header?: Header;
|
|
61
62
|
footer?: Component,
|
|
62
63
|
checkable?: true,
|
|
@@ -105,6 +106,7 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
this.setContent( [
|
|
109
|
+
(props.title || props.icon) ? new Label( { cls: 'title', text: props.title, icon: props.icon }) : null,
|
|
108
110
|
props.header ? props.header : null,
|
|
109
111
|
scroller,
|
|
110
112
|
props.footer,
|
|
@@ -118,7 +120,7 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
|
|
|
118
120
|
} );
|
|
119
121
|
|
|
120
122
|
if( props.items ) {
|
|
121
|
-
this.setItems( props.items );
|
|
123
|
+
this.setItems( props.items, false );
|
|
122
124
|
}
|
|
123
125
|
}
|
|
124
126
|
|
|
@@ -192,8 +194,15 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
|
|
|
192
194
|
}
|
|
193
195
|
else {
|
|
194
196
|
const selitem = this._itemWithID( this._lastsel );
|
|
195
|
-
|
|
196
|
-
|
|
197
|
+
|
|
198
|
+
let nel;
|
|
199
|
+
if( selitem ) {
|
|
200
|
+
nel = sens==kbNav.next ? selitem.nextElement() : selitem.prevElement();
|
|
201
|
+
nel = next_visible( nel, sens==kbNav.next );
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
nel = sens==kbNav.next ? this._view.firstChild() : this._view.lastChild( );
|
|
205
|
+
}
|
|
197
206
|
|
|
198
207
|
if( nel ) {
|
|
199
208
|
const id = nel.getInternalData( "id" );
|
|
@@ -407,10 +416,12 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
|
|
|
407
416
|
this._multisel.clear( );
|
|
408
417
|
}
|
|
409
418
|
|
|
410
|
-
clearSelection( ) {
|
|
419
|
+
clearSelection( fireEvent = true ) {
|
|
411
420
|
if( this._multisel.size ) {
|
|
412
421
|
this._clearSelection( );
|
|
413
|
-
|
|
422
|
+
if( fireEvent ) {
|
|
423
|
+
this.fire( "selectionChange", { selection: [], empty: true } );
|
|
424
|
+
}
|
|
414
425
|
}
|
|
415
426
|
}
|
|
416
427
|
|
|
@@ -426,24 +437,21 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
|
|
|
426
437
|
this._view.clearContent( );
|
|
427
438
|
this._items = items ?? [];
|
|
428
439
|
|
|
429
|
-
let
|
|
440
|
+
let update_sel = false;
|
|
430
441
|
|
|
431
442
|
if( this._items.length ) {
|
|
432
443
|
const content = items.map( x => this.renderItem(x) );
|
|
433
444
|
this._view.setContent( content );
|
|
434
445
|
|
|
435
|
-
if( keepSel ) {
|
|
446
|
+
if( keepSel && oldSel.length>0 ) {
|
|
436
447
|
this.select( oldSel );
|
|
437
448
|
}
|
|
438
|
-
else {
|
|
439
|
-
upsel = true;
|
|
440
|
-
}
|
|
441
449
|
}
|
|
442
450
|
else {
|
|
443
|
-
|
|
451
|
+
update_sel = oldSel.length>0;
|
|
444
452
|
}
|
|
445
453
|
|
|
446
|
-
if(
|
|
454
|
+
if( update_sel ) {
|
|
447
455
|
this.setTimeout( "sel", 100, ( ) => {
|
|
448
456
|
this.fire( "selectionChange", { selection: [], empty: true } );
|
|
449
457
|
} );
|
|
@@ -574,4 +582,15 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
|
|
|
574
582
|
getSelection( ) {
|
|
575
583
|
return Array.from( this._multisel );
|
|
576
584
|
}
|
|
585
|
+
|
|
586
|
+
ensureSelectionVisible( ) {
|
|
587
|
+
const sels = Array.from( this._multisel.values() );
|
|
588
|
+
if( sels.length) {
|
|
589
|
+
const item = this._itemWithID( sels[0] );
|
|
590
|
+
item?.scrollIntoView( {
|
|
591
|
+
behavior: "instant",
|
|
592
|
+
block: "nearest"
|
|
593
|
+
} )
|
|
594
|
+
}
|
|
595
|
+
}
|
|
577
596
|
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
@use "../shared.scss";
|
|
18
18
|
|
|
19
19
|
:root {
|
|
20
|
-
--menu-background: var( --background-
|
|
20
|
+
--menu-background: var( --background-ternary );
|
|
21
21
|
--menu-border: var( --border-hover );
|
|
22
22
|
|
|
23
23
|
--menuitem-color: var( --text-ternary );;
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
.x4menu {
|
|
31
|
-
@extend .shadow-
|
|
31
|
+
@extend .shadow-xxl;
|
|
32
32
|
|
|
33
33
|
position: absolute;
|
|
34
34
|
overflow-y: auto;
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
|
|
40
40
|
background-color: var(--menu-background);
|
|
41
41
|
border: 1px solid var(--menu-border);
|
|
42
|
+
border-left: 4px solid var( --accent-background );
|
|
42
43
|
|
|
43
44
|
max-height: calc( 100vh - 32px );
|
|
44
45
|
|
|
@@ -69,6 +70,17 @@
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
&.danger #icon {
|
|
74
|
+
.fa-primary {
|
|
75
|
+
fill: var( --color-danger-a50 );
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.fa-secondary {
|
|
79
|
+
fill: var( --color-danger-a30 );
|
|
80
|
+
opacity: 1;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
#text {
|
|
73
85
|
@extend .flex;
|
|
74
86
|
}
|
|
@@ -98,6 +98,11 @@ export class MessageBox extends Dialog<DialogProps>
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
|
|
101
|
+
interface InputOptions {
|
|
102
|
+
password?: boolean;
|
|
103
|
+
trim?: boolean;
|
|
104
|
+
}
|
|
105
|
+
|
|
101
106
|
@class_ns( "x4" )
|
|
102
107
|
export class InputBox extends Dialog<DialogProps>
|
|
103
108
|
{
|
|
@@ -110,7 +115,10 @@ export class InputBox extends Dialog<DialogProps>
|
|
|
110
115
|
return input.getValue( );
|
|
111
116
|
}
|
|
112
117
|
|
|
113
|
-
private static _create( msg: string | UnsafeHtml, value: string, title: string ) {
|
|
118
|
+
private static _create( msg: string | UnsafeHtml, value: string, title: string, options?: InputOptions ) {
|
|
119
|
+
|
|
120
|
+
options = {trim: true, password: false, ...options };
|
|
121
|
+
|
|
114
122
|
const box = new InputBox({
|
|
115
123
|
modal: true,
|
|
116
124
|
title,
|
|
@@ -122,7 +130,7 @@ export class InputBox extends Dialog<DialogProps>
|
|
|
122
130
|
new Icon( { iconId: pen_icon }),
|
|
123
131
|
new VBox( { flex: 1, content: [
|
|
124
132
|
new Label( { text: msg } ),
|
|
125
|
-
new Input( { value, type: "text" } )
|
|
133
|
+
new Input( { value, type: options.password ? "password" : "text", trim: options.trim } )
|
|
126
134
|
]})
|
|
127
135
|
]
|
|
128
136
|
}),
|
|
@@ -138,11 +146,11 @@ export class InputBox extends Dialog<DialogProps>
|
|
|
138
146
|
* idem with promise
|
|
139
147
|
*/
|
|
140
148
|
|
|
141
|
-
static async showAsync( msg: string | UnsafeHtml, value: string, title?: string ) : Promise<string> {
|
|
149
|
+
static async showAsync( msg: string | UnsafeHtml, value: string, title?: string, options?: InputOptions ) : Promise<string> {
|
|
142
150
|
|
|
143
|
-
return new Promise( (resolve,
|
|
151
|
+
return new Promise( (resolve, _reject ) => {
|
|
144
152
|
|
|
145
|
-
const box = this._create( msg, value, title );
|
|
153
|
+
const box = this._create( msg, value, title, options );
|
|
146
154
|
|
|
147
155
|
box.on( "btnclick", ( ev ) => {
|
|
148
156
|
asap( ( ) => {
|
|
@@ -21,6 +21,7 @@ import { Rect, Point, class_ns, asap } from '../../core/core_tools';
|
|
|
21
21
|
import { Box } from '../boxes/boxes'
|
|
22
22
|
|
|
23
23
|
import "./popup.module.scss"
|
|
24
|
+
import { getGlobalZoom, getScrollbarSize } from '../../core/core_tools.js';
|
|
24
25
|
|
|
25
26
|
export interface PopupEvents extends ComponentEvents {
|
|
26
27
|
closed: ComponentEvent;
|
|
@@ -143,24 +144,27 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
|
|
|
143
144
|
*/
|
|
144
145
|
|
|
145
146
|
displayAt( x: number, y: number ) {
|
|
147
|
+
const zm = getGlobalZoom( );
|
|
148
|
+
|
|
146
149
|
//TODO: check is already visible
|
|
147
150
|
this.setStyle( {
|
|
148
|
-
left: x+"px",
|
|
149
|
-
top: y+"px",
|
|
151
|
+
left: (x/zm)+"px",
|
|
152
|
+
top: (y/zm)+"px",
|
|
150
153
|
})
|
|
151
154
|
|
|
152
155
|
this._do_show( ); // to compute size
|
|
153
156
|
|
|
154
|
-
const rc = this.getBoundingRect( );
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if( rc.right>
|
|
159
|
-
this.setStyleValue( "left",
|
|
157
|
+
const rc = this.getBoundingRect( ).scale( 1/zm );
|
|
158
|
+
const sbw = getScrollbarSize( );
|
|
159
|
+
|
|
160
|
+
const screen_width = window.innerWidth - sbw;
|
|
161
|
+
if( rc.right>screen_width ) {
|
|
162
|
+
this.setStyleValue( "left", screen_width-rc.width );
|
|
160
163
|
}
|
|
161
164
|
|
|
162
|
-
|
|
163
|
-
|
|
165
|
+
const screen_height = window.innerHeight - sbw;
|
|
166
|
+
if( rc.bottom>screen_height ) {
|
|
167
|
+
this.setStyleValue( "top", screen_height-rc.height );
|
|
164
168
|
}
|
|
165
169
|
}
|
|
166
170
|
|
|
@@ -73,7 +73,7 @@ export class PropertyGrid extends VBox {
|
|
|
73
73
|
if( props.groups ) {
|
|
74
74
|
this.setItems( props.groups );
|
|
75
75
|
}
|
|
76
|
-
}
|
|
76
|
+
}
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
79
|
*
|
|
@@ -125,8 +125,13 @@ export class PropertyGrid extends VBox {
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
let cls = "group";
|
|
129
|
+
if( g.cls ) {
|
|
130
|
+
cls += ' '+g.cls;
|
|
131
|
+
}
|
|
132
|
+
|
|
128
133
|
const tr = new HBox({
|
|
129
|
-
cls
|
|
134
|
+
cls,
|
|
130
135
|
content: [
|
|
131
136
|
g.icon ? new Icon({ id: "icon", iconId: g.icon }) : null,
|
|
132
137
|
new VBox( { content: [
|
|
@@ -240,9 +245,14 @@ export class PropertyGrid extends VBox {
|
|
|
240
245
|
}
|
|
241
246
|
});
|
|
242
247
|
}
|
|
248
|
+
|
|
249
|
+
let cls = 'row';
|
|
250
|
+
if( item.cls ) {
|
|
251
|
+
cls += ' ' + item.cls;
|
|
252
|
+
}
|
|
243
253
|
|
|
244
254
|
return new HBox({
|
|
245
|
-
cls
|
|
255
|
+
cls,
|
|
246
256
|
content: [
|
|
247
257
|
use_hdr ? new Component({ cls: 'cell hdr', content: item.title ?? item.name, tooltip: item.desc }) : null,
|
|
248
258
|
new Component({ cls: 'cell', tag: "label", attrs: { "labelFor": item.name }, content: editor })
|