neo.mjs 6.18.0 → 6.18.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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.18.0'
23
+ * @member {String} version='6.18.1'
24
24
  */
25
- version: '6.18.0'
25
+ version: '6.18.1'
26
26
  }
27
27
 
28
28
  /**
@@ -3,6 +3,7 @@ import Colors from './parts/Colors.mjs';
3
3
  import Container from '../../../../src/container/Base.mjs';
4
4
  import Features from './parts/Features.mjs';
5
5
  import Helix from './parts/Helix.mjs';
6
+ import How from './parts/How.mjs';
6
7
  import HelloWorld from './parts/HelloWorld.mjs';
7
8
  import MainNeo from './parts/MainNeo.mjs';
8
9
 
@@ -29,8 +30,9 @@ class MainContainer extends Container {
29
30
  MainNeo,
30
31
  Features,
31
32
  HelloWorld,
32
- Colors,
33
33
  Helix,
34
+ Colors,
35
+ How,
34
36
  AfterMath
35
37
  ],
36
38
  /**
@@ -39,11 +41,38 @@ class MainContainer extends Container {
39
41
  scrollable: true,
40
42
 
41
43
  domListeners: [{
44
+ intersect(data) {
45
+ Neo.getComponent(data.targetId)?.activate?.()
46
+ },
42
47
  scroll(event) {
43
48
  this.toggleCls('hide-sidebar', event.scrollTop > 80)
44
49
  }
45
50
  }]
46
51
  }
52
+
53
+ /**
54
+ * Triggered after the mounted config got changed
55
+ * @param {Boolean} value
56
+ * @param {Boolean} oldValue
57
+ * @protected
58
+ */
59
+ afterSetMounted(value, oldValue) {
60
+ super.afterSetMounted(value, oldValue);
61
+
62
+ let me = this,
63
+ {id, windowId} = me;
64
+
65
+ value && setTimeout(() => {
66
+ Neo.main.addon.IntersectionObserver.register({
67
+ callback : 'isVisible',
68
+ id,
69
+ observe : ['.page'],
70
+ root : `#${id}`,
71
+ threshold: 1.0,
72
+ windowId
73
+ })
74
+ }, 50)
75
+ }
47
76
  }
48
77
 
49
78
  Neo.setupClass(MainContainer);
@@ -31,26 +31,43 @@ class Colors extends Container {
31
31
  items : [{
32
32
  cls : 'neo-h1',
33
33
  flex: 'none',
34
- html: 'Colors Dashboard'
34
+ html: 'Amazing Potential',
35
+ vdom: {tag: 'h1'}
35
36
  }, {
36
37
  cls : 'neo-h2',
37
38
  flex: 'none',
38
- html: 'Expand the widgets into multiple Windows'
39
+ html: 'Socket Data',
40
+ vdom: {tag: 'h2'}
39
41
  }, {
40
- cls : 'neo-content',
41
42
  flex: 'none',
42
- html: 'The State Management will continue to work.'
43
+ vdom: {tag: 'p'},
44
+ html: [
45
+ 'This is similar to the Helix demo — it\'s an extremely fast multi-window app. Click the start button',
46
+ 'to see the view reflect changes in the data. And the app is multi-window: the table and charts can be',
47
+ 'undocked into their own windows. In fact, the entire demo can be undocked.'
48
+ ].join('')
49
+ }, {
50
+ flex: 'none',
51
+ html: 'But the demo differs from the helix example because the data is provided via a <i>socket</i>.',
52
+ vdom: {tag: 'p'}
53
+ }, {
54
+ flex: 'none',
55
+ vdom: {tag: 'p'},
56
+ html: [
57
+ 'Neo.mjs uniquely fits the bill for applications that need real-time visualizations of real-time data, such as',
58
+ 'stock market trading data and medical or scientific telemetry.'
59
+ ].join('')
43
60
  }]
44
61
  }, {
45
62
  module: Container,
46
63
  flex : '2',
47
- style : {background: 'grey', padding: '20px'},
64
+ style : {background: 'lightgray', padding: '20px'},
48
65
  layout: {ntype: 'vbox', align: 'stretch', pack: 'center'},
49
66
  items : [{
50
- module : LivePreview,
51
- activeView: 'preview',
52
- cls : ['page-live-preview'],
53
- height : '100%',
67
+ module : LivePreview,
68
+ cls : ['page-live-preview'],
69
+ height : '100%',
70
+ reference: 'live-preview',
54
71
 
55
72
  value: [
56
73
  "import Viewport from '../../../../apps/colors/view/Viewport.mjs';",
@@ -67,6 +84,13 @@ class Colors extends Container {
67
84
  }]
68
85
  }]
69
86
  }
87
+
88
+ /**
89
+ *
90
+ */
91
+ activate() {
92
+ this.getReference('live-preview').activeView = 'preview'
93
+ }
70
94
  }
71
95
 
72
96
  Neo.setupClass(Colors);
@@ -12,14 +12,17 @@ class Helix extends Container {
12
12
  * @protected
13
13
  */
14
14
  className: 'Portal.view.home.parts.Helix',
15
-
15
+ /**
16
+ * @member {String[]} cls=['page','cool-stuff']
17
+ */
16
18
  cls: ['page', 'cool-stuff'],
17
-
19
+ /**
20
+ * @member {Object} responsive
21
+ */
18
22
  responsive: {
19
23
  medium: {layout: {ntype: 'vbox', align: 'stretch', pack: 'center'}},
20
24
  large : {layout: {ntype: 'hbox', align: 'stretch', pack: 'center'}}
21
25
  },
22
-
23
26
  /**
24
27
  * @member {Object[]} items
25
28
  */
@@ -31,26 +34,55 @@ class Helix extends Container {
31
34
  items : [{
32
35
  cls : 'neo-h1',
33
36
  flex: 'none',
34
- html: 'Interactive Views'
37
+ html: 'Extreme Speed',
38
+ vdom: {tag: 'h1'}
35
39
  }, {
36
40
  cls : 'neo-h2',
37
41
  flex: 'none',
38
- html: 'Expand the widget into multiple Windows'
42
+ html: '40,000 Updates /s',
43
+ vdom: {tag: 'h2'}
39
44
  }, {
40
- cls : 'neo-content',
45
+ cls : 'neo-h3',
41
46
  flex: 'none',
42
- html: 'The State Management will continue to work.'
47
+ vdom: {tag: 'p'},
48
+
49
+ html: [
50
+ 'This demo shows the Neo.mjs helix component, along with a "Helix Controls" panel. ',
51
+ 'Move your cursor over the helix, then rapidly scroll left and right to rotate, and up and down to zoom. ',
52
+ 'As you do, look at the delta updates counter at the top. ',
53
+ 'Neo.mjs easily handles 40,000 updates per second, and beyond.'
54
+ ].join('')
55
+ }, {
56
+ cls : 'neo-h1',
57
+ flex: 'none',
58
+ html: 'Multi-Window',
59
+ vdom: {tag: 'h1'}
60
+ }, {
61
+ cls : 'neo-h2',
62
+ flex: 'none',
63
+ html: 'Seamless and Simple',
64
+ vdom: {tag: 'h2'}
65
+ }, {
66
+ cls : 'neo-h3',
67
+ flex: 'none',
68
+ vdom: {tag: 'p'},
69
+
70
+ html: [
71
+ 'Click on the small window icon in the Helix Controls title bar and the controls open in their own window ',
72
+ 'which can be moved to a separate monitor. But the application logic doesn\'t care &mdash; ',
73
+ 'the logic updates the controls just like before, and framework seamlessly handles updating the DOM across windows.'
74
+ ].join('')
43
75
  }]
44
76
  }, {
45
77
  module: Container,
46
78
  flex : '2',
47
- style : {background: 'grey', padding: '20px'},
79
+ style : {background: 'lightgray', padding: '20px'},
48
80
  layout: {ntype: 'vbox', align: 'stretch', pack: 'center'},
49
81
  items : [{
50
- module : LivePreview,
51
- activeView: 'preview',
52
- cls : ['page-live-preview'],
53
- height : '100%',
82
+ module : LivePreview,
83
+ cls : ['page-live-preview'],
84
+ height : '100%',
85
+ reference: 'live-preview',
54
86
 
55
87
  value: [
56
88
  "import Viewport from '../../../../examples/component/multiWindowHelix/Viewport.mjs';",
@@ -68,6 +100,13 @@ class Helix extends Container {
68
100
  }]
69
101
  }]
70
102
  }
103
+
104
+ /**
105
+ *
106
+ */
107
+ activate() {
108
+ this.getReference('live-preview').activeView = 'preview'
109
+ }
71
110
  }
72
111
 
73
112
  Neo.setupClass(Helix);
@@ -44,15 +44,18 @@ class HelloWorld extends Container {
44
44
  cls : 'neo-h1',
45
45
  id : 'neo-hello-world-h1',
46
46
  flex: 'none',
47
- html: 'Hello World'
47
+ html: 'Hello World',
48
+ vdom: {tag: 'h1'}
48
49
  }, {
49
50
  cls : 'neo-h2',
50
51
  flex: 'none',
51
- html: 'Your first code snippet'
52
+ html: 'Your first code snippet',
53
+ vdom: {tag: 'h2'}
52
54
  }, {
53
55
  cls : 'neo-content',
54
56
  flex: 'none',
55
- html: 'If you understand these lines, you are ready to start with Neo.mjs'
57
+ html: 'If you understand these lines, you are ready to start with Neo.mjs',
58
+ vdom: {tag: 'p'}
56
59
  }]
57
60
  }, {
58
61
  module: LivePreviewContainer,
@@ -0,0 +1,66 @@
1
+ import Container from '../../../../../src/container/Base.mjs';
2
+
3
+ /**
4
+ * @class Portal.view.home.parts.How
5
+ * @extends Neo.container.Base
6
+ */
7
+ class How extends Container {
8
+ static config = {
9
+ className: 'Portal.view.home.parts.How',
10
+ /**
11
+ * @member {String[]} cls=['page','cool-stuff']
12
+ */
13
+ cls: ['page', 'cool-stuff'],
14
+ /**
15
+ * @member {Object} responsive
16
+ */
17
+ responsive: {
18
+ medium: {layout: {ntype: 'vbox', align: 'stretch', pack: 'center'}},
19
+ large : {layout: {ntype: 'hbox', align: 'stretch', pack: 'center'}}
20
+ },
21
+ /**
22
+ * @member {Object[]} items
23
+ */
24
+ items: [{
25
+ module: Container,
26
+ flex : '1',
27
+ style : {padding: '2rem'},
28
+ layout: {ntype: 'vbox', align: 'center', pack: 'center'},
29
+ items : [{
30
+ cls : 'neo-h1',
31
+ flex: 'none',
32
+ html: 'How?',
33
+ vdom: {tag: 'h1'}
34
+ }, {
35
+ cls : 'neo-h2',
36
+ flex: 'none',
37
+ html: 'How Does Neo.mjs Do It?',
38
+ vdom: {tag: 'h2'}
39
+ }, {
40
+ cls : 'neo-h3',
41
+ flex: 'none',
42
+ vdom: {tag: 'p'},
43
+ html: [
44
+ 'When a Neo.mjs app launches three webworkers are spawned: one that holds app logic, one for tracking delta DOM updates, ',
45
+ 'and one for backend calls. Each webworker runs in its own thread, and thus, in its own processor core. ',
46
+ 'This means these processes run in parallel: your app logic isn\'t affected by DOM changes or ',
47
+ 'by Ajax or socket calls. If you have processor-intensive tasks you can easily run them in their own threads.'
48
+ ].join('')
49
+ }]
50
+ }, {
51
+ module: Container,
52
+ flex : '2',
53
+ style : {background: 'lightgray', padding: '20px'},
54
+ layout: {ntype: 'vbox', align: 'stretch', pack: 'center'},
55
+ items : [{
56
+ flex : 'none',
57
+ style: {width: '100%'},
58
+ vdom : {tag: 'img', src: 'https://s3.amazonaws.com/mjs.neo.learning.images/why/IndexHtmlFlow.png'}
59
+ }]
60
+ }]
61
+ }
62
+ }
63
+
64
+ Neo.setupClass(How);
65
+
66
+ export default How;
@@ -13,7 +13,7 @@ class MainNeo extends Container {
13
13
  */
14
14
  className: 'Portal.view.home.parts.MainNeo',
15
15
 
16
- cls: ['page', 'landing-page'],
16
+ cls: ['page', 'portal-home-main-neo'],
17
17
 
18
18
  layout: {ntype: 'vbox', align: 'center', pack: 'center'},
19
19
  /**
@@ -24,9 +24,10 @@ class MainNeo extends Container {
24
24
  cls : ['vector'],
25
25
  flex : 'none',
26
26
  }, {
27
- cls : 'neo-h1',
27
+ cls : ['neo-h1'],
28
28
  flex: 'none',
29
- html: 'The High-Performance Web Framework for Next Generation Interfaces'
29
+ html: 'The High-Performance Web Framework for Next Generation Interfaces',
30
+ vdom: {tag: 'h1'}
30
31
  }, {
31
32
  module: Container,
32
33
  cls : ['button-group'],
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.18.0'
23
+ * @member {String} version='6.18.1'
24
24
  */
25
- version: '6.18.0'
25
+ version: '6.18.1'
26
26
  }
27
27
 
28
28
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "6.18.0",
3
+ "version": "6.18.1",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -53,27 +53,31 @@ A `Neo.controller.Component` is a simple class associated with a component class
53
53
  instance of its associated controller is automatically created.
54
54
 
55
55
  <pre data-neo>
56
- import Container from '../../../../src/container/Base.mjs';
57
- import Controller from '../../../../src/controller/Component.mjs';
58
- import TextField from '../../../../src/form/field/Text.mjs';
56
+ import Base from '../../../../src/controller/Component.mjs';
59
57
 
60
- class MainViewController extends Controller {
58
+ class MainViewController extends Base {
61
59
  static config = {
62
- className: 'Example.view.MainViewController'
60
+ className: 'Example.view.MainViewController',
63
61
  }
64
62
  onChange(data) {
65
- Neo.Main.log({value: data.value})
63
+ Neo.Main.log({value: data.value});
66
64
  }
65
+
67
66
  }
68
67
  Neo.setupClass(MainViewController);
69
68
 
70
69
 
70
+ import Container from '../../../../src/container/Base.mjs';
71
+ import TextField from '../../../../src/form/field/Text.mjs';
72
+
71
73
  class MainView extends Container {
72
74
  static config = {
73
- className : 'Example.view.MainView',
75
+
74
76
  controller: MainViewController,
75
- layout : {ntype:'vbox', align:'start'},
76
- items : [{
77
+ className: 'Example.view.MainView',
78
+
79
+ layout : {ntype:'vbox', align:'start'},
80
+ items: [{
77
81
  module : TextField,
78
82
  labelText: 'Name',
79
83
  listeners: {
@@ -85,6 +89,8 @@ class MainView extends Container {
85
89
  Neo.setupClass(MainView);
86
90
  </pre>
87
91
 
92
+
93
+
88
94
  (It's important to keep in mind that in Neo.mjs, all class definitions are coded in their own
89
95
  source file: one class per file. In the examples we're putting all the relevant classes together
90
96
  to make it easier to see the source code for every class being used. But in an
@@ -1,4 +1,4 @@
1
- As you read in the Getting Started > Events topic, components, stores, and many other objects fire events.
1
+ As you read in the <a href="#/learn/Events">Getting Started > Events</a> topic, components, stores, and many other objects fire events.
2
2
 
3
3
 
4
4
  <pre data-neo>
@@ -32,12 +32,12 @@ Neo.setupClass(MainView);
32
32
 
33
33
  ### In-line
34
34
 
35
- The event listener function can be coded in-line. Normally, you want event handlers to be in a view's controller,
36
- but for very simple situation it can be convenient to use this syntax.
35
+ The event listener function can be coded in-line. Normally you want event handlers to be in a view's
36
+ controller, but for very simple situation it can be convenient to use this syntax.
37
37
 
38
38
  <pre data-neo>
39
39
  import Container from '../../../../src/container/Base.mjs';
40
- import Button from '../../../../src/button/Base.mjs';
40
+ import TextField from '../../../../src/form/field/Text.mjs';
41
41
 
42
42
  class MainView extends Container {
43
43
  static config = {
@@ -45,10 +45,10 @@ class MainView extends Container {
45
45
  layout : {ntype:'vbox', align:'start'},
46
46
 
47
47
  items: [{
48
- module : Button,
49
- text: 'Button',
50
- listeners: {
51
- click: button => Neo.Main.log('Click!');
48
+ module : TextField,
49
+ labelText: 'Name',
50
+ listeners: {
51
+ change: data => Neo.Main.log({value:data.value})
52
52
  }
53
53
  }]
54
54
  }
@@ -59,12 +59,12 @@ Neo.setupClass(MainView);
59
59
  ### As a view method
60
60
 
61
61
  You can also use the `up.` qualifier to specify a method in the component's parent view. Like the
62
- in-line syntax above, using `up.` might be convenient for simple event handlers, or when you
63
- simply haven't gotten around to definining a view's controller.
62
+ in-line syntax you saw above, using the `up.` syntax might be convenient for simple classees,
63
+ or when you simply haven't gotten around to defining a view's controller.
64
64
 
65
65
  <pre data-neo>
66
66
  import Container from '../../../../src/container/Base.mjs';
67
- import Button from '../../../../src/button/Base.mjs';
67
+ import TextField from '../../../../src/form/field/Text.mjs';
68
68
 
69
69
  class MainView extends Container {
70
70
  static config = {
@@ -72,16 +72,15 @@ class MainView extends Container {
72
72
  layout : {ntype:'vbox', align:'start'},
73
73
 
74
74
  items: [{
75
- module : Button,
76
- text: 'Button',
77
- listeners: {
78
- click: 'up.onButtonClick'
75
+ module : TextField,
76
+ labelText: 'Name',
77
+ listeners: {
78
+ change: 'up.foo'
79
79
  }
80
80
  }]
81
81
  }
82
-
83
- onButtonClick(){
84
- Neo.Main.log(arguments);
82
+ foo(data){
83
+ Neo.Main.log({value:data.value})
85
84
  }
86
85
  }
87
86
  Neo.setupClass(MainView);
@@ -89,12 +88,136 @@ Neo.setupClass(MainView);
89
88
 
90
89
  ### As a controller method
91
90
 
91
+ Despite the examples above, the most correct way of setting up event handlers is to use a controller.
92
+ Any view class can specify a controller &mdash; wWhen the view is created a controller instance is
93
+ also created.
94
+
95
+ <pre data-neo>
96
+ import Controller from '../../../../src/controller/Component.mjs';
97
+
98
+ class MainViewController extends Controller {
99
+ static config = {
100
+ className: 'Example.view.MainViewController'
101
+ }
102
+ foo(data){
103
+ Neo.Main.log({value:data.value})
104
+ }
105
+ }
106
+ Neo.setupClass(MainViewController);
107
+
108
+
109
+ import Container from '../../../../src/container/Base.mjs';
110
+ import TextField from '../../../../src/form/field/Text.mjs';
111
+
112
+ class MainView extends Container {
113
+ static config = {
114
+ controller: {
115
+ module: MainViewController
116
+ },
117
+ className: 'Example.view.MainView',
118
+ layout : {ntype:'vbox', align:'start'},
119
+
120
+ items: [{
121
+ module : TextField,
122
+ labelText: 'Name',
123
+ listeners: {
124
+ change: 'foo'
125
+ }
126
+ }]
127
+ }
128
+ }
129
+ Neo.setupClass(MainView);
130
+ </pre>
131
+
92
132
  ## Adding listeners procedurally
93
133
 
94
134
  Event listeners are normally specified declaratively, via the `listeners: {}` config. But occasionally you need to add
95
135
  a listener proccedurally.
96
136
 
97
- Any obversable class has an `addListener` method. There's also an easier to type version called `on`.
137
+ Any obversable class has an `addListener` method, along with an easier-to-type version called `on`.
138
+
139
+ <pre data-neo>
140
+ import Controller from '../../../../src/controller/Component.mjs';
141
+
142
+ class MainViewController extends Controller {
143
+ static config = {
144
+ className: 'Example.view.MainViewController'
145
+ }
146
+ foo(data){
147
+ Neo.Main.log({value:data.value})
148
+ }
149
+ onComponentConstructed(){
150
+ debugger
151
+ }
152
+ }
153
+ Neo.setupClass(MainViewController);
154
+
155
+
156
+ import Container from '../../../../src/container/Base.mjs';
157
+ import TextField from '../../../../src/form/field/Text.mjs';
158
+
159
+ class MainView extends Container {
160
+ static config = {
161
+ controller: {
162
+ module: MainViewController
163
+ },
164
+ className: 'Example.view.MainView',
165
+ layout : {ntype:'vbox', align:'start'},
166
+
167
+ items: [{
168
+ module : TextField,
169
+ labelText: 'Name',
170
+ listeners: {
171
+ change: 'foo'
172
+ }
173
+ }]
174
+ }
175
+ }
176
+ Neo.setupClass(MainView);
177
+ </pre>
178
+
179
+ The method specified in `on()` doesn't have to be an arrow function; you can use a controller function.
180
+
181
+ <pre data-neo>
182
+ import Controller from '../../../../src/controller/Component.mjs';
183
+
184
+ class MainViewController extends Controller {
185
+ static config = {
186
+ className: 'Example.view.MainViewController'
187
+ }
188
+ foo(data){
189
+ Neo.Main.log('foo' + {value:data.value}
190
+ }
191
+
192
+ // This is a controller lifecycle method run after the controller's view has been constructed
193
+ onComponentConstructed(){
194
+ // Note the use of this.getReference() -- that's used to get a component reference with the specified name
195
+ this.getReference('nameTextfield').on('change', this.foo, this)
196
+ }
197
+ }
198
+ Neo.setupClass(MainViewController);
199
+
200
+
201
+ import Container from '../../../../src/container/Base.mjs';
202
+ import TextField from '../../../../src/form/field/Text.mjs';
203
+
204
+ class MainView extends Container {
205
+ static config = {
206
+ controller: {
207
+ module: MainViewController
208
+ },
209
+ className: 'Example.view.MainView',
210
+ layout : {ntype:'vbox', align:'start'},
211
+
212
+ items: [{
213
+ module : TextField,
214
+ reference: 'nameTextfield', // This component can be fetched using this.getReference('nameTextfield')
215
+ labelText: 'Name'
216
+ }]
217
+ }
218
+ }
219
+ Neo.setupClass(MainView);
220
+ </pre>
98
221
 
99
222
 
100
223
 
@@ -1,55 +1,54 @@
1
1
  .learnneo-header-toolbar {
2
- border-bottom: 1px solid #f2f2f2;
2
+ border-bottom: 1px solid #f2f2f2;
3
3
 
4
- .logo {
5
- margin-left: 1em;
6
- }
7
-
8
- .neo-button {
9
- margin-left: 10px;
10
-
11
- &.no-text {
12
- margin-left: 0;
13
- width: 1.2em;
14
-
15
- &.github-button {
16
- margin-left: 5em;
17
- }
18
-
19
- .neo-button-glyph {
20
- font-size: 24px;
21
- }
4
+ .logo {
5
+ margin-left: 1em;
22
6
  }
23
7
 
24
- .neo-button-glyph {
25
- &.neo-logo-blue {
26
- background-image: url("../../../../../../../resources/images/logo/neo_logo_primary.svg");
27
- height: 24px;
28
- width: 24px;
29
- }
8
+ .neo-button {
9
+ margin-left: 10px;
10
+
11
+ &.no-text {
12
+ margin-left: 0;
13
+ width : 1.2em;
14
+
15
+ &.github-button {
16
+ margin-left: 5em;
17
+ }
18
+
19
+ .neo-button-glyph {
20
+ font-size: 24px;
21
+ }
22
+ }
23
+
24
+ .neo-button-glyph {
25
+ &.neo-logo-blue {
26
+ background-image: url("../../../../../../resources/images/logo/neo_logo_primary.svg");
27
+ height : 24px;
28
+ width : 24px;
29
+ }
30
+ }
30
31
  }
31
- }
32
32
 
33
- .separate-bar {
34
- position: absolute;
35
- right: 20px;
36
- top: 60px;
37
- width: 40px;
38
-
39
- z-index: 9;
40
- transform: rotate(0);
41
- animation: fade-in-animation 200ms linear;
42
- }
33
+ .separate-bar {
34
+ animation: fade-in-animation 200ms linear;
35
+ position: absolute;
36
+ right : 20px;
37
+ top : 60px;
38
+ transform: rotate(0);
39
+ width : 40px;
40
+ z-index : 9;
41
+ }
43
42
 
44
- // find parallel class hide-sidebar
45
- &:has(+div .hide-sidebar) .separate-bar {
46
- animation: fade-animation 200ms linear forwards;
47
- }
43
+ // find parallel class hide-sidebar
44
+ &:has(+div .hide-sidebar) .separate-bar {
45
+ animation: fade-animation 200ms linear forwards;
46
+ }
48
47
  }
49
48
 
50
49
  .vector {
51
- animation: fade-and-scale-animation auto linear;
52
- animation-timeline: --page-scroll;
50
+ animation: fade-and-scale-animation auto linear;
51
+ animation-timeline: --page-scroll;
53
52
  }
54
53
 
55
54
  //@scroll-timeline --page-scroll {
@@ -61,70 +60,71 @@
61
60
 
62
61
  /* Style and position the progress bar */
63
62
  #progress {
64
- position: fixed;
65
- z-index: 1000;
66
- top: 0;
67
- height: 2px;
68
- width: 100%;
69
- background: var(--button-background-color);
70
- background: var(--sem-color-surface-primary-background);
63
+ position: fixed;
64
+ z-index: 1000;
65
+ top: 0;
66
+ height: 2px;
67
+ width: 100%;
68
+ background: var(--button-background-color);
69
+ background: var(--sem-color-surface-primary-background);
71
70
 
72
- scale: 0 1;
73
- transform-origin: left;
71
+ scale: 0 1;
72
+ transform-origin: left;
74
73
 
75
- /* Attach the animation using an anonymous Scroll Progress Timeline */
76
- animation: grow-progress linear;
77
- animation-timeline: --page-scroll;
74
+ /* Attach the animation using an anonymous Scroll Progress Timeline */
75
+ animation: grow-progress linear;
76
+ animation-timeline: --page-scroll;
78
77
  }
79
78
 
80
79
  @keyframes grow-progress {
81
- to { scale: 1 1; }
80
+ to {
81
+ scale: 1 1;
82
+ }
82
83
  }
83
84
 
84
85
  .hello-world {
85
- animation-timeline: view(block 100% -500%);
86
+ animation-timeline: view(block 100% -500%);
86
87
 
87
- animation-name: appear-animation;
88
- animation-fill-mode: both;
89
- animation-duration: 1ms; /* Firefox requires this to apply the animation */
90
- animation-timing-function: linear;
88
+ animation-name: appear-animation;
89
+ animation-fill-mode: both;
90
+ animation-duration: 1ms; /* Firefox requires this to apply the animation */
91
+ animation-timing-function: linear;
91
92
  }
92
93
 
93
94
  @keyframes appear-animation {
94
- 0% {
95
- transform: translateX(-400%);
96
- opacity: 0;
97
- }
98
- 90% {
99
- opacity: .3;
100
- }
101
- 100% {
102
- transform: translateX(0);
103
- opacity: 1;
104
- }
95
+ 0% {
96
+ transform: translateX(-400%);
97
+ opacity : 0;
98
+ }
99
+ 90% {
100
+ opacity: .3;
101
+ }
102
+ 100% {
103
+ transform: translateX(0);
104
+ opacity : 1;
105
+ }
105
106
  }
106
107
 
107
108
  .cool-stuff {
108
- animation-timeline: view(block 100% -500%);
109
-
110
- animation-name: appear-cool-stuff;
111
- animation-fill-mode: both;
112
- animation-duration: 1ms; /* Firefox requires this to apply the animation */
113
- animation-timing-function: linear;
109
+ animation-timeline : view(block 100% -500%);
110
+ animation-name : appear-cool-stuff;
111
+ animation-fill-mode : both;
112
+ animation-duration : 1ms; /* Firefox requires this to apply the animation */
113
+ animation-timing-function: linear;
114
114
  }
115
115
 
116
116
  @keyframes appear-cool-stuff {
117
- 0% {
118
- transform: translateX(400%);
119
- opacity: 0;
120
- }
121
- 90% {
122
- opacity: .3;
123
- }
124
- 100% {
125
- transform: translateX(0);
126
- opacity: 1;
127
- }
117
+ 0% {
118
+ transform: translateX(400%);
119
+ opacity : 0;
120
+ }
121
+ 90% {
122
+ opacity: .3;
123
+ }
124
+ 100% {
125
+ transform: translateX(0);
126
+ opacity : 1;
127
+ }
128
128
  }
129
129
 
130
130
 
@@ -133,65 +133,83 @@
133
133
  //}
134
134
 
135
135
  .portal-home-maincontainer {
136
- scroll-timeline: --page-scroll block;
136
+ scroll-timeline: --page-scroll block;
137
137
  }
138
138
 
139
139
  @keyframes rotateAnimation {
140
- from { transform: rotate(0deg); }
141
- to { transform: rotate(360deg); }
140
+ from {
141
+ transform: rotate(0deg);
142
+ }
143
+ to {
144
+ transform: rotate(360deg);
145
+ }
142
146
  }
143
147
 
144
148
  @keyframes fade-and-scale-animation {
145
- 0% {
146
- opacity: 1;
147
- transform: scale(1);
148
- }
149
- 12%, 100% {
150
- opacity: 0;
151
- transform: scale(1.5);
152
- }
149
+ 0% {
150
+ opacity : 1;
151
+ transform: scale(1);
152
+ }
153
+ 12%, 100% {
154
+ opacity : 0;
155
+ transform: scale(1.5);
156
+ }
153
157
  }
154
158
 
155
159
  @keyframes fade-in-animation {
156
- from { opacity: 0; right: -10px}
157
- to { opacity: 1; right: 20px;}
160
+ from {
161
+ opacity: 0;
162
+ right : -10px
163
+ }
164
+ to {
165
+ opacity: 1;
166
+ right : 20px;
167
+ }
158
168
  }
169
+
159
170
  @keyframes fade-animation {
160
- from { opacity: 1; right: 20px;}
161
- to { opacity: 0; right: -10px}
171
+ from {
172
+ opacity: 1;
173
+ right : 20px;
174
+ }
175
+ to {
176
+ opacity: 0;
177
+ right : -10px
178
+ }
162
179
  }
163
180
 
164
181
  .button-group {
165
- overflow: visible;
182
+ overflow: visible;
166
183
  }
167
184
 
168
185
  .get-started-button {
169
- opacity: 0;
170
- animation: show-get-started-button 400ms 1300ms linear forwards;
186
+ opacity : 0;
187
+ animation: show-get-started-button 400ms 1300ms linear forwards;
171
188
  }
172
189
 
173
190
  .neo-github {
174
- opacity: 0;
175
- animation: show-github-button 600ms 1150ms linear forwards;
191
+ opacity : 0;
192
+ animation: show-github-button 600ms 1150ms linear forwards;
176
193
  }
177
194
 
178
195
  @keyframes show-get-started-button {
179
- from {
180
- opacity: 0;
181
- transform: translate(70px, 30px);
182
- }
183
- to {
184
- opacity: 1;
185
- transform: translate(0, 0);
186
- }
196
+ from {
197
+ opacity : 0;
198
+ transform: translate(70px, 30px);
199
+ }
200
+ to {
201
+ opacity : 1;
202
+ transform: translate(0, 0);
203
+ }
187
204
  }
205
+
188
206
  @keyframes show-github-button {
189
- from {
190
- opacity: 0;
191
- transform: translate(-70px, 50px);
192
- }
193
- to {
194
- opacity: 1;
195
- transform: translate(0, 0);
196
- }
207
+ from {
208
+ opacity : 0;
209
+ transform: translate(-70px, 50px);
210
+ }
211
+ to {
212
+ opacity : 1;
213
+ transform: translate(0, 0);
214
+ }
197
215
  }
@@ -9,11 +9,17 @@
9
9
 
10
10
  .neo-h1 {
11
11
  font-size: min(max(5.5vw, 30px), 64px);
12
+ text-align : center;
13
+ margin : 0;
14
+ line-height : 1em;
12
15
  }
13
16
 
14
17
  .neo-h2 {
15
18
  font-size: min(max(3.5vw, 24px), 44px);
16
- }
19
+ text-align : center;
20
+ margin : 0;
21
+ line-height : 1em;
22
+ }
17
23
 
18
24
  .neo-content {
19
25
  font-size: min(max(2.3vw, 16px), 30px);
@@ -24,27 +30,8 @@
24
30
  }
25
31
  }
26
32
 
27
- .button-group {
28
- display : flex !important;
29
- flex-direction: row-reverse !important;
30
- gap : 8px !important;
31
- }
32
-
33
33
  .neo-h1 {
34
- font-size : 32px;
35
- font-weight : 600;
36
- text-align : center;
37
- margin-bottom: 1.25em;
38
- }
39
-
40
- .vector {
41
- background-image : url("../../../../../../../resources/images/logo/neo_logo_text_primary.svg");
42
- background-position: center center;
43
- background-repeat : no-repeat;
44
- background-size : contain;
45
- height : 10vW;
46
- margin : 0 0 3rem 0;
47
- max-height : 130px;
48
- width : 100%;
34
+ font-size : 32px;
35
+ font-weight: 600;
49
36
  }
50
37
  }
@@ -0,0 +1,22 @@
1
+ .portal-home-main-neo.page {
2
+ .button-group {
3
+ display : flex !important;
4
+ flex-direction: row-reverse !important;
5
+ gap : 8px !important;
6
+ }
7
+
8
+ .neo-h1 {
9
+ margin-bottom: 1.25em;
10
+ }
11
+
12
+ .vector {
13
+ background-image : url("../../../../../../../../resources/images/logo/neo_logo_text_primary.svg");
14
+ background-position: center center;
15
+ background-repeat : no-repeat;
16
+ background-size : contain;
17
+ height : 10vW;
18
+ margin : 0 0 3rem 0;
19
+ max-height : 130px;
20
+ width : 100%;
21
+ }
22
+ }
@@ -260,12 +260,12 @@ const DefaultConfig = {
260
260
  useVdomWorker: true,
261
261
  /**
262
262
  * buildScripts/injectPackageVersion.mjs will update this value
263
- * @default '6.18.0'
263
+ * @default '6.18.1'
264
264
  * @memberOf! module:Neo
265
265
  * @name config.version
266
266
  * @type String
267
267
  */
268
- version: '6.18.0'
268
+ version: '6.18.1'
269
269
  };
270
270
 
271
271
  Object.assign(DefaultConfig, {
@@ -13,8 +13,10 @@ import VDomUtil from '../util/VDom.mjs';
13
13
  import VNodeUtil from '../util/VNode.mjs';
14
14
 
15
15
  const
16
- lengthRE = /^\d+\w+$/,
17
- addUnits = value => value == null ? value : isNaN(value) ? value : `${value}px`;
16
+ addUnits = value => value == null ? value : isNaN(value) ? value : `${value}px`,
17
+ closestController = Symbol.for('closestController'),
18
+ closestModel = Symbol.for('closestModel'),
19
+ lengthRE = /^\d+\w+$/;
18
20
 
19
21
  /**
20
22
  * @class Neo.component.Base
@@ -577,9 +579,11 @@ class Base extends CoreBase {
577
579
  afterSetDomListeners(value, oldValue) {
578
580
  let me = this;
579
581
 
580
- me.getController()?.parseDomListeners(me);
582
+ if (value?.[0] || oldValue?.[0]) {
583
+ me.getController()?.parseDomListeners(me);
581
584
 
582
- DomEventManager.updateDomListeners(me, value, oldValue)
585
+ DomEventManager.updateDomListeners(me, value, oldValue)
586
+ }
583
587
  }
584
588
 
585
589
  /**
@@ -1240,7 +1244,7 @@ class Base extends CoreBase {
1240
1244
  * Creates a KeyNavigation instance if needed.
1241
1245
  * @param {Object} value
1242
1246
  * @param {Object} oldValue
1243
- * @returns {Neo.util.KeyNavigation}
1247
+ * @returns {Neo.util.KeyNavigation|null}
1244
1248
  * @protected
1245
1249
  */
1246
1250
  beforeSetKeys(value, oldValue) {
@@ -1503,10 +1507,10 @@ class Base extends CoreBase {
1503
1507
  const result = [];
1504
1508
 
1505
1509
  if (this.floating) {
1506
- result.push('neo-floating');
1510
+ result.push('neo-floating')
1507
1511
  }
1508
1512
 
1509
- return result;
1513
+ return result
1510
1514
  }
1511
1515
 
1512
1516
  /**
@@ -1543,7 +1547,24 @@ class Base extends CoreBase {
1543
1547
  * @returns {Neo.controller.Component|null}
1544
1548
  */
1545
1549
  getController(ntype) {
1546
- return this.getConfigInstanceByNtype('controller', ntype)
1550
+ let me = this,
1551
+ controller;
1552
+
1553
+ if (!ntype) {
1554
+ controller = me[closestController];
1555
+
1556
+ if (controller) {
1557
+ return controller
1558
+ }
1559
+ }
1560
+
1561
+ controller = me.getConfigInstanceByNtype('controller', ntype);
1562
+
1563
+ if (!ntype) {
1564
+ me[closestController] = controller;
1565
+ }
1566
+
1567
+ return controller
1547
1568
  }
1548
1569
 
1549
1570
  /**
@@ -1553,7 +1574,7 @@ class Base extends CoreBase {
1553
1574
  * @returns {Promise<Neo.util.Rectangle>}
1554
1575
  */
1555
1576
  async getDomRect(id=this.id, appName=this.appName) {
1556
- const result = await Neo.main.DomAccess.getBoundingClientRect({appName, id, windowId: this.windowId});
1577
+ let result = await Neo.main.DomAccess.getBoundingClientRect({appName, id, windowId: this.windowId});
1557
1578
 
1558
1579
  if (Array.isArray(result)) {
1559
1580
  return result.map(rect => Rectangle.clone(rect))
@@ -1572,7 +1593,24 @@ class Base extends CoreBase {
1572
1593
  return null
1573
1594
  }
1574
1595
 
1575
- return this.getConfigInstanceByNtype('model', ntype)
1596
+ let me = this,
1597
+ model;
1598
+
1599
+ if (!ntype) {
1600
+ model = me[closestModel];
1601
+
1602
+ if (model) {
1603
+ return model
1604
+ }
1605
+ }
1606
+
1607
+ model = me.getConfigInstanceByNtype('model', ntype);
1608
+
1609
+ if (!ntype) {
1610
+ me[closestModel] = model
1611
+ }
1612
+
1613
+ return model
1576
1614
  }
1577
1615
 
1578
1616
  /**
@@ -33,12 +33,28 @@ class Observable extends Base {
33
33
  * @returns {String|null} eventId null in case an object gets passed as the name (multiple ids)
34
34
  */
35
35
  addListener(name, opts, scope, eventId, data, order) {
36
- let me = this,
37
- delay = 0,
38
- nameObject = typeof name === 'object',
39
- once = false,
36
+ let me = this,
37
+ delay = 0,
38
+ eventIdObject = typeof eventId === 'object',
39
+ nameObject = typeof name === 'object',
40
+ once = false,
41
+ optsType = typeof opts,
40
42
  listener, existing, eventConfig;
41
43
 
44
+ /*
45
+ * let us support the following format too:
46
+ *
47
+ * currentWorker.on('connected', () => {
48
+ * Base.sendRemotes(className, remote)
49
+ * }, me, {once: true})
50
+ */
51
+ if (eventIdObject && optsType === 'function') {
52
+ eventId.fn = opts;
53
+ opts = eventId;
54
+ optsType = 'object';
55
+ eventId = null;
56
+ }
57
+
42
58
  if (nameObject) {
43
59
  if (name.hasOwnProperty('delay')) {
44
60
  delay = name.delay;
@@ -62,16 +78,16 @@ class Observable extends Base {
62
78
  me.addListener(key, {delay, fn: value, once, scope})
63
79
  }
64
80
  })
65
- } else if (typeof opts === 'object') {
81
+ } else if (optsType === 'object') {
66
82
  delay = delay || opts.delay;
67
83
  eventId = eventId || opts.eventId;
68
84
  listener = opts.fn;
69
85
  once = once || opts.once;
70
86
  order = order || opts.order;
71
87
  scope = scope || opts.scope
72
- } else if (typeof opts === 'function') {
88
+ } else if (optsType === 'function') {
73
89
  listener = opts
74
- } else if (typeof opts === 'string') {
90
+ } else if (optsType === 'string') {
75
91
  listener = opts // VC hook, can get parsed after onConstructed in case the view uses the parent VC
76
92
  } else {
77
93
  throw new Error('Invalid addListener call: ' + name)
@@ -77,6 +77,25 @@ class NeoIntersectionObserver extends Base {
77
77
  })
78
78
  }
79
79
 
80
+ /**
81
+ * @param {IntersectionObserverEntry[]} entries
82
+ * @param {IntersectionObserver} observer
83
+ */
84
+ isVisible(entries, observer) {
85
+ let me = this,
86
+ data, path, target;
87
+
88
+ entries.forEach(entry => {
89
+ target = entry.target;
90
+ data = target.dataset && {...target.dataset} || null;
91
+ path = DomEvents.getPathFromElement(entry.target).map(e => DomEvents.getTargetData(e));
92
+
93
+ if (entry.isIntersecting) {
94
+ me.sendMessage({data, id: observer.rootId, isIntersecting: true, path, targetId: target.id})
95
+ }
96
+ })
97
+ }
98
+
80
99
  /**
81
100
  * Add more or new items into an existing observer instance
82
101
  * @param {Object} data
@@ -128,7 +147,7 @@ class NeoIntersectionObserver extends Base {
128
147
  */
129
148
  register(data) {
130
149
  let me = this,
131
- cache = me.cache,
150
+ {cache} = me,
132
151
  {id, observe} = data,
133
152
  observer;
134
153
 
@@ -153,12 +153,14 @@ class Component extends Base {
153
153
  * @protected
154
154
  */
155
155
  beforeSetStores(value, oldValue) {
156
- let controller = this.component.getController();
156
+ if (value) {
157
+ let controller = this.component.getController();
157
158
 
158
- value && Object.entries(value).forEach(([key, storeValue]) => {
159
- controller?.parseConfig(storeValue);
160
- value[key] = ClassSystemUtil.beforeSetInstance(storeValue)
161
- });
159
+ Object.entries(value).forEach(([key, storeValue]) => {
160
+ controller?.parseConfig(storeValue);
161
+ value[key] = ClassSystemUtil.beforeSetInstance(storeValue)
162
+ })
163
+ }
162
164
 
163
165
  return value
164
166
  }
@@ -445,13 +447,13 @@ class Component extends Base {
445
447
  * @returns {Neo.model.Component|null}
446
448
  */
447
449
  getParent() {
448
- let me = this;
450
+ let {parent} = this;
449
451
 
450
- if (me.parent) {
451
- return me.parent
452
+ if (parent) {
453
+ return parent
452
454
  }
453
455
 
454
- return me.component.parent?.getModel() || null
456
+ return this.component.parent?.getModel() || null
455
457
  }
456
458
 
457
459
  /**