@windwalker-io/unicorn-next 0.1.15 → 0.1.17
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/chunks/grid.js +70 -8
- package/dist/chunks/grid.js.map +1 -1
- package/dist/chunks/show-on.js +1 -1
- package/dist/chunks/show-on.js.map +1 -1
- package/dist/chunks/unicorn.js +299 -60
- package/dist/chunks/unicorn.js.map +1 -1
- package/dist/chunks/validation.js +17 -2
- package/dist/chunks/validation.js.map +1 -1
- package/dist/index.d.ts +84 -19
- package/dist/unicorn.js +32 -31
- package/package.json +1 -1
- package/src/composable/index.ts +1 -0
- package/src/composable/useBsModalAlert.ts +299 -0
- package/src/composable/useForm.ts +45 -11
- package/src/composable/useHttp.ts +50 -3
- package/src/composable/useUIBootstrap5.ts +2 -0
- package/src/module/grid.ts +105 -13
- package/src/module/show-on.ts +1 -1
- package/src/module/validation.ts +29 -6
- package/src/service/dom.ts +1 -1
- package/src/service/ui.ts +2 -0
package/src/module/grid.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __, deleteConfirm, h, loadAlpine, simpleAlert, simpleConfirm, slideDown, slideUp } from '../service';
|
|
1
|
+
import { __, delegate, deleteConfirm, h, loadAlpine, simpleAlert, simpleConfirm, slideDown, slideUp } from '../service';
|
|
2
2
|
import { Nullable } from '../types';
|
|
3
3
|
import type { UnicornFormElement } from './form';
|
|
4
4
|
|
|
@@ -22,9 +22,11 @@ export class UnicornGridElement {
|
|
|
22
22
|
const inputs = this.element.querySelectorAll<HTMLInputElement>('input[data-role=grid-checkbox]');
|
|
23
23
|
|
|
24
24
|
for (const ch of inputs) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
// No-longer need this since browsers will trigger change event when checkbox is checked/unchecked
|
|
26
|
+
// ch.addEventListener('click', () => {
|
|
27
|
+
// ch.dispatchEvent(new CustomEvent('change'));
|
|
28
|
+
// });
|
|
29
|
+
|
|
28
30
|
ch.addEventListener('change', () => {
|
|
29
31
|
const event = new CustomEvent('unicorn:checked', {
|
|
30
32
|
detail: { grid: this }
|
|
@@ -33,6 +35,66 @@ export class UnicornGridElement {
|
|
|
33
35
|
this.form.element?.dispatchEvent(event);
|
|
34
36
|
});
|
|
35
37
|
}
|
|
38
|
+
|
|
39
|
+
if (this.form.element) {
|
|
40
|
+
this.bindMustCheckedEvent(this.form.element);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private bindMustCheckedEvent(form: HTMLFormElement) {
|
|
45
|
+
delegate(document, '[data-must-checked]', 'mousedown', (e) => {
|
|
46
|
+
const target = e.currentTarget as HTMLElement;
|
|
47
|
+
|
|
48
|
+
const selector = target.dataset.mustChecked!;
|
|
49
|
+
|
|
50
|
+
if (!selector || !form.matches(selector)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Prevent modal
|
|
55
|
+
const toggle = target.dataset.bsToggle;
|
|
56
|
+
|
|
57
|
+
if (toggle === 'modal') {
|
|
58
|
+
const modalTarget = target.dataset.bsTarget;
|
|
59
|
+
|
|
60
|
+
if (modalTarget) {
|
|
61
|
+
this.preventBSModal(modalTarget, this.getMustCheckedMessage());
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
preventBSModal(selector?: string | HTMLElement, msg?: string | boolean) {
|
|
68
|
+
let modalElement: HTMLElement | null = null;
|
|
69
|
+
|
|
70
|
+
if (typeof selector === 'string') {
|
|
71
|
+
modalElement = document.querySelector(selector);
|
|
72
|
+
} else if (selector instanceof HTMLElement) {
|
|
73
|
+
const modalTarget = selector.dataset.bsTarget;
|
|
74
|
+
|
|
75
|
+
if (modalTarget) {
|
|
76
|
+
modalElement = document.querySelector(modalTarget);
|
|
77
|
+
} else {
|
|
78
|
+
modalElement = selector;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (modalElement) {
|
|
83
|
+
modalElement?.addEventListener('show.bs.modal', (e) => {
|
|
84
|
+
if (!this.hasChecked()) {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
e.stopPropagation();
|
|
87
|
+
|
|
88
|
+
if (msg) {
|
|
89
|
+
if (msg === true) {
|
|
90
|
+
msg = this.getMustCheckedMessage();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
simpleAlert(msg);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}, { once: true });
|
|
97
|
+
}
|
|
36
98
|
}
|
|
37
99
|
|
|
38
100
|
initComponent(store = 'grid', custom: Record<string, string> = {}) {
|
|
@@ -335,10 +397,12 @@ export class UnicornGridElement {
|
|
|
335
397
|
/**
|
|
336
398
|
* Delete an item by row.
|
|
337
399
|
*/
|
|
338
|
-
async deleteRow(
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
400
|
+
async deleteRow(
|
|
401
|
+
row: number,
|
|
402
|
+
msg?: Nullable<string>,
|
|
403
|
+
url?: Nullable<string>,
|
|
404
|
+
data?: Nullable<Record<string, any>>
|
|
405
|
+
): Promise<boolean> {
|
|
342
406
|
const ch = this.getCheckboxByRow(row);
|
|
343
407
|
|
|
344
408
|
if (!ch) {
|
|
@@ -421,17 +485,33 @@ export class UnicornGridElement {
|
|
|
421
485
|
/**
|
|
422
486
|
* Validate there has one or more checked boxes.
|
|
423
487
|
*/
|
|
424
|
-
validateChecked(
|
|
425
|
-
|
|
426
|
-
|
|
488
|
+
validateChecked(
|
|
489
|
+
event?: Event,
|
|
490
|
+
callback?: (grid: UnicornGridElement) => any,
|
|
491
|
+
errorMsg: string | boolean | null | ((grid: UnicornGridElement) => any) = true
|
|
492
|
+
): this {
|
|
427
493
|
if (!this.hasChecked()) {
|
|
428
|
-
if (
|
|
429
|
-
|
|
494
|
+
if (errorMsg === true) {
|
|
495
|
+
errorMsg = this.getMustCheckedMessage();
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (typeof errorMsg === 'string' && errorMsg !== '') {
|
|
499
|
+
simpleAlert(errorMsg);
|
|
500
|
+
} else if (typeof errorMsg === 'function') {
|
|
501
|
+
errorMsg(this);
|
|
430
502
|
}
|
|
431
503
|
|
|
432
504
|
if (event) {
|
|
433
505
|
event.stopPropagation();
|
|
434
506
|
event.preventDefault();
|
|
507
|
+
|
|
508
|
+
const target = event.currentTarget as HTMLElement;
|
|
509
|
+
|
|
510
|
+
if (target.dataset.bsToggle === 'modal') {
|
|
511
|
+
if (target.dataset.bsTarget) {
|
|
512
|
+
this.preventBSModal(target.dataset.bsTarget);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
435
515
|
}
|
|
436
516
|
|
|
437
517
|
return this;
|
|
@@ -444,6 +524,18 @@ export class UnicornGridElement {
|
|
|
444
524
|
return this;
|
|
445
525
|
}
|
|
446
526
|
|
|
527
|
+
async validateCheckedPromise() {
|
|
528
|
+
if (!this.hasChecked()) {
|
|
529
|
+
throw new Error('No items checked.');
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return this;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
getMustCheckedMessage(): string {
|
|
536
|
+
return __('unicorn.message.grid.checked');
|
|
537
|
+
}
|
|
538
|
+
|
|
447
539
|
hasChecked(): boolean {
|
|
448
540
|
return this.countChecked() > 0;
|
|
449
541
|
}
|
package/src/module/show-on.ts
CHANGED
package/src/module/validation.ts
CHANGED
|
@@ -96,7 +96,7 @@ export class UnicornFormValidation {
|
|
|
96
96
|
options = {};
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
return this.options = mergeDeep({}, defaultOptions, this.options, options);
|
|
99
|
+
return this.options = mergeDeep({}, defaultOptions, this.options || {}, options);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
get scrollEnabled() {
|
|
@@ -350,7 +350,7 @@ export class UnicornFormValidation {
|
|
|
350
350
|
|
|
351
351
|
export class UnicornFieldValidation {
|
|
352
352
|
$input: InputElements | undefined;
|
|
353
|
-
options: Partial<FieldValidationOptions
|
|
353
|
+
options: Partial<FieldValidationOptions> = {};
|
|
354
354
|
|
|
355
355
|
static is = 'uni-field-validate';
|
|
356
356
|
|
|
@@ -504,6 +504,11 @@ export class UnicornFieldValidation {
|
|
|
504
504
|
return true;
|
|
505
505
|
}
|
|
506
506
|
|
|
507
|
+
if (this.hasChildDirectives()) {
|
|
508
|
+
// If has child field validation directives, let them handle the validation.
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
|
|
507
512
|
this.$input.setCustomValidity('');
|
|
508
513
|
let valid = this.$input.checkValidity();
|
|
509
514
|
|
|
@@ -519,7 +524,7 @@ export class UnicornFieldValidation {
|
|
|
519
524
|
return valid;
|
|
520
525
|
}
|
|
521
526
|
|
|
522
|
-
runCustomValidity() {
|
|
527
|
+
protected runCustomValidity() {
|
|
523
528
|
if (!this.$input) {
|
|
524
529
|
return true;
|
|
525
530
|
}
|
|
@@ -572,6 +577,15 @@ export class UnicornFieldValidation {
|
|
|
572
577
|
return true;
|
|
573
578
|
}
|
|
574
579
|
|
|
580
|
+
if (this.$input.hasAttribute('[data-novalidate]')) {
|
|
581
|
+
return true;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (this.hasChildDirectives()) {
|
|
585
|
+
// If has child field validation directives, let them handle the validation.
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
588
|
+
|
|
575
589
|
this.$input.setCustomValidity('');
|
|
576
590
|
let valid = this.$input.checkValidity();
|
|
577
591
|
|
|
@@ -584,7 +598,7 @@ export class UnicornFieldValidation {
|
|
|
584
598
|
return valid;
|
|
585
599
|
}
|
|
586
600
|
|
|
587
|
-
async runCustomValidityAsync(): Promise<boolean> {
|
|
601
|
+
protected async runCustomValidityAsync(): Promise<boolean> {
|
|
588
602
|
if (!this.$input) {
|
|
589
603
|
return true;
|
|
590
604
|
}
|
|
@@ -631,13 +645,13 @@ export class UnicornFieldValidation {
|
|
|
631
645
|
return true;
|
|
632
646
|
}
|
|
633
647
|
|
|
634
|
-
checkCustomDataAttributeValidity(): boolean {
|
|
648
|
+
protected checkCustomDataAttributeValidity(): boolean {
|
|
635
649
|
const error = this.$input?.dataset.validationFail;
|
|
636
650
|
|
|
637
651
|
return this.handleCustomResult(error);
|
|
638
652
|
}
|
|
639
653
|
|
|
640
|
-
checkInputOptionsValidity(): boolean {
|
|
654
|
+
protected checkInputOptionsValidity(): boolean {
|
|
641
655
|
if (!this.$input) {
|
|
642
656
|
return true;
|
|
643
657
|
}
|
|
@@ -828,6 +842,11 @@ export class UnicornFieldValidation {
|
|
|
828
842
|
}
|
|
829
843
|
|
|
830
844
|
showInvalidResponse() {
|
|
845
|
+
if (this.hasChildDirectives()) {
|
|
846
|
+
// If has child field validation directives, let them handle the error message display.
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
|
|
831
850
|
/** @type ValidityState */
|
|
832
851
|
const state = this.$input?.validity;
|
|
833
852
|
let message: string = this.$input?.validationMessage || '';
|
|
@@ -949,6 +968,10 @@ export class UnicornFieldValidation {
|
|
|
949
968
|
|
|
950
969
|
return label;
|
|
951
970
|
}
|
|
971
|
+
|
|
972
|
+
protected hasChildDirectives() {
|
|
973
|
+
return this.el.querySelector('[uni-field-validate]') != null;
|
|
974
|
+
}
|
|
952
975
|
}
|
|
953
976
|
|
|
954
977
|
function camelTo(str: string, sep: string) {
|
package/src/service/dom.ts
CHANGED
|
@@ -191,7 +191,7 @@ export function html<T extends Element = HTMLElement>(html: string): T {
|
|
|
191
191
|
* @see https://gist.github.com/iagobruno/4db2ed62dc40fa841bb9a5c7de92f5f8
|
|
192
192
|
*/
|
|
193
193
|
export function delegate(
|
|
194
|
-
wrapper: Element | string,
|
|
194
|
+
wrapper: Element | Document | string,
|
|
195
195
|
selector: string,
|
|
196
196
|
eventName: string,
|
|
197
197
|
callback: (e: Event) => void
|
package/src/service/ui.ts
CHANGED
|
@@ -433,6 +433,7 @@ export function useDisableOnSubmit(
|
|
|
433
433
|
|
|
434
434
|
const event = options.event || 'submit';
|
|
435
435
|
const spinnerClass = options.spinnerClass || 'spinner-border spinner-border-sm';
|
|
436
|
+
const loadingClass = options.loadingCass || 'is-loading';
|
|
436
437
|
|
|
437
438
|
selectAll<HTMLElement>(buttonSelector, (button) => {
|
|
438
439
|
button.addEventListener('click', (e) => {
|
|
@@ -458,6 +459,7 @@ export function useDisableOnSubmit(
|
|
|
458
459
|
|
|
459
460
|
if (button.dataset.clicked) {
|
|
460
461
|
let icon = button.querySelector(iconSelector);
|
|
462
|
+
button.classList.add(loadingClass);
|
|
461
463
|
|
|
462
464
|
if (icon) {
|
|
463
465
|
const i = html('<i></i>');
|