neo.mjs 6.18.3 → 6.19.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 (81) hide show
  1. package/README.md +28 -214
  2. package/apps/ServiceWorker.mjs +2 -2
  3. package/apps/colors/view/ViewportController.mjs +7 -3
  4. package/apps/portal/data/blog.json +13 -0
  5. package/apps/portal/view/HeaderToolbar.mjs +2 -2
  6. package/apps/portal/view/Viewport.mjs +4 -2
  7. package/apps/portal/view/ViewportController.mjs +89 -8
  8. package/apps/portal/view/blog/Container.mjs +8 -8
  9. package/apps/portal/view/blog/List.mjs +6 -6
  10. package/apps/portal/view/home/MainContainer.mjs +3 -2
  11. package/apps/portal/view/home/parts/Colors.mjs +2 -2
  12. package/apps/portal/view/home/parts/How.mjs +3 -3
  13. package/apps/portal/view/home/parts/MainNeo.mjs +6 -7
  14. package/apps/portal/view/home/parts/References.mjs +88 -0
  15. package/apps/portal/view/learn/MainContainer.mjs +3 -2
  16. package/apps/portal/view/learn/MainContainerController.mjs +11 -0
  17. package/apps/portal/view/learn/PageContainer.mjs +5 -3
  18. package/apps/portal/view/services/Component.mjs +73 -0
  19. package/apps/website/data/blog.json +13 -0
  20. package/examples/ServiceWorker.mjs +2 -2
  21. package/examples/component/carousel/MainContainer.mjs +42 -33
  22. package/examples/layout/cube/MainContainer.mjs +217 -0
  23. package/examples/layout/cube/app.mjs +6 -0
  24. package/examples/layout/cube/index.html +11 -0
  25. package/examples/layout/cube/neo-config.json +6 -0
  26. package/package.json +6 -6
  27. package/resources/data/deck/learnneo/pages/Earthquakes-01-goals.md +32 -0
  28. package/resources/data/deck/learnneo/pages/Earthquakes-Lab-01-generate-a-workspace.md +47 -0
  29. package/resources/data/deck/learnneo/pages/Earthquakes-Lab-02-generate-the-starter-app.md +150 -0
  30. package/resources/data/deck/learnneo/pages/Earthquakes-Lab-03-debugging.md +136 -0
  31. package/resources/data/deck/learnneo/pages/Earthquakes-Lab-04-fetch-data.md +146 -0
  32. package/resources/data/deck/learnneo/pages/Earthquakes-Lab-05-refactor-the-table.md +146 -0
  33. package/resources/data/deck/learnneo/pages/Earthquakes-Lab-06-use-a-view-model.md +301 -0
  34. package/resources/data/deck/learnneo/pages/Earthquakes-Lab-07-use-the-google-maps-addon.md +175 -0
  35. package/resources/data/deck/learnneo/pages/Earthquakes-Lab-08-events.md +38 -0
  36. package/resources/data/deck/learnneo/pages/Earthquakes.md +8 -8
  37. package/resources/data/deck/learnneo/pages/Glossary.md +0 -0
  38. package/resources/data/deck/learnneo/pages/GuideEvents.md +80 -1
  39. package/resources/data/deck/learnneo/tree.json +2 -1
  40. package/resources/images/apps/portal/neo-references.png +0 -0
  41. package/resources/scss/src/apps/portal/Viewport.scss +18 -0
  42. package/resources/scss/src/apps/portal/blog/Container.scss +7 -7
  43. package/resources/scss/src/apps/portal/blog/List.scss +20 -16
  44. package/resources/scss/src/apps/portal/home/parts/MainNeo.scss +4 -5
  45. package/resources/scss/src/apps/portal/home/parts/References.scss +46 -0
  46. package/resources/scss/src/apps/portal/learn/ContentTreeList.scss +20 -0
  47. package/resources/scss/src/apps/portal/learn/ContentView.scss +4 -0
  48. package/resources/scss/src/apps/portal/learn/MainContainer.scss +1 -1
  49. package/resources/scss/src/apps/portal/learn/PageContainer.scss +22 -16
  50. package/resources/scss/src/apps/portal/services/Component.scss +20 -0
  51. package/resources/scss/src/component/Carousel.scss +21 -0
  52. package/resources/scss/src/examples/layout/cube/MainContainer.scss +7 -0
  53. package/resources/scss/src/layout/Cube.scss +80 -0
  54. package/resources/scss/src/tab/Container.scss +10 -10
  55. package/resources/scss/theme-neo-light/apps/portal/blog/Container.scss +3 -0
  56. package/resources/scss/theme-neo-light/form/field/Search.scss +1 -1
  57. package/resources/scss/theme-neo-light/tooltip/Base.scss +1 -1
  58. package/src/DefaultConfig.mjs +2 -2
  59. package/src/Main.mjs +15 -1
  60. package/src/Neo.mjs +14 -3
  61. package/src/component/Base.mjs +18 -1
  62. package/src/container/Base.mjs +3 -1
  63. package/src/dialog/Base.mjs +1 -2
  64. package/src/layout/Base.mjs +43 -6
  65. package/src/layout/Card.mjs +21 -59
  66. package/src/layout/Cube.mjs +428 -0
  67. package/src/layout/Fit.mjs +9 -38
  68. package/src/layout/Flexbox.mjs +16 -17
  69. package/src/layout/Form.mjs +13 -70
  70. package/src/layout/Grid.mjs +6 -18
  71. package/src/main/mixin/DeltaUpdates.mjs +16 -3
  72. package/src/util/Array.mjs +36 -0
  73. package/src/vdom/Helper.mjs +328 -445
  74. package/src/vdom/VNode.mjs +12 -1
  75. package/test/siesta/siesta.js +16 -1
  76. package/test/siesta/tests/VdomCalendar.mjs +2111 -37
  77. package/test/siesta/tests/VdomHelper.mjs +283 -47
  78. package/test/siesta/tests/vdom/Advanced.mjs +367 -0
  79. package/test/siesta/tests/vdom/layout/Cube.mjs +189 -0
  80. package/test/siesta/tests/vdom/table/Container.mjs +133 -0
  81. package/resources/scss/theme-neo-light/apps/portal/learn/ContentTreeList.scss +0 -23
@@ -18,7 +18,8 @@
18
18
  {"name": "Shared Bindable Data", "parentId": "GettingStarted", "isLeaf": true, "id": "ComponentModels"},
19
19
  {"name": "Tutorials", "parentId": null, "isLeaf": false, "expanded": false, "id": "Tutorials", "collapsed": true},
20
20
  {"name": "Rock Scissors Paper", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "RSP", "hidden": true},
21
- {"name": "Earthquakes", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "Earthquakes"},
21
+ {"name": "Earthquakes", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "Earthquakes", "collapsed": true},
22
+
22
23
  {"name": "Todo List", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "TodoList"},
23
24
  {"name": "Guides", "parentId": null, "isLeaf": false, "expanded": false, "id": "InDepth", "collapsed": true},
24
25
  {"name": "Config", "parentId": "InDepth", "isLeaf": false, "id": "Config"},
@@ -0,0 +1,18 @@
1
+ .neo-viewport {
2
+ .neo-layout-cube {
3
+ &.neo-animate {
4
+ .neo-box {
5
+ transition: transform 800ms ease-in-out;
6
+ }
7
+ }
8
+
9
+ .neo-face {
10
+ opacity: 0.8;
11
+ transition: opacity 50ms ease-out;
12
+ }
13
+
14
+ .neo-plane {
15
+ transform: translateZ(0px);
16
+ }
17
+ }
18
+ }
@@ -1,18 +1,18 @@
1
- .website-blog-container {
2
- .website-blog-searchfield {
3
- transition: margin var(--website-transition-duration) ease-out;
1
+ .portal-blog-container {
2
+ .portal-blog-searchfield {
3
+ transition: margin var(--portal-transition-duration) ease-out;
4
4
  width : 240px;
5
5
 
6
6
  @media (max-height: 400px), (max-width: 600px) {
7
- margin: 5px;
7
+ margin: 5px auto;
8
8
  }
9
9
 
10
10
  @media (min-height: 401px) and (min-width: 601px) {
11
- margin: 10px;
11
+ margin: 10px auto;
12
12
  }
13
13
  }
14
14
 
15
- .website-blog-toolbar {
16
- background-color: var(--website-blog-toolbar-background-color);
15
+ .portal-blog-toolbar {
16
+ background-color: var(--portal-blog-toolbar-background-color);
17
17
  }
18
18
  }
@@ -1,15 +1,17 @@
1
- .website-blog-list.neo-list {
2
- transition: padding var(--website-transition-duration) ease-out;
1
+ .portal-blog-list.neo-list {
2
+ transition: padding var(--portal-transition-duration) ease-out;
3
3
 
4
4
  .neo-list-item {
5
- cursor : default;
6
- display : flex;
7
- max-width : 800px;
8
- overflow : hidden;
9
- padding : 0;
10
- transition : height var(--website-transition-duration) ease-out, margin-bottom var(--website-transition-duration) ease-out;
11
- white-space: normal;
12
- width : 100%;
5
+ cursor : default;
6
+ display : flex;
7
+ margin-left : auto;
8
+ margin-right: auto;
9
+ max-width : 800px;
10
+ overflow : hidden;
11
+ padding : 0;
12
+ transition : height var(--portal-transition-duration) ease-out, margin-bottom var(--portal-transition-duration) ease-out;
13
+ white-space : normal;
14
+ width : 100%;
13
15
 
14
16
  .content {
15
17
  flex: 1;
@@ -32,7 +34,7 @@
32
34
  display : inline-block;
33
35
  margin-left: 10px;
34
36
  text-shadow: 1px 1px 1px #000, 1px 1px 1px #fff;
35
- transition : font-size var(--website-transition-duration) ease-out;
37
+ transition : font-size var(--portal-transition-duration) ease-out;
36
38
  }
37
39
 
38
40
  .neo-full-size {
@@ -41,13 +43,13 @@
41
43
  }
42
44
 
43
45
  .neo-inner-details {
44
- transition: line-height var(--website-transition-duration) ease-out;
46
+ transition: line-height var(--portal-transition-duration) ease-out;
45
47
  }
46
48
 
47
49
  .neo-item-bottom-position {
48
50
  bottom : 0;
49
51
  left : 0;
50
- transition: margin var(--website-transition-duration) ease-out;
52
+ transition: margin var(--portal-transition-duration) ease-out;
51
53
  }
52
54
 
53
55
  .neo-item-top-position {
@@ -55,11 +57,13 @@
55
57
  right : 0;
56
58
  text-align : end;
57
59
  text-shadow: 1px 1px 1px #000, 1px 1px 1px #fff;
58
- transition : font-size var(--website-transition-duration) ease-out, margin var(--website-transition-duration) ease-out;
60
+ transition : font-size var(--portal-transition-duration) ease-out, margin var(--portal-transition-duration) ease-out;
59
61
  }
60
62
 
61
63
  .neo-relative {
64
+ height : 100%;
62
65
  position: relative;
66
+ width : 100%;
63
67
  }
64
68
 
65
69
  .neo-title {
@@ -78,13 +82,13 @@
78
82
  .neo-top-20 {
79
83
  align-items: center;
80
84
  display : flex;
81
- transition : margin var(--website-transition-duration) ease-out;
85
+ transition : margin var(--portal-transition-duration) ease-out;
82
86
  }
83
87
 
84
88
  .neo-user-image {
85
89
  border-radius: 50%;
86
90
  display : inline-block;
87
- transition : height var(--website-transition-duration) ease-out, width var(--website-transition-duration) ease-out;
91
+ transition : height var(--portal-transition-duration) ease-out, width var(--portal-transition-duration) ease-out;
88
92
  }
89
93
 
90
94
  .preview-image {
@@ -2,13 +2,13 @@
2
2
  padding: 3em;
3
3
 
4
4
  .button-group {
5
- display : flex !important;
6
- flex-direction: row-reverse !important;
7
- gap : 8px !important;
5
+ display : flex;
6
+ flex-direction: row-reverse;
7
+ gap : 8px;
8
8
  }
9
9
 
10
10
  .neo-h1 {
11
- margin-bottom: 1.25em;
11
+ margin: 3rem;
12
12
  }
13
13
 
14
14
  .vector {
@@ -17,7 +17,6 @@
17
17
  background-repeat : no-repeat;
18
18
  background-size : contain;
19
19
  height : 10vW;
20
- margin : 0 0 3rem 0;
21
20
  max-height : 130px;
22
21
  width : 100%;
23
22
  }
@@ -0,0 +1,46 @@
1
+ .portal-references {
2
+ user-select: none;
3
+
4
+ .neo-carousel {
5
+ width: 90%;
6
+ height: 350px;
7
+ margin: 0 auto;
8
+
9
+ .neo-carousel-inner {
10
+ border-radius: 15px;
11
+ border: 1px solid var(--sem-color-fg-neutral-contrast);
12
+ color: var(--sem-color-fg-neutral-contrast);
13
+
14
+
15
+ &:before {
16
+ content: '';
17
+ position: absolute;
18
+ top: 0;
19
+ bottom: 0;
20
+ left: 0;
21
+ width: 90px;
22
+ z-index: 11;
23
+ background: {
24
+ color: var(--toolbar-background-color);
25
+ image: url('../../../../../../../../resources/images/apps/portal/neo-references.png');
26
+ position: center;
27
+ repeat: no-repeat;
28
+ size: 70% auto;
29
+ }
30
+ }
31
+
32
+ .neo-carousel-item {
33
+ padding-left: 110px;
34
+ display: flex;
35
+ flex-direction: column;
36
+ justify-content: space-evenly;
37
+
38
+ .neo-details {
39
+ margin-top: 1em;
40
+ font-weight: 700;
41
+ font-style: italic;
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
@@ -6,6 +6,26 @@
6
6
  background-color: white;
7
7
  padding : 8px 2px 8px 8px;
8
8
 
9
+ &.neo-tree-list {
10
+ .neo-list-container {
11
+ .neo-list-item {
12
+ .neo-list-item-content:before {
13
+ content: unset !important;
14
+ }
15
+
16
+ &.neo-list-folder {
17
+ .neo-list-item-content:before {
18
+ content: unset !important;
19
+ }
20
+
21
+ &.neo-folder-open .neo-list-item-content:before {
22
+ content: unset !important;
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+
9
29
  .neo-list-container {
10
30
  padding: 3px;
11
31
  }
@@ -18,6 +18,10 @@
18
18
  margin: 0.5em 0 0.7em 0;
19
19
  }
20
20
 
21
+ details {
22
+ margin: 1em 0 1em 0;
23
+ }
24
+
21
25
  details summary {
22
26
  cursor : pointer;
23
27
  transition: margin 300ms ease-out;
@@ -1,4 +1,4 @@
1
- .learnneo-maincontainer {
1
+ .portal-learn-maincontainer {
2
2
  background-color: #f2f2f2;
3
3
 
4
4
  .main-content-splitter {
@@ -1,11 +1,12 @@
1
- .learn-content-container {
1
+ .portal-learn-page-container {
2
2
  overflow: auto;
3
3
 
4
4
  .content-bottom-toolbar {
5
- gap : 8px;
6
- padding : 0 3rem;
7
- margin-bottom: 3rem;
8
- margin-top : 3rem;
5
+ gap : 8px;
6
+ grid-template-columns: repeat(2, 1fr);
7
+ margin-bottom : 3rem;
8
+ margin-top : 3rem;
9
+ padding : 0 3rem;
9
10
 
10
11
  .neo-button {
11
12
  flex : 1 !important;
@@ -18,18 +19,23 @@
18
19
  }
19
20
 
20
21
  .content-bottom-toolbar-previous:before {
21
- content : 'Previous Page';
22
- font-family : var(--core-fontfamily-sans);
23
- position : absolute;
24
- top : var(--cmp-button-spacinghorizontal);
25
- left : var(--cmp-button-spacinghorizontal);
22
+ content : 'Previous Page';
23
+ font-family: var(--core-fontfamily-sans);
24
+ left : var(--cmp-button-spacinghorizontal);
25
+ position : absolute;
26
+ top : var(--cmp-button-spacinghorizontal);
26
27
  }
27
- .content-bottom-toolbar-next:before {
28
- content : 'Next Page';
29
- font-family : var(--core-fontfamily-sans);
30
- position : absolute;
31
- top : var(--cmp-button-spacinghorizontal);
32
- right : var(--cmp-button-spacinghorizontal);
28
+
29
+ .content-bottom-toolbar-next {
30
+ grid-column: 2/3;
31
+
32
+ &:before {
33
+ content : 'Next Page';
34
+ font-family: var(--core-fontfamily-sans);
35
+ position : absolute;
36
+ right : var(--cmp-button-spacinghorizontal);
37
+ top : var(--cmp-button-spacinghorizontal);
38
+ }
33
39
  }
34
40
  }
35
41
  }
@@ -0,0 +1,20 @@
1
+ .portal-services-component {
2
+ background-color: #fff !important;
3
+ padding : 1em 6em;
4
+
5
+ .info-block {
6
+ background-color: lighten(#8BA6FF, 10%);
7
+ border-radius : 10px;
8
+ margin-left : auto;
9
+ margin-right : auto;
10
+ margin-top : 2em;
11
+ max-width : 800px;
12
+ padding : 0.5em 3em 1em 3em;
13
+ }
14
+
15
+ h1 {
16
+ margin-left : auto;
17
+ margin-right: auto;
18
+ width : fit-content;
19
+ }
20
+ }
@@ -68,9 +68,30 @@
68
68
  height : 9rem;
69
69
  overflow : hidden;
70
70
 
71
+ &:before {
72
+ content: '';
73
+ position: absolute;
74
+ background: linear-gradient(90deg, var(--button-text-color-active) 0%, var(--button-text-color-active) 50%, rgba(0, 0, 0, 0) 100%);
75
+ top: 0;
76
+ bottom: 0;
77
+ left: 0;
78
+ width: 30px;
79
+ z-index: 11;
80
+ }
81
+ &:after {
82
+ content: '';
83
+ position: absolute;
84
+ background: linear-gradient(270deg, var(--button-text-color-active) 0%, var(--button-text-color-active) 50%, rgba(0, 0, 0, 0) 100%);
85
+ top: 0;
86
+ bottom: 0;
87
+ right: 0;
88
+ width: 30px;
89
+ z-index: 11;
90
+ }
71
91
  .neo-carousel-item {
72
92
  height : 9rem;
73
93
  padding: 15px;
94
+ text-align: center;
74
95
  }
75
96
  }
76
97
  }
@@ -0,0 +1,7 @@
1
+ .examples-layout-cube-maincontainer {
2
+ .neo-face {
3
+ align-items : center;
4
+ display : flex;
5
+ justify-content: center;
6
+ }
7
+ }
@@ -0,0 +1,80 @@
1
+ /*
2
+ * Container Structure:
3
+ * div.neo-layout-cube
4
+ * div.neo-plane
5
+ * div.neo-box
6
+ * div.neo-face.neo-face-z.front
7
+ * div.neo-face.neo-face-z.back
8
+ * div.neo-face.neo-face-x.left
9
+ * div.neo-face.neo-face-x.right
10
+ * div.neo-face.neo-face-y.top
11
+ * div.neo-face.neo-face-y.bottom
12
+ */
13
+ .neo-layout-cube {
14
+ --backface-visibility: visible;
15
+ --perspective : 600px;
16
+
17
+ --rot-x: 0deg;
18
+ --rot-y: 0deg;
19
+ --rot-z: 0deg;
20
+
21
+ --side-x: 300px; /* horizontal */
22
+ --side-y: 300px; /* vertical */
23
+ --side-z: 300px; /* depth */
24
+
25
+ background-color : transparent;
26
+ height : var(--side-y);
27
+ overflow : visible;
28
+ perspective : var(--perspective);
29
+ perspective-origin: center center;
30
+ width : var(--side-x);
31
+
32
+ .neo-plane {
33
+ transform : translateZ(calc(var(--side-z) / -2));
34
+ transform-style: preserve-3d;
35
+ }
36
+
37
+ .neo-box {
38
+ height : var(--side-y);
39
+ position : relative;
40
+ transform : rotateX(var(--rot-x)) rotateY(var(--rot-y)) rotateZ(var(--rot-z));
41
+ transform-style : preserve-3d;
42
+ transform-origin: center center;
43
+ translate : 0 0 calc(var(--side-z) / -2);
44
+ width : var(--side-x);
45
+ }
46
+
47
+ &.neo-animate {
48
+ .neo-box {
49
+ transition: transform 300ms ease-out;
50
+ }
51
+ }
52
+
53
+ .neo-face {
54
+ backface-visibility: var(--backface-visibility);
55
+ background : center/cover no-repeat;
56
+ position : absolute;
57
+
58
+ &.front {transform: rotateY( 0deg) translateZ(calc(var(--side-z) / 2));}
59
+ &.back {transform: rotateY(180deg) translateZ(calc(var(--side-z) / 2));}
60
+ &.left {transform: rotateY(-90deg) translateZ(calc(var(--side-z) / 2));}
61
+ &.right {transform: rotateY( 90deg) translateZ(calc(var(--side-x) - var(--side-z) / 2));}
62
+ &.top {transform: rotateX( 90deg) translateZ(calc(var(--side-z) / 2));}
63
+ &.bottom {transform: rotateX(-90deg) translateZ(calc(var(--side-y) - var(--side-z) / 2));}
64
+ }
65
+
66
+ .neo-face-x {
67
+ height: var(--side-y);
68
+ width : var(--side-z);
69
+ }
70
+
71
+ .neo-face-y {
72
+ height: var(--side-z);
73
+ width : var(--side-x);
74
+ }
75
+
76
+ .neo-face-z {
77
+ height: var(--side-y);
78
+ width : var(--side-x);
79
+ }
80
+ }
@@ -22,18 +22,18 @@
22
22
  border-top: 0;
23
23
  }
24
24
  }
25
- }
26
25
 
27
- .neo-tab-container-plain {
26
+ &.neo-tab-container-plain {
28
27
 
29
- }
28
+ }
30
29
 
31
- .neo-tab-content-container {
32
- border : var(--tab-container-content-border);
33
- overflow: hidden;
34
- }
30
+ .neo-tab-content-container {
31
+ border : var(--tab-container-content-border);
32
+ overflow: hidden;
33
+ }
35
34
 
36
- .neo-tab-header-toolbar {
37
- background-color: transparent;
38
- padding : 0;
35
+ .neo-tab-header-toolbar {
36
+ background-color: transparent;
37
+ padding : 0;
38
+ }
39
39
  }
@@ -0,0 +1,3 @@
1
+ :root .neo-theme-neo-light { // .portal-blog-container
2
+ --portal-blog-toolbar-background-color: #8BA6FF;
3
+ }
@@ -1,3 +1,3 @@
1
1
  :root .neo-theme-neo-light { // .neo-searchfield
2
- --searchfield-glyph-color: #1c60a0;
2
+ --searchfield-glyph-color: #3E63DD;
3
3
  }
@@ -1,6 +1,6 @@
1
1
  :root .neo-theme-neo-light { // .neo-tooltip
2
2
  // --tooltip-bg : var(--cmp-tooltip-bg);
3
- --tooltip-bg : red;
3
+ --tooltip-bg : #3E63DD;
4
4
  --tooltip-border : none;
5
5
  --tooltip-borderradius : var(--cmp-tooltip-borderradius);
6
6
  --tooltip-boxshadow : none;
@@ -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.3'
263
+ * @default '6.19.0'
264
264
  * @memberOf! module:Neo
265
265
  * @name config.version
266
266
  * @type String
267
267
  */
268
- version: '6.18.3'
268
+ version: '6.19.0'
269
269
  };
270
270
 
271
271
  Object.assign(DefaultConfig, {
package/src/Main.mjs CHANGED
@@ -56,6 +56,7 @@ class Main extends core.Base {
56
56
  'setNeoConfig',
57
57
  'setRoute',
58
58
  'windowClose',
59
+ 'windowCloseAll',
59
60
  'windowMoveTo',
60
61
  'windowOpen',
61
62
  'windowResizeTo'
@@ -471,7 +472,7 @@ class Main extends core.Base {
471
472
  /**
472
473
  * Closes popup windows
473
474
  * @param {Object} data
474
- * @param {Array|String} data.names
475
+ * @param {String|String[]} data.names
475
476
  */
476
477
  windowClose(data) {
477
478
  if (!Array.isArray(data.names)) {
@@ -484,6 +485,19 @@ class Main extends core.Base {
484
485
  })
485
486
  }
486
487
 
488
+ /**
489
+ * Closes all popup windows
490
+ * @param {Object} data
491
+ */
492
+ windowCloseAll(data) {
493
+ Object.values(this.openWindows).forEach(value => {
494
+ console.log(value);
495
+ value.close()
496
+ });
497
+
498
+ this.openWindows = {}
499
+ }
500
+
487
501
  /**
488
502
  * Move a popup window
489
503
  * @param {Object} data
package/src/Neo.mjs CHANGED
@@ -430,7 +430,7 @@ Neo = globalThis.Neo = Object.assign({
430
430
  {ntypeMap} = Neo,
431
431
  proto = cls.prototype || cls,
432
432
  protos = [],
433
- cfg, config, ctor, ntype;
433
+ cfg, config, ctor, ns, ntype;
434
434
 
435
435
  while (proto.__proto__) {
436
436
  ctor = proto.constructor;
@@ -531,8 +531,19 @@ Neo = globalThis.Neo = Object.assign({
531
531
  });
532
532
 
533
533
  if (proto.singleton) {
534
- cls = Neo.create(cls);
535
- Neo.applyToGlobalNs(cls)
534
+ ns = Neo.ns(proto.className);
535
+
536
+ // Only create new singleton instances, in case the namespace is not in use. Using multiple neo versions
537
+ // will cause issues otherwise (e.g. combining dist/production & development). Example: code.LivePreview.
538
+ if (!ns) {
539
+ cls = Neo.create(cls);
540
+ Neo.applyToGlobalNs(cls)
541
+ }
542
+ // If the singleton already exists, just return this version instead.
543
+ // This enables us to still use it with default import statements.
544
+ else {
545
+ return ns
546
+ }
536
547
  }
537
548
 
538
549
  return cls
@@ -333,6 +333,13 @@ class Base extends CoreBase {
333
333
  * @member {String|null} theme_=null
334
334
  */
335
335
  theme_: null,
336
+ /**
337
+ * While it is recommended to define tags inside the vdom of classes,
338
+ * this shortcut enables us to change the vdom root tag on instance level.
339
+ * Use cases: switch a Toolbar to a "nav" tag, switch a SideNav to an "aside" tag.
340
+ * @member {String|null} tag_=null
341
+ */
342
+ tag_: null,
336
343
  /**
337
344
  * Add tooltip config object or a string containing the display text
338
345
  * See tooltip/Base.mjs
@@ -920,6 +927,16 @@ class Base extends CoreBase {
920
927
  }
921
928
  }
922
929
 
930
+ /**
931
+ * Triggered after the tag config got changed
932
+ * @param {String|null} value
933
+ * @param {String|null} oldValue
934
+ * @protected
935
+ */
936
+ afterSetTag(value, oldValue) {
937
+ value && this.changeVdomRootKey('tag', value)
938
+ }
939
+
923
940
  /**
924
941
  * Triggered after the theme config got changed
925
942
  * @param {String|null} value
@@ -1459,7 +1476,7 @@ class Base extends CoreBase {
1459
1476
  // we can not set the config directly => it could already be false,
1460
1477
  // and we still want to pass it further into subtrees
1461
1478
  me._needsVdomUpdate = false;
1462
- me.afterSetNeedsVdomUpdate?.(false, true)
1479
+ me.afterSetNeedsVdomUpdate?.(false, true);
1463
1480
 
1464
1481
  Neo.vdom.Helper.update(opts).catch(err => {
1465
1482
  me.isVdomUpdating = false;
@@ -149,7 +149,9 @@ class Base extends Component {
149
149
  me.items.forEach((item, index) => {
150
150
  oldValue?.removeChildAttributes(item, index);
151
151
  value.applyChildAttributes(item, index)
152
- })
152
+ });
153
+
154
+ oldValue?.destroy()
153
155
  }
154
156
  }
155
157
 
@@ -363,12 +363,11 @@ class Base extends Panel {
363
363
  await me.render(true);
364
364
 
365
365
  let [dialogRect, bodyRect] = await me.getDomRect([me.id, 'document.body']);
366
- console.log(dialogRect, bodyRect);
367
366
 
368
367
  // Move to cover the animation target
369
368
  await Neo.applyDeltas(appName, {
370
369
  id,
371
- style : {
370
+ style: {
372
371
  height: `${rect.height}px`,
373
372
  left : `${rect.left }px`,
374
373
  top : `${rect.top }px`,