neo.mjs 6.13.0 → 6.15.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 (78) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/apps/covid/neo-config.json +1 -1
  3. package/apps/covid/view/HeaderContainer.mjs +2 -2
  4. package/apps/form/view/pages/Page10.mjs +2 -2
  5. package/apps/portal/view/ViewportController.mjs +5 -4
  6. package/apps/portal/view/home/ContentBox.mjs +80 -0
  7. package/apps/portal/view/home/MainContainer.mjs +51 -15
  8. package/apps/portal/view/learn/ContentTreeList.mjs +10 -3
  9. package/apps/portal/view/learn/MainContainerController.mjs +37 -5
  10. package/apps/portal/view/learn/MainContainerModel.mjs +51 -7
  11. package/apps/portal/view/learn/PageContainer.mjs +21 -9
  12. package/apps/sharedcovid/neo-config.json +1 -1
  13. package/apps/sharedcovid/view/HeaderContainer.mjs +2 -2
  14. package/examples/ServiceWorker.mjs +2 -2
  15. package/examples/button/base/MainContainer.mjs +2 -2
  16. package/examples/button/split/MainContainer.mjs +2 -2
  17. package/examples/component/process/MainContainer.mjs +3 -3
  18. package/examples/component/process/realWorldExample/MainContainer.mjs +15 -15
  19. package/examples/component/toast/MainContainer.mjs +4 -4
  20. package/examples/dialog/DemoDialog.mjs +4 -4
  21. package/examples/fieldWithPrefix/MainContainer.mjs +4 -5
  22. package/examples/form/field/{select → combobox}/MainContainer.mjs +7 -10
  23. package/examples/form/field/{select → combobox}/MainModel.mjs +4 -4
  24. package/examples/form/field/{select → combobox}/MainStore.mjs +2 -2
  25. package/examples/form/field/{select → combobox}/app.mjs +1 -1
  26. package/examples/form/field/{select → combobox}/index.html +1 -1
  27. package/examples/form/field/{select → combobox}/neo-config.json +1 -1
  28. package/examples/tableFiltering/MainContainer.mjs +2 -2
  29. package/package.json +4 -4
  30. package/resources/data/deck/learnneo/pages/2023-10-14T19-25-08-153Z.md +16 -1
  31. package/resources/data/deck/learnneo/pages/ComponentsAndContainers.md +180 -0
  32. package/resources/data/deck/learnneo/pages/Config.md +11 -4
  33. package/resources/data/deck/learnneo/pages/DescribingTheUI.md +6 -0
  34. package/resources/data/deck/learnneo/pages/Earthquakes.md +36 -9
  35. package/resources/data/deck/learnneo/pages/Events.md +55 -43
  36. package/resources/data/deck/learnneo/pages/GuideEvents.md +9 -8
  37. package/resources/data/deck/learnneo/pages/References.md +14 -7
  38. package/resources/data/deck/learnneo/pages/TodoList.md +241 -0
  39. package/resources/data/deck/learnneo/pages/WhyNeo-Quick.md +6 -11
  40. package/resources/data/deck/learnneo/tree.json +2 -0
  41. package/resources/scss/src/apps/portal/home/ContentBox.scss +26 -0
  42. package/resources/scss/src/apps/portal/home/MainContainer.scss +4 -12
  43. package/resources/scss/src/apps/portal/learn/MainContainer.scss +0 -7
  44. package/resources/scss/src/apps/portal/learn/PageContainer.scss +35 -0
  45. package/resources/scss/src/apps/portal/learn/PageSectionsPanel.scss +8 -0
  46. package/resources/scss/src/form/field/{Select.scss → ComboBox.scss} +8 -8
  47. package/resources/scss/theme-dark/form/field/ComboBox.scss +9 -0
  48. package/resources/scss/theme-light/form/field/ComboBox.scss +9 -0
  49. package/resources/scss/theme-neo-light/form/field/ComboBox.scss +9 -0
  50. package/src/DefaultConfig.mjs +2 -2
  51. package/src/component/Base.mjs +16 -1
  52. package/src/container/Viewport.mjs +5 -2
  53. package/src/controller/Application.mjs +12 -1
  54. package/src/controller/Base.mjs +15 -4
  55. package/src/controller/Component.mjs +5 -1
  56. package/src/core/Observable.mjs +62 -22
  57. package/src/form/field/Base.mjs +21 -9
  58. package/src/form/field/Chip.mjs +3 -3
  59. package/src/form/field/Color.mjs +3 -3
  60. package/src/form/field/{Select.mjs → ComboBox.mjs} +179 -130
  61. package/src/form/field/Country.mjs +3 -3
  62. package/src/form/field/Text.mjs +7 -10
  63. package/src/form/field/_export.mjs +2 -2
  64. package/src/main/DomEvents.mjs +2 -1
  65. package/src/main/addon/MonacoEditor.mjs +2 -2
  66. package/src/main/addon/Navigator.mjs +27 -24
  67. package/src/selection/ListModel.mjs +13 -14
  68. package/src/selection/Model.mjs +10 -10
  69. package/src/toolbar/Paging.mjs +2 -2
  70. package/src/util/HashHistory.mjs +1 -0
  71. package/src/worker/App.mjs +5 -1
  72. package/src/worker/Manager.mjs +14 -7
  73. package/test/components/app.mjs +1 -1
  74. package/test/components/files/form/field/{Select.mjs → ComboBox.mjs} +9 -7
  75. package/test/components/siesta.js +1 -1
  76. package/resources/scss/theme-dark/form/field/Select.scss +0 -9
  77. package/resources/scss/theme-light/form/field/Select.scss +0 -9
  78. package/resources/scss/theme-neo-light/form/field/Select.scss +0 -9
@@ -1,3 +1,5 @@
1
+ ## Introduction
2
+
1
3
  All components fire events. For example, form fields fire a `change` event, various
2
4
  focus events, and others. Some other types fire events too, such as `Neo.data.Store`,
3
5
  which fires a `load` event after the store is loaded with data.
@@ -5,34 +7,35 @@ which fires a `load` event after the store is loaded with data.
5
7
  Some terminology related to events is that events are _fired_, and as a result, some
6
8
  event _handler_ — or _listener_ — is run.
7
9
 
10
+ ## Listeners
11
+
8
12
  To specify an event handler, use `listeners: {}`, specifying in as many event/handler
9
13
  pairs as you need.
10
14
 
11
15
  The code below shows two text fields, with `listeners` for `change` and `focusEnter`.
12
- (The events for any component are documened in the API docs.)
16
+ (The events for any component are documented in the API docs.)
13
17
 
14
18
  <pre data-neo>
15
- import Base from '../../../../src/container/Base.mjs';
19
+ import Container from '../../../../src/container/Base.mjs';
16
20
  import TextField from '../../../../src/form/field/Text.mjs';
17
- class MainView extends Base {
21
+
22
+ class MainView extends Container {
18
23
  static config = {
19
- className : 'Example.view.MainView',
20
- layout: {ntype:'vbox', align:'start'},
21
- items : [{
22
- module: TextField,
23
- labelText : 'First name',
24
+ className: 'Example.view.MainView',
25
+ layout : {ntype:'vbox', align:'start'},
26
+
27
+ itemDefaults: {
28
+ module : TextField,
24
29
  listeners: {
25
- change: data => Neo.Main.log({value:data.value}),
30
+ change : data => Neo.Main.log({value:data.value}),
26
31
  focusEnter: data => Neo.Main.log({value: `Entering ${data.component.labelText}`})
27
32
  }
28
33
  },
29
- {
30
- module: TextField,
31
- labelText : 'Last name',
32
- listeners: {
33
- change: data => Neo.Main.log({value: data.value}),
34
- focusEnter: data => Neo.Main.log({value: `Entering ${data.component.labelText}`})
35
- }
34
+
35
+ items: [{
36
+ labelText: 'First name'
37
+ }, {
38
+ labelText: 'Last name'
36
39
  }]
37
40
  }
38
41
  }
@@ -42,37 +45,39 @@ Neo.setupClass(MainView);
42
45
  If you run the example, and open the browser's debugger, you'll see the console being logged as you type or give
43
46
  focus to either field.
44
47
 
48
+ ## In-line or separated into a controller
49
+
45
50
  Note that the handlers specify an in-line function. For trivial cases, that might be ok. But normally
46
51
  you'd want better separation of concerns by placing those event handlers in a separate class. Neo.mjs provides
47
52
  that with a _component controller_.
48
53
 
49
54
  A `Neo.controller.Component` is a simple class associated with a component class. As a view is created, an
50
- instance of its associated contoller is automatically created.
55
+ instance of its associated controller is automatically created.
51
56
 
52
57
  <pre data-neo>
53
- import Base from '../../../../src/container/Base.mjs';
54
- import Controller from '../../../../src/controller/Component.mjs';
55
- import TextField from '../../../../src/form/field/Text.mjs';
58
+ import Container from '../../../../src/container/Base.mjs';
59
+ import Controller from '../../../../src/controller/Component.mjs';
60
+ import TextField from '../../../../src/form/field/Text.mjs';
56
61
 
57
62
  class MainViewController extends Controller {
58
63
  static config = {
59
64
  className: 'Example.view.MainViewController'
60
65
  }
61
- onChange(data){
62
- console.log(data.value);
66
+ onChange(data) {
67
+ Neo.Main.log({value: data.value})
63
68
  }
64
69
  }
65
70
  Neo.setupClass(MainViewController);
66
71
 
67
72
 
68
- class MainView extends Base {
73
+ class MainView extends Container {
69
74
  static config = {
70
75
  className : 'Example.view.MainView',
71
76
  controller: MainViewController,
72
- layout: {ntype:'vbox', align:'start'},
73
- items : [{
74
- module: TextField,
75
- labelText : 'Name',
77
+ layout : {ntype:'vbox', align:'start'},
78
+ items : [{
79
+ module : TextField,
80
+ labelText: 'Name',
76
81
  listeners: {
77
82
  change: 'onChange'
78
83
  }
@@ -88,12 +93,16 @@ to make it easier to see the source code for every class being used. But in an
88
93
  actual applications the controller class would be coded in its own source file &mdash; named something
89
94
  like `MainViewController.mjs` &mdash; and that would be imported into the view.)
90
95
 
96
+ ## Neo.core.Observable
97
+
91
98
  The ability to fire events and add listeners is provided by `Neo.core.Observable`, which is mixed into
92
99
  classes that need that ability. All components are observable, `Neo.data.Store` is observable, and some
93
100
  others. `Neo.core.Observable` introduces a few methods and properties, such as `listeners`, which
94
101
  is used in the examples above, `on()` for procedurally adding an event listener, and `fire()`, which is
95
102
  how you fire events in the custom classes you create.
96
103
 
104
+ ## Firing an event when a value changes
105
+
97
106
  Here's example illustrating how `fire()` is used. The code defines a `ToggleButton`
98
107
  class, which is just a button with a `checked` property: the button shows a checked or unchecked
99
108
  checkbox depending on the value of `checked`.
@@ -103,37 +112,40 @@ We'll discuss that at length later, but in a nutshell, config properties ending
103
112
  automatically get lifecycle methods run before the value is assigned, after the value is assigned, and
104
113
  before the value is accessed. We're using the _after_ method to fire a `change` event.
105
114
 
115
+
106
116
  <pre data-neo>
107
- import Base from '../../../../src/container/Base.mjs';
108
- import Button from '../../../../src/button/Base.mjs';
109
- import TextField from '../../../../src/form/field/Text.mjs';
117
+ import Button from '../../../../src/button/Base.mjs';
118
+ import Container from '../../../../src/container/Base.mjs';
110
119
 
111
120
  class ToggleButton extends Button {
112
121
  static config = {
113
122
  className: 'Example.view.ToggleButton',
114
- checked_: false
123
+ checked_ : false
115
124
  }
116
- afterSetChecked(checked){
117
- this.iconCls = checked?'fa fa-square-check':'fa fa-square';
118
- this.fire('change', {component: this, checked}); // This is where our custom event is being fired
125
+ afterSetChecked(checked) {
126
+ this.iconCls = checked ? 'fa fa-square-check' : 'fa fa-square';
127
+
128
+ // This is where our custom event is being fired
129
+ this.fire('change', {component: this, checked})
119
130
  }
120
- onClick(data){
131
+ onClick(data) {
121
132
  super.onClick(data);
122
- this.checked = !this.checked;
133
+ this.checked = !this.checked
123
134
  }
124
135
  }
125
136
  Neo.setupClass(ToggleButton);
126
137
 
127
138
 
128
- class MainView extends Base {
139
+ class MainView extends Container {
129
140
  static config = {
130
- className : 'Example.view.MainView',
131
- layout: {ntype:'vbox', align:'start'},
132
- items : [{
133
- module: ToggleButton,
134
- text: 'Toggle',
141
+ className: 'Example.view.MainView',
142
+ layout : {ntype:'vbox', align:'start'},
143
+ items : [{
144
+ module : ToggleButton,
145
+ text : 'Toggle',
135
146
  listeners: {
136
- change: data => console.log(data.checked) // Here, we're listening to the custom event
147
+ // Here, we're listening to the custom event
148
+ change: data => Neo.Main.log({value: data.checked})
137
149
  }
138
150
  }]
139
151
  }
@@ -1,12 +1,13 @@
1
1
  [Add content on listeners options here]
2
2
 
3
- How are events set up? We don't really care, but in case you're curious: Neo.mjs has a `Neo.core.Observable` class
4
- that can be mixed into any class. It maintains a `listeners` object map that's a key-value pair, where
5
- the key is the event name, and the value is an array of function references. The first time a listener is
6
- added an entry is added to the map using the event name as the key, and the event handler added as the first
7
- item in the associated array. If another listener is added for the same event, a second item is added to the
8
- array. If a new event is added, a new entry is added. Etc. When the event is fired, Neo.mjs looks up the map
9
- entry for the event name, then runs each function in the array, passing whatever data is specified in the
10
- call to `fire()`.
3
+ How are events set up? The details don't really matter, but in case you're curious:
4
+ Neo.mjs has a `Neo.core.Observable` class that can be mixed into any class. It maintains
5
+ a `listeners` object map that's a key-value pair, where the key is the event name, and
6
+ the value is an array of function references. The first time a listener is added, an
7
+ entry is added to the map using the event name as the key, and the event handler added
8
+ as the first item in the associated array. If another listener is added for the same
9
+ event, a second item is added to the array. If a new event is added, a new entry is
10
+ added. Etc. When the event is fired, Neo.mjs looks up the map entry for the event name,
11
+ then runs each function in the array, passing whatever data is specified in the call to `fire()`.
11
12
 
12
13
  <img style="width:80%" src="https://s3.amazonaws.com/mjs.neo.learning.images/gettingStarted/events/ObservableInMemory.png"></img>
@@ -1,3 +1,5 @@
1
+ ## Introduction
2
+
1
3
  Controllers often need to get references to components in order to update
2
4
  the UI or access component properties.
3
5
  There are two common ways of doing that:
@@ -5,11 +7,13 @@ There are two common ways of doing that:
5
7
  - Using the component references passed to the event handler
6
8
  - Tagging a component with a `reference` and using `this.getReference()` in the controller
7
9
 
10
+ ## References are usually passed to event handlers
11
+
8
12
  Here's an example with one button. Clicking on the button will disable it.
9
13
  As you can see, the handler uses the component reference pass in via `data.component`.
10
14
 
11
15
  <pre data-neo>
12
- import Button from '../../../../src/Button/Base.mjs';
16
+ import Button from '../../../../src/button/Base.mjs';
13
17
  import Container from '../../../../src/container/Base.mjs';
14
18
  import Controller from '../../../../src/controller/Component.mjs';
15
19
 
@@ -39,12 +43,14 @@ class MainView extends Container {
39
43
  Neo.setupClass(MainView);
40
44
  </pre>
41
45
 
46
+ ## Using getReference()
47
+
42
48
  But what if we need to get a reference to another component in the view? In that case
43
49
  you tag the component you need with a `reference` config, then use `getReference()` in
44
50
  the controller.
45
51
 
46
52
  <pre data-neo>
47
- import Button from '../../../../src/Button/Base.mjs';
53
+ import Button from '../../../../src/button/Base.mjs';
48
54
  import Container from '../../../../src/container/Base.mjs';
49
55
  import Controller from '../../../../src/controller/Component.mjs';
50
56
 
@@ -53,10 +59,10 @@ class MainViewController extends Controller {
53
59
  className: 'Example.view.MainViewController'
54
60
  }
55
61
  onDisableButtonClick(data){
56
- data.component.disabled = true;
62
+ data.component.disabled = true
57
63
  }
58
64
  onEnableButtonClick(data){
59
- this.getReference('myButton').disabled = false;
65
+ this.getReference('myButton').disabled = false
60
66
  }
61
67
  }
62
68
  Neo.setupClass(MainViewController);
@@ -82,6 +88,7 @@ class MainView extends Container {
82
88
  Neo.setupClass(MainView);
83
89
  </pre>
84
90
 
91
+ ## Getting a reference when debugging
85
92
 
86
93
  There are other ways of getting references, but these are either non-standard or for debugging.
87
94
  For example, components have an `up()` method, and containers have a `down()` method. These look
@@ -98,7 +105,7 @@ The following example gets a reference to the _Learn_ button at the top of this
98
105
  Again &mdash; that use of `Neo.findFirst()` might be handy when debugging, but it should never be used in app logic.
99
106
 
100
107
  <pre data-neo>
101
- import Button from '../../../../src/Button/Base.mjs';
108
+ import Button from '../../../../src/button/Base.mjs';
102
109
  import Container from '../../../../src/container/Base.mjs';
103
110
 
104
111
  class MainView extends Container {
@@ -110,14 +117,14 @@ class MainView extends Container {
110
117
  text : 'Change Learn caption',
111
118
  handler: data=>{
112
119
  const component = Neo.findFirst({text:'Learn'});
113
- component?.set({text: 'Yikes!', ui: 'primary'});
120
+ component?.set({text: 'Yikes!', ui: 'primary'})
114
121
  }
115
122
  }, {
116
123
  module : Button,
117
124
  text : 'Restore Learn caption',
118
125
  handler: data=>{
119
126
  const component = Neo.findFirst({text:'Yikes!'});
120
- component?.set({text: 'Learn', ui: 'ghost'});
127
+ component?.set({text: 'Learn', ui: 'ghost'})
121
128
  }
122
129
  }]
123
130
  }
@@ -0,0 +1,241 @@
1
+ ## HTML Style
2
+
3
+ In case you did not work with neo yet, but come from a more HTML driven ecosystem,
4
+ you could achieve the task in a similar way.
5
+
6
+ <pre data-neo>
7
+ import Component from '../../../../src/component/Base.mjs';
8
+ import NeoArray from '../../../../src/util/Array.mjs';
9
+ import VdomUtil from '../../../../src/util/VDom.mjs';
10
+
11
+ class MainComponent extends Component {
12
+ static config = {
13
+ className: 'Neo.examples.todoList.version1.MainComponent',
14
+ autoMount: true,
15
+ height : 200,
16
+ margin : 10,
17
+ maxWidth : 300,
18
+ style : {border: '1px solid #000', margin: '20px', overflow: 'scroll'},
19
+ width : 300,
20
+
21
+ items: [
22
+ {id: 1, done: true, text: 'Todo Item 1'},
23
+ {id: 2, done: false, text: 'Todo Item 2'},
24
+ {id: 3, done: false, text: 'Todo Item 3'}
25
+ ],
26
+
27
+ inputValue: null,
28
+
29
+ vdom:
30
+ {cn: [
31
+ {tag: 'ol', cn: []},
32
+ {cn: [
33
+ {tag: 'input', cls: ['todo-input'], required: true, style: {marginLeft: '20px'}},
34
+ {tag: 'button', cls: ['todo-add-button'], html : 'Add Item', style: {marginLeft: '1em'}}
35
+ ]}
36
+ ]}
37
+ }
38
+
39
+ construct(config) {
40
+ super.construct(config);
41
+
42
+ let me = this;
43
+
44
+ me.addDomListeners([
45
+ {click: me.onAddButtonClick, delegate: 'todo-add-button'},
46
+ {click: me.onCheckIconClick, delegate: 'todo-item'},
47
+ {input: me.onInputFieldChange, delegate: 'todo-input'}
48
+ ]);
49
+
50
+ me.createItems(me.items || [])
51
+ }
52
+
53
+ createItems(items) {
54
+ let me = this,
55
+ cls;
56
+
57
+ items.forEach(item => {
58
+ cls = ['todo-item'];
59
+
60
+ if (item.done) {
61
+ cls.push('fa', 'fa-check')
62
+ } else {
63
+ cls.push('far', 'fa-square')
64
+ }
65
+
66
+ me.vdom.cn[0].cn.push({
67
+ tag: 'li',
68
+ cn : [
69
+ {tag: 'span', cls, style: {cursor: 'pointer', width: '20px'}},
70
+ {vtype: 'text', html: item.text}
71
+ ]
72
+ });
73
+ });
74
+
75
+ me.update()
76
+ }
77
+
78
+ onAddButtonClick() {
79
+ let me = this;
80
+
81
+ if (me.inputValue) {
82
+ me.createItems([{
83
+ id : null,
84
+ done: false,
85
+ text: me.inputValue
86
+ }])
87
+ }
88
+ }
89
+
90
+ onCheckIconClick(data) {
91
+ let me = this,
92
+ cls = ['far', 'fa-square'],
93
+ oldCls = ['fa', 'fa-check'],
94
+ node = VdomUtil.findVdomChild(me.vdom, data.path[0].id).vdom;
95
+
96
+ if (data.path[0].cls.includes('fa-square')) {
97
+ cls = ['fa', 'fa-check'];
98
+ oldCls = ['far', 'fa-square']
99
+ }
100
+
101
+ NeoArray.remove(node.cls, oldCls);
102
+ NeoArray.add(node.cls, cls);
103
+
104
+ me.update()
105
+ }
106
+
107
+ onInputFieldChange(data) {
108
+ this.inputValue = data.value
109
+ }
110
+ }
111
+
112
+ Neo.setupClass(MainComponent);
113
+ </pre>
114
+
115
+ ## Neo Style
116
+
117
+ content
118
+
119
+ <pre data-neo>
120
+ import Container from '../../../../src/container/Base.mjs';
121
+ import List from '../../../../src/list/Base.mjs';
122
+ import Model from '../../../../src/data/Model.mjs';
123
+ import Store from '../../../../src/data/Store.mjs';
124
+ import TextField from '../../../../src/form/field/Text.mjs';
125
+ import Toolbar from '../../../../src/toolbar/Base.mjs';
126
+
127
+ class TodoListModel extends Model {
128
+ static config = {
129
+ className : 'Neo.examples.todoList.version2.MainModel',
130
+ keyProperty: 'id',
131
+
132
+ fields: [{
133
+ name: 'id',
134
+ type: 'Int'
135
+ }, {
136
+ name: 'done',
137
+ type: 'Boolean'
138
+ }, {
139
+ name: 'text',
140
+ type: 'String'
141
+ }]
142
+ }
143
+ }
144
+
145
+ Neo.setupClass(TodoListModel);
146
+
147
+
148
+ class TodoListStore extends Store {
149
+ static config = {
150
+ className : 'Neo.examples.todoList.version2.TodoListStore',
151
+ keyProperty: 'id',
152
+ model : TodoListModel,
153
+
154
+ data: [
155
+ {id: 1, done: true, text: 'Todo Item 1'},
156
+ {id: 2, done: false, text: 'Todo Item 2'},
157
+ {id: 3, done: false, text: 'Todo Item 3'}
158
+ ],
159
+
160
+ sorters: [{
161
+ property : 'done',
162
+ direction: 'DESC'
163
+ }, {
164
+ property : 'id',
165
+ direction: 'ASC'
166
+ }]
167
+ }
168
+ }
169
+
170
+ Neo.setupClass(TodoListStore);
171
+
172
+
173
+ class MainContainer extends Container {
174
+ static config = {
175
+ className: 'Neo.examples.todoList.version2.MainContainer',
176
+ style : {padding: '20px'},
177
+
178
+ // custom configs
179
+ idCounter: 3,
180
+ store : null
181
+ }
182
+
183
+ construct(config) {
184
+ super.construct(config);
185
+
186
+ let me = this;
187
+
188
+ me.store = Neo.create({
189
+ module: TodoListStore
190
+ });
191
+
192
+ me.items = [{
193
+ module : List,
194
+ displayField : 'text',
195
+ flex : 1,
196
+ store : me.store,
197
+ style : {padding: '5px'},
198
+ useCheckBoxes: true
199
+ }, {
200
+ module: Toolbar,
201
+ flex : 'none',
202
+ dock : 'bottom',
203
+ items : [{
204
+ module : TextField,
205
+ flex : 1,
206
+ labelPosition: 'inline',
207
+ labelText : 'Item Text',
208
+ reference : 'addItemField'
209
+ }, '->', {
210
+ handler : me.onAddButtonClick,
211
+ handlerScope: me,
212
+ scope : me,
213
+ style : {height: '27px', marginLeft: '1em'},
214
+ text : 'Add Item'
215
+ }]
216
+ }];
217
+ }
218
+
219
+ onAddButtonClick() {
220
+ let me = this,
221
+ field = me.down({reference: 'addItemField'}),
222
+ data;
223
+
224
+ if (field.value) {
225
+ me.idCounter++;
226
+
227
+ data = me.store.data;
228
+
229
+ data.push({
230
+ id : me.idCounter,
231
+ done: false,
232
+ text: field.value
233
+ });
234
+
235
+ me.store.data = data
236
+ }
237
+ }
238
+ }
239
+
240
+ Neo.setupClass(MainContainer);
241
+ </pre>
@@ -1,21 +1,16 @@
1
1
  Neo.mjs applications can be written quickly thanks to its syntax, features, and debugging convenience.
2
2
 
3
+ ## Property lifecycle hooks
4
+ Neo.mjs classes let you specify properties in a way that allows code to detect "before" and "after" changes,
5
+ which makes it easy to handle value validation and transformation, and react to changes.
3
6
 
4
- <details>
5
- <summary><h3>Property lifecycle hooks</h3></summary>
6
- Neo.mjs classes let you specify properties in a way that allows code to detect "before" and "after" changes, which makes it easy to handle value validation and transformation, and react to changes.
7
- </details>
8
-
9
- <details>
10
- <summary><h3>Elegant state management</h3></summary>
7
+ ## Elegant state management
11
8
  Neo.mjs has elegant yet powerful state management features that make it easy to create shared, bindable data.
12
9
  For example, if two components are bound to the same property, a change to the property will automatically be
13
10
  applied to both components.
14
- </details>
15
11
 
16
- <details>
17
- <summary><h3>Simple and powerful debugging</h3></summary>
12
+ ## Simple and powerful debugging
18
13
  Debugging is easy because Neo.mjs uses standard JavaScript, the Neo.mjs class config system, and built-in
19
14
  debugging tools. For example, while developing an application you can click on a component, and in the debugger
20
15
  easily inspect the component and update its properties &mdash; these updates are immediately reflected in the running application.
21
- </details>
16
+
@@ -18,10 +18,12 @@
18
18
  {"name": "Tutorials", "parentId": null, "isLeaf": false, "expanded": false, "id": "Tutorials"},
19
19
  {"name": "Rock Scissors Paper", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "RSP", "hidden": true},
20
20
  {"name": "Earthquakes", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "Earthquakes"},
21
+ {"name": "Todo List", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "TodoList"},
21
22
  {"name": "Guides", "parentId": null, "isLeaf": false, "expanded": false, "id": "InDepth"},
22
23
  {"name": "Config", "parentId": "InDepth", "isLeaf": false, "id": "Config"},
23
24
  {"name": "Instance Lifecycle", "parentId": "InDepth", "isLeaf": false, "id": "InstanceLifecycle"},
24
25
  {"name": "User Input (Forms)", "parentId": "InDepth", "isLeaf": false, "id": "Forms"},
26
+ {"name": "Components and Containers", "parentId": "InDepth", "isLeaf": true, "id": "ComponentsAndContainers"},
25
27
  {"name": "Layouts", "parentId": "InDepth", "isLeaf": false, "id": "Layouts"},
26
28
  {"name": "Custom Components", "parentId": "InDepth", "isLeaf": false, "id": "CustomComponents"},
27
29
  {"name": "Events", "parentId": "InDepth", "isLeaf": true, "expanded": false, "id": "GuideEvents"},
@@ -0,0 +1,26 @@
1
+ .portal-content-box {
2
+ border : 1px solid darkgray;
3
+ cursor : pointer;
4
+ color : #000;
5
+ height : 200px;
6
+ margin-top : 2em;
7
+ padding : 0 1em 1em 1em;
8
+ text-decoration: none;
9
+ width : 300px;
10
+
11
+ &:hover {
12
+ background-color: lightblue;
13
+ }
14
+
15
+ &:not(:last-child) {
16
+ margin-right: 3em;
17
+ }
18
+
19
+ .portal-content-box-content {
20
+
21
+ }
22
+
23
+ .portal-content-box-header {
24
+
25
+ }
26
+ }
@@ -1,15 +1,11 @@
1
1
  .newwebsite-viewport {
2
- align-items : center !important;
3
- display : flex !important;
4
- gap : 48px;
5
- justify-content: center !important;
6
- padding : 10% 15% 15% 15%;
2
+ gap : 48px;
3
+ overflow-y: scroll;
4
+ padding : 5%;
7
5
  }
8
6
 
9
7
  .button-group {
10
- display : flex !important;
11
- flex-direction: row-reverse !important;
12
- gap : 8px !important;
8
+ gap: 8px !important;
13
9
  }
14
10
 
15
11
  .neo-h1 {
@@ -26,7 +22,3 @@
26
22
  height : 150px;
27
23
  width : 100%;
28
24
  }
29
-
30
- .get-started-button {
31
- cursor: not-allowed !important;
32
- }
@@ -4,13 +4,6 @@
4
4
  .main-content-splitter {
5
5
  margin: 0;
6
6
  }
7
-
8
- .learn-content-container {
9
- // align-items: center !important;
10
- // padding: 0 3rem;
11
- overflow: scroll;
12
- }
13
-
14
7
  }
15
8
 
16
9