neo.mjs 6.9.11 → 6.10.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.
- package/BACKERS.md +0 -30
- package/apps/ServiceWorker.mjs +2 -2
- package/apps/learnneo/index.html +7 -2
- package/apps/learnneo/neo-config.json +1 -4
- package/apps/learnneo/view/LivePreview.mjs +171 -0
- package/apps/learnneo/view/Viewport.mjs +11 -4
- package/apps/learnneo/view/ViewportController.mjs +2 -2
- package/apps/learnneo/view/home/ContentTreeList.mjs +93 -5
- package/apps/learnneo/view/home/MainContainer.mjs +16 -16
- package/apps/learnneo/view/home/MainContainerController.mjs +5 -20
- package/apps/learnneo/view/home/MainContainerModel.mjs +3 -5
- package/apps/newwebsite/index.html +3 -0
- package/buildScripts/convertDesignTokens.mjs +173 -0
- package/examples/ServiceWorker.mjs +2 -2
- package/package.json +5 -8
- package/resources/data/deck/learnneo/p/2023-10-01T18-29-19-158Z.md +14 -16
- package/resources/data/deck/learnneo/p/2023-10-07T19-18-28-517Z.md +9 -17
- package/resources/data/deck/learnneo/p/2023-10-08T20-20-07-934Z.md +7 -5
- package/resources/data/deck/learnneo/p/2023-10-08T20-20-37-336Z.md +17 -10
- package/resources/data/deck/learnneo/p/2023-10-14T19-25-08-153Z.md +18 -22
- package/resources/data/deck/learnneo/p/2023-10-31T13-59-37-550Z.md +31 -0
- package/resources/data/deck/learnneo/p/MainThreadAddonExample.md +15 -0
- package/resources/data/deck/learnneo/p/MainThreadAddonIntro.md +46 -0
- package/resources/data/deck/learnneo/p/TestLivePreview.md +10 -0
- package/resources/data/deck/learnneo/p/stylesheet.md +22 -8
- package/resources/data/deck/learnneo/t.json +126 -56
- package/resources/data/deck/training/p/2023-01-10T02-21-54-303Z.md +1 -1
- package/resources/data/deck/training/t.json +1276 -1
- package/resources/design-tokens/json/component.json +288 -0
- package/resources/design-tokens/json/core.json +352 -0
- package/resources/design-tokens/json/semantic.json +231 -0
- package/resources/images/logos/Github-logo-black.svg +1 -0
- package/resources/images/logos/Slack-logo-black.svg +17 -0
- package/resources/scss/src/apps/learnneo/Viewport.scss +3 -0
- package/resources/scss/src/apps/learnneo/home/ContentTreeList.scss +60 -13
- package/resources/scss/src/apps/learnneo/home/ContentView.scss +11 -2
- package/resources/scss/src/apps/newwebsite/MainContainer.scss +14 -15
- package/resources/scss/src/list/Base.scss +4 -0
- package/resources/scss/theme-neo-light/Global.scss +36 -16
- package/resources/scss/theme-neo-light/button/Base.scss +46 -45
- package/resources/scss/theme-neo-light/design-tokens/Component.scss +66 -1
- package/resources/scss/theme-neo-light/design-tokens/Core.scss +66 -5
- package/resources/scss/theme-neo-light/design-tokens/Semantic.scss +64 -0
- package/resources/scss/theme-neo-light/list/Base.scss +27 -6
- package/resources/scss/theme-neo-light/tab/header/Button.scss +1 -1
- package/src/DefaultConfig.mjs +2 -2
- package/src/component/StatusBadge.mjs +194 -246
- package/src/component/Video.mjs +19 -25
- package/src/controller/Base.mjs +33 -26
- package/src/core/Base.mjs +2 -2
- package/src/data/connection/Xhr.mjs +1 -1
- package/src/form/field/TextArea.mjs +3 -3
- package/src/main/DomAccess.mjs +64 -70
- package/src/main/DomEvents.mjs +1 -1
- package/src/main/addon/HighlightJS.mjs +16 -1
- package/src/main/addon/Mwc.mjs +6 -1
- package/src/worker/Manager.mjs +8 -3
- package/examples/container/dialog/MainContainer.mjs +0 -68
- package/examples/container/dialog/MainContainerController.mjs +0 -84
- package/examples/container/dialog/app.mjs +0 -6
- package/examples/container/dialog/index.html +0 -11
- package/examples/container/dialog/neo-config.json +0 -7
- package/src/container/Dialog.mjs +0 -205
- package/src/main/addon/Dialog.mjs +0 -68
@@ -0,0 +1,173 @@
|
|
1
|
+
import fs from 'fs-extra';
|
2
|
+
import os from 'os';
|
3
|
+
import path from 'path';
|
4
|
+
|
5
|
+
let jsonPath = './resources/design-tokens/json',
|
6
|
+
jsonFolder = fs.readdirSync(jsonPath),
|
7
|
+
tokenPrefix = '',
|
8
|
+
tokenRegex = new RegExp(/{(.*?)}/g),
|
9
|
+
emptyString, fileContent, keyMaxLength, map, match, matches, output;
|
10
|
+
|
11
|
+
function capitalize(value) {
|
12
|
+
return value[0].toUpperCase() + value.slice(1);
|
13
|
+
}
|
14
|
+
|
15
|
+
function createEmptyString(len) {
|
16
|
+
return ' '.repeat(len);
|
17
|
+
}
|
18
|
+
|
19
|
+
function parseTokens(fileContent, prefix=tokenPrefix, map=[]) {
|
20
|
+
let baseKey, baseValue, keyValue, keys, modify, ns;
|
21
|
+
|
22
|
+
Object.entries(fileContent).forEach(([key, value]) => {
|
23
|
+
key = key.replace(/\?/g, '');
|
24
|
+
key = key.replace(/&/g, '-'); // some token names contain & chars
|
25
|
+
ns = prefix === tokenPrefix ? (tokenPrefix + key) : key === 'value' ? prefix : `${prefix}-${key}`;
|
26
|
+
|
27
|
+
if (typeof value === 'object') {
|
28
|
+
keys = Object.keys(value);
|
29
|
+
modify = value[keys[0]]?.$extensions?.['studio.tokens']?.modify || // the first key could contain the value,
|
30
|
+
value[keys[1]]?.$extensions?.['studio.tokens']?.modify; // so we are checking the 2nd too
|
31
|
+
|
32
|
+
if (modify) {
|
33
|
+
// assuming that each object contains its base value
|
34
|
+
keys.forEach(objKey => {
|
35
|
+
if (!value[objKey].$extensions) {
|
36
|
+
baseKey = objKey;
|
37
|
+
baseValue = value[baseKey].value;
|
38
|
+
}
|
39
|
+
});
|
40
|
+
|
41
|
+
keys.forEach(objKey => {
|
42
|
+
if (objKey !== baseKey) {
|
43
|
+
modify = value[objKey].$extensions?.['studio.tokens']?.modify;
|
44
|
+
keyValue = `${modify.type}(${baseValue}, ${modify.value * 100}%)`;
|
45
|
+
|
46
|
+
map.push([`${ns}-${objKey}`, keyValue]);
|
47
|
+
} else {
|
48
|
+
parseTokens(value[baseKey], `${ns}-${baseKey}`, map);
|
49
|
+
}
|
50
|
+
})
|
51
|
+
} else {
|
52
|
+
parseTokens(value, ns, map);
|
53
|
+
}
|
54
|
+
} else if (key !== 'description' && key !== 'type') {
|
55
|
+
if (typeof value === 'string') {
|
56
|
+
if (!value.includes('{')) {
|
57
|
+
if (value.includes(' ')) {
|
58
|
+
value = `'${value}'`;
|
59
|
+
}
|
60
|
+
} else {
|
61
|
+
value = value.replace(/\?/g, '');
|
62
|
+
matches = value.matchAll(tokenRegex);
|
63
|
+
|
64
|
+
// replace . with - only inside each token
|
65
|
+
for (match of matches) {
|
66
|
+
value = value.replace(match[0], match[0].replace(/\./g, '-'));
|
67
|
+
}
|
68
|
+
|
69
|
+
/*
|
70
|
+
* some design tokens contain operations without empty spaces
|
71
|
+
* e.g. {token}*0.9
|
72
|
+
* calc() relies on having spaces around operators
|
73
|
+
*/
|
74
|
+
value = value.replace(/(\S)(\*)(\S)/g, '$1 $2 $3');
|
75
|
+
value = value.replace(/(\S)(\/)(\S)/g, '$1 $2 $3');
|
76
|
+
|
77
|
+
// most likely a multiplication
|
78
|
+
if (!value.endsWith('}')) {
|
79
|
+
value = `calc(${value})`;
|
80
|
+
}
|
81
|
+
|
82
|
+
// convert tokens into CSS variables
|
83
|
+
value = value.replace(/{(.*?)}/g, `var(--${tokenPrefix}$1)`);
|
84
|
+
|
85
|
+
// multiple occurrences of a css variable need to get wrapped into calc()
|
86
|
+
if (value.indexOf('var') !== value.lastIndexOf('var')) {
|
87
|
+
value = `calc(${value})`;
|
88
|
+
}
|
89
|
+
|
90
|
+
// -token needs to get converted
|
91
|
+
if (value.startsWith('-')) {
|
92
|
+
value = `calc(${value.substring(1)} * -1)`
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
map.push([ns, value]);
|
98
|
+
}
|
99
|
+
});
|
100
|
+
|
101
|
+
return map;
|
102
|
+
}
|
103
|
+
|
104
|
+
function replaceObjectValue(obj) {
|
105
|
+
Object.entries(obj).forEach(([key, value]) => {
|
106
|
+
if (key === 'value') {
|
107
|
+
if (typeof value === 'object') {
|
108
|
+
Object.entries(value).forEach(([valKey, prop]) => {
|
109
|
+
// some token vars contain an empty string, which SCSS can not handle.
|
110
|
+
if (prop === '') {
|
111
|
+
prop = 'none';
|
112
|
+
}
|
113
|
+
|
114
|
+
obj[valKey] = {
|
115
|
+
type : obj.type,
|
116
|
+
value: prop
|
117
|
+
};
|
118
|
+
});
|
119
|
+
|
120
|
+
delete obj.type;
|
121
|
+
delete obj.value;
|
122
|
+
}
|
123
|
+
} else if (typeof value === 'object') {
|
124
|
+
replaceObjectValue(value);
|
125
|
+
}
|
126
|
+
});
|
127
|
+
}
|
128
|
+
|
129
|
+
function sortArray(a, b) {
|
130
|
+
const nameA = a[0].toUpperCase();
|
131
|
+
const nameB = b[0].toUpperCase();
|
132
|
+
if (nameA < nameB) {
|
133
|
+
return -1;
|
134
|
+
}
|
135
|
+
if (nameA > nameB) {
|
136
|
+
return 1;
|
137
|
+
}
|
138
|
+
|
139
|
+
return 0;
|
140
|
+
}
|
141
|
+
|
142
|
+
jsonFolder.forEach(fileName => {
|
143
|
+
if (fileName.endsWith(".json")) {
|
144
|
+
console.log('Parsing file:', fileName);
|
145
|
+
|
146
|
+
fileContent = JSON.parse(fs.readFileSync(path.join(jsonPath, fileName)));
|
147
|
+
keyMaxLength = 0;
|
148
|
+
output = [':root .neo-theme-neo-light {'];
|
149
|
+
|
150
|
+
replaceObjectValue(fileContent);
|
151
|
+
|
152
|
+
map = parseTokens(fileContent);
|
153
|
+
|
154
|
+
map.sort(sortArray);
|
155
|
+
|
156
|
+
map.forEach(item => {
|
157
|
+
keyMaxLength = Math.max(item[0].length, keyMaxLength);
|
158
|
+
});
|
159
|
+
|
160
|
+
map.forEach(item => {
|
161
|
+
emptyString = createEmptyString(keyMaxLength - item[0].length);
|
162
|
+
|
163
|
+
output.push(` --${item[0] + emptyString}: ${item[1]};`);
|
164
|
+
});
|
165
|
+
|
166
|
+
output.push('}');
|
167
|
+
output.push('');
|
168
|
+
|
169
|
+
fileName = capitalize(fileName.split('.').shift()) + '.scss'
|
170
|
+
|
171
|
+
fs.writeFileSync(path.join('./resources/scss/theme-neo-light/design-tokens/', fileName), output.join(os.EOL));
|
172
|
+
}
|
173
|
+
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "neo.mjs",
|
3
|
-
"version": "6.
|
3
|
+
"version": "6.10.0",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -16,6 +16,7 @@
|
|
16
16
|
"build-all-questions": "node ./buildScripts/buildAll.mjs -f",
|
17
17
|
"build-themes": "node ./buildScripts/buildThemes.mjs -f",
|
18
18
|
"build-threads": "node ./buildScripts/webpack/buildThreads.mjs -f",
|
19
|
+
"convert-design-tokens": "node ./buildScripts/convertDesignTokens.mjs",
|
19
20
|
"create-app": "node ./buildScripts/createApp.mjs",
|
20
21
|
"create-class": "node ./buildScripts/createClass.mjs",
|
21
22
|
"create-component": "node ./buildScripts/createComponent.mjs",
|
@@ -40,10 +41,8 @@
|
|
40
41
|
"url": "https://github.com/neomjs/neo/issues"
|
41
42
|
},
|
42
43
|
"homepage": "https://neomjs.github.io/pages/",
|
43
|
-
"
|
44
|
+
"devDependencies": {
|
44
45
|
"@fortawesome/fontawesome-free": "^6.4.2",
|
45
|
-
"@material/mwc-button": "^0.27.0",
|
46
|
-
"@material/mwc-textfield": "^0.27.0",
|
47
46
|
"autoprefixer": "^10.4.16",
|
48
47
|
"chalk": "^5.3.0",
|
49
48
|
"clean-webpack-plugin": "^4.0.0",
|
@@ -57,17 +56,15 @@
|
|
57
56
|
"neo-jsdoc-x": "1.0.5",
|
58
57
|
"postcss": "^8.4.31",
|
59
58
|
"sass": "^1.69.5",
|
59
|
+
"siesta-lite": "5.5.2",
|
60
60
|
"showdown": "^2.1.0",
|
61
|
+
"url": "^0.11.3",
|
61
62
|
"webpack": "^5.89.0",
|
62
63
|
"webpack-cli": "^5.1.4",
|
63
64
|
"webpack-dev-server": "4.15.1",
|
64
65
|
"webpack-hook-plugin": "^1.0.7",
|
65
66
|
"webpack-node-externals": "^3.0.0"
|
66
67
|
},
|
67
|
-
"devDependencies": {
|
68
|
-
"siesta-lite": "5.5.2",
|
69
|
-
"url": "^0.11.3"
|
70
|
-
},
|
71
68
|
"funding": {
|
72
69
|
"type": "GitHub Sponsors",
|
73
70
|
"url": "https://github.com/sponsors/tobiu"
|
@@ -3,29 +3,27 @@ Neo.mjs is a framework used to create <mark>browser-based</mark> applications.
|
|
3
3
|
|
4
4
|
# Some key features and benefits of Neo.mjs are:
|
5
5
|
|
6
|
-
<code><A code snippet></code>
|
7
|
-
|
8
6
|
<details>
|
9
|
-
<summary>Multi-Threaded</summary>
|
7
|
+
<summary><h2>Multi-Threaded</h2></summary>
|
10
8
|
<p>
|
11
9
|
When a Neo.mjs application starts, the framework spawns three web-workers, in addition
|
12
10
|
to the main browser thread, resulting in:
|
13
11
|
<ol>
|
14
12
|
<li>The <b>main</b> browser thread, where DOM updates are applied
|
15
|
-
<li>An <b>application</b> web-worker where normal application
|
13
|
+
<li>An <b>application</b> web-worker where normal application logic is run
|
16
14
|
<li>A <b>data</b> web-worker were HTTP and socket calls are run
|
17
15
|
<li>A <b>view</b> web-worker that manages delta updates
|
18
16
|
</ol>
|
19
17
|
</details>
|
20
18
|
<details>
|
21
|
-
<summary>Extreme Speed</summary>
|
19
|
+
<summary><h2>Extreme Speed</h2></summary>
|
22
20
|
<p>
|
23
|
-
Web-worker
|
21
|
+
Web-worker processes are automatically run in parallel, on separate CPU cores.
|
24
22
|
</p>
|
25
23
|
<p>
|
26
24
|
By contrast, other JavaScript frameworks run in a single thread. That means
|
27
25
|
in a typical framework all business logic, data handling, and DOM rendering compete for
|
28
|
-
CPU
|
26
|
+
CPU resources.
|
29
27
|
</p>
|
30
28
|
<p>
|
31
29
|
This means Neo.mjs applications run and render faster. This is
|
@@ -39,14 +37,14 @@ to run other specialized logic.
|
|
39
37
|
</p>
|
40
38
|
</details>
|
41
39
|
<details>
|
42
|
-
<summary>Quick Application Development</summary>
|
40
|
+
<summary><h2>Quick Application Development</h2></summary>
|
43
41
|
<p>
|
44
|
-
Neo.
|
42
|
+
Neo.mjs classes let you specify properties in a way that allows code to detect "before" and "after"
|
45
43
|
changes. This makes it easy to handle value validation and transformation, and react to changes.
|
46
44
|
</p>
|
47
45
|
<p>
|
48
46
|
Neo.mjs also has elegant yet powerful state management features that make it easy to create shared,
|
49
|
-
bindable data. For example, if two components are bound to the same
|
47
|
+
bindable data. For example, if two components are bound to the same property, a change to the
|
50
48
|
property will automatically be applied to both components.
|
51
49
|
</p>
|
52
50
|
<p>
|
@@ -57,7 +55,7 @@ update its properties ‐ these updates are immediately reflected in the runn
|
|
57
55
|
</p>
|
58
56
|
</details>
|
59
57
|
<details>
|
60
|
-
<summary>Multi-Window Applications</summary>
|
58
|
+
<summary><h2>Multi-Window Applications</h2></summary>
|
61
59
|
<p>
|
62
60
|
Neo.mjs applications can also launch as <i>shared web workers</i>, which allows you to have a single
|
63
61
|
application run in multiple browser windows; those windows could be moved to multiple monitors.
|
@@ -69,10 +67,10 @@ across windows, running seamlessly as a single application.
|
|
69
67
|
</p>
|
70
68
|
</details>
|
71
69
|
<details>
|
72
|
-
<summary>Open-Source and Standards-Based</summary>
|
70
|
+
<summary><h2>Open-Source and Standards-Based</h2></summary>
|
73
71
|
<p>
|
74
|
-
Neo.mjs is an open-source
|
75
|
-
|
72
|
+
Neo.mjs is an open-source framework. Features needed for the community can be added to the
|
73
|
+
framework via pull-requests. And since Neo.mjs uses the standard JavaScript class system,
|
76
74
|
all Neo.mjs classes can be extended.
|
77
75
|
</p>
|
78
76
|
<p>
|
@@ -80,11 +78,11 @@ Neo.mjs uses standard modular JavaScript, so developers don't need to learn non-
|
|
80
78
|
syntax, and there's no need for special pre-compilers or WebPack modules.
|
81
79
|
That means fewer dependencies and easier configuration. Furthermore, the use of
|
82
80
|
standard JavaScript makes debugging easier: any statement you write while developing your
|
83
|
-
|
81
|
+
application can also be run in the debugging console.
|
84
82
|
</p>
|
85
83
|
</details>
|
86
84
|
<details>
|
87
|
-
<summary>Scalable</summary>
|
85
|
+
<summary><h2>Scalable</h2></summary>
|
88
86
|
<p>
|
89
87
|
Applications can become exponentially difficult to implement as application
|
90
88
|
complexity increases. In contrast, the effort to code applications in Neo.mjs
|
@@ -1,9 +1,8 @@
|
|
1
1
|
Neo.mjs classes are standard JavaScript classes. Every source file
|
2
2
|
you write will be a class definition, extending some Neo.mjs
|
3
|
-
class.
|
3
|
+
class.
|
4
4
|
|
5
|
-
<pre>
|
6
|
-
<code class="javascript">
|
5
|
+
<pre data-javascript>
|
7
6
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
8
7
|
|
9
8
|
class Mammal extends Base {
|
@@ -14,15 +13,14 @@ class Mammal extends Base {
|
|
14
13
|
|
15
14
|
const myMammal = Neo.create(Mammal);
|
16
15
|
|
17
|
-
Neo.applyClassConfig(Mammal); // Where Neo.mjs
|
16
|
+
Neo.applyClassConfig(Mammal); // Where Neo.mjs initializes the class config.
|
18
17
|
export default Mammal; // Makes the class available elsewhere.
|
19
|
-
</code>
|
20
18
|
</pre>
|
21
19
|
|
22
20
|
In the example above, we're extending the Neo.mjs base class. The static
|
23
|
-
config block
|
24
|
-
|
25
|
-
|
21
|
+
config block is unique to Neo.mjs; it provides a way of defining special
|
22
|
+
properties, such as the `className` seen above. Over time we'll go into more detail
|
23
|
+
on the static config property.
|
26
24
|
|
27
25
|
The `const myMammal = Neo.create(Mammal);` statement creates an instance of
|
28
26
|
our class. For the sake of our discussion we're putting that statement in the same source
|
@@ -31,8 +29,7 @@ and create instances as needed.
|
|
31
29
|
|
32
30
|
Let's add a `name` propery to the class.
|
33
31
|
|
34
|
-
<pre>
|
35
|
-
<code class="javascript">
|
32
|
+
<pre data-javascript>
|
36
33
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
37
34
|
|
38
35
|
class Mammal extends Base {
|
@@ -50,7 +47,6 @@ console.log(myMammal.name); // Logs "Herbert"
|
|
50
47
|
Neo.applyClassConfig(Mammal);
|
51
48
|
|
52
49
|
export default Mammal;
|
53
|
-
</code>
|
54
50
|
</pre>
|
55
51
|
|
56
52
|
In Neo.mjs, instance properties are usually added in the `static config` block.
|
@@ -65,13 +61,11 @@ anywhere in the class hierarchy.
|
|
65
61
|
Since our class defines a `name` property, we can specify that when creating
|
66
62
|
the instance, using the second argument to the `create` method.
|
67
63
|
|
68
|
-
<pre>
|
69
|
-
<code class="javascript">
|
64
|
+
<pre data-javascript>
|
70
65
|
const myMammal = Neo.create(Mammal, {
|
71
66
|
name: 'Creature'
|
72
67
|
});
|
73
68
|
console.log(myMammal.name); // Logs "Creature"
|
74
|
-
</code>
|
75
69
|
</pre>
|
76
70
|
|
77
71
|
|
@@ -79,8 +73,7 @@ Since _you_ define those properties, you can
|
|
79
73
|
look for them in class methods and use them as needed.
|
80
74
|
Let's add a `speak()` method that uses the `name` property.
|
81
75
|
|
82
|
-
<pre>
|
83
|
-
<code class="javascript">
|
76
|
+
<pre data-javascript>
|
84
77
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
85
78
|
|
86
79
|
class Mammal extends Base {
|
@@ -103,7 +96,6 @@ myMammal.speak(); // Logs "Creature is grunting."
|
|
103
96
|
Neo.applyClassConfig(Mammal);
|
104
97
|
|
105
98
|
export default Mammal;
|
106
|
-
</code>
|
107
99
|
</pre>
|
108
100
|
|
109
101
|
|
@@ -3,7 +3,7 @@ In Neo.mjs you sub-class and override methods in the usual way.
|
|
3
3
|
Here, we'll extend `Mammal` and override the `speak()` method.
|
4
4
|
(For brevity, we'll exclude `export` and `import` statements.)
|
5
5
|
|
6
|
-
<pre
|
6
|
+
<pre data-javascript>
|
7
7
|
class Mammal extends Base {
|
8
8
|
static config = {
|
9
9
|
className: 'Simple.example.Mammal',
|
@@ -16,7 +16,8 @@ class Mammal extends Base {
|
|
16
16
|
}
|
17
17
|
Neo.applyClassConfig(Mammal);
|
18
18
|
</pre>
|
19
|
-
|
19
|
+
|
20
|
+
<pre data-javascript>
|
20
21
|
class Human extends Mammal {
|
21
22
|
static config = {
|
22
23
|
className: 'Simple.example.Human',
|
@@ -37,7 +38,7 @@ Neo.applyClassConfig(Mammal);
|
|
37
38
|
Any class in the hierarchy is free to add new properties and methods. Let's add
|
38
39
|
a property and behavior (method) to the Human class.
|
39
40
|
|
40
|
-
<pre
|
41
|
+
<pre data-javascript>
|
41
42
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
42
43
|
|
43
44
|
class Mammal extends Base {
|
@@ -51,7 +52,8 @@ class Mammal extends Base {
|
|
51
52
|
}
|
52
53
|
}
|
53
54
|
</pre>
|
54
|
-
|
55
|
+
|
56
|
+
<pre data-javascript>
|
55
57
|
class Human extends Mammal {
|
56
58
|
static config = {
|
57
59
|
className: 'Simple.example.Human',
|
@@ -69,7 +71,7 @@ const myPerson = Neo.create(Human, {
|
|
69
71
|
name: 'Herbert'
|
70
72
|
});
|
71
73
|
myPerson.speak(); // Logs "Hello! My name is Herbert. I am not married."
|
72
|
-
myPerson.yodel(); // Logs "
|
74
|
+
myPerson.yodel(); // Logs "Yodelay hee hoo!"
|
73
75
|
|
74
76
|
Neo.applyClassConfig(Human);
|
75
77
|
</pre>
|
@@ -1,29 +1,36 @@
|
|
1
1
|
Neo.mjs uses standard modular JavaScript, so you're free to use other class
|
2
2
|
features, like private members.
|
3
|
-
<pre class="
|
3
|
+
<pre><code class="javascript">
|
4
4
|
class Human extends Mammal {
|
5
5
|
static config = {
|
6
6
|
className: 'Simple.example.Human',
|
7
|
-
name: 'J. Doe',
|
8
|
-
married: false
|
7
|
+
name : 'J. Doe',
|
8
|
+
married : false
|
9
9
|
}
|
10
|
+
|
10
11
|
static #privateStaticField = 'foo'
|
12
|
+
|
11
13
|
#privateInstanceField = 'bar'
|
12
|
-
|
14
|
+
|
15
|
+
#privateInstanceMethod() {
|
13
16
|
console.log(`Psst. Don't tell anyone, but ${this.#privateInstanceField} and ${Human.#privateStaticField}`);
|
14
17
|
}
|
15
|
-
|
18
|
+
|
19
|
+
speak(tellSecret) {
|
16
20
|
console.log(`Hello! My name is ${this.name}. I am ${this.married?'':'not'} married.`);
|
17
21
|
if (tellSecret) this.#privateInstanceMethod();
|
18
22
|
}
|
19
|
-
|
23
|
+
|
24
|
+
yodel() {
|
20
25
|
console.log('Yodelay hee hoo!');
|
21
|
-
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
Neo.applyClassConfig(Human);
|
22
30
|
|
23
31
|
const myPerson = Neo.create(Human, {
|
24
32
|
name: 'Herbert'
|
25
33
|
});
|
26
|
-
myPerson.speak(true);
|
27
34
|
|
28
|
-
|
29
|
-
</pre>
|
35
|
+
myPerson.speak(true);
|
36
|
+
</code></pre>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
The purpose of this tutorial is to let you see the structure of a Neo.mjs workspace,
|
2
|
-
and the
|
2
|
+
and the structure of an application.
|
3
3
|
|
4
|
-
If you
|
4
|
+
If you wish, you can create a workspace for yourself by running `npx neo-app` workspace.
|
5
5
|
|
6
6
|
<img src="https://raw.githubusercontent.com/neomjs/pages/main/resources/images/apps/learnneo/NeoWorkspace.png" style="height: 400px;">
|
7
7
|
|
@@ -12,26 +12,26 @@ serve whose doc root is the workspace.
|
|
12
12
|
<img src="https://raw.githubusercontent.com/neomjs/pages/main/resources/images/apps/learnneo/ServerRoot.png" style="height: 400px;">
|
13
13
|
|
14
14
|
If you drill down into the `src` directory you'll see your applications.
|
15
|
-
|
15
|
+
The `docs` directory holds the Neo.mjs API docs.
|
16
16
|
|
17
17
|
In order to discuss the structure of an app, we'll create a simple starter
|
18
|
-
app
|
18
|
+
app vis this script, run from the workspace. The script prompts for various
|
19
|
+
application settings.
|
19
20
|
|
20
21
|
`npm run create-app-empty`
|
21
22
|
|
22
|
-
At the first prompt, name the app `Foo`, and accept the default for everything else.
|
23
|
+
At the first prompt, we'll name the app `Foo`, and accept the default for everything else.
|
23
24
|
The script creates an application structured as follows.
|
24
25
|
|
25
26
|
<img src="https://raw.githubusercontent.com/neomjs/pages/main/resources/images/apps/learnneo/FooFolder.png" style="height: 400px;">
|
26
27
|
|
27
28
|
These files are part of the typical structure of a Neo.mjs application. The files `index.html`, `app.mjs`, `neo-config.json`, `view/Viewport.mjs` are rarely modified.
|
28
29
|
You will, however, edit the main container, and its associated "controller" and "model",
|
29
|
-
as well as create new views,
|
30
|
+
as well as create new views classes, their controllers, and other application logic.
|
30
31
|
|
31
32
|
Now let's look at a source file. This is the contents of `MainView.mjs`.
|
32
33
|
|
33
|
-
<pre>
|
34
|
-
<code class="javascript">
|
34
|
+
<pre data-javascript>
|
35
35
|
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
36
36
|
import Controller from './MainViewController.mjs';
|
37
37
|
import ViewModel from './MainViewModel.mjs';
|
@@ -51,7 +51,6 @@ class MainView extends Base {
|
|
51
51
|
Neo.applyClassConfig(MainView);
|
52
52
|
|
53
53
|
export default MainView;
|
54
|
-
</code>
|
55
54
|
</pre>
|
56
55
|
|
57
56
|
Neo.mjs views are composed of components. A component can be a "container", which means it
|
@@ -70,8 +69,7 @@ you see how a component is configured let's put a button in the container.
|
|
70
69
|
First, we need to import the class that defines buttons. Then we'll describe the new button in the
|
71
70
|
`items:[].`
|
72
71
|
|
73
|
-
<pre>
|
74
|
-
<code class="javascript">
|
72
|
+
<pre data-javascript>
|
75
73
|
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
76
74
|
import Controller from './MainViewController.mjs';
|
77
75
|
import ViewModel from './MainViewModel.mjs';
|
@@ -95,27 +93,25 @@ class MainView extends Base {
|
|
95
93
|
Neo.applyClassConfig(MainView);
|
96
94
|
|
97
95
|
export default MainView;
|
98
|
-
</code>
|
99
96
|
</pre>
|
100
97
|
|
101
|
-
Note the entry in
|
102
|
-
item in our container. In Neo.mjs terms we're _configuring_ the button. Neo.mjs is
|
103
|
-
which components and objects are
|
104
|
-
what we want, but not how it's done.
|
105
|
-
isn't important here in the container. A non-declarative approach would be
|
106
|
-
where you might way "I want a <button> HTML element with its innerHTML set to some
|
98
|
+
Note the entry in `items:[]`. That's a description of the button that'll be created as the single
|
99
|
+
item in our container. In Neo.mjs terms we're _configuring_ the button. Neo.mjs is a declarative framework,
|
100
|
+
in which components and objects are described. It's an abstraction. In other words, the code describes
|
101
|
+
what we want, but not how it's done. In the code above, we want our container to have one item — a button
|
102
|
+
with some text. _How_ that's done isn't important here in the container. A non-declarative approach would be
|
103
|
+
more focused on _how_, where you might way "I want a <button> HTML element with its innerHTML set to some
|
104
|
+
value."
|
107
105
|
|
108
106
|
In another topic you'll learn about the Neo.mjs config system and declaratively describing
|
109
107
|
views, controllers, and other things.
|
110
108
|
|
111
|
-
If you run the
|
109
|
+
If you run the app you'll see one huge button. That's because the container is configured to
|
112
110
|
use the "fit" layout, which means the container is designed to hold one and only one component,
|
113
111
|
and that component will take up all available space. We could get a more normal looking button
|
114
112
|
by changing the layout.
|
115
113
|
|
116
|
-
`layout: {
|
117
|
-
|
118
|
-
Change that line and look at the running application.
|
114
|
+
`layout: {ntype:'vbox', align:'start},`
|
119
115
|
|
120
116
|
Neo.mjs has scores of component classes.
|
121
117
|
You can extend them to create your own reusable components and sets of components.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<pre data-javascript>
|
2
|
+
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
3
|
+
|
4
|
+
class Mammal extends Base {
|
5
|
+
static config = {
|
6
|
+
className: 'Simple.example.Mammal'
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
const myMammal = Neo.create(Mammal);
|
11
|
+
|
12
|
+
Neo.applyClassConfig(Mammal); // Where Neo.mjs initializes the class config.
|
13
|
+
export default Mammal; // Makes the class available elsewhere.
|
14
|
+
</pre>
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
<pre data-neo>
|
19
|
+
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
20
|
+
|
21
|
+
class Mammal extends Base {
|
22
|
+
static config = {
|
23
|
+
className: 'Simple.example.Mammal'
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
const myMammal = Neo.create(Mammal);
|
28
|
+
|
29
|
+
Neo.applyClassConfig(Mammal); // Where Neo.mjs initializes the class config.
|
30
|
+
export default Mammal; // Makes the class available elsewhere.
|
31
|
+
</pre>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Let's go through the steps of creating a main thread addon.
|
2
|
+
|
3
|
+
Let's say we needed to show a code editor. There are a lot of libraries
|
4
|
+
for this, such as Ace (<a href="https://ace.c9.io/" target="_blank">ace.c9.io</a>).
|
5
|
+
From a coding perspective, these editors have a simple API: a setter
|
6
|
+
to specify the string being edited, a getter to read the string, and
|
7
|
+
a change event fired as the user types.
|
8
|
+
|
9
|
+
Here's what we need to do:
|
10
|
+
- Define a main thread addon and its API
|
11
|
+
- Define a component wrapper
|
12
|
+
|
13
|
+
### Define the Main Thread Addon
|
14
|
+
|
15
|
+
### Define the component wrapper
|