neo.mjs 6.34.0 → 6.36.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 (35) hide show
  1. package/README.md +15 -1
  2. package/apps/ServiceWorker.mjs +2 -2
  3. package/apps/colors/view/ViewportController.mjs +27 -17
  4. package/apps/portal/view/blog/List.mjs +38 -12
  5. package/apps/portal/view/home/FeatureSection.mjs +209 -0
  6. package/apps/portal/view/home/parts/Colors.mjs +34 -84
  7. package/apps/portal/view/home/parts/Features.mjs +1 -1
  8. package/apps/portal/view/home/parts/Helix.mjs +36 -95
  9. package/apps/portal/view/home/parts/How.mjs +31 -48
  10. package/apps/portal/view/learn/ContentView.mjs +53 -20
  11. package/examples/ServiceWorker.mjs +2 -2
  12. package/package.json +3 -3
  13. package/resources/data/deck/learnneo/pages/benefits/Multi-Threading.md +221 -0
  14. package/resources/data/deck/learnneo/tree.json +12 -13
  15. package/resources/scss/src/apps/portal/Viewport.scss +19 -0
  16. package/resources/scss/src/apps/portal/home/ContentBox.scss +9 -2
  17. package/resources/scss/src/apps/portal/home/FeatureSection.scss +68 -0
  18. package/resources/scss/src/apps/portal/home/parts/Colors.scss +0 -11
  19. package/resources/scss/src/apps/portal/home/parts/Helix.scss +1 -7
  20. package/resources/scss/src/apps/portal/home/parts/How.scss +0 -22
  21. package/resources/scss/src/apps/portal/learn/ContentView.scss +8 -0
  22. package/resources/scss/src/code/LivePreview.scss +1 -0
  23. package/src/DefaultConfig.mjs +2 -2
  24. package/src/Neo.mjs +5 -1
  25. package/src/code/LivePreview.mjs +16 -19
  26. package/src/component/Base.mjs +2 -2
  27. package/src/component/Toast.mjs +8 -8
  28. package/src/component/Video.mjs +22 -28
  29. package/src/component/wrapper/AmChart.mjs +15 -8
  30. package/src/main/addon/AmCharts.mjs +1 -1
  31. package/src/main/addon/IntersectionObserver.mjs +19 -3
  32. package/src/manager/DomEvent.mjs +1 -1
  33. package/src/worker/App.mjs +1 -1
  34. package/src/worker/mixin/RemoteMethodAccess.mjs +1 -3
  35. package/resources/data/deck/learnneo/pages/WhyNeo-Multi-Threaded.md +0 -15
@@ -1,15 +1,15 @@
1
1
  {"data": [
2
2
  {"name": "Welcome!", "parentId": null, "isLeaf": true, "id": "Welcome" },
3
- {"name": "Benefits?", "parentId": null, "isLeaf": false, "id": "WhyNeo"},
3
+ {"name": "Benefits", "parentId": null, "isLeaf": false, "id": "WhyNeo"},
4
4
  {"name": "Introduction ", "parentId": "WhyNeo", "isLeaf": true, "id": "WhyNeo-Intro"},
5
- {"name": "Multi-Threaded", "parentId": "WhyNeo", "isLeaf": true, "id": "WhyNeo-Multi-Threaded"},
5
+ {"name": "Multi-Threading", "parentId": "WhyNeo", "isLeaf": true, "id": "benefits.Multi-Threading"},
6
6
  {"name": "Extreme Speed", "parentId": "WhyNeo", "isLeaf": true, "id": "WhyNeo-Speed"},
7
7
  {"name": "Multi-Window Applications", "parentId": "WhyNeo", "isLeaf": true, "id": "WhyNeo-Multi-Window"},
8
8
  {"name": "Quick Application Development", "parentId": "WhyNeo", "isLeaf": true, "id": "WhyNeo-Quick"},
9
9
  {"name": "Complexity and Effort", "parentId": "WhyNeo", "isLeaf": true, "id": "WhyNeo-Effort"},
10
10
  {"name": "Features and Benefits Summary", "parentId": "WhyNeo", "isLeaf": true, "id": "WhyNeo-Features"},
11
11
  {"name": "Getting Started", "parentId": null, "isLeaf": false, "id": "GettingStarted", "collapsed": true},
12
- {"name": "Setup", "parentId": "GettingStarted", "isLeaf": true, "id": "Setup", "hidden": false},
12
+ {"name": "Setup", "parentId": "GettingStarted", "isLeaf": true, "id": "Setup"},
13
13
  {"name": "Workspaces and Applications", "parentId": "GettingStarted", "isLeaf": true, "id": "2023-10-14T19-25-08-153Z"},
14
14
  {"name": "Describing a View", "parentId": "GettingStarted", "isLeaf": true, "id": "DescribingTheUI"},
15
15
  {"name": "Events", "parentId": "GettingStarted", "isLeaf": true, "id": "Events"},
@@ -20,24 +20,23 @@
20
20
  {"name": "Tutorials", "parentId": null, "isLeaf": false, "expanded": false, "id": "Tutorials", "collapsed": true},
21
21
  {"name": "Rock Scissors Paper", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "RSP", "hidden": true},
22
22
  {"name": "Earthquakes", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "Earthquakes", "collapsed": true},
23
-
24
23
  {"name": "Todo List", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "TodoList"},
25
24
  {"name": "Guides", "parentId": null, "isLeaf": false, "expanded": false, "id": "InDepth", "collapsed": true},
26
25
  {"name": "Config", "parentId": "InDepth", "isLeaf": false, "id": "Config"},
27
- {"name": "Instance Lifecycle", "parentId": "InDepth", "isLeaf": false, "id": "InstanceLifecycle"},
28
- {"name": "User Input (Forms)", "parentId": "InDepth", "isLeaf": false, "id": "Forms"},
26
+ {"name": "Instance Lifecycle", "parentId": "InDepth", "isLeaf": false, "id": "InstanceLifecycle", "hidden": true},
27
+ {"name": "User Input (Forms)", "parentId": "InDepth", "isLeaf": false, "id": "Forms", "hidden": true},
29
28
  {"name": "Component and Container Basics", "parentId": "InDepth", "isLeaf": true, "id": "ComponentsAndContainers"},
30
- {"name": "Layouts", "parentId": "InDepth", "isLeaf": false, "id": "Layouts"},
29
+ {"name": "Layouts", "parentId": "InDepth", "isLeaf": false, "id": "Layouts", "hidden": true},
31
30
  {"name": "View Models", "parentId": "InDepth", "isLeaf": true, "id": "GuideViewModels"},
32
- {"name": "Custom Components", "parentId": "InDepth", "isLeaf": true, "id": "CustomComponents"},
31
+ {"name": "Custom Components", "parentId": "InDepth", "isLeaf": true, "id": "CustomComponents", "hidden": true},
33
32
  {"name": "Events", "parentId": "InDepth", "isLeaf": true, "expanded": false, "id": "GuideEvents"},
34
- {"name": "Tables (Stores)", "parentId": "InDepth", "isLeaf": false, "id": "Tables"},
35
- {"name": "Shared Bindable Data (Component Models)", "parentId": "InDepth", "isLeaf": false, "id": "InDepthComponentModels"},
36
- {"name": "Multi-Window Applications", "parentId": "InDepth", "isLeaf": false, "id": "MultiWindow"},
37
- {"name": "Main Thread Addons", "parentId": "InDepth", "isLeaf": false, "id": "MainThreadAddons"},
33
+ {"name": "Tables (Stores)", "parentId": "InDepth", "isLeaf": false, "id": "Tables", "hidden": true},
34
+ {"name": "Shared Bindable Data (Component Models)", "parentId": "InDepth", "isLeaf": false, "id": "InDepthComponentModels", "hidden": true},
35
+ {"name": "Multi-Window Applications", "parentId": "InDepth", "isLeaf": false, "id": "MultiWindow", "hidden": true},
36
+ {"name": "Main Thread Addons", "parentId": "InDepth", "isLeaf": false, "id": "MainThreadAddons", "hidden": true},
38
37
  {"name": "Introduction", "parentId": "MainThreadAddons", "isLeaf": true, "id": "MainThreadAddonIntro"},
39
38
  {"name": "Example", "parentId": "MainThreadAddons", "isLeaf": true, "id": "MainThreadAddonExample"},
40
- {"name": "Mixins", "parentId": "InDepth", "isLeaf": false, "id": "Mixins"},
39
+ {"name": "Mixins", "parentId": "InDepth", "isLeaf": false, "id": "Mixins", "hidden": true},
41
40
  {"name": "JavaScript Classes", "parentId": null, "isLeaf": false, "id": "JavaScriptClasses", "hidden": true},
42
41
  {"name": "Classes, Properties, and Methods", "parentId": "JavaScriptClasses", "isLeaf": true, "id": "2023-10-07T19-18-28-517Z"},
43
42
  {"name": "Overriding Methods", "parentId": "JavaScriptClasses", "isLeaf": true, "id": "2023-10-08T20-20-07-934Z"},
@@ -35,4 +35,23 @@ body {
35
35
  transform: translateZ(0px);
36
36
  }
37
37
  }
38
+
39
+ // the style will get used inside home & learn
40
+ .neo-worker-setup {
41
+ align-items : center;
42
+ background-color: #17141c;
43
+ display : flex;
44
+ height : 100%;
45
+ justify-content : center;
46
+ padding : 20px;
47
+ width : 100%;
48
+
49
+ --fill-opacity : 0.05;
50
+ --stroke-opacity: 0.05;
51
+
52
+ &:hover {
53
+ --fill-opacity : 1;
54
+ --stroke-opacity: 1;
55
+ }
56
+ }
38
57
  }
@@ -13,9 +13,16 @@
13
13
 
14
14
  .portal-content-box-content {
15
15
  padding-left: 1.3em;
16
+ margin-top: 0.75em;
16
17
  }
17
18
 
18
- .portal-content-box-header {
19
-
19
+ .portal-content-box-headline {
20
+ border-bottom: 1px solid #ececec;
21
+ padding-bottom: 0.75em;
22
+ max-width: 85%;
23
+ margin: 1em auto 0 auto;
24
+ text-align: center;
25
+ letter-spacing: 1.5px!important;
26
+ word-spacing: 1.5px;
20
27
  }
21
28
  }
@@ -0,0 +1,68 @@
1
+ .portal-home-feature-section {
2
+ align-items : stretch;
3
+ display : flex;
4
+ flex-wrap : nowrap;
5
+ justify-content : center;
6
+ min-height : 100%;
7
+ scroll-snap-align: center;
8
+
9
+ @media (max-width: 840px) {
10
+ flex-direction: column;
11
+ }
12
+
13
+ &.portal-position-end {
14
+ flex-direction: row-reverse;
15
+ }
16
+
17
+ .neo-content {
18
+ font-size: min(max(2.3vw, 16px), 30px);
19
+ }
20
+
21
+ .neo-h1 {
22
+ font-size : min(max(5.5vw, 30px), 64px);
23
+ line-height: 1em;
24
+ margin : 0;
25
+ text-align : center;
26
+ }
27
+
28
+ .neo-h2 {
29
+ font-size : min(max(3.5vw, 24px), 44px);
30
+ font-weight: 600;
31
+ line-height: 1em;
32
+ margin : 0;
33
+ text-align : center;
34
+ }
35
+
36
+ .page-live-preview {
37
+ height: 100%;
38
+ margin: 0;
39
+ }
40
+
41
+ .portal-content-text {
42
+ align-items : center;
43
+ display : flex;
44
+ flex : 1;
45
+ flex-direction : column;
46
+ flex-wrap : nowrap;
47
+ justify-content: center;
48
+ padding : 2rem;
49
+
50
+ @media (max-width: 600px) {
51
+ flex : .5 !important;
52
+ justify-content: start;
53
+ padding : 1rem;
54
+ }
55
+ }
56
+
57
+ .portal-content-wrapper {
58
+ background-color: lightgray;
59
+ flex : 2;
60
+ padding : 20px;
61
+
62
+ @media (max-width: 600px) {
63
+ max-height: 35em;
64
+ min-height: 35em;
65
+ padding : 5px;
66
+ }
67
+ }
68
+ }
@@ -1,14 +1,3 @@
1
1
  .portal-home-parts-colors {
2
- @media (max-width: 840px) {
3
- &.neo-flex-container {
4
- flex-direction: column;
5
- }
6
- }
7
2
 
8
- @media (max-width: 600px) {
9
- .portal-content-wrapper {
10
- max-height: 46em;
11
- min-height: 46em;
12
- }
13
- }
14
3
  }
@@ -1,13 +1,7 @@
1
1
  .portal-home-parts-helix {
2
- @media (max-width: 840px) {
3
- &.neo-flex-container {
4
- flex-direction: column;
5
- }
6
- }
7
-
8
2
  @media (max-width: 600px) {
9
3
  .portal-content-text {
10
- min-height: 40em;
4
+ min-height: 23em;
11
5
  }
12
6
  }
13
7
  }
@@ -1,25 +1,7 @@
1
1
  .portal-home-parts-how {
2
- .neo-worker-setup {
3
- align-items : center;
4
- display : flex;
5
- height : 100%;
6
- justify-content: center;
7
- width : 100%;
8
-
9
- --fill-opacity : 0.05;
10
- --stroke-opacity: 0.05;
11
-
12
- &:hover {
13
- --fill-opacity : 1;
14
- --stroke-opacity: 1;
15
- }
16
- }
17
-
18
2
  .portal-content-container {
19
- background-color: #17141c;
20
3
  border : 1px solid #e6e6e6;
21
4
  border-radius : 8px;
22
- padding : 20px;
23
5
  }
24
6
 
25
7
  @media (max-width: 500px) {
@@ -33,10 +15,6 @@
33
15
  @media (max-width: 840px) {
34
16
  min-height: 100%;
35
17
 
36
- &.neo-flex-container {
37
- flex-direction: column;
38
- }
39
-
40
18
  .portal-content-text {
41
19
  flex: 0.8 !important;
42
20
  }
@@ -19,6 +19,14 @@
19
19
  padding : 12px;
20
20
  }
21
21
 
22
+ blockquote {
23
+ background-color: var(--sem-color-bg-neutral-default);;
24
+ border-left : 4px solid var(--sem-color-border-default);
25
+ font-style : italic;
26
+ margin-left : 0;
27
+ padding : 5px 5px 5px 15px;
28
+ }
29
+
22
30
  p {
23
31
  margin: 0.5em 0 0.7em 0;
24
32
  }
@@ -1,4 +1,5 @@
1
1
  .neo-code-live-preview {
2
+ height : 400px;
2
3
  margin-bottom : 2em;
3
4
  transition-duration : .3s;
4
5
  transition-property : height, left, top, width;
@@ -260,12 +260,12 @@ const DefaultConfig = {
260
260
  useVdomWorker: true,
261
261
  /**
262
262
  * buildScripts/injectPackageVersion.mjs will update this value
263
- * @default '6.34.0'
263
+ * @default '6.36.0'
264
264
  * @memberOf! module:Neo
265
265
  * @name config.version
266
266
  * @type String
267
267
  */
268
- version: '6.34.0'
268
+ version: '6.36.0'
269
269
  };
270
270
 
271
271
  Object.assign(DefaultConfig, {
package/src/Neo.mjs CHANGED
@@ -633,7 +633,7 @@ function autoGenerateGetSet(proto, key) {
633
633
  }
634
634
 
635
635
  if (!Neo[getSetCache]) {
636
- Neo[getSetCache] = {};
636
+ Neo[getSetCache] = {}
637
637
  }
638
638
 
639
639
  if (!Neo[getSetCache][key]) {
@@ -667,6 +667,10 @@ function autoGenerateGetSet(proto, key) {
667
667
  },
668
668
 
669
669
  set(value) {
670
+ if (value === undefined) {
671
+ return
672
+ }
673
+
670
674
  let me = this,
671
675
  _key = '_' + key,
672
676
  uKey = key[0].toUpperCase() + key.slice(1),
@@ -48,10 +48,6 @@ class LivePreview extends Container {
48
48
  * @member {Boolean} enableFullscreen=true
49
49
  */
50
50
  enableFullscreen: true,
51
- /**
52
- * @member {Number} height=400
53
- */
54
- height: 400,
55
51
  /**
56
52
  * @member {Object|String} layout='fit'
57
53
  */
@@ -226,11 +222,14 @@ class LivePreview extends Container {
226
222
  }
227
223
 
228
224
  let me = this,
225
+ container = me.getPreviewContainer(),
229
226
  source = me.editorValue || me.value,
230
227
  cleanLines = [],
231
- importModuleNames = [],
232
228
  moduleNameAndPath = [],
233
- className = me.findLastClassName(source);
229
+ className = me.findLastClassName(source),
230
+ params = [],
231
+ vars = [],
232
+ codeString, promises;
234
233
 
235
234
  source.split('\n').forEach(line => {
236
235
  let importMatch = line.match(importRegex);
@@ -239,18 +238,14 @@ class LivePreview extends Container {
239
238
  let moduleName = importMatch[1],
240
239
  path = importMatch[2];
241
240
 
242
- moduleNameAndPath.push({moduleName, path});
243
-
244
- importModuleNames.push(moduleName);
241
+ moduleNameAndPath.push({moduleName, path})
245
242
  } else if (line.match(exportRegex)) {
246
243
  // Skip export statements
247
244
  } else {
248
- cleanLines.push(` ${line}`);
245
+ cleanLines.push(` ${line}`)
249
246
  }
250
247
  });
251
248
 
252
- var params = [];
253
- var vars = [];
254
249
  // Figure out the parts of the source we'll be running.
255
250
  // o The promises/import() corresponding to the user's import statements
256
251
  // o The vars holding the name of the imported module based on the module name for each import
@@ -266,14 +261,13 @@ class LivePreview extends Container {
266
261
  // });
267
262
  // Making the promise part of the eval seems weird, but it made it easier to
268
263
  // set up the import vars.
269
-
270
- let promises = moduleNameAndPath.map(item => {
264
+ promises = moduleNameAndPath.map(item => {
271
265
  params.push(`${item.moduleName}Module`);
272
266
  vars.push(` const ${item.moduleName} = ${item.moduleName}Module.default;`);
273
267
  return `import('${item.path}')`
274
268
  });
275
269
 
276
- const codeString = [
270
+ codeString = [
277
271
  'Promise.all([',
278
272
  ` ${promises.join(',\n')}`,
279
273
  `]).then(([${params.join(', ')}]) => {`,
@@ -287,7 +281,6 @@ class LivePreview extends Container {
287
281
  '.catch(error => container.add({ntype:\'component\', html:error.message}));'
288
282
  ].join('\n')
289
283
 
290
- const container = me.getPreviewContainer();
291
284
  container.removeAll();
292
285
 
293
286
  try {
@@ -338,14 +331,18 @@ class LivePreview extends Container {
338
331
  * @param {Number} data.value
339
332
  */
340
333
  onActiveIndexChange(data) {
341
- let me = this,
342
- hidden = data.value !== 1;
334
+ let me = this,
335
+ isPreview = data.value === 1;
343
336
 
344
337
  if (data.item.reference === 'preview') {
345
338
  me.doRunSource()
346
339
  }
340
+ // Navigating to the source view should destroy the app, in case the preview view is not popped out
341
+ else if (!isPreview && !me.previewContainer) {
342
+ me.getReference('preview').removeAll()
343
+ }
347
344
 
348
- me.getReference('popout-window-button').hidden = hidden
345
+ me.getReference('popout-window-button').hidden = !isPreview
349
346
  me.disableRunSource = false;
350
347
  }
351
348
 
@@ -275,9 +275,9 @@ class Base extends CoreBase {
275
275
  parentComponent_: null,
276
276
  /**
277
277
  * The parent component id or document.body
278
- * @member {String} parentId='document.body'
278
+ * @member {String} parentId_='document.body'
279
279
  */
280
- parentId: 'document.body',
280
+ parentId_: 'document.body',
281
281
  /**
282
282
  * Array of Plugin Modules and / or config objects
283
283
  * @member {Array|null} plugins_=null
@@ -114,17 +114,17 @@ class Toast extends Base {
114
114
  }]}
115
115
  }
116
116
 
117
+ /**
118
+ * Timeout in ms after which the toast is removed
119
+ * @member {Number} removeDelay=3000
120
+ */
121
+ removeDelay = 3000
117
122
  /**
118
123
  * Used by the ToastManager
119
124
  * @member {Boolean} running=false
120
125
  * @private
121
126
  */
122
127
  running = false
123
- /**
124
- * Timeout in ms after which the toast is removed
125
- * @member {Number} timeout=3000
126
- */
127
- timeout = 3000 // todo: conflicting class field name => timeout()
128
128
 
129
129
  /**
130
130
  * @param {Object} config
@@ -206,9 +206,9 @@ class Toast extends Base {
206
206
  let me = this;
207
207
 
208
208
  if (!me.closable && value) {
209
- setTimeout(() => {
210
- this.destroy(true)
211
- }, me.timeout)
209
+ me.timeout(me.removeDelay).then(() => {
210
+ me.destroy(true)
211
+ })
212
212
  }
213
213
  }
214
214
 
@@ -38,8 +38,7 @@ class Video extends BaseComponent {
38
38
  */
39
39
  autoplay: false,
40
40
  /**
41
- * In case the browser does not support the video source
42
- * the component should show an error.
41
+ * In case the browser does not support the video source the component should show an error.
43
42
  * @member {Boolean} errorMsg='The browser does not support the video'
44
43
  */
45
44
  errorMsg: 'Your browser does not support the video tag.',
@@ -90,25 +89,7 @@ class Video extends BaseComponent {
90
89
  let me = this;
91
90
 
92
91
  me.handleAutoplay();
93
- me.addDomListeners(
94
- {click: me.play, delegate: '.neo-video-ghost'},
95
- {click: me.pause, delegate: '.neo-video-media'}
96
- )
97
- }
98
-
99
- /**
100
- * beforeSetPlaying autgen by playing_
101
- *
102
- * @param {Boolean} value
103
- * @param {Boolean} oldValue
104
- * @returns {Boolean}
105
- */
106
- beforeSetPlaying(value, oldValue) {
107
- if (!Neo.isBoolean(value)) {
108
- return oldValue
109
- }
110
-
111
- return value
92
+ me.addDomListeners({click: me.play, delegate: '.neo-video-ghost'});
112
93
  }
113
94
 
114
95
  /**
@@ -137,23 +118,37 @@ class Video extends BaseComponent {
137
118
  afterSetUrl(value, oldValue) {
138
119
  if (!value) return;
139
120
 
140
- let {vdom} = this,
141
- media = VDomUtil.getFlags(vdom, 'media')[0];
121
+ let {vdom} = this,
122
+ media = VDomUtil.getFlags(vdom, 'media')[0],
123
+ ua = navigator.userAgent || navigator.vendor || window.opera,
124
+ isOperaMini = /Opera Mini/i.test(ua);
142
125
 
143
126
  media.cn = [{
144
127
  tag: 'source',
145
128
  src: value,
146
129
  type: this.type
147
- }, {
148
- tag: 'span',
149
- html: this.errorMsg,
150
130
  }];
151
131
 
132
+ // Opera Mini might not support the video-source => check the user agent string
133
+ if (isOperaMini) {
134
+ media.cn.push({
135
+ tag: 'span',
136
+ html: this.errorMsg,
137
+ });
138
+ }
139
+
152
140
  this.update()
153
141
  }
154
142
 
155
143
  /**
156
144
  * autoplay - run the event listeners
145
+ * Only called in constructor and sets playing => calls update already
146
+ *
147
+ * Rationale: update() sends the vdom & vnode on a workers roundtrip to get the deltas.
148
+ * While this is happening, the component locks itself for future updates until the new vnode got back (async).
149
+ * After the delay the framework would trigger a 2nd roundtrip to get the deltas for the visible node.
150
+ *
151
+ * @protected
157
152
  */
158
153
  handleAutoplay() {
159
154
  if (!this.autoplay) return;
@@ -166,12 +161,11 @@ class Video extends BaseComponent {
166
161
  // Allows inline playback on iOS devices
167
162
  media.playsInline = true;
168
163
 
169
- this.update();
170
164
  this.playing = true;
171
165
  }
172
166
 
173
167
  /**
174
- * Clicked media
168
+ * Simulates `Clicked media` programmatically
175
169
  */
176
170
  pause() {
177
171
  this.playing = false
@@ -89,24 +89,23 @@ class AmChart extends Component {
89
89
  * @protected
90
90
  */
91
91
  afterSetMounted(value, oldValue) {
92
- let me = this,
93
- {appName, id, windowId} = me;
92
+ let me = this,
93
+ {appName, id, windowId} = me,
94
+ opts = {appName, id, windowId};
94
95
 
95
96
  if (value === false && oldValue !== undefined) {
96
- Neo.main.addon.AmCharts.destroy({appName, id, windowId})
97
+ Neo.main.addon.AmCharts.destroy(opts)
97
98
  }
98
99
 
99
100
  super.afterSetMounted(value, oldValue);
100
101
 
101
102
  if (value) {
102
- let opts = {
103
- appName,
103
+ opts = {
104
+ ...opts,
104
105
  combineSeriesTooltip: me.combineSeriesTooltip,
105
106
  config : me.chartConfig,
106
- id,
107
107
  package : me.package,
108
- type : me.chartType,
109
- windowId
108
+ type : me.chartType
110
109
  };
111
110
 
112
111
  if (me.chartData) {
@@ -136,6 +135,14 @@ class AmChart extends Component {
136
135
  return value
137
136
  }
138
137
 
138
+ destroy(...args) {
139
+ let {appName, id, windowId} = this;
140
+
141
+ Neo.main.addon.AmCharts.destroy({appName, id, windowId})
142
+
143
+ super.destroy(...args)
144
+ }
145
+
139
146
  /**
140
147
  *
141
148
  */
@@ -181,7 +181,7 @@ class AmCharts extends Base {
181
181
  * @param {String} data.id
182
182
  */
183
183
  destroy(data) {
184
- this.charts[data.id].dispose();
184
+ this.charts[data.id]?.dispose?.();
185
185
  delete this.charts[data.id]
186
186
  }
187
187
 
@@ -102,11 +102,14 @@ class NeoIntersectionObserver extends Base {
102
102
  * @param {Boolean} [data.disconnect=false] true removes all currently observed targets
103
103
  * @param {String} data.id
104
104
  * @param {String|String[]} data.observe The querySelector to match elements
105
- * @returns {Boolean} true in case the targets got observed, false in case they got cached prior to a register() call
105
+ * @returns {Object} opts
106
+ * {Boolean} opts.cached : true in case the observer is not registered yet
107
+ * {Number} opts.countTargets: amount of found target nodes inside the DOM
106
108
  */
107
109
  observe(data) {
108
110
  let me = this,
109
111
  cache = me.cache,
112
+ cached = false,
110
113
  {id, observe} = data,
111
114
  observer = me.map[data.id],
112
115
  targets = [];
@@ -126,6 +129,8 @@ class NeoIntersectionObserver extends Base {
126
129
  observer.observe(target)
127
130
  })
128
131
  } else {
132
+ cached = true;
133
+
129
134
  if (!cache[id]) {
130
135
  cache[id] = []
131
136
  }
@@ -133,7 +138,10 @@ class NeoIntersectionObserver extends Base {
133
138
  cache[id].push(data);
134
139
  }
135
140
 
136
- return !!observer
141
+ return {
142
+ cached,
143
+ countTargets: targets.length
144
+ }
137
145
  }
138
146
 
139
147
  /**
@@ -144,11 +152,15 @@ class NeoIntersectionObserver extends Base {
144
152
  * @param {String} data.root
145
153
  * @param {String} data.rootMargin='0px'
146
154
  * @param {Number|Number[]} data.threshold=0.0
155
+ * @returns {Boolean}
156
+ * if data.observe is passed: true in case there is at least one found target node inside the DOM
157
+ * if data.observe is not passed: true
147
158
  */
148
159
  register(data) {
149
160
  let me = this,
150
161
  {cache} = me,
151
162
  {id, observe} = data,
163
+ returnValue = true,
152
164
  observer;
153
165
 
154
166
  me.map[id] = observer = new IntersectionObserver(me[data.callback].bind(me), {
@@ -159,12 +171,16 @@ class NeoIntersectionObserver extends Base {
159
171
 
160
172
  observer.rootId = data.id; // storing the component id
161
173
 
162
- observe && me.observe({id, observe});
174
+ if (observe) {
175
+ returnValue = me.observe({id, observe})
176
+ }
163
177
 
164
178
  if (cache[id]) {
165
179
  cache[id].forEach(item => me.observe(item));
166
180
  delete cache[id]
167
181
  }
182
+
183
+ return returnValue
168
184
  }
169
185
 
170
186
  /**