neo.mjs 6.10.9 → 6.10.11
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/apps/ServiceWorker.mjs +2 -2
- package/apps/portal/view/learn/ContentTreeList.mjs +24 -12
- package/apps/portal/view/learn/LivePreview.mjs +28 -11
- package/buildScripts/createAppMinimal.mjs +391 -0
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/button/base/neo-config.json +2 -1
- package/examples/list/chip/neo-config.json +1 -2
- package/package.json +72 -70
- package/resources/data/deck/learnneo/data/theBeatles.json +22 -0
- package/resources/data/deck/learnneo/p/2023-10-14T19-25-08-153Z.md +29 -20
- package/resources/data/deck/learnneo/p/ComponentModels.md +116 -1
- package/resources/data/deck/learnneo/p/Config.md +157 -0
- package/resources/data/deck/learnneo/p/DescribingTheUI.md +67 -1
- package/resources/data/deck/learnneo/p/Earthquakes.md +214 -0
- package/resources/data/deck/learnneo/p/Events.md +142 -1
- package/resources/data/deck/learnneo/p/Extending.md +116 -1
- package/resources/data/deck/learnneo/p/References.md +126 -0
- package/resources/data/deck/learnneo/p/TestLivePreview.md +28 -6
- package/resources/data/deck/learnneo/t.json +5 -6
- package/resources/data/deck/training/p/2022-12-27T21-55-30-948Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-27T22-23-55-083Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-29T16-00-13-223Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-29T18-34-25-826Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-29T18-36-56-893Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-31T18-43-56-338Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-31T18-51-50-682Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-31T18-54-04-176Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-01T17-49-18-429Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-01T21-23-17-716Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-06T23-21-31-685Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-06T23-34-13-897Z.md +2 -2
- package/resources/data/deck/training/p/2023-01-06T23-46-36-687Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-08T01-24-21-088Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-08T02-11-26-333Z.md +2 -2
- package/resources/data/deck/training/p/2023-01-14T00-40-27-784Z.md +2 -2
- package/resources/data/deck/training/p/2023-07-31T00-37-21-927Z.md +2 -2
- package/resources/data/deck/training/p/2023-10-14T19-25-08-153Z.md +3 -3
- package/resources/scss/src/apps/newwebsite/Viewport.scss +32 -0
- package/resources/scss/src/apps/portal/learn/ContentView.scss +20 -4
- package/resources/scss/src/apps/portal/learn/LivePreview.scss +8 -0
- package/resources/scss/src/component/Base.scss +13 -4
- package/resources/scss/src/form/field/Select.scss +2 -5
- package/resources/scss/src/form/field/Text.scss +0 -1
- package/resources/scss/src/list/Base.scss +47 -2
- package/resources/scss/src/list/Chip.scss +10 -4
- package/resources/scss/theme-dark/list/Base.scss +11 -10
- package/resources/scss/theme-light/list/Base.scss +11 -10
- package/resources/scss/theme-neo-light/design-tokens/Components.scss +3 -0
- package/resources/scss/theme-neo-light/list/Base.scss +1 -0
- package/src/DefaultConfig.mjs +3 -3
- package/src/collection/Base.mjs +4 -0
- package/src/component/Base.mjs +7 -0
- package/src/container/Base.mjs +6 -12
- package/src/core/Base.mjs +5 -2
- package/src/data/Model.mjs +7 -0
- package/src/data/RecordFactory.mjs +5 -4
- package/src/form/field/Base.mjs +11 -0
- package/src/form/field/Picker.mjs +0 -1
- package/src/form/field/Select.mjs +208 -257
- package/src/form/field/Text.mjs +3 -3
- package/src/form/field/trigger/Base.mjs +5 -6
- package/src/layout/Flexbox.mjs +23 -31
- package/src/layout/HBox.mjs +1 -1
- package/src/layout/VBox.mjs +1 -1
- package/src/list/Base.mjs +64 -31
- package/src/main/DomAccess.mjs +55 -28
- package/src/main/DomEvents.mjs +2 -1
- package/src/main/DomUtils.mjs +66 -0
- package/src/main/addon/Navigator.mjs +332 -0
- package/src/manager/DomEvent.mjs +2 -1
- package/src/selection/ListModel.mjs +46 -82
- package/src/selection/Model.mjs +56 -33
- package/src/util/Array.mjs +5 -2
- package/src/util/Function.mjs +31 -0
- package/src/util/String.mjs +9 -0
- package/src/vdom/Helper.mjs +1 -2
- package/test/components/app.mjs +4 -3
- package/test/components/files/component/ChipList.mjs +125 -0
- package/test/components/files/form/field/Select.mjs +177 -2
- package/test/components/siesta.js +34 -1
package/package.json
CHANGED
@@ -1,72 +1,74 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
2
|
+
"name" : "neo.mjs",
|
3
|
+
"version" : "6.10.11",
|
4
|
+
"description" : "The webworkers driven UI framework",
|
5
|
+
"type" : "module",
|
6
|
+
"repository" : {
|
7
|
+
"type" : "git",
|
8
|
+
"url" : "https://github.com/neomjs/neo.git"
|
9
|
+
},
|
10
|
+
"bin" : {
|
11
|
+
"neo-cc" : "./buildScripts/createClass.mjs"
|
12
|
+
},
|
13
|
+
"scripts" : {
|
14
|
+
"add-config" : "node ./buildScripts/addConfig.mjs",
|
15
|
+
"build-all" : "node ./buildScripts/buildAll.mjs -f -n",
|
16
|
+
"build-all-questions" : "node ./buildScripts/buildAll.mjs -f",
|
17
|
+
"build-themes" : "node ./buildScripts/buildThemes.mjs -f",
|
18
|
+
"build-threads" : "node ./buildScripts/webpack/buildThreads.mjs -f",
|
19
|
+
"convert-design-tokens" : "node ./buildScripts/convertDesignTokens.mjs",
|
20
|
+
"create-app" : "node ./buildScripts/createApp.mjs",
|
21
|
+
"create-app-minimal" : "node ./buildScripts/createAppMinimal.mjs",
|
22
|
+
"create-class" : "node ./buildScripts/createClass.mjs",
|
23
|
+
"create-component" : "node ./buildScripts/createComponent.mjs",
|
24
|
+
"generate-docs-json" : "node ./buildScripts/docs/jsdocx.mjs",
|
25
|
+
"inject-package-version" : "node ./buildScripts/injectPackageVersion.mjs",
|
26
|
+
"server-start" : "webpack serve -c ./buildScripts/webpack/webpack.server.config.mjs --open",
|
27
|
+
"test" : "echo \"Error: no test specified\" && exit 1",
|
28
|
+
"watch-themes" : "node ./buildScripts/watchThemes.mjs"
|
29
|
+
},
|
30
|
+
"keywords" : [
|
31
|
+
"javascript",
|
32
|
+
"frontend",
|
33
|
+
"framework",
|
34
|
+
"webworker",
|
35
|
+
"ecmascript",
|
36
|
+
"css",
|
37
|
+
"json"
|
38
|
+
],
|
39
|
+
"author" : "Tobias Uhlig, Rich Waters",
|
40
|
+
"license" : "MIT",
|
41
|
+
"bugs" : {
|
42
|
+
"url" : "https://github.com/neomjs/neo/issues"
|
43
|
+
},
|
44
|
+
"homepage" : "https://neomjs.github.io/pages/",
|
45
|
+
"devDependencies" : {
|
46
|
+
"@fortawesome/fontawesome-free" : "^6.5.1",
|
47
|
+
"autoprefixer" : "^10.4.16",
|
48
|
+
"chalk" : "^5.3.0",
|
49
|
+
"clean-webpack-plugin" : "^4.0.0",
|
50
|
+
"commander" : "^11.1.0",
|
51
|
+
"cssnano" : "^6.0.2",
|
52
|
+
"envinfo" : "^7.11.0",
|
53
|
+
"fs-extra" : "^11.2.0",
|
54
|
+
"highlightjs-line-numbers.js" : "^2.8.0",
|
55
|
+
"inquirer" : "^9.2.12",
|
56
|
+
"neo-jsdoc" : "1.0.1",
|
57
|
+
"neo-jsdoc-x" : "1.0.5",
|
58
|
+
"postcss" : "^8.4.32",
|
59
|
+
"sass" : "^1.69.5",
|
60
|
+
"siesta-lite" : "5.5.2",
|
61
|
+
"showdown" : "^2.1.0",
|
62
|
+
"url" : "^0.11.3",
|
63
|
+
"webpack" : "^5.89.0",
|
64
|
+
"webpack-cli" : "^5.1.4",
|
65
|
+
"webpack-dev-server" : "4.15.1",
|
66
|
+
"webpack-hook-plugin" : "^1.0.7",
|
67
|
+
"webpack-node-externals" : "^3.0.0"
|
68
|
+
},
|
69
|
+
"funding" : {
|
70
|
+
"type" : "GitHub Sponsors",
|
71
|
+
"url" : "https://github.com/sponsors/tobiu"
|
72
|
+
}
|
73
|
+
|
72
74
|
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"first": "John",
|
4
|
+
"last": "Lennon",
|
5
|
+
"dob": "1940/10/09"
|
6
|
+
},
|
7
|
+
{
|
8
|
+
"first": "Paul",
|
9
|
+
"last": "McCartney",
|
10
|
+
"dob": "1942/06/18"
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"first": "George",
|
14
|
+
"last": "Harrison",
|
15
|
+
"dob": "1943/02/25"
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"first": "Ringo",
|
19
|
+
"last": "Starr",
|
20
|
+
"dob": "1940/07/07"
|
21
|
+
}
|
22
|
+
]
|
@@ -78,8 +78,7 @@ class MainView extends Container {
|
|
78
78
|
className : 'Foo.view.MainView',
|
79
79
|
controller: Controller,
|
80
80
|
model : ViewModel,
|
81
|
-
|
82
|
-
layout: {ntype: 'fit'},
|
81
|
+
layout: {ntype:'vbox', align:'start'},
|
83
82
|
items : [{
|
84
83
|
module: Button,
|
85
84
|
text : 'Button'
|
@@ -92,26 +91,36 @@ Neo.applyClassConfig(MainView);
|
|
92
91
|
export default MainView;
|
93
92
|
</pre>
|
94
93
|
|
95
|
-
Note the entry in `items:[]`. That's a description of the button that
|
96
|
-
|
97
|
-
|
98
|
-
what we want, but not how it's done. In the code above, we want our container to have one item —
|
99
|
-
with some text. _How_ that's done isn't important
|
100
|
-
|
101
|
-
value."
|
94
|
+
Note the entry in `items:[]`. That's a description of the button that will be the single item in our
|
95
|
+
container. In Neo.mjs terms we're _configuring_ the button. Neo.mjs is a declarative framework, in
|
96
|
+
which components and objects are described. It's an abstraction. In other words, the code describes
|
97
|
+
what we want, but not how it's done. In the code above, we want our container to have one item —
|
98
|
+
a button with some text. _How_ that's done isn't important. A non-declarative approach would be more
|
99
|
+
focused on _how_, where you might way "I want a <button> HTML element with its innerHTML set to
|
100
|
+
some value."
|
102
101
|
|
103
|
-
In another topic you'll learn about the Neo.mjs config system and declaratively describing
|
104
|
-
|
102
|
+
In another topic you'll learn about the Neo.mjs config system and declaratively describing views,
|
103
|
+
controllers, and other things.
|
105
104
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
by changing the layout.
|
105
|
+
Here's a simplified running example. The `model` and `controller` are omitted, because they aren't
|
106
|
+
actually used in the example, and the import root path is different to reflect the location of the
|
107
|
+
Neo.mjs libarary relative to the examples.
|
110
108
|
|
111
|
-
`layout: {ntype:'vbox', align:'start},`
|
112
109
|
|
113
|
-
|
114
|
-
|
110
|
+
<pre data-neo>
|
111
|
+
import Base from '../../../../src/container/Base.mjs';
|
112
|
+
import Button from '../../../../src/button/Base.mjs';
|
113
|
+
import Split from '../../../../src/button/Split.mjs';
|
114
|
+
class MainView extends Base {
|
115
|
+
static config = {
|
116
|
+
className : 'Example.view.MainView',
|
117
|
+
layout: {ntype:'vbox', align:'start'},
|
118
|
+
items : [{
|
119
|
+
module: Button,
|
120
|
+
text : 'Button'
|
121
|
+
}]
|
122
|
+
}
|
123
|
+
}
|
124
|
+
Neo.applyClassConfig(MainView);
|
125
|
+
</pre>
|
115
126
|
|
116
|
-
Other topics discuss coding applications, how the config system works, controllers,
|
117
|
-
and bindable data. However, as long as we're here
|
@@ -1 +1,116 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
Neo has a feature that allows shared, bindable, data.
|
3
|
+
|
4
|
+
A _view model_ — `Neo.model.Component` — instance holds properties that
|
5
|
+
can be bound to component properties.
|
6
|
+
|
7
|
+
<pre data-neo>
|
8
|
+
import Base from '../../../../src/container/Base.mjs';
|
9
|
+
import Label from '../../../../src/component/Label.mjs';
|
10
|
+
import TextField from '../../../../src/form/field/Text.mjs';
|
11
|
+
|
12
|
+
class MainView extends Base {
|
13
|
+
static config = {
|
14
|
+
className : 'Example.view.MainView',
|
15
|
+
|
16
|
+
model: {
|
17
|
+
data: {
|
18
|
+
foo: 'Hi there!'
|
19
|
+
}
|
20
|
+
},
|
21
|
+
layout: 'vbox',
|
22
|
+
items: [{
|
23
|
+
module: Label,
|
24
|
+
bind: {
|
25
|
+
text: data => `The value of foo is "${data.foo}"` // The "text" property is set as data.foo changes
|
26
|
+
}
|
27
|
+
}, {
|
28
|
+
module: TextField,
|
29
|
+
bind: {
|
30
|
+
value: {twoWay: true, value: data => data.foo} // "twoWay" means data.foo is set as the text field changes
|
31
|
+
},
|
32
|
+
labelText: 'Bound to foo:',
|
33
|
+
width: 300,
|
34
|
+
}],
|
35
|
+
style: {padding: '1em'},
|
36
|
+
}
|
37
|
+
}
|
38
|
+
Neo.applyClassConfig(MainView);
|
39
|
+
</pre>
|
40
|
+
|
41
|
+
View model properties are visible up the containment hierarchy:
|
42
|
+
Properties introduced in a parent container will be available to any child component, and properties
|
43
|
+
introduces in a specific component are only visible to that component. This approach makes it easy to control scope.
|
44
|
+
|
45
|
+
In this example the main view has three child items of type `MyPanel`. The main view has a view model with a
|
46
|
+
`foo` property, and the third child has its own view model with a `foo` property.
|
47
|
+
|
48
|
+
`MyPanel` contains a `Neo.componnet.Label` whose `text` value is bound to `foo`. To resolve the binding, Neo.mjs looks up the
|
49
|
+
containment hierarchy until it finds the value. For the first two panels the label binding looks in the label, then in its `MyPanel`
|
50
|
+
container, then in the main view where it finds `foo`. For the third child panel the label binding looks in the label,
|
51
|
+
then in its `MyPanel` and finds it because the third copy of `MyPanel` has its own view model with the `foo` property.
|
52
|
+
|
53
|
+
The bottom line is the Neo.mjs view model and binding approach is simple and powerful, and gives you easy control over the scope
|
54
|
+
of a value. Thus, you can share properties as globally or narrowly as needed.
|
55
|
+
|
56
|
+
<pre data-neo>
|
57
|
+
import Base from '../../../../src/container/Base.mjs';
|
58
|
+
import Panel from '../../../../src/container/Panel.mjs';
|
59
|
+
import Label from '../../../../src/component/Label.mjs';
|
60
|
+
|
61
|
+
class MyPanel extends Panel {
|
62
|
+
static config = {
|
63
|
+
className : 'Example.view.MyPanel',
|
64
|
+
headers: [{
|
65
|
+
dock: 'top',
|
66
|
+
items: [{ module: Label, text: 'MyPanel' }]
|
67
|
+
}],
|
68
|
+
items: [{
|
69
|
+
module: Label,
|
70
|
+
bind: {
|
71
|
+
text: data => `The value of foo is "${data.foo}"`
|
72
|
+
},
|
73
|
+
style: {margin: '1em'}
|
74
|
+
}],
|
75
|
+
style: {margin: '1em'},
|
76
|
+
}
|
77
|
+
}
|
78
|
+
Neo.applyClassConfig(MyPanel);
|
79
|
+
|
80
|
+
class MainView extends Base {
|
81
|
+
static config = {
|
82
|
+
className : 'Example.view.MainView',
|
83
|
+
|
84
|
+
model: {
|
85
|
+
data: {
|
86
|
+
foo: 'parent'
|
87
|
+
}
|
88
|
+
},
|
89
|
+
layout: 'hbox',
|
90
|
+
items: [{
|
91
|
+
module: MyPanel,
|
92
|
+
}, {
|
93
|
+
module: MyPanel,
|
94
|
+
}, {
|
95
|
+
module: MyPanel,
|
96
|
+
model: {
|
97
|
+
data: {
|
98
|
+
foo: 'child'
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}],
|
102
|
+
style: {margin: '1em'},
|
103
|
+
}
|
104
|
+
}
|
105
|
+
Neo.applyClassConfig(MainView);
|
106
|
+
</pre>
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
Note that in the example above, the view model is in-line. Normally your view model would be
|
113
|
+
coded in its own class that extends 'Neo.model.Component', and you'd use that in your component.
|
114
|
+
Just like with items component configs, trivial configs are often done in-line, and non-trivial
|
115
|
+
configs are coded as separate classes.
|
116
|
+
|
@@ -0,0 +1,157 @@
|
|
1
|
+
As you've probably noticed, Neo.mjs classes have a `static config` property.
|
2
|
+
|
3
|
+
The `config` specifies properties that are applied to instances as they are
|
4
|
+
created. In addition, Neo.mjs uses that information to set up propoerty lifecycle
|
5
|
+
methods.
|
6
|
+
|
7
|
+
Here's an example of a new component class `Simple` with three config properties:
|
8
|
+
|
9
|
+
1. `className` — used by Neo.mjs to keep track of every class
|
10
|
+
2. `foo` — an instance property
|
11
|
+
2. `bar_` — another instance property
|
12
|
+
|
13
|
+
<pre data-neo>
|
14
|
+
import Component from '../../../../src/component/Base.mjs';
|
15
|
+
import Container from '../../../../src/container/Base.mjs';
|
16
|
+
|
17
|
+
class Simple extends Component {
|
18
|
+
static config = {
|
19
|
+
className: 'Example.view.Simple',
|
20
|
+
|
21
|
+
foo: 1, // An instance field and its initial (default) value
|
22
|
+
bar_: '' // Another instance field -- note the underscore at the end
|
23
|
+
|
24
|
+
}
|
25
|
+
|
26
|
+
}
|
27
|
+
Neo.applyClassConfig(Simple);
|
28
|
+
|
29
|
+
|
30
|
+
class MainView extends Container {
|
31
|
+
static config = {
|
32
|
+
className: 'Example.view.MainView',
|
33
|
+
|
34
|
+
items: [{
|
35
|
+
module: Simple,
|
36
|
+
|
37
|
+
foo: 17, // This is applied to the instance
|
38
|
+
bar: 'hi there' // This is applied to the instance
|
39
|
+
|
40
|
+
}]
|
41
|
+
|
42
|
+
}
|
43
|
+
}
|
44
|
+
Neo.applyClassConfig(MainView);
|
45
|
+
</pre>
|
46
|
+
|
47
|
+
The `Simple` class doesn't have any content, so if you run the code you won't see anything. We'll
|
48
|
+
change that in the next example.
|
49
|
+
|
50
|
+
Note that the `bar` property is defined with an underscore at the end. That tags the property as
|
51
|
+
a _lifecyle property_. A lifecycle property provides methods that are run as the property is
|
52
|
+
updated or accessed. You're free to implment the methods to implement business rules, normalize
|
53
|
+
values, or have side-effects, such as updating a view or firing an event.
|
54
|
+
|
55
|
+
<pre data-neo>
|
56
|
+
import Component from '../../../../src/component/Base.mjs';
|
57
|
+
import Container from '../../../../src/container/Base.mjs';
|
58
|
+
|
59
|
+
class Simple extends Component {
|
60
|
+
static config = {
|
61
|
+
className: 'Example.view.Simple',
|
62
|
+
|
63
|
+
foo: 1, // An instance field and its initial (default) value
|
64
|
+
bar_: null // Another instance field -- note the underscore at the end
|
65
|
+
|
66
|
+
}
|
67
|
+
|
68
|
+
beforeGetBar(){
|
69
|
+
|
70
|
+
}
|
71
|
+
beforeSetBar(value, oldValue){
|
72
|
+
// Use value if it's not empty
|
73
|
+
if (value) return value;
|
74
|
+
}
|
75
|
+
afterSetBar(value, oldValue){
|
76
|
+
this.html = value;
|
77
|
+
this.fire('barChange', {component: this, value, oldValue});
|
78
|
+
}
|
79
|
+
|
80
|
+
}
|
81
|
+
Neo.applyClassConfig(Simple);
|
82
|
+
|
83
|
+
|
84
|
+
class MainView extends Container {
|
85
|
+
static config = {
|
86
|
+
className: 'Example.view.MainView',
|
87
|
+
|
88
|
+
items: [{
|
89
|
+
module: Simple,
|
90
|
+
|
91
|
+
foo: 17 , // This is applied to the instance
|
92
|
+
bar: 'hi there' // This is applied to the instance
|
93
|
+
|
94
|
+
}]
|
95
|
+
|
96
|
+
}
|
97
|
+
}
|
98
|
+
Neo.applyClassConfig(MainView);
|
99
|
+
</pre>
|
100
|
+
|
101
|
+
This time if you run the code you'll "hi there" in the view. That's because the Simple instance is
|
102
|
+
configured with `bar: 'hi there'`, and since that's a lifecycle property the `afterSetBar()` method
|
103
|
+
is run. That method updates the view with the passed value.
|
104
|
+
|
105
|
+
Updating a view is a common use case for the _afterSet_ method. It's also often used to fire an event.
|
106
|
+
Look at this code: `afterSetBar()` fires an event, and the config in the `items[]` is listening to it.
|
107
|
+
|
108
|
+
<pre data-neo>
|
109
|
+
import Component from '../../../../src/component/Base.mjs';
|
110
|
+
import Container from '../../../../src/container/Base.mjs';
|
111
|
+
|
112
|
+
class Simple extends Component {
|
113
|
+
static config = {
|
114
|
+
className: 'Example.view.Simple',
|
115
|
+
|
116
|
+
foo: 1, // An instance field and its initial (default) value
|
117
|
+
bar_: null // Another instance field -- note the underscore at the end
|
118
|
+
|
119
|
+
}
|
120
|
+
|
121
|
+
beforeGetBar(){
|
122
|
+
|
123
|
+
}
|
124
|
+
beforeSetBar(value, oldValue){
|
125
|
+
// Use value if it's not empty
|
126
|
+
if (value) return value;
|
127
|
+
}
|
128
|
+
afterSetBar(value, oldValue){
|
129
|
+
this.html = value;
|
130
|
+
this.fire('barChange', {component: this, value, oldValue});
|
131
|
+
}
|
132
|
+
|
133
|
+
}
|
134
|
+
Neo.applyClassConfig(Simple);
|
135
|
+
|
136
|
+
|
137
|
+
class MainView extends Container {
|
138
|
+
static config = {
|
139
|
+
className: 'Example.view.MainView',
|
140
|
+
|
141
|
+
items: [{
|
142
|
+
module: Simple,
|
143
|
+
|
144
|
+
foo: 17 , // This is applied to the instance
|
145
|
+
bar: 'hi there', // This is applied to the instance
|
146
|
+
|
147
|
+
listeners: {
|
148
|
+
barChange: data => Neo.Main.alert({message: data.value})
|
149
|
+
}
|
150
|
+
|
151
|
+
}]
|
152
|
+
|
153
|
+
}
|
154
|
+
}
|
155
|
+
Neo.applyClassConfig(MainView);
|
156
|
+
</pre>
|
157
|
+
|
@@ -1 +1,67 @@
|
|
1
|
-
|
1
|
+
A Neo.mjs view is comprised of components and containers. A component is a visual widget, like a button,
|
2
|
+
and a container is a visual collection of components.
|
3
|
+
|
4
|
+
Neo.mjs is declarative, where your code _describes_ or _configures_ the things its creating.
|
5
|
+
|
6
|
+
For example, if you wanted to create a button, you'd look in the API docs and see that buttons
|
7
|
+
have a few key configs, including `text` and `iconCls`. The configs are properties you can
|
8
|
+
use to describe the component you're creating> You can also access or set the properties dynamically.
|
9
|
+
|
10
|
+
<pre data-neo>
|
11
|
+
import Base from '../../../../src/container/Base.mjs';
|
12
|
+
import Button from '../../../../src/button/Base.mjs';
|
13
|
+
class MainView extends Base {
|
14
|
+
static config = {
|
15
|
+
className : 'Example.view.MainView',
|
16
|
+
layout: {ntype:'vbox', align:'start'},
|
17
|
+
items : [{
|
18
|
+
module: Button,
|
19
|
+
text : 'Home',
|
20
|
+
iconCls: 'fa fa-home'
|
21
|
+
}]
|
22
|
+
}
|
23
|
+
}
|
24
|
+
Neo.applyClassConfig(MainView);
|
25
|
+
</pre>
|
26
|
+
|
27
|
+
The button config is just an object describing the button being created. In the example, it has three
|
28
|
+
properties:
|
29
|
+
|
30
|
+
- `module` is the type of thing being created; it's the imported module name.
|
31
|
+
- `text` is the button's text
|
32
|
+
- `iconCls` is the css class used for the button's icon. Neo.mjs automatically includes Font Awesome,
|
33
|
+
and `fa fa-home` matches a Font Awesome css class.
|
34
|
+
|
35
|
+
Components are almost always placed within a container. A container is a component that visually holds other
|
36
|
+
components. Containers have an `items:[]` config, which is an array of the components within the container.
|
37
|
+
Containers also have a `layout` property, which describes how the items are arranged.
|
38
|
+
|
39
|
+
Let's put a second button in the container.
|
40
|
+
|
41
|
+
<pre data-neo>
|
42
|
+
import Base from '../../../../src/container/Base.mjs';
|
43
|
+
import Button from '../../../../src/button/Base.mjs';
|
44
|
+
class MainView extends Base {
|
45
|
+
static config = {
|
46
|
+
className : 'Example.view.MainView',
|
47
|
+
layout: {ntype:'vbox', align:'start'}, // Change the ntype to 'hbox'
|
48
|
+
items : [{
|
49
|
+
module: Button,
|
50
|
+
text : 'Home',
|
51
|
+
iconCls: 'fa fa-home'
|
52
|
+
},{
|
53
|
+
module: Button,
|
54
|
+
text : 'Star',
|
55
|
+
iconCls: 'fa fa-star'
|
56
|
+
}]
|
57
|
+
}
|
58
|
+
}
|
59
|
+
Neo.applyClassConfig(MainView);
|
60
|
+
</pre>
|
61
|
+
|
62
|
+
If you run the example you'll see two buttons, arranged according to the `layout`. If you'd like,
|
63
|
+
modify the code to specify `ntype:'hbox'` and run it again.
|
64
|
+
|
65
|
+
Note that the layout specifies `ntype` rather than `module`. An `ntype` is an alias for a class
|
66
|
+
that has already been imported. Containers import all the layout types, so since we've already
|
67
|
+
imported container we can simply use `ntype` to specify which layout we want.
|