inviton-powerduck 0.0.340 → 0.0.341
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/common/ladda-lite.ts +66 -47
- package/components/button/ladda-button.tsx +35 -6
- package/package.json +1 -1
package/common/ladda-lite.ts
CHANGED
|
@@ -319,8 +319,8 @@ namespace laddaLiteUtils {
|
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
-
if (!retTarget.
|
|
323
|
-
retTarget.
|
|
322
|
+
if (!retTarget.classList.contains('ladda-button-root')) {
|
|
323
|
+
retTarget.classList.add('ladda-button-root');
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
return retTarget;
|
|
@@ -368,58 +368,76 @@ namespace laddaLiteUtils {
|
|
|
368
368
|
spinner: any;
|
|
369
369
|
}
|
|
370
370
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
371
|
+
/**
|
|
372
|
+
* Brings `button` to a known-good ladda state and returns its (cached)
|
|
373
|
+
* instance, (re)creating only whatever is missing. Safe — and meant — to be
|
|
374
|
+
* called on every spin.
|
|
375
|
+
*
|
|
376
|
+
* Why idempotent instead of "create once": the host <button> is usually owned
|
|
377
|
+
* by a framework (Vue, here). When that framework re-renders the button it
|
|
378
|
+
* overwrites `className` and can rebuild the button's children, which strips
|
|
379
|
+
* the `ladda-*` classes (the spinner CSS is entirely scoped to `.ladda-button`)
|
|
380
|
+
* and/or the `.ladda-label` / `.ladda-spinner` wrappers. The original
|
|
381
|
+
* create-once code then reused a cached instance and never restored any of it,
|
|
382
|
+
* so the spinner silently broke on the 2nd/3rd activation. Re-asserting the
|
|
383
|
+
* full contract here (without double-wrapping) makes it self-healing.
|
|
384
|
+
*/
|
|
385
|
+
export const ensureLadda = (button: any): LaddaInstance | null => {
|
|
386
|
+
if (!globalState.windowExists || button == null) {
|
|
387
|
+
return null;
|
|
374
388
|
}
|
|
375
389
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const docRange = document.createRange();
|
|
381
|
-
docRange.selectNodeContents(button);
|
|
382
|
-
docRange.surroundContents(laddaLabel);
|
|
383
|
-
button.appendChild(laddaLabel);
|
|
390
|
+
// Re-assert classes/attrs every time (a framework re-render may have dropped them).
|
|
391
|
+
button.classList.add('ladda-button-root');
|
|
392
|
+
button.classList.add('ladda-button');
|
|
393
|
+
button.setAttribute('data-style', 'zoom-in');
|
|
384
394
|
|
|
385
|
-
//
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
button.
|
|
389
|
-
button.
|
|
395
|
+
// Wrap the (framework-rendered) content into a single .ladda-label, exactly
|
|
396
|
+
// once. If a re-render removed it, re-wrap; if it survived, reuse it as-is so
|
|
397
|
+
// we never produce nested .ladda-label > .ladda-label.
|
|
398
|
+
let spinnerHost: HTMLElement = button.querySelector(':scope > .ladda-spinner');
|
|
399
|
+
let label: HTMLElement = button.querySelector(':scope > .ladda-label');
|
|
400
|
+
if (label == null) {
|
|
401
|
+
label = document.createElement('span');
|
|
402
|
+
label.setAttribute('class', 'ladda-label');
|
|
403
|
+
const content = Array.prototype.slice.call(button.childNodes).filter((n: any) => n !== spinnerHost);
|
|
404
|
+
content.forEach((n: any) => label.appendChild(n));
|
|
405
|
+
button.insertBefore(label, button.firstChild);
|
|
406
|
+
}
|
|
390
407
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
408
|
+
if (spinnerHost == null) {
|
|
409
|
+
spinnerHost = document.createElement('span');
|
|
410
|
+
spinnerHost.setAttribute('class', 'ladda-spinner');
|
|
411
|
+
button.appendChild(spinnerHost);
|
|
412
|
+
}
|
|
394
413
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
414
|
+
// Resolve (or (re)create) the cached spinner instance for this button.
|
|
415
|
+
let id = button.getAttribute(ID_ATTRIBUTE);
|
|
416
|
+
let laddaInstance: LaddaInstance = id != null ? instanceCache[id] : null;
|
|
417
|
+
if (laddaInstance == null) {
|
|
418
|
+
id = String(Math.floor(Math.random() * 999999999 + 1));
|
|
419
|
+
button.setAttribute(ID_ATTRIBUTE, id);
|
|
420
|
+
laddaInstance = {
|
|
421
|
+
timer: <any>null,
|
|
422
|
+
spinner: createSpinner(button),
|
|
423
|
+
};
|
|
424
|
+
instanceCache[id] = laddaInstance;
|
|
425
|
+
}
|
|
399
426
|
|
|
400
|
-
instanceCache[newId] = laddaInstance;
|
|
401
427
|
return laddaInstance;
|
|
402
428
|
};
|
|
403
429
|
}
|
|
404
430
|
|
|
405
431
|
export class LaddaLite {
|
|
406
432
|
static showSpin(target: HTMLElement): void {
|
|
407
|
-
if (target == null) {
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (!globalState.windowExists) {
|
|
433
|
+
if (target == null || !globalState.windowExists) {
|
|
412
434
|
return;
|
|
413
435
|
}
|
|
414
436
|
|
|
415
|
-
let laddaInstance;
|
|
416
437
|
const button = laddaLiteUtils.getTarget(target);
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
laddaInstance = laddaLiteUtils.createLaddaInstance(button);
|
|
421
|
-
} else {
|
|
422
|
-
laddaInstance = laddaLiteUtils.instanceCache[instanceId];
|
|
438
|
+
const laddaInstance = laddaLiteUtils.ensureLadda(button);
|
|
439
|
+
if (laddaInstance == null) {
|
|
440
|
+
return;
|
|
423
441
|
}
|
|
424
442
|
|
|
425
443
|
clearTimeout(laddaInstance.timer);
|
|
@@ -429,20 +447,21 @@ export class LaddaLite {
|
|
|
429
447
|
}
|
|
430
448
|
|
|
431
449
|
static hideSpin(target: HTMLElement): void {
|
|
432
|
-
if (target == null) {
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
if (!globalState.windowExists) {
|
|
450
|
+
if (target == null || !globalState.windowExists) {
|
|
437
451
|
return;
|
|
438
452
|
}
|
|
439
453
|
|
|
440
454
|
const button = laddaLiteUtils.getTarget(target);
|
|
441
455
|
const instanceId = laddaLiteUtils.getInstanceId(button);
|
|
442
|
-
const laddaInstance = laddaLiteUtils.instanceCache[instanceId];
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
456
|
+
const laddaInstance = instanceId != null ? laddaLiteUtils.instanceCache[instanceId] : null;
|
|
457
|
+
|
|
458
|
+
// Always re-enable and clear the loading flag, even if the cached instance
|
|
459
|
+
// was lost (e.g. the framework replaced the button element) — never strand a
|
|
460
|
+
// disabled button.
|
|
461
|
+
button.disabled = false;
|
|
462
|
+
button.removeAttribute('data-loading');
|
|
463
|
+
|
|
464
|
+
if (laddaInstance != null) {
|
|
446
465
|
laddaInstance.timer = setTimeout(() => {
|
|
447
466
|
laddaInstance.spinner.stop();
|
|
448
467
|
}, 1000);
|
|
@@ -26,35 +26,64 @@ class LaddaButtonComponent extends TsxComponent<LaddaButtonArgs> implements Ladd
|
|
|
26
26
|
@Prop() loading!: boolean;
|
|
27
27
|
@Prop() clicked: (e: any) => Promise<any>;
|
|
28
28
|
|
|
29
|
+
// Whether the spinner should currently be showing. Tracked so `updated()` can
|
|
30
|
+
// restore the ladda DOM after a Vue re-render strips it (Ladda mutates this
|
|
31
|
+
// Vue-owned <button> out-of-band, so any patch can wipe its classes/wrappers).
|
|
32
|
+
private _spinning: boolean = false;
|
|
33
|
+
|
|
29
34
|
@Watch('loading')
|
|
30
35
|
onLoadingChanged(val: boolean) {
|
|
31
36
|
if (val) {
|
|
32
|
-
|
|
37
|
+
this.spin(this.$el as HTMLElement);
|
|
33
38
|
} else {
|
|
34
|
-
|
|
39
|
+
this.unspin(this.$el as HTMLElement);
|
|
35
40
|
}
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
mounted() {
|
|
39
44
|
if (this.loading) {
|
|
40
|
-
|
|
45
|
+
this.spin(this.$el as HTMLElement);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
updated() {
|
|
50
|
+
// Vue just patched this button. If we're mid-spin and the patch stripped
|
|
51
|
+
// ladda's class or spinner wrapper, re-assert it (ensureLadda is idempotent,
|
|
52
|
+
// so this is a no-op when nothing was lost).
|
|
53
|
+
if (!this._spinning) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const el = this.$el as HTMLElement;
|
|
58
|
+
if (!el.classList.contains('ladda-button') || el.querySelector('.ladda-spinner') == null) {
|
|
59
|
+
LaddaLite.showSpin(el);
|
|
41
60
|
}
|
|
42
61
|
}
|
|
43
62
|
|
|
63
|
+
private spin(target: HTMLElement) {
|
|
64
|
+
this._spinning = true;
|
|
65
|
+
LaddaLite.showSpin(target);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private unspin(target: HTMLElement) {
|
|
69
|
+
this._spinning = false;
|
|
70
|
+
LaddaLite.hideSpin(target);
|
|
71
|
+
}
|
|
72
|
+
|
|
44
73
|
handleButtonClicked(e) {
|
|
45
74
|
let targetElem = e.target as HTMLElement;
|
|
46
75
|
if (targetElem.nodeName.toLowerCase() != 'button') {
|
|
47
76
|
targetElem = targetElem.closest('button') as HTMLElement;
|
|
48
77
|
}
|
|
49
78
|
|
|
50
|
-
|
|
79
|
+
this.spin(targetElem);
|
|
51
80
|
|
|
52
81
|
this.clicked(e)
|
|
53
82
|
.then(() => {
|
|
54
|
-
|
|
83
|
+
this.unspin(targetElem);
|
|
55
84
|
})
|
|
56
85
|
.catch(() => {
|
|
57
|
-
|
|
86
|
+
this.unspin(targetElem);
|
|
58
87
|
});
|
|
59
88
|
}
|
|
60
89
|
|