vanilla-jui 1.3.11 → 1.4.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/dist/index.d.ts +2927 -0
- package/dist/index.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +4 -3
- package/src/components/accordion.ts +522 -0
- package/src/components/drop.ts +497 -0
- package/src/components/flow.ts +1579 -0
- package/src/components/form.ts +953 -0
- package/src/components/{icons.js → icons.ts} +24 -11
- package/src/components/menu.ts +615 -0
- package/src/components/{modal.js → modal.ts} +560 -237
- package/src/components/offcanvas.ts +496 -0
- package/src/components/{pagination.js → pagination.ts} +251 -76
- package/src/components/parabola.ts +335 -0
- package/src/components/{sticky.js → sticky.ts} +123 -98
- package/src/components/{swiper.js → swiper.ts} +510 -232
- package/src/components/tabs.ts +984 -0
- package/src/components/theme.ts +437 -0
- package/src/components/toast.ts +371 -0
- package/src/components/toc.ts +385 -0
- package/src/components/tooltip.ts +179 -0
- package/src/components/validator.ts +596 -0
- package/src/core/{Component.js → Component.ts} +134 -27
- package/src/css/animation.css +31 -1
- package/src/css/card.css +1 -1
- package/src/css/color.css +863 -1013
- package/src/css/color_p3.css +822 -975
- package/src/css/components.css +1 -0
- package/src/css/form.css +1 -1
- package/src/css/icon.css +17 -1
- package/src/css/index.css +2 -2
- package/src/css/menu.css +1 -1
- package/src/css/tabs.css +1 -0
- package/src/css/tokens.css +1 -1
- package/src/index.ts +37 -0
- package/src/locales/{index.js → index.ts} +1 -2
- package/src/types.d.ts +1 -0
- package/src/utilities/browser.ts +131 -0
- package/src/utilities/cache.ts +57 -0
- package/src/utilities/core.ts +614 -0
- package/src/utilities/dom.ts +468 -0
- package/src/utilities/events.ts +106 -0
- package/src/utilities/http.ts +35 -0
- package/src/utilities/storage.ts +46 -0
- package/src/components/accordion.js +0 -373
- package/src/components/drop.js +0 -437
- package/src/components/flow.js +0 -1133
- package/src/components/form.js +0 -585
- package/src/components/menu.js +0 -422
- package/src/components/offcanvas.js +0 -332
- package/src/components/parabola.js +0 -295
- package/src/components/tabs.js +0 -746
- package/src/components/theme.js +0 -353
- package/src/components/toast.js +0 -329
- package/src/components/toc.js +0 -226
- package/src/components/tooltip.js +0 -86
- package/src/components/validator.js +0 -586
- package/src/index.js +0 -45
- package/src/locales/index.min.js +0 -1
- package/src/utilities/browser.js +0 -111
- package/src/utilities/cache.js +0 -159
- package/src/utilities/core.js +0 -502
- package/src/utilities/debug.js +0 -103
- package/src/utilities/dom.js +0 -313
- package/src/utilities/events.js +0 -69
- package/src/utilities/http.js +0 -30
- package/src/utilities/legacy-dom.js +0 -179
- package/src/utilities/storage.js +0 -46
- /package/src/{components/components.js → css/themes/index.css} +0 -0
- /package/src/icons/{index.js → index.ts} +0 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { jsx } from 'vanilla-signal';
|
|
2
|
+
|
|
3
|
+
import { randomId, timer, validateParam } from '../utilities/core.ts';
|
|
4
|
+
import { q } from '../utilities/dom.ts';
|
|
5
|
+
import { listen } from '../utilities/events.ts';
|
|
6
|
+
import { icon } from './icons.ts';
|
|
7
|
+
|
|
8
|
+
export type ToastType = 'info' | 'success' | 'warning' | 'error' | 'primary';
|
|
9
|
+
|
|
10
|
+
export interface ToastClassNames {
|
|
11
|
+
container: string;
|
|
12
|
+
toast: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
message: string;
|
|
15
|
+
shown: string;
|
|
16
|
+
hidden: string;
|
|
17
|
+
lite: string;
|
|
18
|
+
action: string;
|
|
19
|
+
actions: string;
|
|
20
|
+
button: string;
|
|
21
|
+
cancelButton: string;
|
|
22
|
+
actionButton: string;
|
|
23
|
+
info: string;
|
|
24
|
+
success: string;
|
|
25
|
+
warning: string;
|
|
26
|
+
error: string;
|
|
27
|
+
primary: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type ToastClassNameConfig = Partial<ToastClassNames>;
|
|
31
|
+
|
|
32
|
+
export interface ToastOptions {
|
|
33
|
+
className?: ToastClassNameConfig;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ToastActionProps extends ToastOptions {
|
|
37
|
+
text?: {
|
|
38
|
+
cancel?: string;
|
|
39
|
+
action?: string;
|
|
40
|
+
};
|
|
41
|
+
onAction?: () => void | Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface ResolvedToastOptions {
|
|
45
|
+
className: ToastClassNames;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const DEFAULT_CLASS_NAMES: ToastClassNames = {
|
|
49
|
+
container: 'j-toast-container',
|
|
50
|
+
toast: 'j-toast',
|
|
51
|
+
icon: 'toast-icon',
|
|
52
|
+
message: 'toast-message',
|
|
53
|
+
shown: 'is-shown',
|
|
54
|
+
hidden: 'is-hidden',
|
|
55
|
+
lite: 'j-toast-lite',
|
|
56
|
+
action: 'is-action',
|
|
57
|
+
actions: 'toast-actions',
|
|
58
|
+
button: 'j-button is-sm',
|
|
59
|
+
cancelButton: 'is-ghost',
|
|
60
|
+
actionButton: 'is-outline',
|
|
61
|
+
info: 'is-info',
|
|
62
|
+
success: 'is-success',
|
|
63
|
+
warning: 'is-warning',
|
|
64
|
+
error: 'is-error',
|
|
65
|
+
primary: 'is-primary',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const TOAST_TYPE_RULE = {
|
|
69
|
+
type: 'string',
|
|
70
|
+
enum: ['info', 'success', 'warning', 'error', 'primary'],
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const TOAST_DURATION_RULE = {
|
|
74
|
+
type: 'number',
|
|
75
|
+
validate: (value: unknown) => typeof value === 'number' && value >= 0,
|
|
76
|
+
message: 'expects a positive number or 0.',
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const LITE_DURATION_RULE = {
|
|
80
|
+
type: 'number',
|
|
81
|
+
validate: (value: unknown) => typeof value === 'number' && value > 0,
|
|
82
|
+
message: 'expects a number greater than 0.',
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
function mergeClassNames(className?: ToastClassNameConfig): ToastClassNames {
|
|
86
|
+
return { ...DEFAULT_CLASS_NAMES, ...className };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function joinClasses(
|
|
90
|
+
...classes: Array<string | null | undefined | false>
|
|
91
|
+
): string {
|
|
92
|
+
return classes.filter(Boolean).join(' ');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Toast 消息提示工具。
|
|
97
|
+
*
|
|
98
|
+
* 以静态方法方式使用,支持多类型堆叠消息和单实例轻提示。
|
|
99
|
+
*/
|
|
100
|
+
export class Toast {
|
|
101
|
+
static timers = new Set<string>();
|
|
102
|
+
static disposers = new Map<HTMLElement, () => void>();
|
|
103
|
+
private static classNames = new WeakMap<HTMLElement, ToastClassNames>();
|
|
104
|
+
private static options: ResolvedToastOptions = {
|
|
105
|
+
className: DEFAULT_CLASS_NAMES,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
static configure(options: ToastOptions = {}): ToastOptions {
|
|
109
|
+
Toast.options = {
|
|
110
|
+
className: mergeClassNames(options.className),
|
|
111
|
+
};
|
|
112
|
+
return Toast.options;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private static resolveClassNames(options?: ToastOptions): ToastClassNames {
|
|
116
|
+
return mergeClassNames({
|
|
117
|
+
...Toast.options.className,
|
|
118
|
+
...options?.className,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static show(
|
|
123
|
+
message = '',
|
|
124
|
+
duration = 3000,
|
|
125
|
+
type: ToastType = 'info',
|
|
126
|
+
options: ToastOptions = {}
|
|
127
|
+
): HTMLElement {
|
|
128
|
+
validateParam('message', message, 'string', 'Toast.show');
|
|
129
|
+
validateParam('duration', duration, TOAST_DURATION_RULE, 'Toast.show');
|
|
130
|
+
validateParam('type', type, TOAST_TYPE_RULE, 'Toast.show');
|
|
131
|
+
|
|
132
|
+
const className = Toast.resolveClassNames(options);
|
|
133
|
+
const toastContainer = Toast.getOrCreateContainer(className);
|
|
134
|
+
const id = randomId();
|
|
135
|
+
const toast = jsx('div', {
|
|
136
|
+
className: joinClasses(className.toast, className[type]),
|
|
137
|
+
'data-toast': id,
|
|
138
|
+
children: [
|
|
139
|
+
jsx('span', {
|
|
140
|
+
className: className.icon,
|
|
141
|
+
'data-toast-icon': id,
|
|
142
|
+
children: icon(type === 'primary' ? 'info' : type),
|
|
143
|
+
}),
|
|
144
|
+
jsx('span', {
|
|
145
|
+
className: className.message,
|
|
146
|
+
'data-toast-message': id,
|
|
147
|
+
children: message,
|
|
148
|
+
}),
|
|
149
|
+
],
|
|
150
|
+
}) as HTMLElement;
|
|
151
|
+
|
|
152
|
+
Toast.classNames.set(toast, className);
|
|
153
|
+
toastContainer.appendChild(toast);
|
|
154
|
+
|
|
155
|
+
Toast.setTimer(id, 'show', () => toast.classList.add(className.shown), 10);
|
|
156
|
+
|
|
157
|
+
if (duration > 0) {
|
|
158
|
+
Toast.setTimer(id, 'hide', () => Toast.hide(toast), duration);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const disposeClick = listen(toast, 'click', () => Toast.hide(toast));
|
|
162
|
+
Toast.disposers.set(toast, disposeClick);
|
|
163
|
+
|
|
164
|
+
return toast;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static success(
|
|
168
|
+
message = '',
|
|
169
|
+
duration = 3000,
|
|
170
|
+
options: ToastOptions = {}
|
|
171
|
+
): HTMLElement {
|
|
172
|
+
return Toast.show(message, duration, 'success', options);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static info(
|
|
176
|
+
message = '',
|
|
177
|
+
duration = 3000,
|
|
178
|
+
options: ToastOptions = {}
|
|
179
|
+
): HTMLElement {
|
|
180
|
+
return Toast.show(message, duration, 'info', options);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static primary(
|
|
184
|
+
message = '',
|
|
185
|
+
duration = 3000,
|
|
186
|
+
options: ToastOptions = {}
|
|
187
|
+
): HTMLElement {
|
|
188
|
+
return Toast.show(message, duration, 'primary', options);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static warning(
|
|
192
|
+
message = '',
|
|
193
|
+
duration = 3000,
|
|
194
|
+
options: ToastOptions = {}
|
|
195
|
+
): HTMLElement {
|
|
196
|
+
return Toast.show(message, duration, 'warning', options);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static error(
|
|
200
|
+
message = '',
|
|
201
|
+
duration = 3000,
|
|
202
|
+
options: ToastOptions = {}
|
|
203
|
+
): HTMLElement {
|
|
204
|
+
return Toast.show(message, duration, 'error', options);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
static hide(toast: HTMLElement | null | undefined): void {
|
|
208
|
+
if (!toast) return;
|
|
209
|
+
|
|
210
|
+
const className = Toast.classNames.get(toast) || Toast.options.className;
|
|
211
|
+
Toast.disposers.get(toast)?.();
|
|
212
|
+
Toast.disposers.delete(toast);
|
|
213
|
+
|
|
214
|
+
toast.classList.remove(className.shown);
|
|
215
|
+
toast.classList.add(className.hidden);
|
|
216
|
+
|
|
217
|
+
const id = toast.dataset.toast || randomId();
|
|
218
|
+
Toast.setTimer(
|
|
219
|
+
id,
|
|
220
|
+
'remove',
|
|
221
|
+
() => {
|
|
222
|
+
toast.remove();
|
|
223
|
+
|
|
224
|
+
const container = q<HTMLElement>('[data-toast-container]');
|
|
225
|
+
if (container && container.children.length === 0) {
|
|
226
|
+
container.remove();
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
300
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
static lite(
|
|
234
|
+
message = '',
|
|
235
|
+
duration = 2000,
|
|
236
|
+
options: ToastOptions = {}
|
|
237
|
+
): HTMLElement {
|
|
238
|
+
validateParam('message', message, 'string', 'Toast.lite');
|
|
239
|
+
validateParam('duration', duration, LITE_DURATION_RULE, 'Toast.lite');
|
|
240
|
+
|
|
241
|
+
const className = Toast.resolveClassNames(options);
|
|
242
|
+
q<HTMLElement>('[data-toast-lite]')?.remove();
|
|
243
|
+
|
|
244
|
+
const id = randomId();
|
|
245
|
+
const lite = jsx('div', {
|
|
246
|
+
className: className.lite,
|
|
247
|
+
'data-toast': id,
|
|
248
|
+
'data-toast-lite': '',
|
|
249
|
+
children: message,
|
|
250
|
+
}) as HTMLElement;
|
|
251
|
+
|
|
252
|
+
Toast.classNames.set(lite, className);
|
|
253
|
+
document.body.appendChild(lite);
|
|
254
|
+
|
|
255
|
+
Toast.setTimer(id, 'show', () => lite.classList.add(className.shown), 10);
|
|
256
|
+
Toast.setTimer(
|
|
257
|
+
id,
|
|
258
|
+
'hide',
|
|
259
|
+
() => {
|
|
260
|
+
lite.classList.remove(className.shown);
|
|
261
|
+
lite.classList.add(className.hidden);
|
|
262
|
+
Toast.setTimer(id, 'remove', () => lite.remove(), 300);
|
|
263
|
+
},
|
|
264
|
+
duration
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
return lite;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
static action(message = '', props: ToastActionProps = {}): HTMLElement {
|
|
271
|
+
validateParam('message', message, 'string', 'Toast.action');
|
|
272
|
+
|
|
273
|
+
const className = Toast.resolveClassNames(props);
|
|
274
|
+
const toastContainer = Toast.getOrCreateContainer(className);
|
|
275
|
+
const id = randomId();
|
|
276
|
+
const action = jsx('div', {
|
|
277
|
+
className: joinClasses(className.toast, className.action),
|
|
278
|
+
'data-toast': id,
|
|
279
|
+
'data-toast-action': '',
|
|
280
|
+
children: [
|
|
281
|
+
jsx('div', {
|
|
282
|
+
className: className.message,
|
|
283
|
+
'data-toast-message': id,
|
|
284
|
+
children: message,
|
|
285
|
+
}),
|
|
286
|
+
jsx('div', {
|
|
287
|
+
className: className.actions,
|
|
288
|
+
'data-toast-actions': id,
|
|
289
|
+
children: [
|
|
290
|
+
jsx('button', {
|
|
291
|
+
className: joinClasses(className.button, className.cancelButton),
|
|
292
|
+
children: props.text?.cancel || 'cancel',
|
|
293
|
+
'data-action': 'cancel',
|
|
294
|
+
onClick: () => Toast.hide(action),
|
|
295
|
+
}),
|
|
296
|
+
jsx('button', {
|
|
297
|
+
className: joinClasses(className.button, className.actionButton),
|
|
298
|
+
children: props.text?.action || 'action',
|
|
299
|
+
'data-action': 'toast-action',
|
|
300
|
+
onClick: async () => {
|
|
301
|
+
await props.onAction?.();
|
|
302
|
+
Toast.hide(action);
|
|
303
|
+
},
|
|
304
|
+
}),
|
|
305
|
+
],
|
|
306
|
+
}),
|
|
307
|
+
],
|
|
308
|
+
}) as HTMLElement;
|
|
309
|
+
|
|
310
|
+
Toast.classNames.set(action, className);
|
|
311
|
+
toastContainer.appendChild(action);
|
|
312
|
+
|
|
313
|
+
Toast.setTimer(
|
|
314
|
+
id,
|
|
315
|
+
'show',
|
|
316
|
+
() => {
|
|
317
|
+
action.classList.add(className.shown);
|
|
318
|
+
q<HTMLButtonElement>('[data-action="toast-action"]', action)?.focus();
|
|
319
|
+
},
|
|
320
|
+
10
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
return action;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private static getOrCreateContainer(className: ToastClassNames): HTMLElement {
|
|
327
|
+
let toastContainer = q<HTMLElement>('[data-toast-container]');
|
|
328
|
+
if (!toastContainer) {
|
|
329
|
+
toastContainer = jsx('div', {
|
|
330
|
+
className: className.container,
|
|
331
|
+
'data-toast-container': '',
|
|
332
|
+
}) as HTMLElement;
|
|
333
|
+
document.body.appendChild(toastContainer);
|
|
334
|
+
} else {
|
|
335
|
+
toastContainer.className = className.container;
|
|
336
|
+
}
|
|
337
|
+
return toastContainer;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private static setTimer(
|
|
341
|
+
id: string,
|
|
342
|
+
action: string,
|
|
343
|
+
callback: () => void,
|
|
344
|
+
delay: number
|
|
345
|
+
): string {
|
|
346
|
+
const key = `${id}-${action}`;
|
|
347
|
+
Toast.timers.add(key);
|
|
348
|
+
timer.start(key, delay, () => {
|
|
349
|
+
Toast.timers.delete(key);
|
|
350
|
+
callback();
|
|
351
|
+
});
|
|
352
|
+
return key;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
static clearAll(): void {
|
|
356
|
+
for (const key of Toast.timers) {
|
|
357
|
+
timer.cancel(key);
|
|
358
|
+
}
|
|
359
|
+
Toast.timers.clear();
|
|
360
|
+
|
|
361
|
+
for (const dispose of Toast.disposers.values()) dispose();
|
|
362
|
+
Toast.disposers.clear();
|
|
363
|
+
|
|
364
|
+
q<HTMLElement>('[data-toast-container]')?.remove();
|
|
365
|
+
q<HTMLElement>('[data-toast-lite]')?.remove();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
static destroyAll(): void {
|
|
369
|
+
Toast.clearAll();
|
|
370
|
+
}
|
|
371
|
+
}
|