neo.mjs 4.4.18 → 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 +1 -1
- package/resources/scss/src/dialog/Toast.scss +164 -0
- package/src/dialog/Toast.mjs +190 -6
- package/src/form/field/Select.mjs +11 -0
- package/src/manager/Toast.mjs +173 -0
- package/src/manager/ToastDialog.mjs +0 -29
package/package.json
CHANGED
@@ -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
|
+
}
|
package/src/dialog/Toast.mjs
CHANGED
@@ -1,25 +1,209 @@
|
|
1
1
|
import Base from './Base.mjs';
|
2
|
-
import ToastManager from '../manager/
|
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
|
-
*
|
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
|
-
|
21
|
-
|
22
|
-
|
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
|
|
@@ -226,6 +226,17 @@ class Select extends Picker {
|
|
226
226
|
beforeSetStore(value, oldValue) {
|
227
227
|
oldValue?.destroy();
|
228
228
|
|
229
|
+
// to reduce boilerplate code, a store config object without a defined model should default
|
230
|
+
// to displayField & valueField defaults
|
231
|
+
if (Neo.typeOf(value) === 'Object' && !value.model) {
|
232
|
+
value.model = {
|
233
|
+
fields: [
|
234
|
+
{name: 'id', type: 'String'},
|
235
|
+
{name: 'name', type: 'String'}
|
236
|
+
]
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
229
240
|
return ClassSystemUtil.beforeSetInstance(value, Store);
|
230
241
|
}
|
231
242
|
|
@@ -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;
|