neo.mjs 8.10.1 → 8.12.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.
Files changed (47) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/apps/portal/index.html +1 -1
  3. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  4. package/examples/ConfigurationViewport.mjs +1 -7
  5. package/examples/ServiceWorker.mjs +2 -2
  6. package/examples/table/container/MainContainer.mjs +1 -2
  7. package/examples/tableFiltering/MainContainer.mjs +1 -1
  8. package/examples/tableFiltering/MainStore.mjs +10 -10
  9. package/package.json +2 -2
  10. package/resources/scss/src/draggable/DragProxyComponent.scss +9 -0
  11. package/resources/scss/src/draggable/grid/header/toolbar/SortZone.scss +16 -0
  12. package/resources/scss/src/draggable/table/header/toolbar/SortZone.scss +32 -0
  13. package/resources/scss/src/grid/View.scss +0 -18
  14. package/resources/scss/src/grid/header/Toolbar.scss +0 -1
  15. package/resources/scss/src/table/View.scss +4 -18
  16. package/resources/scss/src/table/header/Button.scss +0 -4
  17. package/resources/scss/theme-dark/draggable/grid/header/toolbar/SortZone.scss +3 -0
  18. package/resources/scss/theme-dark/draggable/table/header/toolbar/SortZone.scss +3 -0
  19. package/resources/scss/theme-light/draggable/grid/header/toolbar/SortZone.scss +3 -0
  20. package/resources/scss/theme-light/draggable/table/header/toolbar/SortZone.scss +3 -0
  21. package/resources/scss/theme-neo-light/draggable/grid/header/toolbar/SortZone.scss +3 -0
  22. package/resources/scss/theme-neo-light/draggable/table/header/toolbar/SortZone.scss +3 -0
  23. package/src/DefaultConfig.mjs +2 -2
  24. package/src/Main.mjs +9 -3
  25. package/src/component/Base.mjs +2 -6
  26. package/src/draggable/grid/header/toolbar/SortZone.mjs +74 -0
  27. package/src/draggable/table/header/toolbar/SortZone.mjs +70 -0
  28. package/src/draggable/toolbar/SortZone.mjs +23 -14
  29. package/src/form/field/ComboBox.mjs +1 -5
  30. package/src/grid/header/Button.mjs +0 -109
  31. package/src/grid/header/Toolbar.mjs +32 -0
  32. package/src/main/DomAccess.mjs +14 -17
  33. package/src/main/DomEvents.mjs +10 -50
  34. package/src/main/addon/DragDrop.mjs +9 -20
  35. package/src/selection/grid/BaseModel.mjs +1 -1
  36. package/src/selection/table/BaseModel.mjs +8 -0
  37. package/src/selection/table/CellColumnModel.mjs +28 -26
  38. package/src/selection/table/CellColumnRowModel.mjs +25 -23
  39. package/src/selection/table/CellModel.mjs +49 -42
  40. package/src/selection/table/CellRowModel.mjs +18 -20
  41. package/src/selection/table/ColumnModel.mjs +26 -60
  42. package/src/selection/table/RowModel.mjs +16 -48
  43. package/src/table/Container.mjs +6 -6
  44. package/src/table/View.mjs +26 -20
  45. package/src/table/header/Button.mjs +55 -156
  46. package/src/table/header/Toolbar.mjs +34 -2
  47. package/src/util/Rectangle.mjs +1 -1
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='8.10.1'
23
+ * @member {String} version='8.12.0'
24
24
  */
25
- version: '8.10.1'
25
+ version: '8.12.0'
26
26
  }
27
27
 
28
28
  /**
@@ -16,7 +16,7 @@
16
16
  "@type": "Organization",
17
17
  "name": "Neo.mjs"
18
18
  },
19
- "datePublished": "2025-01-27",
19
+ "datePublished": "2025-01-29",
20
20
  "publisher": {
21
21
  "@type": "Organization",
22
22
  "name": "Neo.mjs"
@@ -107,7 +107,7 @@ class FooterContainer extends Container {
107
107
  }, {
108
108
  module: Component,
109
109
  cls : ['neo-version'],
110
- html : 'v8.10.1'
110
+ html : 'v8.12.0'
111
111
  }]
112
112
  }],
113
113
  /**
@@ -208,13 +208,7 @@ class ConfigurationViewport extends Viewport {
208
208
  if (target === 'cmp') {
209
209
  me.exampleComponent.theme = newTheme
210
210
  } else {
211
- Neo.applyDeltas(me.appName, {
212
- id : me.id, // the viewport can get imported into other apps, so an id makes sense for scoping
213
- cls: {
214
- add : [newTheme],
215
- remove: [oldTheme]
216
- }
217
- })
211
+ me.app.mainView.theme = newTheme
218
212
  }
219
213
  }
220
214
  }
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='8.10.1'
23
+ * @member {String} version='8.12.0'
24
24
  */
25
- version: '8.10.1'
25
+ version: '8.12.0'
26
26
  }
27
27
 
28
28
  /**
@@ -100,8 +100,7 @@ class MainContainer extends ConfigurationViewport {
100
100
  style.tableLayout = '';
101
101
  }
102
102
 
103
- me.exampleComponent.style = style;
104
- me.exampleComponent.update()
103
+ me.exampleComponent.style = style
105
104
  }
106
105
  },
107
106
  style: {marginTop: '10px'}
@@ -68,7 +68,7 @@ class MainContainer extends Viewport {
68
68
 
69
69
  store: {
70
70
  autoLoad : true,
71
- keyProperty: 'name',
71
+ keyProperty: 'code',
72
72
  url : '../../resources/examples/data/countries.json',
73
73
 
74
74
  model: {
@@ -12,16 +12,16 @@ class MainStore extends Store {
12
12
  model : Model,
13
13
 
14
14
  data: [
15
- {id: 1, country: 'Germany', firstname: 'Tobias', isOnline: true, lastname: 'Uhlig', luckyNumber: 1, specialDate: '2020-08-10'},
16
- {id: 2, country: 'United States', firstname: 'Rich', isOnline: false, lastname: 'Waters', luckyNumber: 2, specialDate: '2020-08-09'},
17
- {id: 3, country: 'Germany', firstname: 'Nils', isOnline: true, lastname: 'Dehl', luckyNumber: 3, specialDate: '2020-08-09'},
18
- {id: 4, country: 'United States', firstname: 'Gerard', isOnline: true, lastname: 'Horan', luckyNumber: 1, specialDate: '2020-08-10'},
19
- {id: 5, country: 'Slovakia', firstname: 'Jozef', isOnline: false, lastname: 'Sakalos', luckyNumber: 2, specialDate: '2020-08-08'},
20
- {id: 6, country: 'Germany', firstname: 'Bastian', isOnline: false, lastname: 'Haustein', luckyNumber: 3, specialDate: '2020-08-10'},
21
- {id: 7, country: 'United States', firstname: 'Durlabh', isOnline: true, lastname: 'Jain', luckyNumber: 1, specialDate: '2020-08-08'},
22
- {id: 8, country: 'Canada', firstname: 'Kevin', isOnline: true, lastname: 'Cassidy', luckyNumber: 2, specialDate: '2020-08-10'},
23
- {id: 9, country: 'UK', firstname: 'Nikola', isOnline: true, lastname: 'Markovic', luckyNumber: 3, specialDate: '2020-08-09'},
24
- {id: 10, country: 'United States', firstname: 'Hyle', isOnline: false, lastname: 'Campbell', luckyNumber: 1, specialDate: '2020-08-10'}
15
+ {id: 1, country: 'Germany', firstname: 'Tobias', isOnline: true, lastname: 'Uhlig', luckyNumber: 1, specialDate: '2025-08-10'},
16
+ {id: 2, country: 'United States', firstname: 'Rich', isOnline: false, lastname: 'Waters', luckyNumber: 2, specialDate: '2025-08-09'},
17
+ {id: 3, country: 'Germany', firstname: 'Nils', isOnline: true, lastname: 'Dehl', luckyNumber: 3, specialDate: '2025-08-09'},
18
+ {id: 4, country: 'United States', firstname: 'Gerard', isOnline: true, lastname: 'Horan', luckyNumber: 1, specialDate: '2025-08-10'},
19
+ {id: 5, country: 'Slovakia', firstname: 'Jozef', isOnline: false, lastname: 'Sakalos', luckyNumber: 2, specialDate: '2025-08-08'},
20
+ {id: 6, country: 'Germany', firstname: 'Bastian', isOnline: false, lastname: 'Haustein', luckyNumber: 3, specialDate: '2025-08-10'},
21
+ {id: 7, country: 'United States', firstname: 'Durlabh', isOnline: true, lastname: 'Jain', luckyNumber: 1, specialDate: '2025-08-08'},
22
+ {id: 8, country: 'Canada', firstname: 'Kevin', isOnline: true, lastname: 'Cassidy', luckyNumber: 2, specialDate: '2025-08-10'},
23
+ {id: 9, country: 'UK', firstname: 'Nikola', isOnline: true, lastname: 'Markovic', luckyNumber: 3, specialDate: '2025-08-09'},
24
+ {id: 10, country: 'United States', firstname: 'Hyle', isOnline: false, lastname: 'Campbell', luckyNumber: 1, specialDate: '2025-08-10'}
25
25
  ]
26
26
  }
27
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "8.10.1",
3
+ "version": "8.12.0",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -54,7 +54,7 @@
54
54
  "envinfo": "^7.14.0",
55
55
  "fs-extra": "^11.3.0",
56
56
  "highlightjs-line-numbers.js": "^2.9.0",
57
- "inquirer": "^12.3.2",
57
+ "inquirer": "^12.3.3",
58
58
  "marked": "^15.0.6",
59
59
  "monaco-editor": "0.50.0",
60
60
  "neo-jsdoc": "1.0.1",
@@ -1,3 +1,12 @@
1
+ body:has(.neo-is-dragging) {
2
+ cursor: move !important;
3
+
4
+ // We can not put pointer-events: none on the same level as cursor, since it prevents cursor changes
5
+ * {
6
+ pointer-events: none !important;
7
+ }
8
+ }
9
+
1
10
  .neo-dragproxy {
2
11
  pointer-events : none;
3
12
  position : absolute !important;
@@ -0,0 +1,16 @@
1
+ .neo-grid-header-toolbar {
2
+ &.neo-dragproxy {
3
+ height: 30px !important; // Hack to increase the height by the border-bottom height (29 + 1)
4
+
5
+ .neo-button {
6
+ border-right: 1px solid var(--grid-container-border-color);
7
+ }
8
+ }
9
+
10
+ &.neo-is-dragging {
11
+ .neo-button {
12
+ border-right: 1px solid var(--grid-container-border-color); // Would be missing for the last button otherwise
13
+ opacity : var(--grid-header-button-opacity-is-dragging);
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,32 @@
1
+ .neo-table-container:has(.neo-is-dragging) {
2
+ border-top-width: 1px;
3
+ }
4
+
5
+ .neo-table-header-toolbar {
6
+ &.neo-dragproxy {
7
+ border-bottom: 1px solid var(--table-container-border-color);
8
+ height : 31px !important; // Hack to increase the height by the border-bottom height (29 + 1)
9
+ padding: 0 0 1px 0;
10
+
11
+ .neo-table-header-button {
12
+ border-right: 1px solid var(--table-container-border-color);
13
+ }
14
+ }
15
+
16
+ &.neo-is-dragging {
17
+ height: 32px !important;
18
+
19
+ .neo-table-header-button {
20
+ border-right: 1px solid var(--table-container-border-color); // Would be missing for the last button otherwise
21
+ opacity : var(--table-header-button-opacity-is-dragging);
22
+ }
23
+
24
+ .neo-draggable {
25
+ background-color : unset;
26
+ height : 32px !important;
27
+ transition-duration : 200ms;
28
+ transition-property : left, top;
29
+ transition-timing-function: ease-out;
30
+ }
31
+ }
32
+ }
@@ -102,21 +102,3 @@
102
102
  }
103
103
  }
104
104
  }
105
-
106
- .neo-selection-cellcolumnmodel,
107
- .neo-selection-cellcolumnrowmodel,
108
- .neo-selection-cellmodel,
109
- .neo-selection-cellrowmodel,
110
- .neo-selection-columnmodel,
111
- .neo-selection-rowmodel {
112
- .neo-grid-row {
113
- &:focus {
114
- outline: 0;
115
- }
116
- .neo-grid-cell {
117
- &:focus {
118
- outline: 0;
119
- }
120
- }
121
- }
122
- }
@@ -1,6 +1,5 @@
1
1
  .neo-grid-header-toolbar {
2
2
  border-bottom: 1px solid var(--grid-container-border-color);
3
- border-top : 1px solid var(--grid-container-border-color);
4
3
  padding : 0;
5
4
  width : max-content;
6
5
  }
@@ -1,4 +1,8 @@
1
1
  .neo-table-view {
2
+ &:focus {
3
+ outline: none;
4
+ }
5
+
2
6
  .neo-center {
3
7
  text-align: center;
4
8
  }
@@ -71,21 +75,3 @@
71
75
  }
72
76
  }
73
77
  }
74
-
75
- .neo-selection-cellcolumnmodel,
76
- .neo-selection-cellcolumnrowmodel,
77
- .neo-selection-cellmodel,
78
- .neo-selection-cellrowmodel,
79
- .neo-selection-columnmodel,
80
- .neo-selection-rowmodel {
81
- .neo-table-row {
82
- &:focus {
83
- outline: 0;
84
- }
85
- .neo-table-cell {
86
- &:focus {
87
- outline: 0;
88
- }
89
- }
90
- }
91
- }
@@ -16,10 +16,6 @@
16
16
  white-space : nowrap;
17
17
  width : 100% !important;
18
18
 
19
- &.neo-drag-over {
20
- background-image: linear-gradient(green, darkgreen);;
21
- }
22
-
23
19
  &.neo-sort-asc, &.neo-sort-desc {
24
20
  .neo-button-glyph {
25
21
  opacity: 1;
@@ -0,0 +1,3 @@
1
+ :root .neo-theme-dark { // .neo-grid-header-toolbar.neo-is-dragging
2
+ --grid-header-button-opacity-is-dragging: 0.3;
3
+ }
@@ -0,0 +1,3 @@
1
+ :root .neo-theme-dark { // .neo-table-header-toolbar.neo-is-dragging
2
+ --table-header-button-opacity-is-dragging: 0.3;
3
+ }
@@ -0,0 +1,3 @@
1
+ :root .neo-theme-light { // .neo-grid-header-toolbar.neo-is-dragging
2
+ --grid-header-button-opacity-is-dragging: 0.7;
3
+ }
@@ -0,0 +1,3 @@
1
+ :root .neo-theme-light { // .neo-table-header-toolbar.neo-is-dragging
2
+ --table-header-button-opacity-is-dragging: 0.7;
3
+ }
@@ -0,0 +1,3 @@
1
+ :root .neo-theme-neo-light { // .neo-grid-header-toolbar.neo-is-dragging
2
+ --grid-header-button-opacity-is-dragging: 0.7;
3
+ }
@@ -0,0 +1,3 @@
1
+ :root .neo-theme-neo-light { // .neo-table-header-toolbar.neo-is-dragging
2
+ --table-header-button-opacity-is-dragging: 0.7;
3
+ }
@@ -262,12 +262,12 @@ const DefaultConfig = {
262
262
  useVdomWorker: true,
263
263
  /**
264
264
  * buildScripts/injectPackageVersion.mjs will update this value
265
- * @default '8.10.1'
265
+ * @default '8.12.0'
266
266
  * @memberOf! module:Neo
267
267
  * @name config.version
268
268
  * @type String
269
269
  */
270
- version: '8.10.1'
270
+ version: '8.12.0'
271
271
  };
272
272
 
273
273
  Object.assign(DefaultConfig, {
package/src/Main.mjs CHANGED
@@ -158,13 +158,19 @@ class Main extends core.Base {
158
158
  /**
159
159
  * Request specific accessible window attributes by path into the app worker.
160
160
  * Keep in mind that this excludes anything DOM related or instances.
161
- * Example: Neo.Main.getByPath({path: 'navigator.language'}).then(data => {})
161
+ * In case your path matches a method, you can also pass params for it.
162
+ * @example:
163
+ * Neo.Main.getByPath({path: 'navigator.language'}).then(data => {})
164
+ * @example:
165
+ * Neo.Main.getByPath({path: 'CSS.supports', params: ['display: flex']}).then(data => {})
162
166
  * @param {Object} data
167
+ * @param {Array} data.params=[]
163
168
  * @param {String} data.path
164
169
  * @returns {*}
165
170
  */
166
- getByPath(data) {
167
- return Neo.nsWithArrays(data.path)
171
+ getByPath({params=[], path}) {
172
+ let target = Neo.nsWithArrays(path);
173
+ return Neo.isFunction(target) ? target(...params) : target
168
174
  }
169
175
 
170
176
  /**
@@ -331,7 +331,7 @@ class Component extends Base {
331
331
  */
332
332
  style_: null,
333
333
  /**
334
- * You can pass an used theme directly to any component,
334
+ * You can pass a used theme directly to any component,
335
335
  * to style specific component trees differently from your main view.
336
336
  * @member {String|null} theme_=null
337
337
  */
@@ -1119,11 +1119,7 @@ class Component extends Base {
1119
1119
  }
1120
1120
  }
1121
1121
 
1122
- if (me.isVdomUpdating || me.silentVdomUpdate) {
1123
- me.needsVdomUpdate = true
1124
- } else if (me.mounted) {
1125
- me.updateCls(value, oldValue)
1126
- }
1122
+ me.update()
1127
1123
  }
1128
1124
 
1129
1125
  /**
@@ -0,0 +1,74 @@
1
+ import BaseSortZone from '../../../toolbar/SortZone.mjs';
2
+ import NeoArray from '../../../../util/Array.mjs';
3
+
4
+ /**
5
+ * @class Neo.draggable.grid.header.toolbar.SortZone
6
+ * @extends Neo.draggable.toolbar.SortZone
7
+ */
8
+ class SortZone extends BaseSortZone {
9
+ static config = {
10
+ /**
11
+ * @member {String} className='Neo.draggable.grid.header.toolbar.SortZone'
12
+ * @protected
13
+ */
14
+ className: 'Neo.draggable.grid.header.toolbar.SortZone',
15
+ /**
16
+ * @member {String} ntype='grid-header-toolbar-sortzone'
17
+ * @protected
18
+ */
19
+ ntype: 'grid-header-toolbar-sortzone',
20
+ /**
21
+ * @member {String|null} itemMargin=null
22
+ * @protected
23
+ */
24
+ itemMargin: '1px',
25
+ /**
26
+ * @member {Boolean} moveVertical=false
27
+ */
28
+ moveVertical: false
29
+ }
30
+
31
+ /**
32
+ * @param {Neo.util.Rectangle} rect
33
+ * @param {Neo.util.Rectangle} parentRect
34
+ */
35
+ adjustProxyRectToParent(rect, parentRect) {
36
+ rect.x = rect.x - parentRect.x - 1;
37
+ rect.y = rect.y - parentRect.y - 1
38
+ }
39
+
40
+ /**
41
+ * @param {Number} fromIndex
42
+ * @param {Number} toIndex
43
+ */
44
+ moveTo(fromIndex, toIndex) {
45
+ super.moveTo(fromIndex, toIndex);
46
+
47
+ // It is crucial to use _columns to not get a shallow copy
48
+ NeoArray.move(this.owner.parent._columns, fromIndex, toIndex);
49
+ }
50
+
51
+ /**
52
+ * @param {Object} data
53
+ */
54
+ async onDragEnd(data) {
55
+ await super.onDragEnd(data);
56
+
57
+ let {owner} = this;
58
+
59
+ owner.items.forEach((item, index) => {
60
+ item.vdom['aria-colindex'] = index + 1; // 1 based
61
+ });
62
+
63
+ owner.updateDepth = 2;
64
+ owner.update();
65
+
66
+ await owner.passSizeToView();
67
+
68
+ await this.timeout(20);
69
+
70
+ owner.parent.view.createViewData()
71
+ }
72
+ }
73
+
74
+ export default Neo.setupClass(SortZone);
@@ -0,0 +1,70 @@
1
+ import BaseSortZone from '../../../toolbar/SortZone.mjs';
2
+ import NeoArray from '../../../../util/Array.mjs';
3
+
4
+ /**
5
+ * @class Neo.draggable.table.header.toolbar.SortZone
6
+ * @extends Neo.draggable.toolbar.SortZone
7
+ */
8
+ class SortZone extends BaseSortZone {
9
+ static config = {
10
+ /**
11
+ * @member {String} className='Neo.draggable.table.header.toolbar.SortZone'
12
+ * @protected
13
+ */
14
+ className: 'Neo.draggable.table.header.toolbar.SortZone',
15
+ /**
16
+ * @member {String} ntype='table-header-toolbar-sortzone'
17
+ * @protected
18
+ */
19
+ ntype: 'table-header-toolbar-sortzone',
20
+ /**
21
+ * @member {String|null} itemMargin=null
22
+ * @protected
23
+ */
24
+ itemMargin: '-2px 1px 1px 1px',
25
+ /**
26
+ * @member {Boolean} moveVertical=false
27
+ */
28
+ moveVertical: false,
29
+ /**
30
+ * @member {Number} offsetY=0
31
+ */
32
+ offsetY: 5
33
+ }
34
+
35
+ /**
36
+ * @param {Neo.util.Rectangle} rect
37
+ * @param {Neo.util.Rectangle} parentRect
38
+ */
39
+ adjustProxyRectToParent(rect, parentRect) {
40
+ rect.x = rect.x - parentRect.x - 1;
41
+ rect.y = rect.y - parentRect.y
42
+ }
43
+
44
+ /**
45
+ * @param {Number} fromIndex
46
+ * @param {Number} toIndex
47
+ */
48
+ moveTo(fromIndex, toIndex) {
49
+ super.moveTo(fromIndex, toIndex);
50
+
51
+ // It is crucial to use _columns to not get a shallow copy
52
+ NeoArray.move(this.owner.parent._columns, fromIndex, toIndex);
53
+ }
54
+
55
+ /**
56
+ * @param {Object} data
57
+ */
58
+ async onDragEnd(data) {
59
+ await super.onDragEnd(data);
60
+
61
+ let {owner} = this;
62
+
63
+ owner.updateDepth = 2;
64
+ owner.update();
65
+
66
+ owner.parent.view.createViewData()
67
+ }
68
+ }
69
+
70
+ export default Neo.setupClass(SortZone);
@@ -31,6 +31,11 @@ class SortZone extends DragZone {
31
31
  * @protected
32
32
  */
33
33
  indexMap: null,
34
+ /**
35
+ * @member {String|null} itemMargin=null
36
+ * @protected
37
+ */
38
+ itemMargin: null,
34
39
  /**
35
40
  * @member {Array|null} itemRects=null
36
41
  * @protected
@@ -96,11 +101,12 @@ class SortZone extends DragZone {
96
101
  owner.style = ownerStyle;
97
102
 
98
103
  owner.items.forEach((item, index) => {
99
- itemStyle = item.style || {};
104
+ itemStyle = item.wrapperStyle || {};
100
105
 
101
106
  Object.assign(itemStyle, {
102
107
  height : itemStyles[index].height || null,
103
108
  left : null,
109
+ margin : null,
104
110
  position: null,
105
111
  top : null,
106
112
  width : itemStyles[index].width || null
@@ -110,7 +116,7 @@ class SortZone extends DragZone {
110
116
  itemStyle.visibility = null
111
117
  }
112
118
 
113
- item.style = itemStyle
119
+ item.wrapperStyle = itemStyle
114
120
  });
115
121
 
116
122
  if (me.startIndex !== me.currentIndex) {
@@ -202,8 +208,8 @@ class SortZone extends DragZone {
202
208
  indexMap[index] = index;
203
209
 
204
210
  itemStyles.push({
205
- height: item.style?.height,
206
- width : item.style?.width
211
+ height: item.height ? `${item.height}px` : item.style?.height,
212
+ width : item.width ? `${item.width}px` : item.style?.width
207
213
  })
208
214
  });
209
215
 
@@ -221,12 +227,15 @@ class SortZone extends DragZone {
221
227
  me.itemRects = itemRects;
222
228
 
223
229
  owner.items.forEach((item, index) => {
224
- itemStyle = item.style || {};
230
+ itemStyle = item.wrapperStyle || {};
225
231
  rect = itemRects[index];
226
232
 
227
- item.style = Object.assign(itemStyle, {
233
+ me.adjustProxyRectToParent?.(rect, me.ownerRect);
234
+
235
+ item.wrapperStyle = Object.assign(itemStyle, {
228
236
  height : `${rect.height}px`,
229
237
  left : `${rect.left}px`,
238
+ margin : me.itemMargin,
230
239
  position: 'absolute',
231
240
  top : `${rect.top}px`,
232
241
  width : `${rect.width}px`
@@ -235,9 +244,9 @@ class SortZone extends DragZone {
235
244
 
236
245
  // we need to add a short (1 frame) delay to ensure the item has switched to an absolute position
237
246
  me.timeout(5).then(() => {
238
- itemStyle = button.style || {};
247
+ itemStyle = button.wrapperStyle || {};
239
248
  itemStyle.visibility = 'hidden';
240
- button.style = itemStyle
249
+ button.wrapperStyle = itemStyle
241
250
  })
242
251
  })
243
252
  }
@@ -288,14 +297,14 @@ class SortZone extends DragZone {
288
297
  * @param {Object} rect
289
298
  */
290
299
  updateItem(index, rect) {
291
- let me = this,
292
- item = me.owner.items[me.indexMap[index]],
293
- {style} = item;
300
+ let me = this,
301
+ item = me.owner.items[me.indexMap[index]],
302
+ {wrapperStyle} = item;
294
303
 
295
- style.left = `${rect.left}px`;
296
- style.top = `${rect.top}px`;
304
+ wrapperStyle.left = `${rect.left}px`;
305
+ wrapperStyle.top = `${rect.top}px`;
297
306
 
298
- item.style = style
307
+ item.wrapperStyle = wrapperStyle
299
308
  }
300
309
  }
301
310
 
@@ -450,10 +450,7 @@ class ComboBox extends Picker {
450
450
  fireChangeEvent(value, oldValue) {
451
451
  let me = this,
452
452
  FormContainer = Neo.form?.Container,
453
- params;
454
-
455
- if (!(me.forceSelection && !value)) {
456
- params = {component: me, oldValue, value};
453
+ params = {component: me, oldValue, value};
457
454
 
458
455
  me.fire('change', params);
459
456
 
@@ -464,7 +461,6 @@ class ComboBox extends Picker {
464
461
  }
465
462
  })
466
463
  }
467
- }
468
464
  }
469
465
 
470
466
  /**