otimus-library 0.4.90 → 0.4.92
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/fesm2022/otimus-library.mjs +149 -71
- package/fesm2022/otimus-library.mjs.map +1 -1
- package/index.d.ts +60 -13
- package/package.json +1 -1
- package/styles/variables.scss +14 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, Injectable, Input, Directive, input, inject, ElementRef, model, output, HostListener, EventEmitter, Output, ContentChildren, forwardRef, ChangeDetectionStrategy, effect, ContentChild, ViewChildren, ViewChild, ViewEncapsulation, HostBinding, PLATFORM_ID, RendererFactory2, signal, ViewContainerRef, computed, viewChild, booleanAttribute } from '@angular/core';
|
|
2
|
+
import { Component, Injectable, Input, Directive, input, inject, ElementRef, model, output, HostListener, EventEmitter, Output, ContentChildren, forwardRef, ChangeDetectionStrategy, effect, ContentChild, ViewChildren, ViewChild, ViewEncapsulation, HostBinding, PLATFORM_ID, RendererFactory2, signal, ViewContainerRef, computed, viewChild, booleanAttribute, DestroyRef } from '@angular/core';
|
|
3
|
+
import { Subject, filter } from 'rxjs';
|
|
3
4
|
import * as i2$1 from '@angular/cdk/menu';
|
|
4
5
|
import { CdkMenuModule } from '@angular/cdk/menu';
|
|
5
6
|
import * as i1 from '@angular/common';
|
|
@@ -12,10 +13,10 @@ import * as i3 from '@angular/cdk/overlay';
|
|
|
12
13
|
import { Overlay, OverlayPositionBuilder } from '@angular/cdk/overlay';
|
|
13
14
|
import * as i1$2 from '@angular/router';
|
|
14
15
|
import { RouterModule } from '@angular/router';
|
|
15
|
-
import { filter } from 'rxjs';
|
|
16
16
|
import * as i2$2 from '@angular/platform-browser';
|
|
17
17
|
import * as i2$3 from '@angular/cdk/table';
|
|
18
18
|
import { CdkTableModule } from '@angular/cdk/table';
|
|
19
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
19
20
|
|
|
20
21
|
class OtimusLibraryComponent {
|
|
21
22
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OtimusLibraryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
@@ -48,73 +49,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
|
|
|
48
49
|
|
|
49
50
|
class OcToastService {
|
|
50
51
|
constructor() {
|
|
51
|
-
this.
|
|
52
|
-
|
|
52
|
+
this.nextId = 1;
|
|
53
|
+
/** Emits each toast opened via `openToast`. Rendered by `OcToastComponent`. */
|
|
54
|
+
this.opened = new Subject();
|
|
55
|
+
this.opened$ = this.opened.asObservable();
|
|
53
56
|
this.openToast = (toastStatus, toastMessage, toastCounter, promiseKey) => {
|
|
54
57
|
const toast = {
|
|
55
|
-
id: this.
|
|
58
|
+
id: this.nextId++,
|
|
56
59
|
counter: toastCounter || 5,
|
|
57
60
|
status: toastStatus,
|
|
58
61
|
message: toastMessage,
|
|
59
62
|
promiseKey,
|
|
60
63
|
hasAnimation: true,
|
|
61
64
|
};
|
|
62
|
-
|
|
63
|
-
return to.status === toastStatus && to.message === toastMessage;
|
|
64
|
-
});
|
|
65
|
-
if (toastExists) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const keyExists = this.toastList.find((to) => to.promiseKey === toast.promiseKey);
|
|
69
|
-
if (keyExists) {
|
|
70
|
-
this.toastList = this.toastList.map((to) => {
|
|
71
|
-
if (to.promiseKey === promiseKey) {
|
|
72
|
-
return { ...toast, hasAnimation: false };
|
|
73
|
-
}
|
|
74
|
-
return to;
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
this.toastList.push(toast);
|
|
78
|
-
if (!this.isRunning) {
|
|
79
|
-
this.renderToasts();
|
|
80
|
-
}
|
|
65
|
+
this.opened.next(toast);
|
|
81
66
|
};
|
|
82
67
|
}
|
|
83
|
-
closeToast(id) {
|
|
84
|
-
this.toastList = this.toastList.map((to) => {
|
|
85
|
-
if (to.id === id) {
|
|
86
|
-
return { ...to, counter: 0 };
|
|
87
|
-
}
|
|
88
|
-
return to;
|
|
89
|
-
});
|
|
90
|
-
this.currentToast = this.toastList[0];
|
|
91
|
-
}
|
|
92
|
-
renderToasts() {
|
|
93
|
-
if (this.toastList.length === 0) {
|
|
94
|
-
this.isRunning = false;
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
this.isRunning = true;
|
|
98
|
-
this.currentToast = this.toastList[0];
|
|
99
|
-
const toastInterval = setInterval(() => {
|
|
100
|
-
if (this.toastList.length === 0) {
|
|
101
|
-
clearInterval(toastInterval);
|
|
102
|
-
this.isRunning = false;
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
this.currentToast = this.toastList[0];
|
|
106
|
-
if (this.currentToast.status !== 'carregando') {
|
|
107
|
-
this.currentToast.counter--;
|
|
108
|
-
}
|
|
109
|
-
if (this.currentToast.counter <= 0) {
|
|
110
|
-
this.toastList = this.toastList.filter((to) => {
|
|
111
|
-
return to.status !== this.currentToast.status && to.message !== this.currentToast.message;
|
|
112
|
-
});
|
|
113
|
-
clearInterval(toastInterval);
|
|
114
|
-
this.renderToasts();
|
|
115
|
-
}
|
|
116
|
-
}, 1000);
|
|
117
|
-
}
|
|
118
68
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OcToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
119
69
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OcToastService, providedIn: 'root' }); }
|
|
120
70
|
}
|
|
@@ -3793,12 +3743,14 @@ class OcOtpComponent {
|
|
|
3793
3743
|
this.ocError = input(...(ngDevMode ? [undefined, { debugName: "ocError" }] : []));
|
|
3794
3744
|
this.ocDisabled = input(false, ...(ngDevMode ? [{ debugName: "ocDisabled" }] : []));
|
|
3795
3745
|
this.ocAutoFocus = input(false, ...(ngDevMode ? [{ debugName: "ocAutoFocus" }] : []));
|
|
3746
|
+
this.ocAlphanumeric = input(false, ...(ngDevMode ? [{ debugName: "ocAlphanumeric" }] : []));
|
|
3796
3747
|
this.value = model('', ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
3797
3748
|
this.complete = new EventEmitter();
|
|
3798
3749
|
this.digits = signal(Array(6).fill(''), ...(ngDevMode ? [{ debugName: "digits" }] : []));
|
|
3799
3750
|
this.midpoint = computed(() => this.ocLength() / 2, ...(ngDevMode ? [{ debugName: "midpoint" }] : []));
|
|
3800
3751
|
this.shake = signal(false, ...(ngDevMode ? [{ debugName: "shake" }] : []));
|
|
3801
3752
|
this.shakeTimer = null;
|
|
3753
|
+
this.inputMode = computed(() => this.ocAlphanumeric() ? 'text' : 'numeric', ...(ngDevMode ? [{ debugName: "inputMode" }] : []));
|
|
3802
3754
|
effect(() => {
|
|
3803
3755
|
const len = this.ocLength();
|
|
3804
3756
|
const current = this.digits();
|
|
@@ -3810,7 +3762,7 @@ class OcOtpComponent {
|
|
|
3810
3762
|
effect(() => {
|
|
3811
3763
|
const incoming = this.value();
|
|
3812
3764
|
const len = this.ocLength();
|
|
3813
|
-
const sanitized = (incoming ?? '').
|
|
3765
|
+
const sanitized = this.sanitize(incoming ?? '').slice(0, len);
|
|
3814
3766
|
const next = Array(len).fill('').map((_, i) => sanitized[i] ?? '');
|
|
3815
3767
|
const current = this.digits();
|
|
3816
3768
|
const same = current.length === next.length && current.every((d, i) => d === next[i]);
|
|
@@ -3847,7 +3799,7 @@ class OcOtpComponent {
|
|
|
3847
3799
|
if (this.ocDisabled()) {
|
|
3848
3800
|
return;
|
|
3849
3801
|
}
|
|
3850
|
-
const raw = event.target.value
|
|
3802
|
+
const raw = this.sanitize(event.target.value).slice(0, 1);
|
|
3851
3803
|
const next = [...this.digits()];
|
|
3852
3804
|
next[idx] = raw;
|
|
3853
3805
|
this.digits.set(next);
|
|
@@ -3873,7 +3825,7 @@ class OcOtpComponent {
|
|
|
3873
3825
|
return;
|
|
3874
3826
|
}
|
|
3875
3827
|
const len = this.ocLength();
|
|
3876
|
-
const text = (event.clipboardData?.getData('text') ?? '').
|
|
3828
|
+
const text = this.sanitize(event.clipboardData?.getData('text') ?? '').slice(0, len);
|
|
3877
3829
|
if (text.length === len) {
|
|
3878
3830
|
event.preventDefault();
|
|
3879
3831
|
const next = text.split('');
|
|
@@ -3882,18 +3834,24 @@ class OcOtpComponent {
|
|
|
3882
3834
|
this.complete.emit(text);
|
|
3883
3835
|
}
|
|
3884
3836
|
}
|
|
3837
|
+
sanitize(raw) {
|
|
3838
|
+
if (this.ocAlphanumeric()) {
|
|
3839
|
+
return raw.replace(/[^A-Za-z0-9]/g, '').toUpperCase();
|
|
3840
|
+
}
|
|
3841
|
+
return raw.replace(/\D/g, '');
|
|
3842
|
+
}
|
|
3885
3843
|
focusBox(idx) {
|
|
3886
3844
|
const target = this.inputs?.get(idx);
|
|
3887
3845
|
target?.nativeElement.focus();
|
|
3888
3846
|
target?.nativeElement.select?.();
|
|
3889
3847
|
}
|
|
3890
3848
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OcOtpComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3891
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: OcOtpComponent, isStandalone: true, selector: "oc-otp", inputs: { ocLength: { classPropertyName: "ocLength", publicName: "ocLength", isSignal: true, isRequired: false, transformFunction: null }, ocSeparator: { classPropertyName: "ocSeparator", publicName: "ocSeparator", isSignal: true, isRequired: false, transformFunction: null }, ocError: { classPropertyName: "ocError", publicName: "ocError", isSignal: true, isRequired: false, transformFunction: null }, ocDisabled: { classPropertyName: "ocDisabled", publicName: "ocDisabled", isSignal: true, isRequired: false, transformFunction: null }, ocAutoFocus: { classPropertyName: "ocAutoFocus", publicName: "ocAutoFocus", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", complete: "complete" }, viewQueries: [{ propertyName: "inputs", predicate: ["otpInput"], descendants: true }], ngImport: i0, template: "<div\n class=\"oc-otp\"\n [class.oc-otp--error]=\"!!ocError()\"\n [class.oc-otp--shake]=\"shake()\"\n (paste)=\"onPaste($event)\"\n>\n @for (digit of digits(); track $index) {\n @if (ocSeparator() && $index === midpoint()) {\n <span\n class=\"oc-otp__separator\"\n data-testid=\"oc-otp-separator\"\n aria-hidden=\"true\"\n >-</span\n >\n }\n <input\n #otpInput\n class=\"oc-otp__input\"\n type=\"text\"\n inputmode=\"
|
|
3849
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: OcOtpComponent, isStandalone: true, selector: "oc-otp", inputs: { ocLength: { classPropertyName: "ocLength", publicName: "ocLength", isSignal: true, isRequired: false, transformFunction: null }, ocSeparator: { classPropertyName: "ocSeparator", publicName: "ocSeparator", isSignal: true, isRequired: false, transformFunction: null }, ocError: { classPropertyName: "ocError", publicName: "ocError", isSignal: true, isRequired: false, transformFunction: null }, ocDisabled: { classPropertyName: "ocDisabled", publicName: "ocDisabled", isSignal: true, isRequired: false, transformFunction: null }, ocAutoFocus: { classPropertyName: "ocAutoFocus", publicName: "ocAutoFocus", isSignal: true, isRequired: false, transformFunction: null }, ocAlphanumeric: { classPropertyName: "ocAlphanumeric", publicName: "ocAlphanumeric", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", complete: "complete" }, viewQueries: [{ propertyName: "inputs", predicate: ["otpInput"], descendants: true }], ngImport: i0, template: "<div\n class=\"oc-otp\"\n [class.oc-otp--error]=\"!!ocError()\"\n [class.oc-otp--shake]=\"shake()\"\n (paste)=\"onPaste($event)\"\n>\n @for (digit of digits(); track $index) {\n @if (ocSeparator() && $index === midpoint()) {\n <span\n class=\"oc-otp__separator\"\n data-testid=\"oc-otp-separator\"\n aria-hidden=\"true\"\n >-</span\n >\n }\n <input\n #otpInput\n class=\"oc-otp__input\"\n type=\"text\"\n [attr.inputmode]=\"inputMode()\"\n autocomplete=\"one-time-code\"\n maxlength=\"1\"\n [attr.data-testid]=\"'oc-otp-' + $index\"\n [value]=\"digit\"\n [disabled]=\"ocDisabled()\"\n (input)=\"onInput($index, $event)\"\n (keydown)=\"onKey($index, $event)\"\n />\n }\n</div>\n", styles: [".oc-otp{display:flex;align-items:center;justify-content:center;gap:8px}.oc-otp__input{flex:1 1 0;min-width:0;max-width:56px;height:56px;border:1px solid #d1d5db;border-radius:10px;background:#f8f9ff;font:inherit;font-size:24px;font-weight:500;color:#353535;text-align:center;outline:none;transition:all .15s ease}.oc-otp__input:focus{background:#fff;border-color:#00dda3;box-shadow:0 4px 3.2px #00dda314,0 0 0 4px #00dda324}.oc-otp__input:disabled{cursor:not-allowed;opacity:.6}.oc-otp__separator{flex:0 0 auto;color:#8f9596;font-size:24px;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1;padding:0 2px}.oc-otp--error .oc-otp__input{border-color:#ed3a3a}.oc-otp--shake{animation:oc-otp-shake .32s ease}@keyframes oc-otp-shake{0%,to{transform:translate(0)}20%{transform:translate(-4px)}40%{transform:translate(4px)}60%{transform:translate(-3px)}80%{transform:translate(2px)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
3892
3850
|
}
|
|
3893
3851
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OcOtpComponent, decorators: [{
|
|
3894
3852
|
type: Component,
|
|
3895
|
-
args: [{ selector: 'oc-otp', imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "<div\n class=\"oc-otp\"\n [class.oc-otp--error]=\"!!ocError()\"\n [class.oc-otp--shake]=\"shake()\"\n (paste)=\"onPaste($event)\"\n>\n @for (digit of digits(); track $index) {\n @if (ocSeparator() && $index === midpoint()) {\n <span\n class=\"oc-otp__separator\"\n data-testid=\"oc-otp-separator\"\n aria-hidden=\"true\"\n >-</span\n >\n }\n <input\n #otpInput\n class=\"oc-otp__input\"\n type=\"text\"\n inputmode=\"
|
|
3896
|
-
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { ocLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocLength", required: false }] }], ocSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocSeparator", required: false }] }], ocError: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocError", required: false }] }], ocDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocDisabled", required: false }] }], ocAutoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocAutoFocus", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], complete: [{
|
|
3853
|
+
args: [{ selector: 'oc-otp', imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "<div\n class=\"oc-otp\"\n [class.oc-otp--error]=\"!!ocError()\"\n [class.oc-otp--shake]=\"shake()\"\n (paste)=\"onPaste($event)\"\n>\n @for (digit of digits(); track $index) {\n @if (ocSeparator() && $index === midpoint()) {\n <span\n class=\"oc-otp__separator\"\n data-testid=\"oc-otp-separator\"\n aria-hidden=\"true\"\n >-</span\n >\n }\n <input\n #otpInput\n class=\"oc-otp__input\"\n type=\"text\"\n [attr.inputmode]=\"inputMode()\"\n autocomplete=\"one-time-code\"\n maxlength=\"1\"\n [attr.data-testid]=\"'oc-otp-' + $index\"\n [value]=\"digit\"\n [disabled]=\"ocDisabled()\"\n (input)=\"onInput($index, $event)\"\n (keydown)=\"onKey($index, $event)\"\n />\n }\n</div>\n", styles: [".oc-otp{display:flex;align-items:center;justify-content:center;gap:8px}.oc-otp__input{flex:1 1 0;min-width:0;max-width:56px;height:56px;border:1px solid #d1d5db;border-radius:10px;background:#f8f9ff;font:inherit;font-size:24px;font-weight:500;color:#353535;text-align:center;outline:none;transition:all .15s ease}.oc-otp__input:focus{background:#fff;border-color:#00dda3;box-shadow:0 4px 3.2px #00dda314,0 0 0 4px #00dda324}.oc-otp__input:disabled{cursor:not-allowed;opacity:.6}.oc-otp__separator{flex:0 0 auto;color:#8f9596;font-size:24px;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1;padding:0 2px}.oc-otp--error .oc-otp__input{border-color:#ed3a3a}.oc-otp--shake{animation:oc-otp-shake .32s ease}@keyframes oc-otp-shake{0%,to{transform:translate(0)}20%{transform:translate(-4px)}40%{transform:translate(4px)}60%{transform:translate(-3px)}80%{transform:translate(2px)}}\n"] }]
|
|
3854
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { ocLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocLength", required: false }] }], ocSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocSeparator", required: false }] }], ocError: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocError", required: false }] }], ocDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocDisabled", required: false }] }], ocAutoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocAutoFocus", required: false }] }], ocAlphanumeric: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocAlphanumeric", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], complete: [{
|
|
3897
3855
|
type: Output
|
|
3898
3856
|
}], inputs: [{
|
|
3899
3857
|
type: ViewChildren,
|
|
@@ -4598,17 +4556,137 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
|
|
|
4598
4556
|
args: [{ selector: 'oc-notification', standalone: true, imports: [CommonModule], template: "<div\n #card\n class=\"oc-notif\"\n [ngClass]=\"{\n closing: closing(),\n 'swiped-out': swipedOut(),\n dragging: drag().active,\n clickable: ocClickable()\n }\"\n [ngStyle]=\"styleVars()\"\n (click)=\"onClick()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n>\n <div class=\"oc-notif-avatar-slot\">\n <ng-content select=\"[ocNotificationAvatar]\"></ng-content>\n </div>\n\n <div class=\"oc-notif-body\">\n <div class=\"oc-notif-kind\">\n <ng-content select=\"[ocNotificationKind]\"></ng-content>\n </div>\n <div class=\"oc-notif-row1\">\n <span class=\"oc-notif-name\">\n <ng-content select=\"[ocNotificationTitle]\"></ng-content>\n </span>\n </div>\n <div class=\"oc-notif-msg\">\n <ng-content></ng-content>\n </div>\n <div class=\"oc-notif-badge-slot\">\n <ng-content select=\"[ocNotificationBadge]\"></ng-content>\n </div>\n </div>\n\n <div class=\"oc-notif-actions\">\n <span class=\"oc-notif-meta\">\n <ng-content select=\"[ocNotificationTime]\"></ng-content>\n </span>\n @if (ocClosable()) {\n <button\n class=\"oc-notif-close\"\n type=\"button\"\n [attr.aria-label]=\"ocCloseLabel()\"\n [title]=\"ocCloseLabel()\"\n (click)=\"onCloseClick($event)\"\n >\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n }\n </div>\n</div>\n", styles: [":host{display:block}.oc-notif{position:relative;display:flex;align-items:flex-start;gap:10px;background:#f8f9ff;border:1px solid rgba(85,5,162,.25);border-radius:var(--notif-radius, 14px);padding:10px 72px 10px 10px;box-shadow:0 1px 3px #1e08320a,0 1px 1px #1e083205;-webkit-user-select:none;user-select:none;transition:transform .2s cubic-bezier(.2,.9,.2,1.05),box-shadow .2s ease,background .2s ease;touch-action:pan-y}.oc-notif.clickable{cursor:pointer}.oc-notif:hover{transform:translateY(-1px);background:#f8f9ff;box-shadow:0 3px 8px -2px #1e08320f,0 1px 2px #1e083208}.oc-notif.closing{animation:ocnSlideOut .28s cubic-bezier(.4,0,1,1) forwards;pointer-events:none}.oc-notif.dragging{transition:none}.oc-notif.swiped-out{animation:ocnSwipeOut .24s cubic-bezier(.4,0,1,1) forwards;pointer-events:none}@keyframes ocnSlideOut{to{opacity:0;transform:translate(60px) scale(.94)}}@keyframes ocnSwipeOut{to{opacity:0;transform:translate(var(--swipe-out-x, -120%)) scale(.9)}}.oc-notif-avatar-slot{flex:0 0 auto;display:flex;align-items:center;justify-content:center}.oc-notif-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.oc-notif-kind{font-size:10px;font-weight:400;color:#8f9596;letter-spacing:.1px;line-height:1.2;margin-bottom:1px}.oc-notif-kind:empty{display:none}.oc-notif-row1{display:flex;align-items:baseline;gap:6px;min-width:0}.oc-notif-name{font-size:12.5px;font-weight:700;color:#1e0832;line-height:1.25;letter-spacing:-.1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto;min-width:0}.oc-notif-meta{font-size:10.5px;font-weight:500;color:#8f9596;white-space:nowrap;line-height:1}.oc-notif-meta:empty{display:none}.oc-notif-msg{font-size:12px;color:#353535;line-height:1.4;margin-top:3px;word-break:break-word;display:-webkit-box;-webkit-line-clamp:var(--notif-line-clamp, 2);line-clamp:var(--notif-line-clamp, 2);-webkit-box-orient:vertical;overflow:hidden}.oc-notif-msg:empty{display:none}.oc-notif-badge-slot:empty{display:none}.oc-notif-actions{position:absolute;top:8px;right:8px;display:flex;align-items:center;gap:6px;z-index:2}.oc-notif-close{width:20px;height:20px;border-radius:6px;border:0;background:transparent;color:#8f9596;cursor:pointer;display:grid;place-items:center;transition:background .15s ease,color .15s ease}.oc-notif-close:hover{background:#f7f7f7;color:#353535}.oc-notif-close .material-symbols-outlined{font-size:13px}\n"] }]
|
|
4599
4557
|
}], propDecorators: { ocClosable: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocClosable", required: false }] }], ocClickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocClickable", required: false }] }], ocSwipeable: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocSwipeable", required: false }] }], ocSwipeDirection: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocSwipeDirection", required: false }] }], ocBorderRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocBorderRadius", required: false }] }], ocLineClamp: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocLineClamp", required: false }] }], ocCloseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ocCloseLabel", required: false }] }], ocClose: [{ type: i0.Output, args: ["ocClose"] }], ocClick: [{ type: i0.Output, args: ["ocClick"] }], card: [{ type: i0.ViewChild, args: ['card', { isSignal: true }] }] } });
|
|
4600
4558
|
|
|
4559
|
+
const STATUS_CONF = {
|
|
4560
|
+
sucesso: { cssKey: 'sucesso', icon: 'check_circle' },
|
|
4561
|
+
success: { cssKey: 'sucesso', icon: 'check_circle' },
|
|
4562
|
+
éxito: { cssKey: 'sucesso', icon: 'check_circle' },
|
|
4563
|
+
erro: { cssKey: 'erro', icon: 'error' },
|
|
4564
|
+
error: { cssKey: 'erro', icon: 'error' },
|
|
4565
|
+
informação: { cssKey: 'info', icon: 'info' },
|
|
4566
|
+
informacao: { cssKey: 'info', icon: 'info' },
|
|
4567
|
+
información: { cssKey: 'info', icon: 'info' },
|
|
4568
|
+
information: { cssKey: 'info', icon: 'info' },
|
|
4569
|
+
carregando: { cssKey: 'loading', icon: 'progress_activity' },
|
|
4570
|
+
cargando: { cssKey: 'loading', icon: 'progress_activity' },
|
|
4571
|
+
loading: { cssKey: 'loading', icon: 'progress_activity' },
|
|
4572
|
+
};
|
|
4573
|
+
const DEFAULT_CONF = { cssKey: 'info', icon: 'info' };
|
|
4574
|
+
const MAX_VISIBLE = 3;
|
|
4575
|
+
/** Must match the `oc-toast-out` animation duration in the scss. */
|
|
4576
|
+
const LEAVE_MS = 240;
|
|
4577
|
+
/**
|
|
4578
|
+
* Center-bottom toast stack, drawer-safe (renders above the `oc-drawer` scrim
|
|
4579
|
+
* at `z-index: 1100`). Mount a single instance at the application root, e.g.
|
|
4580
|
+
* `<oc-toast />`.
|
|
4581
|
+
*
|
|
4582
|
+
* Toasts are triggered through `OcToastService.openToast(...)`. Renders a pill
|
|
4583
|
+
* with the status-tint palette, stacks up to 3 (oldest on top), auto-dismisses
|
|
4584
|
+
* after the per-toast countdown (loading persists), pauses the countdown while
|
|
4585
|
+
* hovered, replaces a `promiseKey` toast in place (loading → result) and
|
|
4586
|
+
* de-dupes identical status+message toasts by renewing their timer.
|
|
4587
|
+
*/
|
|
4601
4588
|
class OcToastComponent {
|
|
4602
|
-
constructor(
|
|
4603
|
-
this.
|
|
4589
|
+
constructor() {
|
|
4590
|
+
this.toastService = inject(OcToastService);
|
|
4591
|
+
this.destroyRef = inject(DestroyRef);
|
|
4592
|
+
/** Visible + leaving toasts, ordered oldest → newest. */
|
|
4593
|
+
this.toasts = signal([], ...(ngDevMode ? [{ debugName: "toasts" }] : []));
|
|
4594
|
+
/** True while the pointer hovers the stack — freezes every countdown. */
|
|
4595
|
+
this.paused = signal(false, ...(ngDevMode ? [{ debugName: "paused" }] : []));
|
|
4596
|
+
/** Removal timers for toasts playing their leave animation. */
|
|
4597
|
+
this.leaveTimers = new Map();
|
|
4598
|
+
/** Single 1s tick drives every countdown so hover-pause is trivial. */
|
|
4599
|
+
this.tick = setInterval(() => this.onTick(), 1000);
|
|
4600
|
+
this.toastService.opened$
|
|
4601
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
4602
|
+
.subscribe((toast) => this.onOpened(toast));
|
|
4603
|
+
}
|
|
4604
|
+
ngOnDestroy() {
|
|
4605
|
+
clearInterval(this.tick);
|
|
4606
|
+
this.leaveTimers.forEach((timer) => clearTimeout(timer));
|
|
4607
|
+
this.leaveTimers.clear();
|
|
4608
|
+
}
|
|
4609
|
+
/** Maps any status alias to its icon + css key (defaults to info). */
|
|
4610
|
+
resolve(status) {
|
|
4611
|
+
return STATUS_CONF[(status ?? '').toLowerCase()] ?? DEFAULT_CONF;
|
|
4612
|
+
}
|
|
4613
|
+
isLoading(status) {
|
|
4614
|
+
return this.resolve(status).cssKey === 'loading';
|
|
4615
|
+
}
|
|
4616
|
+
/** Older toasts dim slightly; clamps the css `data-stack-pos` to 0..2. */
|
|
4617
|
+
stackPos(index) {
|
|
4618
|
+
return Math.min(this.toasts().length - 1 - index, 2);
|
|
4619
|
+
}
|
|
4620
|
+
/** Plays the leave animation, then drops the toast from the stack. */
|
|
4621
|
+
dismiss(id) {
|
|
4622
|
+
this.toasts.update((list) => list.map((toast) => (toast.id === id ? { ...toast, leaving: true } : toast)));
|
|
4623
|
+
if (this.leaveTimers.has(id)) {
|
|
4624
|
+
return;
|
|
4625
|
+
}
|
|
4626
|
+
const timer = setTimeout(() => {
|
|
4627
|
+
this.toasts.update((list) => list.filter((toast) => toast.id !== id));
|
|
4628
|
+
this.leaveTimers.delete(id);
|
|
4629
|
+
}, LEAVE_MS);
|
|
4630
|
+
this.leaveTimers.set(id, timer);
|
|
4631
|
+
}
|
|
4632
|
+
onOpened(toast) {
|
|
4633
|
+
// A loading toast carrying a promiseKey is later replaced in place by its
|
|
4634
|
+
// result (e.g. carregando → sucesso) — keep its slot rather than stacking.
|
|
4635
|
+
if (toast.promiseKey) {
|
|
4636
|
+
const existing = this.toasts().find((item) => item.promiseKey === toast.promiseKey && !item.leaving);
|
|
4637
|
+
if (existing) {
|
|
4638
|
+
this.toasts.update((list) => list.map((item) => item.id === existing.id
|
|
4639
|
+
? { ...item, status: toast.status, message: toast.message, counter: toast.counter }
|
|
4640
|
+
: item));
|
|
4641
|
+
return;
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
// De-dupe: an identical (status + message) toast already visible just has
|
|
4645
|
+
// its countdown renewed instead of stacking a copy.
|
|
4646
|
+
const duplicate = this.toasts().find((item) => item.status === toast.status && item.message === toast.message && !item.leaving);
|
|
4647
|
+
if (duplicate) {
|
|
4648
|
+
this.toasts.update((list) => list.map((item) => (item.id === duplicate.id ? { ...item, counter: toast.counter } : item)));
|
|
4649
|
+
return;
|
|
4650
|
+
}
|
|
4651
|
+
// Evict the oldest visible toast once the stack is at capacity.
|
|
4652
|
+
const visible = this.toasts().filter((item) => !item.leaving);
|
|
4653
|
+
if (visible.length >= MAX_VISIBLE) {
|
|
4654
|
+
this.dismiss(visible[0].id);
|
|
4655
|
+
}
|
|
4656
|
+
const item = {
|
|
4657
|
+
id: toast.id,
|
|
4658
|
+
status: toast.status,
|
|
4659
|
+
message: toast.message,
|
|
4660
|
+
counter: toast.counter,
|
|
4661
|
+
promiseKey: toast.promiseKey,
|
|
4662
|
+
leaving: false,
|
|
4663
|
+
};
|
|
4664
|
+
this.toasts.update((list) => [...list, item]);
|
|
4604
4665
|
}
|
|
4605
|
-
|
|
4606
|
-
|
|
4666
|
+
onTick() {
|
|
4667
|
+
if (this.paused()) {
|
|
4668
|
+
return;
|
|
4669
|
+
}
|
|
4670
|
+
const expired = [];
|
|
4671
|
+
this.toasts.update((list) => list.map((toast) => {
|
|
4672
|
+
if (toast.leaving || this.isLoading(toast.status)) {
|
|
4673
|
+
return toast;
|
|
4674
|
+
}
|
|
4675
|
+
const counter = toast.counter - 1;
|
|
4676
|
+
if (counter <= 0) {
|
|
4677
|
+
expired.push(toast.id);
|
|
4678
|
+
}
|
|
4679
|
+
return { ...toast, counter };
|
|
4680
|
+
}));
|
|
4681
|
+
expired.forEach((id) => this.dismiss(id));
|
|
4682
|
+
}
|
|
4683
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OcToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4684
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: OcToastComponent, isStandalone: true, selector: "oc-toast", ngImport: i0, template: "<div\n class=\"oc-toast-stack\"\n (mouseenter)=\"paused.set(true)\"\n (mouseleave)=\"paused.set(false)\"\n>\n @for (toast of toasts(); track toast.id; let i = $index) {\n <div\n class=\"oc-toast status-{{ resolve(toast.status).cssKey }}\"\n [class.is-leaving]=\"toast.leaving\"\n [attr.data-stack-pos]=\"stackPos(i)\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <span class=\"oc-toast-icon\">\n @if (isLoading(toast.status)) {\n <span\n class=\"oc-toast-spinner\"\n aria-hidden=\"true\"\n ></span>\n } @else {\n <span class=\"material-symbols-outlined\">{{ resolve(toast.status).icon }}</span>\n }\n </span>\n\n <span class=\"oc-toast-msg\">{{ toast.message }}</span>\n\n <button\n class=\"oc-toast-close\"\n type=\"button\"\n aria-label=\"Fechar\"\n (click)=\"dismiss(toast.id)\"\n >\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n </div>\n }\n</div>\n", styles: ["@charset \"UTF-8\";.oc-toast-stack{position:fixed;left:50%;bottom:24px;transform:translate(-50%);display:flex;flex-direction:column;align-items:center;gap:10px;z-index:1100;pointer-events:none;width:max-content;max-width:calc(100% - 48px)}.oc-toast-stack>*{pointer-events:auto}@keyframes oc-toast-in{0%{opacity:0;transform:translateY(28px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes oc-toast-out{0%{opacity:1;transform:translateY(0) scale(1);max-height:200px;margin-top:0}to{opacity:0;transform:translateY(16px) scale(.96);max-height:0;margin-top:-10px}}.oc-toast{display:flex;align-items:center;gap:10px;min-width:280px;max-width:520px;padding:10px 6px 10px 14px;border:1px solid;border-radius:999px;box-shadow:0 12px 28px #1e08321a,0 3px 8px #1e08320d;font-family:Ubuntu,sans-serif;-webkit-user-select:none;user-select:none;animation:oc-toast-in .32s cubic-bezier(.2,.9,.2,1)}.oc-toast.is-leaving{animation:oc-toast-out .24s ease forwards;pointer-events:none}.oc-toast[data-stack-pos=\"1\"]{opacity:.94}.oc-toast[data-stack-pos=\"2\"]{opacity:.84}.oc-toast.status-sucesso{background:#e6fbf4;border-color:#b7efdb;color:#08643d}.oc-toast.status-erro{background:#fde9e9;border-color:#f5bfbf;color:#7a1717}.oc-toast.status-info,.oc-toast.status-loading{background:#f2eaf9;border-color:#dcc8ee;color:#3d0676}.oc-toast-icon{flex-shrink:0;display:grid;place-items:center}.oc-toast-icon .material-symbols-outlined{font-size:20px}.oc-toast-msg{flex:1;min-width:0;font-size:14px;line-height:1.4;font-weight:400;text-wrap:pretty;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.oc-toast-close{flex-shrink:0;display:grid;place-items:center;width:28px;height:28px;border:0;border-radius:50%;background:transparent;color:inherit;opacity:.55;cursor:pointer;transition:opacity .15s ease,background .15s ease}.oc-toast-close:hover{opacity:1;background:#0000000f}.oc-toast-close .material-symbols-outlined{font-size:18px}.oc-toast-spinner{width:20px;height:20px;border:2.5px solid currentColor;border-right-color:transparent;border-radius:50%;opacity:.9;animation:oc-toast-spin .85s linear infinite}@keyframes oc-toast-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.oc-toast,.oc-toast.is-leaving{animation:none}.oc-toast-spinner{animation-duration:1.6s}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4607
4685
|
}
|
|
4608
4686
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OcToastComponent, decorators: [{
|
|
4609
4687
|
type: Component,
|
|
4610
|
-
args: [{ selector: 'oc-toast', imports: [
|
|
4611
|
-
}], ctorParameters: () => [
|
|
4688
|
+
args: [{ selector: 'oc-toast', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"oc-toast-stack\"\n (mouseenter)=\"paused.set(true)\"\n (mouseleave)=\"paused.set(false)\"\n>\n @for (toast of toasts(); track toast.id; let i = $index) {\n <div\n class=\"oc-toast status-{{ resolve(toast.status).cssKey }}\"\n [class.is-leaving]=\"toast.leaving\"\n [attr.data-stack-pos]=\"stackPos(i)\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <span class=\"oc-toast-icon\">\n @if (isLoading(toast.status)) {\n <span\n class=\"oc-toast-spinner\"\n aria-hidden=\"true\"\n ></span>\n } @else {\n <span class=\"material-symbols-outlined\">{{ resolve(toast.status).icon }}</span>\n }\n </span>\n\n <span class=\"oc-toast-msg\">{{ toast.message }}</span>\n\n <button\n class=\"oc-toast-close\"\n type=\"button\"\n aria-label=\"Fechar\"\n (click)=\"dismiss(toast.id)\"\n >\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n </div>\n }\n</div>\n", styles: ["@charset \"UTF-8\";.oc-toast-stack{position:fixed;left:50%;bottom:24px;transform:translate(-50%);display:flex;flex-direction:column;align-items:center;gap:10px;z-index:1100;pointer-events:none;width:max-content;max-width:calc(100% - 48px)}.oc-toast-stack>*{pointer-events:auto}@keyframes oc-toast-in{0%{opacity:0;transform:translateY(28px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes oc-toast-out{0%{opacity:1;transform:translateY(0) scale(1);max-height:200px;margin-top:0}to{opacity:0;transform:translateY(16px) scale(.96);max-height:0;margin-top:-10px}}.oc-toast{display:flex;align-items:center;gap:10px;min-width:280px;max-width:520px;padding:10px 6px 10px 14px;border:1px solid;border-radius:999px;box-shadow:0 12px 28px #1e08321a,0 3px 8px #1e08320d;font-family:Ubuntu,sans-serif;-webkit-user-select:none;user-select:none;animation:oc-toast-in .32s cubic-bezier(.2,.9,.2,1)}.oc-toast.is-leaving{animation:oc-toast-out .24s ease forwards;pointer-events:none}.oc-toast[data-stack-pos=\"1\"]{opacity:.94}.oc-toast[data-stack-pos=\"2\"]{opacity:.84}.oc-toast.status-sucesso{background:#e6fbf4;border-color:#b7efdb;color:#08643d}.oc-toast.status-erro{background:#fde9e9;border-color:#f5bfbf;color:#7a1717}.oc-toast.status-info,.oc-toast.status-loading{background:#f2eaf9;border-color:#dcc8ee;color:#3d0676}.oc-toast-icon{flex-shrink:0;display:grid;place-items:center}.oc-toast-icon .material-symbols-outlined{font-size:20px}.oc-toast-msg{flex:1;min-width:0;font-size:14px;line-height:1.4;font-weight:400;text-wrap:pretty;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.oc-toast-close{flex-shrink:0;display:grid;place-items:center;width:28px;height:28px;border:0;border-radius:50%;background:transparent;color:inherit;opacity:.55;cursor:pointer;transition:opacity .15s ease,background .15s ease}.oc-toast-close:hover{opacity:1;background:#0000000f}.oc-toast-close .material-symbols-outlined{font-size:18px}.oc-toast-spinner{width:20px;height:20px;border:2.5px solid currentColor;border-right-color:transparent;border-radius:50%;opacity:.9;animation:oc-toast-spin .85s linear infinite}@keyframes oc-toast-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.oc-toast,.oc-toast.is-leaving{animation:none}.oc-toast-spinner{animation-duration:1.6s}}\n"] }]
|
|
4689
|
+
}], ctorParameters: () => [] });
|
|
4612
4690
|
|
|
4613
4691
|
class OcToggleComponent {
|
|
4614
4692
|
constructor() {
|