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.
@@ -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