neo.mjs 4.4.19 → 4.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "4.4.19",
3
+ "version": "4.5.0",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -0,0 +1,164 @@
1
+ .neo-toast {
2
+ // todo: theming
3
+ --toast-background-color: lightblue;
4
+ --toast-color : #083741;
5
+
6
+ align-items : center;
7
+ background-color: var(--toast-background-color);
8
+ border-radius : 0.5rem;
9
+ box-shadow : 0 0.25rem 0.5rem rgba(0, 0, 0, 0.15);
10
+ color : var(--toast-color);
11
+ display : flex;
12
+ position : fixed;
13
+
14
+ & > div {
15
+ background-color: transparent;
16
+
17
+ .neo-toast-inner {
18
+ align-items: center;
19
+ display : flex;
20
+
21
+ &.neo-toast-has-title {
22
+ .neo-toast-text {
23
+ text-align: left;
24
+ }
25
+ }
26
+
27
+ & > div {
28
+ padding: 0.25em 0.5em;
29
+ }
30
+
31
+ .neo-toast-icon {
32
+ border-right: 2px solid var(--toast-color);
33
+ flex : 1;
34
+ font-size : 1.5em;
35
+ }
36
+
37
+ .neo-toast-text {
38
+ padding : 0.25em 1em;
39
+ text-align: center;
40
+
41
+ .neo-toast-msg {
42
+ font-size: 0.8em;
43
+ }
44
+
45
+ .neo-toast-title {
46
+ padding-bottom: 0.2em;
47
+ }
48
+ }
49
+
50
+ .neo-toast-close {
51
+ background : transparent;
52
+ border : 0;
53
+ color : inherit;
54
+ cursor : pointer;
55
+ font-size : 1.5rem;
56
+ line-height: 1.5;
57
+ margin-left: auto;
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ /* Toast positions */
64
+ .neo-toast-tr {
65
+ right: 1rem;
66
+ top : 1rem;
67
+ }
68
+
69
+ .neo-toast-tc {
70
+ left : 50%;
71
+ top : 1rem;
72
+ transform: translateX(-50%);
73
+ }
74
+
75
+ .neo-toast-tl {
76
+ left: 1rem;
77
+ top : 1rem;
78
+ }
79
+
80
+ .neo-toast-br {
81
+ bottom: 1rem;
82
+ right : 1rem;
83
+ }
84
+
85
+ .neo-toast-bc {
86
+ bottom : 1rem;
87
+ left : 50%;
88
+ transform: translateX(-50%);
89
+ }
90
+
91
+ .neo-toast-bl {
92
+ bottom: 1rem;
93
+ left : 1rem;
94
+ }
95
+
96
+ /* Toast slide-in animation */
97
+ @keyframes neo-toast-slide-down-in {
98
+ from {
99
+ transform: translateY(-150%);
100
+ }
101
+ to {
102
+ transform: translateY(0);
103
+ }
104
+ }
105
+
106
+ @keyframes neo-toast-slide-up-in {
107
+ from {
108
+ transform: translateY(150%);
109
+ }
110
+ to {
111
+ transform: translateY(0);
112
+ }
113
+ }
114
+
115
+ @keyframes neo-toast-slide-left-in {
116
+ from {
117
+ transform: translateX(-150%);
118
+ }
119
+ to {
120
+ transform: translateX(0);
121
+ }
122
+ }
123
+
124
+ @keyframes neo-toast-slide-right-in {
125
+ from {
126
+ transform: translateX(150%);
127
+ }
128
+ to {
129
+ transform: translateX(0);
130
+ }
131
+ }
132
+
133
+ /* Add the slide-in animation to the toast when the slide-in class is added */
134
+ .neo-toast-slide-down-in {
135
+ animation: neo-toast-slide-down-in 0.25s ease-out;
136
+ }
137
+
138
+ .neo-toast-slide-up-in {
139
+ animation: neo-toast-slide-up-in 0.25s ease-out;
140
+ }
141
+
142
+ .neo-toast-slide-left-in {
143
+ animation: neo-toast-slide-left-in 0.25s ease-out;
144
+ }
145
+
146
+ .neo-toast-slide-right-in {
147
+ animation: neo-toast-slide-right-in 0.25s ease-out;
148
+ }
149
+
150
+ /* Toast fade-out animation */
151
+ @keyframes neo-toast-fade-out {
152
+ from {
153
+ opacity: 1;
154
+ }
155
+ to {
156
+ opacity: 0;
157
+ }
158
+ }
159
+
160
+ /* Add the fade-out animation to the toast when the fade-out class is added */
161
+ .neo-toast-fade-out {
162
+ animation : neo-toast-fade-out 0.25s ease-out;
163
+ animation-fill-mode: forwards;
164
+ }
@@ -1,25 +1,209 @@
1
1
  import Base from './Base.mjs';
2
- import ToastManager from '../manager/ToastDialog.mjs';
2
+ import ToastManager from '../manager/Toast.mjs';
3
3
 
4
4
  /**
5
5
  * @class Neo.dialog.Toast
6
6
  * @extends Neo.dialog.Base
7
+ *
8
+ * @example
9
+ Neo.toast({
10
+ // mandatory
11
+ appName : this.component.appName,
12
+ msg : 'Alarm was set to 11:30 for journey into Neo development',
13
+ // optional defaults
14
+ closable : true, // false
15
+ iconCls : 'fa fa-bell', // null
16
+ maxWidth : 300, // 250
17
+ position : 'br', // 'tr'
18
+ slideDirection : 'right', // 'down'
19
+ title : 'Alarm Clock' // null
20
+ })
7
21
  */
8
22
  class Toast extends Base {
23
+ /**
24
+ * If true makes the toast sticky and show a close icon
25
+ * @member {Boolean} closable=false
26
+ */
27
+ closable = false
28
+ /**
29
+ * Change to use your own fade out animation
30
+ * @member {String} fadeOutCls='neo-toast-fade-out'
31
+ */
32
+ fadeOutCls = 'neo-toast-fade-out'
33
+ /**
34
+ * If set, it shows this icon in front of the text
35
+ * e.g. 'fa fa-cog'
36
+ * @member {String|null} iconCls=null
37
+ */
38
+ iconCls = null
39
+ /**
40
+ * Used by the ToastManager
41
+ * @member {Boolean} running=false
42
+ * @private
43
+ */
44
+ running = false
45
+ /**
46
+ * Change the complete styling with custom cls
47
+ * @member {String} toastCls='neo-toast-'
48
+ */
49
+ toastCls = 'neo-toast-'
50
+ /**
51
+ * Used by the ToastManager
52
+ * @member {String|null} toastManagerId=null
53
+ * @private
54
+ */
55
+ toastManagerId = null
56
+
9
57
  static getConfig() {return {
10
58
  /**
11
59
  * @member {String} className='Neo.dialog.Toast'
12
60
  * @protected
13
61
  */
14
- className: 'Neo.dialog.Toast'
62
+ className: 'Neo.dialog.Toast',
63
+ /**
64
+ * @member {String} ntype='toast'
65
+ * @protected
66
+ */
67
+ ntype: 'toast',
68
+ /**
69
+ * The Toast should not be moved
70
+ * @member {Boolean} draggable=false
71
+ */
72
+ draggable: false,
73
+ /**
74
+ * Header is not meant to be shown.
75
+ * @member {Object} headerConfig={hidden:true}
76
+ */
77
+ headerConfig: {
78
+ hidden: true
79
+ },
80
+ /**
81
+ * Limits the width of the Toast
82
+ * @member {Number} maxWidth=250
83
+ */
84
+ maxWidth: 250,
85
+ /**
86
+ * Sets the minimum height of the Toast
87
+ * @member {Number} minHeight=50
88
+ */
89
+ minHeight: 50,
90
+ /**
91
+ * Your message. You can also pass in an iconCls
92
+ * @member {String|null} msg_=null
93
+ */
94
+ msg_: null,
95
+ /**
96
+ * Describes the position of the toast, e.g. bl=bottom-left
97
+ * This creates a cls `toastCls + position`
98
+ * @member {'tl'|'tc'|'tr'|'bl'|'bc'|'br'} position='tr'
99
+ */
100
+ position_: 'tr',
101
+ /**
102
+ * @member {Boolean} resizable=false
103
+ */
104
+ resizable: false,
105
+ /**
106
+ * Describes which direction from which side the toasts slides-in
107
+ * This creates a cls `toastCls + slide- + direction + in`
108
+ * @member {'down'|'up'|'left'|'right'} slideDirection_=null
109
+ */
110
+ slideDirection_: 'down',
111
+ /**
112
+ * Timeout in ms after which the toast is removed
113
+ * @member {Number} timeout_=3000
114
+ */
115
+ timeout_: 3000,
116
+ /**
117
+ * @member {String|null} title=null
118
+ */
119
+ title: null,
120
+ /**
121
+ * @member {Function} itemTpl
122
+ */
123
+ itemTpl: data => {
124
+ let cls = data.cls;
125
+
126
+ return [
127
+ {cls: [`${cls}icon`, data.iconCls], removeDom: !data.iconCls},
128
+ {cls: `${cls}text`, cn: [
129
+ {cls: `${cls}title`, innerHTML: `${data.title}`, removeDom: !data.title},
130
+ {cls: `${cls}msg`, innerHTML: `${data.msg}`}
131
+ ]},
132
+ {cls: `${cls}close fa fa-close`, removeDom: !data.closable}
133
+ ]}
15
134
  }}
16
135
 
17
136
  /**
18
- * @param {Object} config
137
+ * Using the afterSetMsg to trigger the setup of the dom
138
+ * A new container is added as an item.
139
+ * We cannot use the vdom here.
140
+ *
141
+ * @param {String|null} value
142
+ * @param {String|null} oldValue
143
+ */
144
+ afterSetMsg(value, oldValue) {
145
+ let me = this,
146
+ toastCls = me.toastCls,
147
+ data = {closable: me.closable, cls: toastCls, iconCls: me.iconCls, msg: me.msg, title: me.title},
148
+ titleCls = (me.title && me.iconCls) ? `${toastCls}has-title` : '',
149
+ vdom = {cn: me.itemTpl(data)};
150
+
151
+ me.add({
152
+ cls: [`${toastCls}inner`, titleCls],
153
+ vdom
154
+ });
155
+
156
+ // if closable add a listener to the close-element
157
+ me.closable && me.addDomListeners([
158
+ {click: {fn: me.unregister, delegate: `.${me.toastCls}close`, scope: me}}
159
+ ])
160
+ }
161
+
162
+ /**
163
+ * Apply a cls, based on the position
164
+ * @param {String} value
165
+ * @param {String} oldValue
19
166
  */
20
- construct(config) {
21
- super.construct(config);
22
- ToastManager.register(this);
167
+ afterSetPosition(value, oldValue) {
168
+ value && this.addCls(`${this.toastCls}${value}`)
169
+ }
170
+
171
+ /**
172
+ * Apply a cls, based on the slideDirection
173
+ * @param {String} value
174
+ * @param {String} oldValue
175
+ */
176
+ afterSetSlideDirection(value, oldValue) {
177
+ value && this.addCls(`${this.toastCls}slide-${value}-in`)
178
+ }
179
+
180
+ /**
181
+ * Close the toast after the timeout if not closable
182
+ * @param {Number} value
183
+ * @param {Number} oldValue
184
+ */
185
+ async afterSetTimeout(value, oldValue) {
186
+ if (!this.closable && value) {
187
+ await Neo.timeout(value);
188
+ this.unregister();
189
+ }
190
+ }
191
+
192
+ /**
193
+ * After the close-click or timeout, we unregister the toast
194
+ * from the ToastManager
195
+ */
196
+ unregister() {
197
+ let me = this;
198
+
199
+ me.addDomListeners({
200
+ animationend: function () {
201
+ ToastManager.removeToast(me.toastManagerId);
202
+ me.destroy(true);
203
+ }
204
+ })
205
+
206
+ me.addCls(me.fadeOutCls);
23
207
  }
24
208
  }
25
209
 
@@ -0,0 +1,173 @@
1
+ import Base from './Base.mjs';
2
+
3
+ /**
4
+ * See Neo.dialog.Toast for examples
5
+ * @class Neo.manager.Toast
6
+ * @extends Neo.manager.Base
7
+ * @singleton
8
+ */
9
+ class Toast extends Base {
10
+ /**
11
+ * This is the default config for the Neo.dialog.Toast
12
+ * @member {Object}
13
+ */
14
+ defaultToastConfig = {
15
+ closable : false,
16
+ cls : ['neo-toast'],
17
+ maxWidth : 250,
18
+ position : 'tr',
19
+ running : false,
20
+ slideDirection: 'down',
21
+ timeout : 3000,
22
+ title : null
23
+ }
24
+ /**
25
+ * Currently only 1 is supported, because they would overlap
26
+ * @member {1} maxToasts=1
27
+ */
28
+ maxToasts = 1
29
+ /**
30
+ * Counts the currently running Toasts per area
31
+ * @member {Object} running
32
+ */
33
+ running = {
34
+ bc: 0, bl: 0, br: 0,
35
+ tc: 0, tl: 0, tr: 0
36
+ }
37
+ /**
38
+ * If you prefer your own class to open, override here
39
+ * @member {String} toastClass='Neo.dialog.Toast'
40
+ */
41
+ toastClass = 'Neo.dialog.Toast'
42
+
43
+ static getConfig() {return {
44
+ /**
45
+ * @member {String} className='Neo.manager.Toast'
46
+ * @protected
47
+ */
48
+ className: 'Neo.manager.Toast',
49
+ /**
50
+ * @member {Boolean} singleton=true
51
+ * @protected
52
+ */
53
+ singleton: true
54
+ }}
55
+
56
+ construct(config) {
57
+ super.construct(config);
58
+ Neo.toast = this.createToast.bind(this);
59
+ }
60
+
61
+ /**
62
+ * @param {Object} item
63
+ */
64
+ register(item) {
65
+ super.register(item);
66
+ this.runQueue();
67
+ }
68
+
69
+ /**
70
+ * Removes a collection item passed by reference or key
71
+ * @param {Object|String} item
72
+ */
73
+ unregister(item) {
74
+ super.unregister(item);
75
+ this.runQueue();
76
+ }
77
+
78
+ /**
79
+ * Create the Toast definition and pass it to the Collection
80
+ *
81
+ * @param {Object} toast
82
+ * @returns {Object}
83
+ */
84
+ createToast(toast) {
85
+ let me = this,
86
+ id;
87
+
88
+ if (!toast.msg || !toast.appName) {
89
+ !toast.msg && Neo.logError('[Neo.manager.Toast] Toast has to define a msg');
90
+ !toast.appName && Neo.logError('[Neo.manager.Toast] Toast has to define an appName. Typically me.appName.');
91
+ return null;
92
+ }
93
+
94
+ id = Neo.core.IdGenerator.getId('toastmanager-toast');
95
+
96
+ toast = {
97
+ id,
98
+ toastManagerId: id,
99
+ ...me.defaultToastConfig,
100
+ ...toast
101
+ };
102
+
103
+ me.register(toast);
104
+
105
+ return toast.toastManagerId;
106
+ }
107
+
108
+ /**
109
+ * Removes a task from collection.
110
+ * @param {String} toastId
111
+ */
112
+ removeToast(toastId) {
113
+ let me = this;
114
+
115
+ // decrease total of displayed toasts for a position
116
+ me.running[me.map.get(toastId).position]--;
117
+ me.unregister(toastId);
118
+ }
119
+
120
+ /**
121
+ * Runs a ToastManager to show an item from collection.
122
+ */
123
+ runQueue() {
124
+ let me = this,
125
+ toast;
126
+
127
+ if (me.getCount > 0) {
128
+ toast = me.findFirstToast();
129
+
130
+ toast && me.showToast(toast)
131
+ }
132
+ }
133
+
134
+ showToast(toast) {
135
+ let toastConfig = Neo.clone(toast);
136
+ // increase total of displayed toasts for a position
137
+ this.running[toastConfig.position]++
138
+ // Neo.create does not allow to pass an id
139
+ delete toastConfig.id;
140
+ Neo.create(this.toastClass, toastConfig);
141
+ }
142
+
143
+ /**
144
+ * Find the first toast based on the maximum allowed toasts
145
+ * @returns {*}
146
+ */
147
+ findFirstToast() {
148
+ let me = this,
149
+ firstToast, item;
150
+
151
+ me.filters = [{property: 'running', value: false}];
152
+ me.filter();
153
+
154
+ for (item of me.map.values()) {
155
+ if (me.running[item.position] < me.maxToasts) {
156
+ firstToast = item;
157
+ break;
158
+ }
159
+ }
160
+
161
+ me.clearFilters();
162
+
163
+ return firstToast;
164
+ }
165
+ }
166
+
167
+ Neo.applyClassConfig(Toast);
168
+
169
+ let instance = Neo.create(Toast);
170
+
171
+ Neo.applyToGlobalNs(instance);
172
+
173
+ export default instance;
@@ -1,29 +0,0 @@
1
- import Base from '../manager/Base.mjs';
2
-
3
- /**
4
- * @class Neo.manager.ToastDialog
5
- * @extends Neo.manager.Base
6
- * @singleton
7
- */
8
- class ToastDialog extends Base {
9
- static getConfig() {return {
10
- /**
11
- * @member {String} className='Neo.manager.ToastDialog'
12
- * @protected
13
- */
14
- className: 'Neo.manager.ToastDialog',
15
- /**
16
- * @member {Boolean} singleton=true
17
- * @protected
18
- */
19
- singleton: true
20
- }}
21
- }
22
-
23
- Neo.applyClassConfig(ToastDialog);
24
-
25
- let instance = Neo.create(ToastDialog);
26
-
27
- Neo.applyToGlobalNs(instance);
28
-
29
- export default instance;