neo.mjs 8.16.0 → 8.17.0
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/apps/ServiceWorker.mjs +2 -2
- package/apps/portal/index.html +1 -1
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/examples/ServiceWorker.mjs +2 -2
- package/package.json +1 -1
- package/resources/scss/src/grid/Container.scss +12 -68
- package/resources/scss/src/grid/Scrollbar.scss +21 -0
- package/resources/scss/src/grid/View.scss +29 -2
- package/src/DefaultConfig.mjs +2 -2
- package/src/grid/Container.mjs +33 -14
- package/src/grid/Scrollbar.mjs +118 -0
- package/src/grid/View.mjs +1 -1
- package/src/main/addon/ScrollSync.mjs +90 -0
- package/src/worker/App.mjs +17 -0
package/apps/ServiceWorker.mjs
CHANGED
package/apps/portal/index.html
CHANGED
package/package.json
CHANGED
@@ -4,74 +4,18 @@
|
|
4
4
|
overflow-y : hidden;
|
5
5
|
overscroll-behavior: none;
|
6
6
|
position : relative;
|
7
|
-
}
|
8
|
-
|
9
|
-
.neo-grid-container {
|
10
|
-
border : 1px solid var(--grid-container-border-color);
|
11
|
-
border-spacing : 0;
|
12
|
-
color : var(--grid-container-color);
|
13
|
-
font-size : 13px;
|
14
|
-
font-weight : 400;
|
15
|
-
height : 100%;
|
16
|
-
line-height : 19px;
|
17
|
-
overscroll-behavior: none;
|
18
|
-
overflow-y : hidden;
|
19
|
-
position : absolute;
|
20
|
-
width : 100%;
|
21
|
-
|
22
|
-
.neo-grid-row {
|
23
|
-
display: flex;
|
24
|
-
width : 100%;
|
25
|
-
}
|
26
|
-
|
27
|
-
.neo-grid-header-toolbar .neo-grid-row:nth-child(1) .neo-grid-header-cell {
|
28
|
-
z-index : 10;
|
29
|
-
}
|
30
|
-
|
31
|
-
.neo-grid-body {
|
32
|
-
display : block;
|
33
|
-
max-height: 300px; // an initial dummy value to reduce the flickering until the real height is available
|
34
|
-
overflow-y: scroll;
|
35
|
-
}
|
36
|
-
|
37
|
-
.neo-grid-row:last-child {
|
38
|
-
.neo-grid-cell {
|
39
|
-
border-bottom-width: 0 !important;
|
40
|
-
}
|
41
|
-
}
|
42
|
-
|
43
|
-
.neo-grid-row.neo-even {
|
44
|
-
.neo-grid-cell {
|
45
|
-
background-color: var(--grid-container-cell-background-color-even);
|
46
|
-
}
|
47
|
-
}
|
48
|
-
|
49
|
-
.neo-grid-header-cell {
|
50
|
-
position: sticky;
|
51
|
-
top : 0;
|
52
|
-
z-index : 5;
|
53
|
-
}
|
54
|
-
|
55
|
-
.neo-grid-cell, .neo-grid-header-cell {
|
56
|
-
border-bottom: 1px solid var(--grid-container-border-color);
|
57
|
-
border-right : 1px solid var(--grid-container-border-color);
|
58
|
-
height : inherit;
|
59
|
-
min-width : 300px;
|
60
|
-
|
61
|
-
&:last-child {
|
62
|
-
border-right-width : 0;
|
63
|
-
}
|
64
|
-
|
65
|
-
&.neo-locked {
|
66
|
-
left: 0;
|
67
|
-
}
|
68
|
-
}
|
69
7
|
|
70
|
-
.neo-grid-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
8
|
+
.neo-grid-container {
|
9
|
+
border : 1px solid var(--grid-container-border-color);
|
10
|
+
border-spacing : 0;
|
11
|
+
color : var(--grid-container-color);
|
12
|
+
font-size : 13px;
|
13
|
+
font-weight : 400;
|
14
|
+
height : 100%;
|
15
|
+
line-height : 19px;
|
16
|
+
overscroll-behavior: none;
|
17
|
+
overflow-y : hidden;
|
18
|
+
position : absolute;
|
19
|
+
width : 100%;
|
76
20
|
}
|
77
21
|
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
.neo-grid-scrollbar {
|
2
|
+
bottom : 1px;
|
3
|
+
opacity : 0;
|
4
|
+
overflow-y : scroll;
|
5
|
+
position : absolute;
|
6
|
+
right : 0;
|
7
|
+
top : 31px; // header-toolbar height
|
8
|
+
transition : opacity 1s ease-out;
|
9
|
+
width : 16px;
|
10
|
+
z-index : 2;
|
11
|
+
|
12
|
+
&:hover {
|
13
|
+
opacity: 1;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
.neo-grid-wrapper:has(.neo-grid-view.neo-is-scrolling) {
|
18
|
+
.neo-grid-scrollbar {
|
19
|
+
opacity: 1;
|
20
|
+
}
|
21
|
+
}
|
@@ -4,17 +4,19 @@
|
|
4
4
|
overflow-x : hidden;
|
5
5
|
overflow-y : auto;
|
6
6
|
position : relative;
|
7
|
+
scrollbar-width: none;
|
7
8
|
|
8
9
|
&:focus {
|
9
10
|
outline: none;
|
10
11
|
}
|
11
12
|
|
12
|
-
.neo-grid-
|
13
|
+
.neo-grid-stretcher {
|
13
14
|
height : 1px;
|
14
15
|
position : absolute;
|
15
16
|
top : 0;
|
16
17
|
visibility : hidden;
|
17
18
|
width : 1px;
|
19
|
+
z-index : 1001; // Above the column dragProxy element
|
18
20
|
}
|
19
21
|
}
|
20
22
|
|
@@ -52,6 +54,13 @@
|
|
52
54
|
|
53
55
|
.neo-grid-row {
|
54
56
|
position: absolute;
|
57
|
+
width : 100%;
|
58
|
+
|
59
|
+
&:last-child {
|
60
|
+
.neo-grid-cell {
|
61
|
+
border-bottom-width: 0 !important;
|
62
|
+
}
|
63
|
+
}
|
55
64
|
|
56
65
|
&:hover {
|
57
66
|
.neo-grid-cell {
|
@@ -59,6 +68,12 @@
|
|
59
68
|
}
|
60
69
|
}
|
61
70
|
|
71
|
+
&.neo-even {
|
72
|
+
.neo-grid-cell {
|
73
|
+
background-color: var(--grid-container-cell-background-color-even);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
62
77
|
// selection.RowModel
|
63
78
|
&.neo-selected {
|
64
79
|
.neo-grid-cell {
|
@@ -68,7 +83,19 @@
|
|
68
83
|
}
|
69
84
|
|
70
85
|
.neo-grid-cell {
|
71
|
-
|
86
|
+
align-items : center;
|
87
|
+
background-color: var(--grid-container-cell-background-color);
|
88
|
+
border-bottom : 1px solid var(--grid-container-border-color);
|
89
|
+
border-right : 1px solid var(--grid-container-border-color);
|
90
|
+
display : flex;
|
91
|
+
height : inherit;
|
92
|
+
padding : 2px 10px 2px;
|
93
|
+
position : absolute;
|
94
|
+
width : fit-content;
|
95
|
+
|
96
|
+
&:last-child {
|
97
|
+
border-right-width : 0;
|
98
|
+
}
|
72
99
|
|
73
100
|
// selection.CellModel
|
74
101
|
&.neo-selected {
|
package/src/DefaultConfig.mjs
CHANGED
@@ -262,12 +262,12 @@ const DefaultConfig = {
|
|
262
262
|
useVdomWorker: true,
|
263
263
|
/**
|
264
264
|
* buildScripts/injectPackageVersion.mjs will update this value
|
265
|
-
* @default '8.
|
265
|
+
* @default '8.17.0'
|
266
266
|
* @memberOf! module:Neo
|
267
267
|
* @name config.version
|
268
268
|
* @type String
|
269
269
|
*/
|
270
|
-
version: '8.
|
270
|
+
version: '8.17.0'
|
271
271
|
};
|
272
272
|
|
273
273
|
Object.assign(DefaultConfig, {
|
package/src/grid/Container.mjs
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import BaseContainer from '../container/Base.mjs';
|
2
2
|
import ClassSystemUtil from '../util/ClassSystem.mjs';
|
3
|
+
import GridScrollbar from './Scrollbar.mjs';
|
3
4
|
import GridView from './View.mjs';
|
4
5
|
import Store from '../data/Store.mjs';
|
5
6
|
import * as header from './header/_export.mjs';
|
@@ -70,6 +71,11 @@ class GridContainer extends BaseContainer {
|
|
70
71
|
* @member {Number} rowHeight_=32
|
71
72
|
*/
|
72
73
|
rowHeight_: 32,
|
74
|
+
/**
|
75
|
+
* @member {Neo.grid.Scrollbar|null} scrollbar=null
|
76
|
+
* @protected
|
77
|
+
*/
|
78
|
+
scrollbar: null,
|
73
79
|
/**
|
74
80
|
* @member {Boolean} showHeaderFilters_=false
|
75
81
|
*/
|
@@ -98,7 +104,7 @@ class GridContainer extends BaseContainer {
|
|
98
104
|
*/
|
99
105
|
items: null,
|
100
106
|
/**
|
101
|
-
* @member {Object} _vdom
|
107
|
+
* @member {Object} _vdom
|
102
108
|
*/
|
103
109
|
_vdom:
|
104
110
|
{cls: ['neo-grid-wrapper'], cn: [
|
@@ -134,8 +140,8 @@ class GridContainer extends BaseContainer {
|
|
134
140
|
construct(config) {
|
135
141
|
super.construct(config);
|
136
142
|
|
137
|
-
let me
|
138
|
-
{rowHeight, store} = me;
|
143
|
+
let me = this,
|
144
|
+
{appName, rowHeight, store, windowId} = me;
|
139
145
|
|
140
146
|
me.headerToolbarId = Neo.getId('grid-header-toolbar');
|
141
147
|
me.viewId = Neo.getId('grid-view');
|
@@ -147,13 +153,26 @@ class GridContainer extends BaseContainer {
|
|
147
153
|
sortable : me.sortable,
|
148
154
|
...me.headerToolbarConfig
|
149
155
|
}, {
|
150
|
-
module: GridView,
|
151
|
-
|
156
|
+
module : GridView,
|
157
|
+
flex : 1,
|
158
|
+
gridContainer: me,
|
159
|
+
id : me.viewId,
|
152
160
|
rowHeight,
|
153
161
|
store,
|
154
162
|
...me.viewConfig
|
155
163
|
}];
|
156
164
|
|
165
|
+
me.scrollbar = Neo.create({
|
166
|
+
module : GridScrollbar,
|
167
|
+
appName,
|
168
|
+
parentId: me.id,
|
169
|
+
rowHeight,
|
170
|
+
store,
|
171
|
+
windowId
|
172
|
+
});
|
173
|
+
|
174
|
+
me.vdom.cn.push(me.scrollbar.createVdomReference())
|
175
|
+
|
157
176
|
me.vdom.id = me.getWrapperId();
|
158
177
|
|
159
178
|
me.createColumns(me.columns);
|
@@ -219,15 +238,10 @@ class GridContainer extends BaseContainer {
|
|
219
238
|
*/
|
220
239
|
async addResizeObserver(mounted) {
|
221
240
|
let me = this,
|
222
|
-
ResizeObserver = Neo.main?.addon?.ResizeObserver,
|
223
241
|
{windowId} = me,
|
242
|
+
ResizeObserver = await Neo.currentWorker.getAddon('ResizeObserver', windowId),
|
224
243
|
resizeParams = {id: me.id, windowId};
|
225
244
|
|
226
|
-
if (!ResizeObserver) {
|
227
|
-
await Neo.Main.importAddon({name: 'ResizeObserver', windowId});
|
228
|
-
ResizeObserver = Neo.main.addon.ResizeObserver
|
229
|
-
}
|
230
|
-
|
231
245
|
if (mounted) {
|
232
246
|
ResizeObserver.register(resizeParams);
|
233
247
|
await me.passSizeToView()
|
@@ -505,12 +519,17 @@ class GridContainer extends BaseContainer {
|
|
505
519
|
|
506
520
|
/**
|
507
521
|
* @param {Object} data
|
522
|
+
* @param {Number} data.scrollLeft
|
523
|
+
* @param {Object} data.target
|
508
524
|
*/
|
509
|
-
onScroll({scrollLeft}) {
|
525
|
+
onScroll({scrollLeft, target}) {
|
510
526
|
let me = this;
|
511
527
|
|
512
|
-
|
513
|
-
|
528
|
+
// We must ignore events for grid-scrollbar
|
529
|
+
if (target.id.includes('grid-container')) {
|
530
|
+
me.headerToolbar.scrollLeft = scrollLeft;
|
531
|
+
me.view.scrollPosition = {x: scrollLeft, y: me.view.scrollPosition.y}
|
532
|
+
}
|
514
533
|
}
|
515
534
|
|
516
535
|
/**
|
@@ -0,0 +1,118 @@
|
|
1
|
+
import Component from '../component/Base.mjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @class Neo.grid.Scrollbar
|
5
|
+
* @extends Neo.component.Base
|
6
|
+
*/
|
7
|
+
class GridScrollbar extends Component {
|
8
|
+
static config = {
|
9
|
+
/**
|
10
|
+
* @member {String} className='Neo.grid.Scrollbar'
|
11
|
+
* @protected
|
12
|
+
*/
|
13
|
+
className: 'Neo.grid.Scrollbar',
|
14
|
+
/**
|
15
|
+
* @member {String} ntype='grid-scrollbar'
|
16
|
+
* @protected
|
17
|
+
*/
|
18
|
+
ntype: 'grid-scrollbar',
|
19
|
+
/**
|
20
|
+
* @member {String[]} baseCls=['neo-grid-scrollbar']
|
21
|
+
* @protected
|
22
|
+
*/
|
23
|
+
baseCls: ['neo-grid-scrollbar'],
|
24
|
+
/**
|
25
|
+
* Number in px
|
26
|
+
* @member {Number} rowHeight_=0
|
27
|
+
*/
|
28
|
+
rowHeight_: 0,
|
29
|
+
/**
|
30
|
+
* @member {Neo.data.Store|null} store_=null
|
31
|
+
*/
|
32
|
+
store_: null,
|
33
|
+
/**
|
34
|
+
* @member {Object} _vdom
|
35
|
+
*/
|
36
|
+
_vdom:
|
37
|
+
{cn: [
|
38
|
+
{cls: ['neo-grid-scrollbar-content']}
|
39
|
+
]}
|
40
|
+
}
|
41
|
+
|
42
|
+
/**
|
43
|
+
* @param {Boolean} mounted
|
44
|
+
* @protected
|
45
|
+
*/
|
46
|
+
async addScrollSync(mounted) {
|
47
|
+
let me = this,
|
48
|
+
{windowId} = me,
|
49
|
+
ScrollSync = await Neo.currentWorker.getAddon('ScrollSync', windowId),
|
50
|
+
params = {id: me.id, windowId};
|
51
|
+
|
52
|
+
if (mounted) {
|
53
|
+
ScrollSync.register({
|
54
|
+
fromId: me.parent.view.vdom.id,
|
55
|
+
toId : me.id,
|
56
|
+
...params
|
57
|
+
})
|
58
|
+
} else {
|
59
|
+
ScrollSync.unregister(params)
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
/**
|
64
|
+
* Triggered after the mounted config got changed
|
65
|
+
* @param {Boolean} value
|
66
|
+
* @param {Boolean} oldValue
|
67
|
+
* @protected
|
68
|
+
*/
|
69
|
+
afterSetMounted(value, oldValue) {
|
70
|
+
super.afterSetMounted(value, oldValue);
|
71
|
+
oldValue !== undefined && this.addScrollSync(value)
|
72
|
+
}
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Triggered after the rowHeight config got changed
|
76
|
+
* @param {Number} value
|
77
|
+
* @param {Number} oldValue
|
78
|
+
* @protected
|
79
|
+
*/
|
80
|
+
afterSetRowHeight(value, oldValue) {
|
81
|
+
value > 0 && this.updateScrollHeight()
|
82
|
+
}
|
83
|
+
|
84
|
+
/**
|
85
|
+
* Triggered after the store config got changed
|
86
|
+
* @param {Neo.data.Store|null} value
|
87
|
+
* @param {Neo.data.Store|null} oldValue
|
88
|
+
* @protected
|
89
|
+
*/
|
90
|
+
afterSetStore(value, oldValue) {
|
91
|
+
if (value) {
|
92
|
+
let me = this;
|
93
|
+
|
94
|
+
value.on({
|
95
|
+
load : me.updateScrollHeight,
|
96
|
+
scope: me
|
97
|
+
});
|
98
|
+
|
99
|
+
value.getCount() > 0 && me.updateScrollHeight()
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
*
|
105
|
+
*/
|
106
|
+
updateScrollHeight() {
|
107
|
+
let me = this,
|
108
|
+
countRecords = me.store.getCount(),
|
109
|
+
{rowHeight} = me;
|
110
|
+
|
111
|
+
if (countRecords > 0 && rowHeight > 0) {
|
112
|
+
me.vdom.cn[0].height = `${(countRecords + 1) * rowHeight}px`;
|
113
|
+
me.update()
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
export default Neo.setupClass(GridScrollbar);
|
package/src/grid/View.mjs
CHANGED
@@ -0,0 +1,90 @@
|
|
1
|
+
import Base from './Base.mjs';
|
2
|
+
import DomAccess from '../DomAccess.mjs';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Syncs the scroll state of 2 DOM nodes
|
6
|
+
* @class Neo.main.addon.ScrollSync
|
7
|
+
* @extends Neo.main.addon.Base
|
8
|
+
*/
|
9
|
+
class ScrollSync extends Base {
|
10
|
+
static config = {
|
11
|
+
/**
|
12
|
+
* @member {String} className='Neo.main.addon.ScrollSync'
|
13
|
+
* @protected
|
14
|
+
*/
|
15
|
+
className: 'Neo.main.addon.ScrollSync',
|
16
|
+
/**
|
17
|
+
* Remote method access for other workers
|
18
|
+
* @member {Object} remote
|
19
|
+
* @protected
|
20
|
+
*/
|
21
|
+
remote: {
|
22
|
+
app: [
|
23
|
+
'register',
|
24
|
+
'unregister'
|
25
|
+
]
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* @param {String} fromId
|
31
|
+
* @param {String} toId
|
32
|
+
* @param {String} direction
|
33
|
+
*/
|
34
|
+
addScrollListener(fromId, toId, direction) {
|
35
|
+
DomAccess.getElement(fromId)?.addEventListener('scroll', this.onScroll.bind(this, toId, direction))
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* @param {String} toId
|
40
|
+
* @param {String} direction
|
41
|
+
* @param {Event} event
|
42
|
+
*/
|
43
|
+
onScroll(toId, direction, event) {
|
44
|
+
let node = DomAccess.getElement(toId),
|
45
|
+
{scrollLeft, scrollTop} = event.target;
|
46
|
+
|
47
|
+
if (node) {
|
48
|
+
if (direction === 'both') {
|
49
|
+
node.scrollTo({
|
50
|
+
behavior: 'instant',
|
51
|
+
left : scrollLeft,
|
52
|
+
top : scrollTop
|
53
|
+
})
|
54
|
+
} else if (direction === 'horizontal') {
|
55
|
+
node.scrollLeft = scrollLeft
|
56
|
+
} else if (direction === 'vertical') {
|
57
|
+
node.scrollTop = scrollTop
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* @param {Object} data
|
64
|
+
* @param {String} direction='vertical' 'horizontal', 'vertical' or 'both'
|
65
|
+
* @param {String} fromId
|
66
|
+
* @param {String} id The owner id (e.g. component id)
|
67
|
+
* @param {String} toId
|
68
|
+
* @param {Boolean} twoWay=true Sync the target's scroll state back to the source node
|
69
|
+
*/
|
70
|
+
register({direction='vertical', fromId, id, toId, twoWay=true}) {
|
71
|
+
console.log('register', direction, fromId, id, toId, twoWay);
|
72
|
+
|
73
|
+
let me = this;
|
74
|
+
|
75
|
+
me.addScrollListener(fromId, toId, direction);
|
76
|
+
|
77
|
+
if (twoWay) {
|
78
|
+
me.addScrollListener(toId, fromId, direction)
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* @param {Object} data
|
84
|
+
*/
|
85
|
+
unregister(data) {
|
86
|
+
console.log('unregister', data)
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
export default Neo.setupClass(ScrollSync);
|
package/src/worker/App.mjs
CHANGED
@@ -242,6 +242,23 @@ class App extends Base {
|
|
242
242
|
})
|
243
243
|
}
|
244
244
|
|
245
|
+
/**
|
246
|
+
* Convenience shortcut to lazy-load main thread addons, in case they are not imported yet
|
247
|
+
* @param {String} name
|
248
|
+
* @param {Number} windowId
|
249
|
+
* @returns {Promise<Neo.main.addon.Base>} The namespace of the addon to use via remote method access
|
250
|
+
*/
|
251
|
+
async getAddon(name, windowId) {
|
252
|
+
let addon = Neo.main?.addon?.[name];
|
253
|
+
|
254
|
+
if (!addon) {
|
255
|
+
await Neo.Main.importAddon({name, windowId});
|
256
|
+
addon = Neo.main.addon[name]
|
257
|
+
}
|
258
|
+
|
259
|
+
return addon
|
260
|
+
}
|
261
|
+
|
245
262
|
/**
|
246
263
|
* Get configs of any app realm based Neo instance from main
|
247
264
|
* @param {Object} data
|