tecnualng 21.0.26 → 21.0.28
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/tecnualng.mjs
CHANGED
|
@@ -1016,6 +1016,13 @@ class ThemeService {
|
|
|
1016
1016
|
description: 'Neon cyberpunk vibes',
|
|
1017
1017
|
primaryColor: '#00f2ff',
|
|
1018
1018
|
isDark: true
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
name: 'futuristic-light',
|
|
1022
|
+
displayName: 'Futuristic Light',
|
|
1023
|
+
description: 'Clean cyberpunk aesthetic',
|
|
1024
|
+
primaryColor: '#00c2cc',
|
|
1025
|
+
isDark: false
|
|
1019
1026
|
}
|
|
1020
1027
|
];
|
|
1021
1028
|
constructor() {
|
|
@@ -2035,6 +2042,381 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
|
|
|
2035
2042
|
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"tng-select-wrapper\" [class.tng-select-open]=\"selectDirective()?.isOpen()\">\n @if (label()) {\n <label class=\"tng-select-label\" [attr.for]=\"selectId()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"tng-select-container\">\n <select\n [id]=\"selectId()\"\n tngSelect\n [enableMulti]=\"enableMulti()\"\n [enableSearch]=\"enableSearch()\"\n [placeholder]=\"placeholder()\"\n [customTrigger]=\"true\"\n [multiple]=\"enableMulti()\"\n [triggerRef]=\"triggerDisplay\"\n [(selectedValues)]=\"value\"\n [disabled]=\"effectiveDisabled()\"\n [attr.aria-label]=\"ariaLabel() || label()\"\n >\n @for (option of options(); track option.value) {\n <option [value]=\"option.value\" [disabled]=\"option.disabled\">\n {{ option.label }}\n </option>\n }\n </select>\n\n <div\n class=\"tng-select-display\"\n #triggerDisplay\n [class.disabled]=\"effectiveDisabled()\"\n (click)=\"onDisplayClick($event)\"\n >\n <span class=\"tng-select-display-text\">\n {{ displayText() }}\n </span>\n <i class=\"fa fa-chevron-down tng-select-arrow\"></i>\n </div>\n </div>\n\n @if (hint()) {\n <div class=\"tng-select-hint\">\n {{ hint() }}\n </div>\n }\n</div>\n", styles: [":host{display:block;margin-bottom:1.5rem;font-family:var(--tng-font-family, \"Inter\", sans-serif)}.tng-select-wrapper{width:100%}.tng-select-label{display:block;margin-bottom:.5rem;font-size:.9rem;font-weight:500;color:var(--tng-text, #333)}.tng-select-container{position:relative}.tng-select-display{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.75rem 1rem;border:1px solid var(--tng-border, #999);border-radius:var(--tng-border-radius, 4px);background:var(--tng-surface, #ffffff);cursor:pointer;transition:all .2s ease;min-height:48px;font-family:var(--tng-font-family, \"Inter\", sans-serif)}.tng-select-display:hover:not(.disabled){border-color:var(--tng-text-secondary, #757575)}.tng-select-display.disabled{opacity:.6;cursor:not-allowed;background:var(--tng-background, #fafafa)}.tng-select-wrapper.tng-select-open .tng-select-display,.tng-select-display.tng-select-open{border-color:var(--tng-primary, #00f2ff);border-width:2px;padding:calc(.75rem - 1px) calc(1rem - 1px)}.tng-select-display-text{flex:1;color:var(--tng-text, #333);font-size:1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tng-select-display-text:empty:before{content:attr(data-placeholder);color:var(--tng-text-secondary, #757575)}.tng-select-arrow{color:var(--tng-text-secondary, #757575);transition:transform .2s ease;font-size:.8rem}.tng-select-wrapper.tng-select-open .tng-select-arrow,.tng-select-display.tng-select-open .tng-select-arrow{transform:rotate(180deg)}.tng-select-hint{margin-top:.25rem;font-size:.85rem;color:var(--tng-text-secondary, #757575)}\n"] }]
|
|
2036
2043
|
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], enableMulti: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableMulti", required: false }] }], enableSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSearch", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], selectDirective: [{ type: i0.ViewChild, args: [i0.forwardRef(() => TngSelectDirective), { isSignal: true }] }] } });
|
|
2037
2044
|
|
|
2045
|
+
class TngSliderComponent {
|
|
2046
|
+
// Inputs
|
|
2047
|
+
min = input(0, ...(ngDevMode ? [{ debugName: "min" }] : []));
|
|
2048
|
+
max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : []));
|
|
2049
|
+
step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : []));
|
|
2050
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
2051
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
2052
|
+
orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
|
|
2053
|
+
// Internal state
|
|
2054
|
+
value = model(0, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
2055
|
+
isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
|
|
2056
|
+
// Elements
|
|
2057
|
+
track = viewChild.required('track');
|
|
2058
|
+
// Computed
|
|
2059
|
+
percentage = computed(() => {
|
|
2060
|
+
const min = this.min();
|
|
2061
|
+
const max = this.max();
|
|
2062
|
+
const val = this.value();
|
|
2063
|
+
if (max === min)
|
|
2064
|
+
return 0;
|
|
2065
|
+
const percent = ((val - min) / (max - min)) * 100;
|
|
2066
|
+
return Math.min(Math.max(percent, 0), 100);
|
|
2067
|
+
}, ...(ngDevMode ? [{ debugName: "percentage" }] : []));
|
|
2068
|
+
// CVA callbacks
|
|
2069
|
+
onChange = () => { };
|
|
2070
|
+
onTouched = () => { };
|
|
2071
|
+
constructor() {
|
|
2072
|
+
// Ensure value respects min/max/step when inputs change
|
|
2073
|
+
effect(() => {
|
|
2074
|
+
const val = this.value();
|
|
2075
|
+
const clamped = this.clampAndStep(val);
|
|
2076
|
+
if (val !== clamped) {
|
|
2077
|
+
this.value.set(clamped);
|
|
2078
|
+
}
|
|
2079
|
+
}, { allowSignalWrites: true });
|
|
2080
|
+
}
|
|
2081
|
+
// CVA Implementation
|
|
2082
|
+
writeValue(value) {
|
|
2083
|
+
if (value !== null && value !== undefined) {
|
|
2084
|
+
this.value.set(this.clampAndStep(value));
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
registerOnChange(fn) {
|
|
2088
|
+
this.onChange = fn;
|
|
2089
|
+
}
|
|
2090
|
+
registerOnTouched(fn) {
|
|
2091
|
+
this.onTouched = fn;
|
|
2092
|
+
}
|
|
2093
|
+
setDisabledState(isDisabled) {
|
|
2094
|
+
// We handle disabled state via input, but CVA can also set it
|
|
2095
|
+
// Usually we'd sync this with a signal if we wanted to support both
|
|
2096
|
+
}
|
|
2097
|
+
// Interaction Logic
|
|
2098
|
+
onStart(event) {
|
|
2099
|
+
if (this.disabled())
|
|
2100
|
+
return;
|
|
2101
|
+
this.isDragging.set(true);
|
|
2102
|
+
this.onTouched();
|
|
2103
|
+
this.updateValueFromEvent(event);
|
|
2104
|
+
// Prevent text selection while dragging
|
|
2105
|
+
event.preventDefault();
|
|
2106
|
+
}
|
|
2107
|
+
onMove(event) {
|
|
2108
|
+
if (!this.isDragging() || this.disabled())
|
|
2109
|
+
return;
|
|
2110
|
+
this.updateValueFromEvent(event);
|
|
2111
|
+
}
|
|
2112
|
+
onEnd() {
|
|
2113
|
+
this.isDragging.set(false);
|
|
2114
|
+
}
|
|
2115
|
+
updateValueFromEvent(event) {
|
|
2116
|
+
const rect = this.track().nativeElement.getBoundingClientRect();
|
|
2117
|
+
let percent = 0;
|
|
2118
|
+
if (this.orientation() === 'horizontal') {
|
|
2119
|
+
const clientX = this.getClientX(event);
|
|
2120
|
+
percent = (clientX - rect.left) / rect.width;
|
|
2121
|
+
}
|
|
2122
|
+
else {
|
|
2123
|
+
const clientY = this.getClientY(event);
|
|
2124
|
+
// In vertical mode, 0 is at bottom, so we invert logic or CSS
|
|
2125
|
+
// Typically slider goes bottom->top.
|
|
2126
|
+
// clientY is 0 at top.
|
|
2127
|
+
// So percent = (rect.bottom - clientY) / rect.height
|
|
2128
|
+
percent = (rect.bottom - clientY) / rect.height;
|
|
2129
|
+
}
|
|
2130
|
+
percent = Math.min(Math.max(percent, 0), 1);
|
|
2131
|
+
const range = this.max() - this.min();
|
|
2132
|
+
const rawValue = this.min() + percent * range;
|
|
2133
|
+
const newValue = this.clampAndStep(rawValue);
|
|
2134
|
+
if (this.value() !== newValue) {
|
|
2135
|
+
this.value.set(newValue);
|
|
2136
|
+
this.onChange(newValue);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
getClientX(event) {
|
|
2140
|
+
if (event instanceof MouseEvent) {
|
|
2141
|
+
return event.clientX;
|
|
2142
|
+
}
|
|
2143
|
+
return event.touches[0].clientX;
|
|
2144
|
+
}
|
|
2145
|
+
getClientY(event) {
|
|
2146
|
+
if (event instanceof MouseEvent) {
|
|
2147
|
+
return event.clientY;
|
|
2148
|
+
}
|
|
2149
|
+
return event.touches[0].clientY;
|
|
2150
|
+
}
|
|
2151
|
+
clampAndStep(value) {
|
|
2152
|
+
const min = this.min();
|
|
2153
|
+
const max = this.max();
|
|
2154
|
+
const step = this.step();
|
|
2155
|
+
let clamped = Math.min(Math.max(value, min), max);
|
|
2156
|
+
if (step > 0) {
|
|
2157
|
+
const steps = Math.round((clamped - min) / step);
|
|
2158
|
+
clamped = min + steps * step;
|
|
2159
|
+
// Re-clamp to handle floating point issues or partial steps at max
|
|
2160
|
+
clamped = Math.min(Math.max(clamped, min), max);
|
|
2161
|
+
}
|
|
2162
|
+
return clamped;
|
|
2163
|
+
}
|
|
2164
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2165
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: TngSliderComponent, isStandalone: true, selector: "tng-slider", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "mousedown": "onStart($event)", "touchstart": "onStart($event)", "window:mousemove": "onMove($event)", "window:touchmove": "onMove($event)", "window:mouseup": "onEnd()", "window:touchend": "onEnd()" } }, providers: [
|
|
2166
|
+
{
|
|
2167
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2168
|
+
useExisting: forwardRef(() => TngSliderComponent),
|
|
2169
|
+
multi: true,
|
|
2170
|
+
},
|
|
2171
|
+
], viewQueries: [{ propertyName: "track", first: true, predicate: ["track"], descendants: true, isSignal: true }], ngImport: i0, template: "<div \n class=\"tng-slider-container\" \n [class.disabled]=\"disabled()\"\n [class.dragging]=\"isDragging()\"\n [class.vertical]=\"orientation() === 'vertical'\">\n \n @if (label()) {\n <label class=\"tng-slider-label\">{{ label() }}</label>\n }\n\n <div class=\"tng-slider-wrapper\">\n <div class=\"tng-slider-track\" #track>\n <div \n class=\"tng-slider-fill\" \n [style.width.%]=\"orientation() === 'horizontal' ? percentage() : 100\"\n [style.height.%]=\"orientation() === 'vertical' ? percentage() : 100\">\n </div>\n <div \n class=\"tng-slider-thumb\" \n [style.left.%]=\"orientation() === 'horizontal' ? percentage() : 50\"\n [style.bottom.%]=\"orientation() === 'vertical' ? percentage() : undefined\">\n <div class=\"tng-slider-thumb-knob\"></div>\n <div class=\"tng-slider-thumb-label\">{{ value() }}</div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;width:100%}.tng-slider-container{display:flex;flex-direction:column;gap:.5rem;padding:1rem 0;-webkit-user-select:none;user-select:none}.tng-slider-container.disabled{opacity:.5;pointer-events:none;filter:grayscale(1)}.tng-slider-label{font-family:inherit;font-size:.875rem;font-weight:500;color:var(--tng-text);margin-bottom:.25rem}.tng-slider-wrapper{position:relative;height:24px;display:flex;align-items:center;cursor:pointer;touch-action:none}.tng-slider-track{position:relative;width:100%;height:6px;background:rgba(var(--tng-primary),.2);background:color-mix(in srgb,var(--tng-primary),transparent 80%);border-radius:3px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);overflow:visible;border:1px solid color-mix(in srgb,var(--tng-primary),transparent 90%);box-shadow:inset 0 1px 3px #0003}.tng-slider-fill{position:absolute;top:0;left:0;height:100%;background:linear-gradient(90deg,var(--tng-primary),var(--tng-secondary));border-radius:3px;transition:width .2s cubic-bezier(.4,0,.2,1);box-shadow:0 0 10px color-mix(in srgb,var(--tng-primary),transparent 50%)}.tng-slider-thumb{position:absolute;top:50%;transform:translate(-50%,-50%);width:24px;height:24px;display:flex;align-items:center;justify-content:center;z-index:2;transition:left .2s cubic-bezier(.4,0,.2,1)}.tng-slider-thumb-knob{width:20px;height:20px;background:var(--tng-surface);border:2px solid var(--tng-primary);border-radius:50%;box-shadow:0 2px 5px #0000004d;transition:transform .1s ease,box-shadow .2s ease}.tng-slider-thumb-knob:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:8px;height:8px;background:var(--tng-primary);border-radius:50%;opacity:.5}.tng-slider-thumb-label{position:absolute;top:-35px;left:50%;transform:translate(-50%) scale(0);background:color-mix(in srgb,var(--tng-surface),transparent 10%);color:var(--tng-primary);padding:4px 8px;border-radius:6px;font-size:.75rem;font-weight:700;border:1px solid color-mix(in srgb,var(--tng-primary),transparent 70%);pointer-events:none;transition:transform .2s cubic-bezier(.175,.885,.32,1.275),opacity .2s ease;opacity:0;box-shadow:0 4px 10px #0003;white-space:nowrap}.tng-slider-container:hover .tng-slider-thumb-knob{box-shadow:0 0 15px color-mix(in srgb,var(--tng-primary),transparent 60%)}.tng-slider-container:hover .tng-slider-thumb-label,.tng-slider-container.dragging .tng-slider-thumb-label{transform:translate(-50%) scale(1);opacity:1}.tng-slider-container.dragging .tng-slider-fill,.tng-slider-container.dragging .tng-slider-thumb{transition:none}.tng-slider-container.dragging .tng-slider-thumb-knob{transform:scale(1.1);background:var(--tng-primary);border-color:var(--tng-text);box-shadow:0 0 20px color-mix(in srgb,var(--tng-primary),transparent 40%)}.tng-slider-container.dragging .tng-slider-thumb-knob:after{background:var(--tng-text);opacity:1}.tng-slider-container.dragging .tng-slider-track{cursor:grabbing}.tng-slider-container.vertical{height:100%;min-height:150px;flex-direction:column;align-items:center}.tng-slider-container.vertical .tng-slider-wrapper{width:24px;height:100%;flex-direction:column}.tng-slider-container.vertical .tng-slider-track{width:6px;height:100%}.tng-slider-container.vertical .tng-slider-fill{width:100%;bottom:0;top:auto;transition:height .2s cubic-bezier(.4,0,.2,1)}.tng-slider-container.vertical .tng-slider-thumb{top:auto;left:50%;transform:translate(-50%,50%);transition:bottom .2s cubic-bezier(.4,0,.2,1)}.tng-slider-container.vertical .tng-slider-thumb-label{top:50%;left:35px;transform:translateY(-50%) scale(0)}.tng-slider-container.vertical:hover .tng-slider-thumb-label,.tng-slider-container.vertical.dragging .tng-slider-thumb-label{transform:translateY(-50%) scale(1)}.tng-slider-container.vertical.dragging .tng-slider-fill,.tng-slider-container.vertical.dragging .tng-slider-thumb{transition:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
2172
|
+
}
|
|
2173
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngSliderComponent, decorators: [{
|
|
2174
|
+
type: Component,
|
|
2175
|
+
args: [{ selector: 'tng-slider', standalone: true, imports: [CommonModule], providers: [
|
|
2176
|
+
{
|
|
2177
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2178
|
+
useExisting: forwardRef(() => TngSliderComponent),
|
|
2179
|
+
multi: true,
|
|
2180
|
+
},
|
|
2181
|
+
], template: "<div \n class=\"tng-slider-container\" \n [class.disabled]=\"disabled()\"\n [class.dragging]=\"isDragging()\"\n [class.vertical]=\"orientation() === 'vertical'\">\n \n @if (label()) {\n <label class=\"tng-slider-label\">{{ label() }}</label>\n }\n\n <div class=\"tng-slider-wrapper\">\n <div class=\"tng-slider-track\" #track>\n <div \n class=\"tng-slider-fill\" \n [style.width.%]=\"orientation() === 'horizontal' ? percentage() : 100\"\n [style.height.%]=\"orientation() === 'vertical' ? percentage() : 100\">\n </div>\n <div \n class=\"tng-slider-thumb\" \n [style.left.%]=\"orientation() === 'horizontal' ? percentage() : 50\"\n [style.bottom.%]=\"orientation() === 'vertical' ? percentage() : undefined\">\n <div class=\"tng-slider-thumb-knob\"></div>\n <div class=\"tng-slider-thumb-label\">{{ value() }}</div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;width:100%}.tng-slider-container{display:flex;flex-direction:column;gap:.5rem;padding:1rem 0;-webkit-user-select:none;user-select:none}.tng-slider-container.disabled{opacity:.5;pointer-events:none;filter:grayscale(1)}.tng-slider-label{font-family:inherit;font-size:.875rem;font-weight:500;color:var(--tng-text);margin-bottom:.25rem}.tng-slider-wrapper{position:relative;height:24px;display:flex;align-items:center;cursor:pointer;touch-action:none}.tng-slider-track{position:relative;width:100%;height:6px;background:rgba(var(--tng-primary),.2);background:color-mix(in srgb,var(--tng-primary),transparent 80%);border-radius:3px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);overflow:visible;border:1px solid color-mix(in srgb,var(--tng-primary),transparent 90%);box-shadow:inset 0 1px 3px #0003}.tng-slider-fill{position:absolute;top:0;left:0;height:100%;background:linear-gradient(90deg,var(--tng-primary),var(--tng-secondary));border-radius:3px;transition:width .2s cubic-bezier(.4,0,.2,1);box-shadow:0 0 10px color-mix(in srgb,var(--tng-primary),transparent 50%)}.tng-slider-thumb{position:absolute;top:50%;transform:translate(-50%,-50%);width:24px;height:24px;display:flex;align-items:center;justify-content:center;z-index:2;transition:left .2s cubic-bezier(.4,0,.2,1)}.tng-slider-thumb-knob{width:20px;height:20px;background:var(--tng-surface);border:2px solid var(--tng-primary);border-radius:50%;box-shadow:0 2px 5px #0000004d;transition:transform .1s ease,box-shadow .2s ease}.tng-slider-thumb-knob:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:8px;height:8px;background:var(--tng-primary);border-radius:50%;opacity:.5}.tng-slider-thumb-label{position:absolute;top:-35px;left:50%;transform:translate(-50%) scale(0);background:color-mix(in srgb,var(--tng-surface),transparent 10%);color:var(--tng-primary);padding:4px 8px;border-radius:6px;font-size:.75rem;font-weight:700;border:1px solid color-mix(in srgb,var(--tng-primary),transparent 70%);pointer-events:none;transition:transform .2s cubic-bezier(.175,.885,.32,1.275),opacity .2s ease;opacity:0;box-shadow:0 4px 10px #0003;white-space:nowrap}.tng-slider-container:hover .tng-slider-thumb-knob{box-shadow:0 0 15px color-mix(in srgb,var(--tng-primary),transparent 60%)}.tng-slider-container:hover .tng-slider-thumb-label,.tng-slider-container.dragging .tng-slider-thumb-label{transform:translate(-50%) scale(1);opacity:1}.tng-slider-container.dragging .tng-slider-fill,.tng-slider-container.dragging .tng-slider-thumb{transition:none}.tng-slider-container.dragging .tng-slider-thumb-knob{transform:scale(1.1);background:var(--tng-primary);border-color:var(--tng-text);box-shadow:0 0 20px color-mix(in srgb,var(--tng-primary),transparent 40%)}.tng-slider-container.dragging .tng-slider-thumb-knob:after{background:var(--tng-text);opacity:1}.tng-slider-container.dragging .tng-slider-track{cursor:grabbing}.tng-slider-container.vertical{height:100%;min-height:150px;flex-direction:column;align-items:center}.tng-slider-container.vertical .tng-slider-wrapper{width:24px;height:100%;flex-direction:column}.tng-slider-container.vertical .tng-slider-track{width:6px;height:100%}.tng-slider-container.vertical .tng-slider-fill{width:100%;bottom:0;top:auto;transition:height .2s cubic-bezier(.4,0,.2,1)}.tng-slider-container.vertical .tng-slider-thumb{top:auto;left:50%;transform:translate(-50%,50%);transition:bottom .2s cubic-bezier(.4,0,.2,1)}.tng-slider-container.vertical .tng-slider-thumb-label{top:50%;left:35px;transform:translateY(-50%) scale(0)}.tng-slider-container.vertical:hover .tng-slider-thumb-label,.tng-slider-container.vertical.dragging .tng-slider-thumb-label{transform:translateY(-50%) scale(1)}.tng-slider-container.vertical.dragging .tng-slider-fill,.tng-slider-container.vertical.dragging .tng-slider-thumb{transition:none}\n"] }]
|
|
2182
|
+
}], ctorParameters: () => [], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], track: [{ type: i0.ViewChild, args: ['track', { isSignal: true }] }], onStart: [{
|
|
2183
|
+
type: HostListener,
|
|
2184
|
+
args: ['mousedown', ['$event']]
|
|
2185
|
+
}, {
|
|
2186
|
+
type: HostListener,
|
|
2187
|
+
args: ['touchstart', ['$event']]
|
|
2188
|
+
}], onMove: [{
|
|
2189
|
+
type: HostListener,
|
|
2190
|
+
args: ['window:mousemove', ['$event']]
|
|
2191
|
+
}, {
|
|
2192
|
+
type: HostListener,
|
|
2193
|
+
args: ['window:touchmove', ['$event']]
|
|
2194
|
+
}], onEnd: [{
|
|
2195
|
+
type: HostListener,
|
|
2196
|
+
args: ['window:mouseup']
|
|
2197
|
+
}, {
|
|
2198
|
+
type: HostListener,
|
|
2199
|
+
args: ['window:touchend']
|
|
2200
|
+
}] } });
|
|
2201
|
+
|
|
2202
|
+
class TngLoaderComponent {
|
|
2203
|
+
type = input('spinner', ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
2204
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
2205
|
+
duration = input(null, ...(ngDevMode ? [{ debugName: "duration" }] : []));
|
|
2206
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
2207
|
+
progress = input(null, ...(ngDevMode ? [{ debugName: "progress" }] : []));
|
|
2208
|
+
fullscreen = input(false, ...(ngDevMode ? [{ debugName: "fullscreen" }] : []));
|
|
2209
|
+
inline = input(false, ...(ngDevMode ? [{ debugName: "inline" }] : []));
|
|
2210
|
+
hidden = input(false, ...(ngDevMode ? [{ debugName: "hidden" }] : []));
|
|
2211
|
+
color = input(null, ...(ngDevMode ? [{ debugName: "color" }] : []));
|
|
2212
|
+
hostClasses = computed(() => {
|
|
2213
|
+
const classes = [];
|
|
2214
|
+
if (this.fullscreen()) {
|
|
2215
|
+
classes.push('tng-loader--fullscreen');
|
|
2216
|
+
}
|
|
2217
|
+
if (this.inline()) {
|
|
2218
|
+
classes.push('tng-loader--inline');
|
|
2219
|
+
}
|
|
2220
|
+
if (this.hidden()) {
|
|
2221
|
+
classes.push('tng-loader--hidden');
|
|
2222
|
+
}
|
|
2223
|
+
if (this.color()) {
|
|
2224
|
+
classes.push(`tng-loader--${this.color()}`);
|
|
2225
|
+
}
|
|
2226
|
+
classes.push(`tng-loader--type-${this.type()}`);
|
|
2227
|
+
classes.push(`tng-loader--size-${this.size()}`);
|
|
2228
|
+
return classes.join(' ');
|
|
2229
|
+
}, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
|
|
2230
|
+
// Helper for dynamic styles like duration
|
|
2231
|
+
containerStyles = computed(() => {
|
|
2232
|
+
const styles = {};
|
|
2233
|
+
if (this.duration()) {
|
|
2234
|
+
styles['--tng-loader-duration'] = this.duration();
|
|
2235
|
+
}
|
|
2236
|
+
return styles;
|
|
2237
|
+
}, ...(ngDevMode ? [{ debugName: "containerStyles" }] : []));
|
|
2238
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2239
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: TngLoaderComponent, isStandalone: true, selector: "tng-loader", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, progress: { classPropertyName: "progress", publicName: "progress", isSignal: true, isRequired: false, transformFunction: null }, fullscreen: { classPropertyName: "fullscreen", publicName: "fullscreen", isSignal: true, isRequired: false, transformFunction: null }, inline: { classPropertyName: "inline", publicName: "inline", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "attr.role": "\"status\"", "attr.aria-label": "label() || \"Loading\"", "attr.aria-hidden": "hidden() ? \"true\" : \"false\"" }, classAttribute: "tng-loader" }, ngImport: i0, template: "@if (!hidden()) {\n <div class=\"tng-loader__container\" [style]=\"containerStyles()\">\n \n @switch (type()) {\n @case ('spinner') {\n <svg class=\"tng-loader__spinner\" viewBox=\"0 0 50 50\">\n <circle class=\"tng-loader__spinner-path\" cx=\"25\" cy=\"25\" r=\"20\" fill=\"none\" stroke-width=\"5\"></circle>\n </svg>\n }\n \n @case ('bar') {\n <div class=\"tng-loader__bar\">\n <div class=\"tng-loader__bar-track\"></div>\n <div class=\"tng-loader__bar-fill\" \n [style.width.%]=\"progress() || 0\"\n [class.tng-loader__bar-fill--indeterminate]=\"progress() === null\">\n </div>\n </div>\n }\n \n @case ('dots') {\n <div class=\"tng-loader__dots\">\n <div class=\"tng-loader__dot\"></div>\n <div class=\"tng-loader__dot\"></div>\n <div class=\"tng-loader__dot\"></div>\n </div>\n }\n \n @case ('pulse') {\n <div class=\"tng-loader__pulse\"></div>\n }\n }\n\n @if (label()) {\n <div class=\"tng-loader__label\">{{ label() }}</div>\n }\n </div>\n}\n", styles: [".tng-loader{display:block;box-sizing:border-box;--tng-loader-size: 48px;--tng-loader-color: var(--tng-primary, #6200ee);--tng-loader-duration: 1.5s}.tng-loader--inline{display:inline-block;vertical-align:middle}.tng-loader--hidden{display:none!important}.tng-loader--fullscreen{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9999;display:flex;align-items:center;justify-content:center}.tng-loader--fullscreen .tng-loader__container{background:var(--tng-surface, white);padding:32px;border-radius:16px;box-shadow:0 4px 20px #00000026;display:flex;flex-direction:column;align-items:center;gap:16px}.tng-loader__container{display:flex;align-items:center;justify-content:center;flex-direction:column;gap:8px;color:var(--tng-loader-color)}.tng-loader__label{font-size:.875rem;font-weight:500;font-family:inherit;color:currentColor;opacity:.8}.tng-loader--size-sm{--tng-loader-size: 24px}.tng-loader--size-md{--tng-loader-size: 48px}.tng-loader--size-lg{--tng-loader-size: 72px}.tng-loader--size-xl{--tng-loader-size: 96px}.tng-loader--primary{--tng-loader-color: var(--tng-primary)}.tng-loader--secondary{--tng-loader-color: var(--tng-secondary)}.tng-loader--accent{--tng-loader-color: var(--tng-accent, #00e5ff)}.tng-loader--warn{--tng-loader-color: var(--tng-error, #b00020)}.tng-loader--type-spinner .tng-loader__spinner{width:var(--tng-loader-size);height:var(--tng-loader-size);animation:tng-rotate var(--tng-loader-duration) linear infinite}.tng-loader--type-spinner .tng-loader__spinner-path{stroke:currentColor;stroke-linecap:round;animation:tng-dash var(--tng-loader-duration) ease-in-out infinite}.tng-loader__bar{width:100%;min-width:200px;height:4px;background-color:color-mix(in srgb,currentColor,transparent 80%);border-radius:4px;overflow:hidden;position:relative}.tng-loader__bar-track{position:absolute;top:0;left:0;width:100%;height:100%}.tng-loader__bar-fill{height:100%;background-color:currentColor;transition:width .3s ease}.tng-loader__bar-fill--indeterminate{width:30%;position:absolute;animation:tng-indeterminate-bar var(--tng-loader-duration) infinite linear}.tng-loader--size-sm .tng-loader__bar{height:2px;min-width:100px}.tng-loader--size-lg .tng-loader__bar{height:6px;min-width:300px}.tng-loader--size-xl .tng-loader__bar{height:8px;min-width:400px}.tng-loader__dots{display:flex;gap:calc(var(--tng-loader-size) / 6);height:var(--tng-loader-size);align-items:center}.tng-loader__dots .tng-loader__dot{width:calc(var(--tng-loader-size) / 4);height:calc(var(--tng-loader-size) / 4);background-color:currentColor;border-radius:50%;animation:tng-bounce var(--tng-loader-duration) infinite ease-in-out both}.tng-loader__dots .tng-loader__dot:nth-child(1){animation-delay:-.32s}.tng-loader__dots .tng-loader__dot:nth-child(2){animation-delay:-.16s}.tng-loader__pulse{width:var(--tng-loader-size);height:var(--tng-loader-size);background-color:currentColor;border-radius:50%;animation:tng-pulse var(--tng-loader-duration) infinite ease-in-out}@keyframes tng-rotate{to{transform:rotate(360deg)}}@keyframes tng-dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes tng-indeterminate-bar{0%{left:-30%}to{left:100%}}@keyframes tng-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}@keyframes tng-pulse{0%{transform:scale(0);opacity:1}to{transform:scale(1);opacity:0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
2240
|
+
}
|
|
2241
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngLoaderComponent, decorators: [{
|
|
2242
|
+
type: Component,
|
|
2243
|
+
args: [{ selector: 'tng-loader', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
2244
|
+
'class': 'tng-loader',
|
|
2245
|
+
'[class]': 'hostClasses()',
|
|
2246
|
+
'[attr.role]': '"status"',
|
|
2247
|
+
'[attr.aria-label]': 'label() || "Loading"',
|
|
2248
|
+
'[attr.aria-hidden]': 'hidden() ? "true" : "false"',
|
|
2249
|
+
}, template: "@if (!hidden()) {\n <div class=\"tng-loader__container\" [style]=\"containerStyles()\">\n \n @switch (type()) {\n @case ('spinner') {\n <svg class=\"tng-loader__spinner\" viewBox=\"0 0 50 50\">\n <circle class=\"tng-loader__spinner-path\" cx=\"25\" cy=\"25\" r=\"20\" fill=\"none\" stroke-width=\"5\"></circle>\n </svg>\n }\n \n @case ('bar') {\n <div class=\"tng-loader__bar\">\n <div class=\"tng-loader__bar-track\"></div>\n <div class=\"tng-loader__bar-fill\" \n [style.width.%]=\"progress() || 0\"\n [class.tng-loader__bar-fill--indeterminate]=\"progress() === null\">\n </div>\n </div>\n }\n \n @case ('dots') {\n <div class=\"tng-loader__dots\">\n <div class=\"tng-loader__dot\"></div>\n <div class=\"tng-loader__dot\"></div>\n <div class=\"tng-loader__dot\"></div>\n </div>\n }\n \n @case ('pulse') {\n <div class=\"tng-loader__pulse\"></div>\n }\n }\n\n @if (label()) {\n <div class=\"tng-loader__label\">{{ label() }}</div>\n }\n </div>\n}\n", styles: [".tng-loader{display:block;box-sizing:border-box;--tng-loader-size: 48px;--tng-loader-color: var(--tng-primary, #6200ee);--tng-loader-duration: 1.5s}.tng-loader--inline{display:inline-block;vertical-align:middle}.tng-loader--hidden{display:none!important}.tng-loader--fullscreen{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9999;display:flex;align-items:center;justify-content:center}.tng-loader--fullscreen .tng-loader__container{background:var(--tng-surface, white);padding:32px;border-radius:16px;box-shadow:0 4px 20px #00000026;display:flex;flex-direction:column;align-items:center;gap:16px}.tng-loader__container{display:flex;align-items:center;justify-content:center;flex-direction:column;gap:8px;color:var(--tng-loader-color)}.tng-loader__label{font-size:.875rem;font-weight:500;font-family:inherit;color:currentColor;opacity:.8}.tng-loader--size-sm{--tng-loader-size: 24px}.tng-loader--size-md{--tng-loader-size: 48px}.tng-loader--size-lg{--tng-loader-size: 72px}.tng-loader--size-xl{--tng-loader-size: 96px}.tng-loader--primary{--tng-loader-color: var(--tng-primary)}.tng-loader--secondary{--tng-loader-color: var(--tng-secondary)}.tng-loader--accent{--tng-loader-color: var(--tng-accent, #00e5ff)}.tng-loader--warn{--tng-loader-color: var(--tng-error, #b00020)}.tng-loader--type-spinner .tng-loader__spinner{width:var(--tng-loader-size);height:var(--tng-loader-size);animation:tng-rotate var(--tng-loader-duration) linear infinite}.tng-loader--type-spinner .tng-loader__spinner-path{stroke:currentColor;stroke-linecap:round;animation:tng-dash var(--tng-loader-duration) ease-in-out infinite}.tng-loader__bar{width:100%;min-width:200px;height:4px;background-color:color-mix(in srgb,currentColor,transparent 80%);border-radius:4px;overflow:hidden;position:relative}.tng-loader__bar-track{position:absolute;top:0;left:0;width:100%;height:100%}.tng-loader__bar-fill{height:100%;background-color:currentColor;transition:width .3s ease}.tng-loader__bar-fill--indeterminate{width:30%;position:absolute;animation:tng-indeterminate-bar var(--tng-loader-duration) infinite linear}.tng-loader--size-sm .tng-loader__bar{height:2px;min-width:100px}.tng-loader--size-lg .tng-loader__bar{height:6px;min-width:300px}.tng-loader--size-xl .tng-loader__bar{height:8px;min-width:400px}.tng-loader__dots{display:flex;gap:calc(var(--tng-loader-size) / 6);height:var(--tng-loader-size);align-items:center}.tng-loader__dots .tng-loader__dot{width:calc(var(--tng-loader-size) / 4);height:calc(var(--tng-loader-size) / 4);background-color:currentColor;border-radius:50%;animation:tng-bounce var(--tng-loader-duration) infinite ease-in-out both}.tng-loader__dots .tng-loader__dot:nth-child(1){animation-delay:-.32s}.tng-loader__dots .tng-loader__dot:nth-child(2){animation-delay:-.16s}.tng-loader__pulse{width:var(--tng-loader-size);height:var(--tng-loader-size);background-color:currentColor;border-radius:50%;animation:tng-pulse var(--tng-loader-duration) infinite ease-in-out}@keyframes tng-rotate{to{transform:rotate(360deg)}}@keyframes tng-dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes tng-indeterminate-bar{0%{left:-30%}to{left:100%}}@keyframes tng-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}@keyframes tng-pulse{0%{transform:scale(0);opacity:1}to{transform:scale(1);opacity:0}}\n"] }]
|
|
2250
|
+
}], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], duration: [{ type: i0.Input, args: [{ isSignal: true, alias: "duration", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], progress: [{ type: i0.Input, args: [{ isSignal: true, alias: "progress", required: false }] }], fullscreen: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullscreen", required: false }] }], inline: [{ type: i0.Input, args: [{ isSignal: true, alias: "inline", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }] } });
|
|
2251
|
+
|
|
2252
|
+
class TngNotificationService {
|
|
2253
|
+
notifications = signal([], ...(ngDevMode ? [{ debugName: "notifications" }] : []));
|
|
2254
|
+
timers = new Map();
|
|
2255
|
+
remainingTimes = new Map();
|
|
2256
|
+
startTimes = new Map();
|
|
2257
|
+
activeNotifications = this.notifications.asReadonly();
|
|
2258
|
+
show(message, options = {}) {
|
|
2259
|
+
const id = options.id || this.generateId();
|
|
2260
|
+
const duration = options.duration ?? 3000;
|
|
2261
|
+
const config = {
|
|
2262
|
+
id,
|
|
2263
|
+
message,
|
|
2264
|
+
type: options.type || 'default',
|
|
2265
|
+
position: options.position || 'top-right',
|
|
2266
|
+
duration,
|
|
2267
|
+
clipboard: options.clipboard,
|
|
2268
|
+
closable: options.closable ?? true,
|
|
2269
|
+
icon: options.icon,
|
|
2270
|
+
pauseOnHover: options.pauseOnHover ?? true,
|
|
2271
|
+
};
|
|
2272
|
+
this.notifications.update(current => [...current, config]);
|
|
2273
|
+
if (duration > 0) {
|
|
2274
|
+
this.startTimer(id, duration);
|
|
2275
|
+
}
|
|
2276
|
+
return id;
|
|
2277
|
+
}
|
|
2278
|
+
success(message, options) {
|
|
2279
|
+
return this.show(message, { ...options, type: 'success' });
|
|
2280
|
+
}
|
|
2281
|
+
error(message, options) {
|
|
2282
|
+
return this.show(message, { ...options, type: 'error' });
|
|
2283
|
+
}
|
|
2284
|
+
warning(message, options) {
|
|
2285
|
+
return this.show(message, { ...options, type: 'warning' });
|
|
2286
|
+
}
|
|
2287
|
+
info(message, options) {
|
|
2288
|
+
return this.show(message, { ...options, type: 'info' });
|
|
2289
|
+
}
|
|
2290
|
+
remove(id) {
|
|
2291
|
+
this.clearTimer(id);
|
|
2292
|
+
this.notifications.update(current => current.filter(n => n.id !== id));
|
|
2293
|
+
}
|
|
2294
|
+
clear() {
|
|
2295
|
+
this.timers.forEach((timer) => clearTimeout(timer));
|
|
2296
|
+
this.timers.clear();
|
|
2297
|
+
this.remainingTimes.clear();
|
|
2298
|
+
this.startTimes.clear();
|
|
2299
|
+
this.notifications.set([]);
|
|
2300
|
+
}
|
|
2301
|
+
pauseTimer(id) {
|
|
2302
|
+
const notification = this.notifications().find(n => n.id === id);
|
|
2303
|
+
if (!notification?.pauseOnHover || !this.timers.has(id))
|
|
2304
|
+
return;
|
|
2305
|
+
clearTimeout(this.timers.get(id));
|
|
2306
|
+
this.timers.delete(id);
|
|
2307
|
+
const elapsed = Date.now() - (this.startTimes.get(id) || 0);
|
|
2308
|
+
const duration = notification.duration || 3000;
|
|
2309
|
+
const remaining = this.remainingTimes.has(id)
|
|
2310
|
+
? this.remainingTimes.get(id) - elapsed
|
|
2311
|
+
: duration - elapsed;
|
|
2312
|
+
this.remainingTimes.set(id, remaining > 0 ? remaining : 0);
|
|
2313
|
+
}
|
|
2314
|
+
resumeTimer(id) {
|
|
2315
|
+
const notification = this.notifications().find(n => n.id === id);
|
|
2316
|
+
if (!notification?.pauseOnHover || !this.remainingTimes.has(id))
|
|
2317
|
+
return;
|
|
2318
|
+
const remaining = this.remainingTimes.get(id) || 0;
|
|
2319
|
+
if (remaining > 0) {
|
|
2320
|
+
this.startTimer(id, remaining);
|
|
2321
|
+
}
|
|
2322
|
+
else {
|
|
2323
|
+
this.remove(id);
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
startTimer(id, duration) {
|
|
2327
|
+
this.startTimes.set(id, Date.now());
|
|
2328
|
+
const timerId = setTimeout(() => {
|
|
2329
|
+
this.remove(id);
|
|
2330
|
+
}, duration);
|
|
2331
|
+
this.timers.set(id, timerId);
|
|
2332
|
+
}
|
|
2333
|
+
clearTimer(id) {
|
|
2334
|
+
if (this.timers.has(id)) {
|
|
2335
|
+
clearTimeout(this.timers.get(id));
|
|
2336
|
+
this.timers.delete(id);
|
|
2337
|
+
}
|
|
2338
|
+
this.remainingTimes.delete(id);
|
|
2339
|
+
this.startTimes.delete(id);
|
|
2340
|
+
}
|
|
2341
|
+
generateId() {
|
|
2342
|
+
return Math.random().toString(36).substring(2, 9);
|
|
2343
|
+
}
|
|
2344
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngNotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2345
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngNotificationService, providedIn: 'root' });
|
|
2346
|
+
}
|
|
2347
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngNotificationService, decorators: [{
|
|
2348
|
+
type: Injectable,
|
|
2349
|
+
args: [{
|
|
2350
|
+
providedIn: 'root'
|
|
2351
|
+
}]
|
|
2352
|
+
}] });
|
|
2353
|
+
|
|
2354
|
+
class TngToastComponent {
|
|
2355
|
+
config = input.required(...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
2356
|
+
service = inject(TngNotificationService);
|
|
2357
|
+
onMouseEnter() {
|
|
2358
|
+
this.service.pauseTimer(this.config().id);
|
|
2359
|
+
}
|
|
2360
|
+
onMouseLeave() {
|
|
2361
|
+
this.service.resumeTimer(this.config().id);
|
|
2362
|
+
}
|
|
2363
|
+
close() {
|
|
2364
|
+
this.service.remove(this.config().id);
|
|
2365
|
+
}
|
|
2366
|
+
// Copied tooltip state
|
|
2367
|
+
showCopiedTooltip = signal(false, ...(ngDevMode ? [{ debugName: "showCopiedTooltip" }] : []));
|
|
2368
|
+
copyToClipboard() {
|
|
2369
|
+
const text = this.config().clipboard;
|
|
2370
|
+
if (text) {
|
|
2371
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
2372
|
+
// Show tooltip
|
|
2373
|
+
this.showCopiedTooltip.set(true);
|
|
2374
|
+
console.log('Copied to clipboard');
|
|
2375
|
+
// Hide after 4 seconds
|
|
2376
|
+
setTimeout(() => {
|
|
2377
|
+
this.showCopiedTooltip.set(false);
|
|
2378
|
+
}, 4000);
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
get iconClass() {
|
|
2383
|
+
const type = this.config().type;
|
|
2384
|
+
const customIcon = this.config().icon;
|
|
2385
|
+
if (customIcon)
|
|
2386
|
+
return customIcon;
|
|
2387
|
+
switch (type) {
|
|
2388
|
+
case 'success': return 'fa fa-check-circle';
|
|
2389
|
+
case 'error': return 'fa fa-exclamation-circle';
|
|
2390
|
+
case 'warning': return 'fa fa-exclamation-triangle';
|
|
2391
|
+
case 'info': return 'fa fa-info-circle';
|
|
2392
|
+
default: return 'fa fa-bell';
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2396
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: TngToastComponent, isStandalone: true, selector: "tng-toast", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div \n class=\"tng-toast\" \n [class]=\"'tng-toast--' + config().type\"\n (mouseenter)=\"onMouseEnter()\"\n (mouseleave)=\"onMouseLeave()\">\n \n <div class=\"tng-toast__icon\">\n <i [class]=\"iconClass\"></i>\n </div>\n\n <div class=\"tng-toast__content\">\n <div class=\"tng-toast__message\">{{ config().message }}</div>\n </div>\n\n <div class=\"tng-toast__actions\">\n @if (config().clipboard) {\n <div class=\"tng-toast__action-wrapper\">\n <button class=\"tng-toast__action-btn\" (click)=\"copyToClipboard()\" aria-label=\"Copy to clipboard\">\n <i class=\"fa fa-copy\"></i>\n </button>\n @if (showCopiedTooltip()) {\n <div class=\"tng-toast__tooltip\">\u00A1Texto copiado al portapapeles!</div>\n }\n </div>\n }\n \n @if (config().closable) {\n <button class=\"tng-toast__close-btn\" (click)=\"close()\" aria-label=\"Close notification\">\n <i class=\"fa fa-times\"></i>\n </button>\n }\n </div>\n\n @if (config().duration! > 0) {\n <div class=\"tng-toast__progress\" [style.animation-duration]=\"config().duration + 'ms'\"></div>\n }\n</div>\n", styles: [".tng-toast{position:relative;display:flex;align-items:center;padding:12px 16px;border-radius:8px;background:var(--tng-surface, white);box-shadow:var(--tng-shadow-md, 0 4px 6px -1px rgba(0, 0, 0, .1));min-width:300px;max-width:400px;gap:12px;pointer-events:auto;border-left:4px solid transparent;color:var(--tng-text, #333);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);font-family:inherit;font-size:.875rem;line-height:1.4;margin-bottom:8px;animation:tng-toast-fade-in .3s ease-out forwards}.tng-toast__icon{flex-shrink:0;font-size:1.25rem;display:flex;align-items:center}.tng-toast__content{flex:1;word-break:break-word}.tng-toast__actions{display:flex;gap:8px;margin-left:8px}.tng-toast__action-btn,.tng-toast__close-btn{background:transparent;border:none;cursor:pointer;padding:4px;color:inherit;opacity:.6;transition:opacity .2s;border-radius:4px}.tng-toast__action-btn:hover,.tng-toast__close-btn:hover{opacity:1;background:#0000000d}.tng-toast--success{border-left-color:var(--tng-success, #2e7d32)}.tng-toast--success .tng-toast__icon{color:var(--tng-success, #2e7d32)}.tng-toast--error{border-left-color:var(--tng-error, #d32f2f)}.tng-toast--error .tng-toast__icon{color:var(--tng-error, #d32f2f)}.tng-toast--warning{border-left-color:var(--tng-warning, #ed6c02)}.tng-toast--warning .tng-toast__icon{color:var(--tng-warning, #ed6c02)}.tng-toast--info{border-left-color:var(--tng-info, #0288d1)}.tng-toast--info .tng-toast__icon{color:var(--tng-info, #0288d1)}.tng-toast--default{border-left-color:var(--tng-separator, #e0e0e0)}.tng-toast--default .tng-toast__icon{color:var(--tng-text-secondary, #757575)}@keyframes tng-toast-fade-in{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.tng-toast__action-wrapper{position:relative;display:inline-block}.tng-toast__tooltip{position:absolute;bottom:100%;right:50%;transform:translate(50%);background-color:#333;color:#fff;padding:4px 8px;border-radius:4px;font-size:.75rem;white-space:nowrap;opacity:0;animation:tng-tooltip-fade .3s ease forwards;pointer-events:none;margin-bottom:8px;z-index:10}.tng-toast__tooltip:after{content:\"\";position:absolute;top:100%;left:50%;margin-left:-4px;border-width:4px;border-style:solid;border-color:#333 transparent transparent transparent}.tng-toast__progress{position:absolute;bottom:0;left:0;height:4px;background-color:var(--tng-toast-color, #ccc);width:100%;transform-origin:left;animation:tng-toast-progress linear forwards;border-bottom-left-radius:8px;border-bottom-right-radius:8px}.tng-toast--success{--tng-toast-color: var(--tng-success, #2e7d32)}.tng-toast--error{--tng-toast-color: var(--tng-error, #d32f2f)}.tng-toast--warning{--tng-toast-color: var(--tng-warning, #ed6c02)}.tng-toast--info{--tng-toast-color: var(--tng-info, #0288d1)}.tng-toast--default{--tng-toast-color: var(--tng-text-secondary, #757575)}.tng-toast:hover .tng-toast__progress{animation-play-state:paused}@keyframes tng-toast-progress{0%{width:100%}to{width:0%}}@keyframes tng-tooltip-fade{0%{opacity:0;transform:translate(50%) translateY(4px)}to{opacity:1;transform:translate(50%) translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
2397
|
+
}
|
|
2398
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngToastComponent, decorators: [{
|
|
2399
|
+
type: Component,
|
|
2400
|
+
args: [{ selector: 'tng-toast', standalone: true, imports: [CommonModule], template: "<div \n class=\"tng-toast\" \n [class]=\"'tng-toast--' + config().type\"\n (mouseenter)=\"onMouseEnter()\"\n (mouseleave)=\"onMouseLeave()\">\n \n <div class=\"tng-toast__icon\">\n <i [class]=\"iconClass\"></i>\n </div>\n\n <div class=\"tng-toast__content\">\n <div class=\"tng-toast__message\">{{ config().message }}</div>\n </div>\n\n <div class=\"tng-toast__actions\">\n @if (config().clipboard) {\n <div class=\"tng-toast__action-wrapper\">\n <button class=\"tng-toast__action-btn\" (click)=\"copyToClipboard()\" aria-label=\"Copy to clipboard\">\n <i class=\"fa fa-copy\"></i>\n </button>\n @if (showCopiedTooltip()) {\n <div class=\"tng-toast__tooltip\">\u00A1Texto copiado al portapapeles!</div>\n }\n </div>\n }\n \n @if (config().closable) {\n <button class=\"tng-toast__close-btn\" (click)=\"close()\" aria-label=\"Close notification\">\n <i class=\"fa fa-times\"></i>\n </button>\n }\n </div>\n\n @if (config().duration! > 0) {\n <div class=\"tng-toast__progress\" [style.animation-duration]=\"config().duration + 'ms'\"></div>\n }\n</div>\n", styles: [".tng-toast{position:relative;display:flex;align-items:center;padding:12px 16px;border-radius:8px;background:var(--tng-surface, white);box-shadow:var(--tng-shadow-md, 0 4px 6px -1px rgba(0, 0, 0, .1));min-width:300px;max-width:400px;gap:12px;pointer-events:auto;border-left:4px solid transparent;color:var(--tng-text, #333);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);font-family:inherit;font-size:.875rem;line-height:1.4;margin-bottom:8px;animation:tng-toast-fade-in .3s ease-out forwards}.tng-toast__icon{flex-shrink:0;font-size:1.25rem;display:flex;align-items:center}.tng-toast__content{flex:1;word-break:break-word}.tng-toast__actions{display:flex;gap:8px;margin-left:8px}.tng-toast__action-btn,.tng-toast__close-btn{background:transparent;border:none;cursor:pointer;padding:4px;color:inherit;opacity:.6;transition:opacity .2s;border-radius:4px}.tng-toast__action-btn:hover,.tng-toast__close-btn:hover{opacity:1;background:#0000000d}.tng-toast--success{border-left-color:var(--tng-success, #2e7d32)}.tng-toast--success .tng-toast__icon{color:var(--tng-success, #2e7d32)}.tng-toast--error{border-left-color:var(--tng-error, #d32f2f)}.tng-toast--error .tng-toast__icon{color:var(--tng-error, #d32f2f)}.tng-toast--warning{border-left-color:var(--tng-warning, #ed6c02)}.tng-toast--warning .tng-toast__icon{color:var(--tng-warning, #ed6c02)}.tng-toast--info{border-left-color:var(--tng-info, #0288d1)}.tng-toast--info .tng-toast__icon{color:var(--tng-info, #0288d1)}.tng-toast--default{border-left-color:var(--tng-separator, #e0e0e0)}.tng-toast--default .tng-toast__icon{color:var(--tng-text-secondary, #757575)}@keyframes tng-toast-fade-in{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.tng-toast__action-wrapper{position:relative;display:inline-block}.tng-toast__tooltip{position:absolute;bottom:100%;right:50%;transform:translate(50%);background-color:#333;color:#fff;padding:4px 8px;border-radius:4px;font-size:.75rem;white-space:nowrap;opacity:0;animation:tng-tooltip-fade .3s ease forwards;pointer-events:none;margin-bottom:8px;z-index:10}.tng-toast__tooltip:after{content:\"\";position:absolute;top:100%;left:50%;margin-left:-4px;border-width:4px;border-style:solid;border-color:#333 transparent transparent transparent}.tng-toast__progress{position:absolute;bottom:0;left:0;height:4px;background-color:var(--tng-toast-color, #ccc);width:100%;transform-origin:left;animation:tng-toast-progress linear forwards;border-bottom-left-radius:8px;border-bottom-right-radius:8px}.tng-toast--success{--tng-toast-color: var(--tng-success, #2e7d32)}.tng-toast--error{--tng-toast-color: var(--tng-error, #d32f2f)}.tng-toast--warning{--tng-toast-color: var(--tng-warning, #ed6c02)}.tng-toast--info{--tng-toast-color: var(--tng-info, #0288d1)}.tng-toast--default{--tng-toast-color: var(--tng-text-secondary, #757575)}.tng-toast:hover .tng-toast__progress{animation-play-state:paused}@keyframes tng-toast-progress{0%{width:100%}to{width:0%}}@keyframes tng-tooltip-fade{0%{opacity:0;transform:translate(50%) translateY(4px)}to{opacity:1;transform:translate(50%) translateY(0)}}\n"] }]
|
|
2401
|
+
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }] } });
|
|
2402
|
+
|
|
2403
|
+
class TngNotificationContainerComponent {
|
|
2404
|
+
service = inject(TngNotificationService);
|
|
2405
|
+
notifications = this.service.activeNotifications;
|
|
2406
|
+
topLeft = computed(() => this.notifications().filter(n => n.position === 'top-left'), ...(ngDevMode ? [{ debugName: "topLeft" }] : []));
|
|
2407
|
+
topRight = computed(() => this.notifications().filter(n => n.position === 'top-right' || !n.position), ...(ngDevMode ? [{ debugName: "topRight" }] : []));
|
|
2408
|
+
topCenter = computed(() => this.notifications().filter(n => n.position === 'top-center'), ...(ngDevMode ? [{ debugName: "topCenter" }] : []));
|
|
2409
|
+
bottomLeft = computed(() => this.notifications().filter(n => n.position === 'bottom-left'), ...(ngDevMode ? [{ debugName: "bottomLeft" }] : []));
|
|
2410
|
+
bottomRight = computed(() => this.notifications().filter(n => n.position === 'bottom-right'), ...(ngDevMode ? [{ debugName: "bottomRight" }] : []));
|
|
2411
|
+
bottomCenter = computed(() => this.notifications().filter(n => n.position === 'bottom-center'), ...(ngDevMode ? [{ debugName: "bottomCenter" }] : []));
|
|
2412
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngNotificationContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2413
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: TngNotificationContainerComponent, isStandalone: true, selector: "tng-notification-container", ngImport: i0, template: "<div class=\"tng-notification-container tng-notification-container--top-left\">\n @for (notification of topLeft(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--top-right\">\n @for (notification of topRight(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--top-center\">\n @for (notification of topCenter(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--bottom-left\">\n @for (notification of bottomLeft(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--bottom-right\">\n @for (notification of bottomRight(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--bottom-center\">\n @for (notification of bottomCenter(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n", styles: [".tng-notification-container{position:fixed;z-index:9999;display:flex;flex-direction:column;pointer-events:none;padding:16px;gap:12px;max-width:100vw;box-sizing:border-box}.tng-notification-container--top-left{top:0;left:0;align-items:flex-start}.tng-notification-container--top-right{top:0;right:0;align-items:flex-end}.tng-notification-container--top-center{top:0;left:50%;transform:translate(-50%);align-items:center}.tng-notification-container--bottom-left{bottom:0;left:0;flex-direction:column-reverse;align-items:flex-start}.tng-notification-container--bottom-right{bottom:0;right:0;flex-direction:column-reverse;align-items:flex-end}.tng-notification-container--bottom-center{bottom:0;left:50%;transform:translate(-50%);flex-direction:column-reverse;align-items:center}@media(max-width:600px){.tng-notification-container{width:100%;padding:12px}.tng-notification-container--top-left,.tng-notification-container--top-right,.tng-notification-container--top-center,.tng-notification-container--bottom-left,.tng-notification-container--bottom-right,.tng-notification-container--bottom-center{left:0;right:0;transform:none;align-items:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: TngToastComponent, selector: "tng-toast", inputs: ["config"] }] });
|
|
2414
|
+
}
|
|
2415
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngNotificationContainerComponent, decorators: [{
|
|
2416
|
+
type: Component,
|
|
2417
|
+
args: [{ selector: 'tng-notification-container', standalone: true, imports: [CommonModule, TngToastComponent], template: "<div class=\"tng-notification-container tng-notification-container--top-left\">\n @for (notification of topLeft(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--top-right\">\n @for (notification of topRight(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--top-center\">\n @for (notification of topCenter(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--bottom-left\">\n @for (notification of bottomLeft(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--bottom-right\">\n @for (notification of bottomRight(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n\n<div class=\"tng-notification-container tng-notification-container--bottom-center\">\n @for (notification of bottomCenter(); track notification.id) {\n <tng-toast [config]=\"notification\"></tng-toast>\n }\n</div>\n", styles: [".tng-notification-container{position:fixed;z-index:9999;display:flex;flex-direction:column;pointer-events:none;padding:16px;gap:12px;max-width:100vw;box-sizing:border-box}.tng-notification-container--top-left{top:0;left:0;align-items:flex-start}.tng-notification-container--top-right{top:0;right:0;align-items:flex-end}.tng-notification-container--top-center{top:0;left:50%;transform:translate(-50%);align-items:center}.tng-notification-container--bottom-left{bottom:0;left:0;flex-direction:column-reverse;align-items:flex-start}.tng-notification-container--bottom-right{bottom:0;right:0;flex-direction:column-reverse;align-items:flex-end}.tng-notification-container--bottom-center{bottom:0;left:50%;transform:translate(-50%);flex-direction:column-reverse;align-items:center}@media(max-width:600px){.tng-notification-container{width:100%;padding:12px}.tng-notification-container--top-left,.tng-notification-container--top-right,.tng-notification-container--top-center,.tng-notification-container--bottom-left,.tng-notification-container--bottom-right,.tng-notification-container--bottom-center{left:0;right:0;transform:none;align-items:center}}\n"] }]
|
|
2418
|
+
}] });
|
|
2419
|
+
|
|
2038
2420
|
/*
|
|
2039
2421
|
* Public API Surface of tecnualng
|
|
2040
2422
|
*/
|
|
@@ -2043,5 +2425,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
|
|
|
2043
2425
|
* Generated bundle index. Do not edit.
|
|
2044
2426
|
*/
|
|
2045
2427
|
|
|
2046
|
-
export { TecnualDatepickerComponent, TecnualInputComponent, TecnualTableComponent, ThemeService, TngButton, TngCardComponent, TngExpansionPanelComponent, TngFormFieldComponent, TngInputDirective, TngMenuComponent, TngMenuGroupComponent, TngMenuItemComponent, TngSelectComponent, TngSelectDirective, TngSelectPanelComponent, TngSidebarComponent, TngTabComponent, TngTabsComponent, TngTextareaComponent, TngTextareaDirective, TngToolbarComponent, TngTooltipComponent, TngTooltipDirective };
|
|
2428
|
+
export { TecnualDatepickerComponent, TecnualInputComponent, TecnualTableComponent, ThemeService, TngButton, TngCardComponent, TngExpansionPanelComponent, TngFormFieldComponent, TngInputDirective, TngLoaderComponent, TngMenuComponent, TngMenuGroupComponent, TngMenuItemComponent, TngNotificationContainerComponent, TngNotificationService, TngSelectComponent, TngSelectDirective, TngSelectPanelComponent, TngSidebarComponent, TngSliderComponent, TngTabComponent, TngTabsComponent, TngTextareaComponent, TngTextareaDirective, TngToastComponent, TngToolbarComponent, TngTooltipComponent, TngTooltipDirective };
|
|
2047
2429
|
//# sourceMappingURL=tecnualng.mjs.map
|