neo.mjs 6.15.11 → 6.16.1

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 (38) hide show
  1. package/apps/colors/app.mjs +6 -0
  2. package/apps/colors/childapps/widget/app.mjs +7 -0
  3. package/apps/colors/childapps/widget/index.html +11 -0
  4. package/apps/colors/childapps/widget/neo-config.json +10 -0
  5. package/apps/colors/childapps/widget/view/Viewport.mjs +19 -0
  6. package/apps/colors/index.html +11 -0
  7. package/apps/colors/model/Color.mjs +59 -0
  8. package/apps/colors/neo-config.json +9 -0
  9. package/apps/colors/store/Colors.mjs +24 -0
  10. package/apps/colors/view/BarChartComponent.mjs +67 -0
  11. package/apps/colors/view/PieChartComponent.mjs +53 -0
  12. package/apps/colors/view/TableContainer.mjs +73 -0
  13. package/apps/colors/view/Viewport.mjs +83 -0
  14. package/apps/colors/view/ViewportController.mjs +268 -0
  15. package/apps/colors/view/ViewportModel.mjs +32 -0
  16. package/apps/covid/view/MainContainerController.mjs +1 -1
  17. package/apps/sharedcovid/view/MainContainerController.mjs +1 -1
  18. package/buildScripts/webpack/json/myApps.template.json +1 -0
  19. package/examples/layout/card/MainContainer.mjs +148 -0
  20. package/examples/layout/card/app.mjs +6 -0
  21. package/examples/layout/card/index.html +11 -0
  22. package/examples/layout/card/neo-config.json +6 -0
  23. package/package.json +9 -9
  24. package/resources/scss/src/apps/colors/BarChartComponent.scss +3 -0
  25. package/resources/scss/src/apps/colors/PieChartComponent.scss +3 -0
  26. package/resources/scss/src/apps/colors/TableContainer.scss +44 -0
  27. package/resources/scss/src/apps/colors/Viewport.scss +17 -0
  28. package/resources/scss/src/layout/Card.scss +17 -0
  29. package/src/component/Base.mjs +6 -0
  30. package/src/component/wrapper/AmChart.mjs +16 -16
  31. package/src/core/Base.mjs +2 -2
  32. package/src/date/SelectorContainer.mjs +3 -0
  33. package/src/layout/Card.mjs +115 -24
  34. package/src/main/addon/AmCharts.mjs +3 -0
  35. package/src/model/Component.mjs +5 -1
  36. package/src/table/Container.mjs +42 -0
  37. package/src/worker/App.mjs +2 -1
  38. package/test/components/files/form/field/ComboBox.mjs +4 -3
@@ -0,0 +1,268 @@
1
+ import Component from '../../../src/controller/Component.mjs';
2
+
3
+ /**
4
+ * @class Colors.view.ViewportController
5
+ * @extends Neo.controller.Component
6
+ */
7
+ class ViewportController extends Component {
8
+ static config = {
9
+ /**
10
+ * @member {String} className='Colors.view.ViewportController'
11
+ * @protected
12
+ */
13
+ className: 'Colors.view.ViewportController'
14
+ }
15
+
16
+ /**
17
+ * @member {String[]} connectedApps=[]
18
+ */
19
+ connectedApps = []
20
+ /**
21
+ * @member {Number|null} intervalId
22
+ */
23
+ intervalId = null
24
+ /**
25
+ * @member {Object} widgetIndexMap
26
+ */
27
+ widgetIndexMap = {
28
+ 'bar-chart': 3,
29
+ 'pie-chart': 2,
30
+ table : 1
31
+ }
32
+
33
+ /**
34
+ * @param {String} name The name of the reference
35
+ */
36
+ async createPopupWindow(name) {
37
+ let me = this,
38
+ widget = me.getReference(name),
39
+ winData = await Neo.Main.getWindowData(),
40
+ rect = await me.component.getDomRect(widget.vdom.id), // using the vdom id to always get the top-level node
41
+ {height, left, top, width} = rect;
42
+
43
+ height -= 50; // popup header in Chrome
44
+ left += winData.screenLeft;
45
+ top += (winData.outerHeight - winData.innerHeight + winData.screenTop);
46
+
47
+ Neo.Main.windowOpen({
48
+ url : `./childapps/widget/index.html?name=${name}`,
49
+ windowFeatures: `height=${height},left=${left},top=${top},width=${width}`,
50
+ windowName : name
51
+ })
52
+ }
53
+
54
+ /**
55
+ * @returns {Object[]}
56
+ */
57
+ generateData() {
58
+ let me = this,
59
+ data = [],
60
+ i = 0,
61
+ len = 20;
62
+
63
+ for (; i < len; i++) {
64
+ data.push({
65
+ id : `row${i + 1}`,
66
+ columnA: me.getRandomInteger(),
67
+ columnB: me.getRandomInteger(),
68
+ columnC: me.getRandomInteger(),
69
+ columnD: me.getRandomInteger(),
70
+ columnE: me.getRandomInteger(),
71
+ columnF: me.getRandomInteger(),
72
+ columnG: me.getRandomInteger(),
73
+ columnH: me.getRandomInteger(),
74
+ columnI: me.getRandomInteger(),
75
+ columnJ: me.getRandomInteger()
76
+ })
77
+ }
78
+
79
+ return data
80
+ }
81
+
82
+ /**
83
+ * @returns {Number}
84
+ */
85
+ getRandomInteger() {
86
+ return Math.floor(Math.random() * 5) + 1
87
+ }
88
+
89
+ /**
90
+ * @param {Object} data
91
+ * @param {String} data.appName
92
+ * @param {Number} data.windowId
93
+ */
94
+ async onAppConnect(data) {
95
+ if (data.appName !== 'Colors') {
96
+ let me = this,
97
+ app = Neo.apps[data.appName],
98
+ mainView = app.mainView,
99
+ {windowId} = data,
100
+ url = await Neo.Main.getByPath({path: 'document.URL', windowId}),
101
+ widgetName = new URL(url).searchParams.get('name'),
102
+ widget = me.getReference(widgetName),
103
+ widgetParent = widget.up();
104
+
105
+ me.connectedApps.push(widgetName);
106
+
107
+ widgetParent.remove(widget, false);
108
+ mainView.add(widget)
109
+ }
110
+ }
111
+
112
+ /**
113
+ * @param {Object} data
114
+ * @param {String} data.appName
115
+ * @param {Number} data.windowId
116
+ */
117
+ async onAppDisconnect(data) {
118
+ let me = this,
119
+ {appName, windowId} = data,
120
+ url = await Neo.Main.getByPath({path: 'document.URL', windowId}),
121
+ widgetName = new URL(url).searchParams.get('name'),
122
+ widget = me.getReference(widgetName),
123
+ widgetParent = widget.up();
124
+
125
+ // Closing a code preview window needs to drop the preview back into the related main app
126
+ if (appName !== 'Colors') {
127
+ widgetParent.remove(widget, false);
128
+ me.component.insert(me.widgetIndexMap[widgetName], widget);
129
+
130
+ me.getReference(`detach-${widgetName}-button`).disabled = false
131
+ }
132
+ // Close popup windows when closing or reloading the main window
133
+ else {
134
+ Neo.Main.windowClose({names: me.connectedApps, windowId})
135
+ }
136
+ }
137
+
138
+ /**
139
+ *
140
+ */
141
+ onConstructed() {
142
+ super.onConstructed();
143
+
144
+ let me = this;
145
+
146
+ Neo.currentWorker.on({
147
+ connect : me.onAppConnect,
148
+ disconnect: me.onAppDisconnect,
149
+ scope : me
150
+ })
151
+ }
152
+
153
+ /**
154
+ *
155
+ */
156
+ onComponentConstructed() {
157
+ super.onComponentConstructed();
158
+
159
+ let me = this,
160
+ data = me.generateData();
161
+
162
+ me.getStore('colors').data = data;
163
+ me.updateCharts(data)
164
+ }
165
+
166
+ /**
167
+ * @param {Object} data
168
+ */
169
+ async onDetachBarChartButtonClick(data) {
170
+ data.component.disabled = true;
171
+ await this.createPopupWindow('bar-chart')
172
+ }
173
+
174
+ /**
175
+ * @param {Object} data
176
+ */
177
+ async onDetachPieChartButtonClick(data) {
178
+ data.component.disabled = true;
179
+ await this.createPopupWindow('pie-chart')
180
+ }
181
+
182
+ /**
183
+ * @param {Object} data
184
+ */
185
+ async onDetachTableButtonClick(data) {
186
+ data.component.disabled = true;
187
+ await this.createPopupWindow('table')
188
+ }
189
+
190
+ /**
191
+ * @param {Object} data
192
+ */
193
+ onStopButtonClick(data) {
194
+ let me = this;
195
+
196
+ if (me.intervalId) {
197
+ clearInterval(me.intervalId);
198
+ me.intervalId = null
199
+ }
200
+ }
201
+
202
+ /**
203
+ * @param {Object} data
204
+ */
205
+ onStartButtonClick(data) {
206
+ let me = this,
207
+ intervalTime = 1000 / 60, // assuming 60 FPS
208
+ store = me.getStore('colors'),
209
+ table = me.getReference('table'),
210
+ tableView = table.view;
211
+
212
+ if (!me.intervalId) {
213
+ me.intervalId = setInterval(() => {
214
+ let data = me.generateData();
215
+
216
+ tableView.silentVdomUpdate = true;
217
+
218
+ store.items.forEach((record, index) => {
219
+ record.set(data[index])
220
+ });
221
+
222
+ tableView.silentVdomUpdate = false;
223
+
224
+ tableView.update();
225
+
226
+ me.updateCharts(data)
227
+ }, intervalTime);
228
+ }
229
+ }
230
+
231
+ /**
232
+ * @param {Object} data
233
+ */
234
+ updateCharts(data) {
235
+ let startCharCode = 'A'.charCodeAt(0),
236
+ colorSummary = {
237
+ colorA: 0,
238
+ colorB: 0,
239
+ colorC: 0,
240
+ colorD: 0,
241
+ colorE: 0
242
+ },
243
+ chartData;
244
+
245
+ data.forEach(item => {
246
+ Object.entries(item).forEach(([key, value]) => {
247
+ if (key !== 'id') {
248
+ colorSummary['color' + String.fromCharCode(startCharCode + value - 1)]++
249
+ }
250
+ })
251
+ });
252
+
253
+ chartData = [
254
+ {color: '#247acb', count: colorSummary['colorA']},
255
+ {color: '#4493de', count: colorSummary['colorB']},
256
+ {color: '#6face6', count: colorSummary['colorC']},
257
+ {color: '#9bc5ed', count: colorSummary['colorD']},
258
+ {color: '#c6def5', count: colorSummary['colorE']}
259
+ ];
260
+
261
+ this.getReference('bar-chart').chartData = chartData;
262
+ this.getReference('pie-chart').chartData = chartData
263
+ }
264
+ }
265
+
266
+ Neo.setupClass(ViewportController);
267
+
268
+ export default ViewportController;
@@ -0,0 +1,32 @@
1
+ import Component from '../../../src/model/Component.mjs';
2
+ import ColorsStore from '../store/Colors.mjs';
3
+
4
+ /**
5
+ * @class Colors.view.ViewportModel
6
+ * @extends Neo.model.Component
7
+ */
8
+ class ViewportModel extends Component {
9
+ static config = {
10
+ /**
11
+ * @member {String} className='Colors.view.ViewportModel'
12
+ * @protected
13
+ */
14
+ className: 'Colors.view.ViewportModel',
15
+ /**
16
+ * @member {Object} data
17
+ */
18
+ data: {},
19
+ /**
20
+ * @member {Object} stores
21
+ */
22
+ stores: {
23
+ colors: {
24
+ module: ColorsStore
25
+ }
26
+ }
27
+ }
28
+ }
29
+
30
+ Neo.setupClass(ViewportModel);
31
+
32
+ export default ViewportModel;
@@ -232,7 +232,7 @@ class MainContainerController extends ComponentController {
232
232
  record;
233
233
 
234
234
  if (store.getCount() > 0) {
235
- if (Neo.isObject(value)) {
235
+ if (Neo.isRecord(value)) {
236
236
  record = value;
237
237
  value = value[component.displayField];
238
238
  } else {
@@ -408,7 +408,7 @@ class MainContainerController extends ComponentController {
408
408
  record;
409
409
 
410
410
  if (store.getCount() > 0) {
411
- if (Neo.isObject(value)) {
411
+ if (Neo.isRecord(value)) {
412
412
  record = value;
413
413
  value = value[component.displayField]
414
414
  } else {
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "apps": [
3
+ "Colors",
3
4
  "Covid",
4
5
  "Docs",
5
6
  "Form",
@@ -0,0 +1,148 @@
1
+ import ConfigurationViewport from '../../ConfigurationViewport.mjs';
2
+ import Container from '../../../src/container/Base.mjs';
3
+ import NumberField from '../../../src/form/field/Number.mjs';
4
+ import Radio from '../../../src/form/field/Radio.mjs';
5
+ import Toolbar from '../../../src/toolbar/Base.mjs';
6
+
7
+ /**
8
+ * @class Neo.examples.layout.card.MainContainer
9
+ * @extends Neo.examples.ConfigurationViewport
10
+ */
11
+ class MainContainer extends ConfigurationViewport {
12
+ static config = {
13
+ className : 'Neo.examples.layout.card.MainContainer',
14
+ configItemLabelWidth: 160,
15
+ configItemWidth : 280,
16
+ layout : {ntype: 'hbox', align: 'stretch'}
17
+ }
18
+
19
+ createConfigurationComponents() {
20
+ let me = this,
21
+ {layout} = me.exampleComponent.getItem('card-container');
22
+
23
+ return [{
24
+ module : Radio,
25
+ checked : layout.slideDirection === 'horizontal',
26
+ hideValueLabel: false,
27
+ labelText : 'slideDirection',
28
+ listeners : {change: me.onRadioLayoutChange.bind(me, 'slideDirection', 'horizontal')},
29
+ name : 'slideDirection',
30
+ valueLabelText: 'horizontal'
31
+ }, {
32
+ module : Radio,
33
+ checked : layout.slideDirection === 'vertical',
34
+ hideValueLabel: false,
35
+ labelText : '',
36
+ listeners : {change: me.onRadioLayoutChange.bind(me, 'slideDirection', 'vertical')},
37
+ name : 'slideDirection',
38
+ valueLabelText: 'vertical'
39
+ }, {
40
+ module : Radio,
41
+ checked : layout.slideDirection === null,
42
+ hideValueLabel: false,
43
+ labelText : '',
44
+ listeners : {change: me.onRadioLayoutChange.bind(me, 'slideDirection', null)},
45
+ name : 'slideDirection',
46
+ valueLabelText: 'null'
47
+ }, {
48
+ module : NumberField,
49
+ clearable : true,
50
+ labelText : 'height',
51
+ listeners : {change: me.onConfigChange.bind(me, 'height')},
52
+ maxValue : 300,
53
+ minValue : 30,
54
+ stepSize : 5,
55
+ style : {marginTop: '10px'},
56
+ value : me.exampleComponent.height
57
+ }, {
58
+ module : NumberField,
59
+ clearable : true,
60
+ labelText : 'width',
61
+ listeners : {change: me.onConfigChange.bind(me, 'width')},
62
+ maxValue : 300,
63
+ minValue : 100,
64
+ stepSize : 5,
65
+ style : {marginTop: '10px'},
66
+ value : me.exampleComponent.width
67
+ }];
68
+ }
69
+
70
+ /**
71
+ * @returns {Neo.component.Base}
72
+ */
73
+ createExampleComponent() {
74
+ return Neo.create({
75
+ module : Container,
76
+ height : 300,
77
+ width : 400,
78
+
79
+ items: [{
80
+ module : Container,
81
+ layout : {ntype: 'card', slideDirection: 'horizontal'},
82
+ reference: 'card-container',
83
+
84
+ items: [{
85
+ style: {backgroundColor: 'red'}
86
+ }, {
87
+ style: {backgroundColor: 'blue'}
88
+ }, {
89
+ style: {backgroundColor: 'green'}
90
+ }]
91
+ }, {
92
+ module: Toolbar,
93
+ flex : 'none',
94
+ style : {marginTop: '1em'},
95
+
96
+ items: [{
97
+ disabled: true,
98
+ handler : 'up.onPrevButtonClick',
99
+ reference: 'prev-button',
100
+ text : 'Prev'
101
+ }, '->', {
102
+ handler : 'up.onNextButtonClick',
103
+ reference: 'next-button',
104
+ text : 'Next'
105
+ }]
106
+ }]
107
+ })
108
+ }
109
+
110
+ /**
111
+ * @param {Object} data
112
+ */
113
+ onNextButtonClick(data) {
114
+ let cardContainer = this.getItem('card-container'),
115
+ {layout} = cardContainer;
116
+
117
+ layout.activeIndex++;
118
+ data.component.disabled = layout.activeIndex === cardContainer.items.length - 1;
119
+ this.getItem('prev-button').disabled = false
120
+ }
121
+
122
+ /**
123
+ * @param {String} config
124
+ * @param {String} value
125
+ * @param {Object} opts
126
+ */
127
+ onRadioLayoutChange(config, value, opts) {
128
+ if (opts.value === true) { // we only want to listen to check events, not uncheck
129
+ this.getItem('card-container').layout[config] = value
130
+ }
131
+ }
132
+
133
+ /**
134
+ * @param {Object} data
135
+ */
136
+ onPrevButtonClick(data) {
137
+ let cardContainer = this.getItem('card-container'),
138
+ {layout} = cardContainer;
139
+
140
+ layout.activeIndex--;
141
+ data.component.disabled = layout.activeIndex === 0;
142
+ this.getItem('next-button').disabled = false
143
+ }
144
+ }
145
+
146
+ Neo.setupClass(MainContainer);
147
+
148
+ export default MainContainer;
@@ -0,0 +1,6 @@
1
+ import MainContainer from './MainContainer.mjs';
2
+
3
+ export const onStart = () => Neo.app({
4
+ mainView: MainContainer,
5
+ name : 'Neo.examples.layout.card'
6
+ });
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE HTML>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5
+ <meta charset="UTF-8">
6
+ <title>Neo Card Layout</title>
7
+ </head>
8
+ <body>
9
+ <script src="../../../src/MicroLoader.mjs" type="module"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,6 @@
1
+ {
2
+ "appPath" : "examples/layout/card/app.mjs",
3
+ "basePath" : "../../../",
4
+ "environment": "development",
5
+ "mainPath" : "./Main.mjs"
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "6.15.11",
3
+ "version": "6.16.1",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -47,23 +47,23 @@
47
47
  "autoprefixer": "^10.4.19",
48
48
  "chalk": "^5.3.0",
49
49
  "clean-webpack-plugin": "^4.0.0",
50
- "commander": "^12.0.0",
51
- "cssnano": "^6.1.2",
52
- "envinfo": "^7.12.0",
50
+ "commander": "^12.1.0",
51
+ "cssnano": "^7.0.2",
52
+ "envinfo": "^7.13.0",
53
53
  "fs-extra": "^11.2.0",
54
54
  "highlightjs-line-numbers.js": "^2.8.0",
55
- "inquirer": "^9.2.18",
56
- "marked": "^12.0.1",
57
- "monaco-editor": "^0.47.0",
55
+ "inquirer": "^9.2.23",
56
+ "marked": "^12.0.2",
57
+ "monaco-editor": "^0.49.0",
58
58
  "neo-jsdoc": "1.0.1",
59
59
  "neo-jsdoc-x": "1.0.5",
60
60
  "postcss": "^8.4.38",
61
- "sass": "^1.75.0",
61
+ "sass": "^1.77.4",
62
62
  "siesta-lite": "5.5.2",
63
63
  "url": "^0.11.3",
64
64
  "webpack": "^5.91.0",
65
65
  "webpack-cli": "^5.1.4",
66
- "webpack-dev-server": "^4.15.2",
66
+ "webpack-dev-server": "^5.0.4",
67
67
  "webpack-hook-plugin": "^1.0.7",
68
68
  "webpack-node-externals": "^3.0.0"
69
69
  },
@@ -0,0 +1,3 @@
1
+ .colors-bar-chart {
2
+ border: 1px solid #555;
3
+ }
@@ -0,0 +1,3 @@
1
+ .colors-pie-chart {
2
+ border: 1px solid #555;
3
+ }
@@ -0,0 +1,44 @@
1
+ $base-color: #1c60a0;
2
+
3
+ .colors-table-container.neo-table-container {
4
+ width: 100%;
5
+
6
+ .color-1 {
7
+ background-color: lighten($base-color, 10%);
8
+ }
9
+
10
+ .color-2 {
11
+ background-color: lighten($base-color, 20%);
12
+ }
13
+
14
+ .color-3 {
15
+ background-color: lighten($base-color, 30%);
16
+ }
17
+
18
+ .color-4 {
19
+ background-color: lighten($base-color, 40%);
20
+ }
21
+
22
+ .color-5 {
23
+ background-color: lighten($base-color, 50%);
24
+ }
25
+
26
+ .neo-index-column {
27
+ max-width: 40px;
28
+ min-width: 40px;
29
+ width : 40px;
30
+ }
31
+
32
+ .neo-table-view {
33
+ .neo-table-row {
34
+ &:hover .neo-table-cell {
35
+ background-color: #d0aa72;
36
+ color : #2b2b2b;
37
+ }
38
+ }
39
+ }
40
+
41
+ td, th {
42
+ min-width: 10%;
43
+ }
44
+ }
@@ -0,0 +1,17 @@
1
+ .colors-viewport {
2
+ padding: 2em;
3
+
4
+ > * {
5
+ &:not(:first-child) {
6
+ margin-top: 2em;
7
+ }
8
+ }
9
+
10
+ .portal-header-toolbar {
11
+ .neo-button {
12
+ &:not(:first-child) {
13
+ margin-left: .5em;
14
+ }
15
+ }
16
+ }
17
+ }
@@ -9,4 +9,21 @@
9
9
  display: none !important;
10
10
  }
11
11
  }
12
+
13
+ .neo-animation-wrapper {
14
+ display : flex;
15
+ transition : transform 300ms cubic-bezier(0.47, 0, 0.745, 0.715);
16
+ will-change: transform;
17
+
18
+ > * {
19
+ flex: 1 0 auto;
20
+ }
21
+ }
22
+
23
+ .neo-relative {
24
+ height : 100%;
25
+ overflow: hidden;
26
+ position: relative;
27
+ width : 100%;
28
+ }
12
29
  }
@@ -944,6 +944,12 @@ class Base extends CoreBase {
944
944
  if (controller && value) {
945
945
  controller.windowId = value
946
946
  }
947
+
948
+ // If a component gets moved into a different window, an update cycle might still be running.
949
+ // Since the update might no longer get mapped, we want to re-enable this instance for future updates.
950
+ if (oldValue) {
951
+ this.isVdomUpdating = false
952
+ }
947
953
  }
948
954
 
949
955
  /**