@neural-ui/core 1.5.14 → 1.6.1
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/neural-ui-core-accordion.mjs +13 -9
- package/fesm2022/neural-ui-core-accordion.mjs.map +1 -1
- package/fesm2022/neural-ui-core-alert.mjs +25 -14
- package/fesm2022/neural-ui-core-alert.mjs.map +1 -1
- package/fesm2022/neural-ui-core-autocomplete.mjs +53 -28
- package/fesm2022/neural-ui-core-autocomplete.mjs.map +1 -1
- package/fesm2022/neural-ui-core-avatar.mjs +23 -13
- package/fesm2022/neural-ui-core-avatar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-badge.mjs +15 -9
- package/fesm2022/neural-ui-core-badge.mjs.map +1 -1
- package/fesm2022/neural-ui-core-block-ui.mjs +16 -11
- package/fesm2022/neural-ui-core-block-ui.mjs.map +1 -1
- package/fesm2022/neural-ui-core-breadcrumb.mjs +8 -6
- package/fesm2022/neural-ui-core-breadcrumb.mjs.map +1 -1
- package/fesm2022/neural-ui-core-button.mjs +29 -16
- package/fesm2022/neural-ui-core-button.mjs.map +1 -1
- package/fesm2022/neural-ui-core-calendar.mjs +75 -50
- package/fesm2022/neural-ui-core-calendar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-card.mjs +13 -8
- package/fesm2022/neural-ui-core-card.mjs.map +1 -1
- package/fesm2022/neural-ui-core-chart.mjs +45 -24
- package/fesm2022/neural-ui-core-chart.mjs.map +1 -1
- package/fesm2022/neural-ui-core-checkbox.mjs +15 -9
- package/fesm2022/neural-ui-core-checkbox.mjs.map +1 -1
- package/fesm2022/neural-ui-core-chip.mjs +23 -13
- package/fesm2022/neural-ui-core-chip.mjs.map +1 -1
- package/fesm2022/neural-ui-core-code-block.mjs +32 -17
- package/fesm2022/neural-ui-core-code-block.mjs.map +1 -1
- package/fesm2022/neural-ui-core-color-picker.mjs +19 -11
- package/fesm2022/neural-ui-core-color-picker.mjs.map +1 -1
- package/fesm2022/neural-ui-core-command-palette.mjs +16 -11
- package/fesm2022/neural-ui-core-command-palette.mjs.map +1 -1
- package/fesm2022/neural-ui-core-confirm-dialog.mjs +6 -6
- package/fesm2022/neural-ui-core-context-menu.mjs +12 -9
- package/fesm2022/neural-ui-core-context-menu.mjs.map +1 -1
- package/fesm2022/neural-ui-core-dashboard-grid.mjs +11 -7
- package/fesm2022/neural-ui-core-dashboard-grid.mjs.map +1 -1
- package/fesm2022/neural-ui-core-date-input.mjs +111 -57
- package/fesm2022/neural-ui-core-date-input.mjs.map +1 -1
- package/fesm2022/neural-ui-core-divider.mjs +7 -5
- package/fesm2022/neural-ui-core-divider.mjs.map +1 -1
- package/fesm2022/neural-ui-core-empty-state.mjs +13 -8
- package/fesm2022/neural-ui-core-empty-state.mjs.map +1 -1
- package/fesm2022/neural-ui-core-filter-bar.mjs +19 -11
- package/fesm2022/neural-ui-core-filter-bar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-icon.mjs +11 -7
- package/fesm2022/neural-ui-core-icon.mjs.map +1 -1
- package/fesm2022/neural-ui-core-image-gallery.mjs +23 -13
- package/fesm2022/neural-ui-core-image-gallery.mjs.map +1 -1
- package/fesm2022/neural-ui-core-image-viewer.mjs +22 -14
- package/fesm2022/neural-ui-core-image-viewer.mjs.map +1 -1
- package/fesm2022/neural-ui-core-input-otp.mjs +19 -11
- package/fesm2022/neural-ui-core-input-otp.mjs.map +1 -1
- package/fesm2022/neural-ui-core-input.mjs +67 -35
- package/fesm2022/neural-ui-core-input.mjs.map +1 -1
- package/fesm2022/neural-ui-core-kanban.mjs +17 -11
- package/fesm2022/neural-ui-core-kanban.mjs.map +1 -1
- package/fesm2022/neural-ui-core-knob.mjs +41 -22
- package/fesm2022/neural-ui-core-knob.mjs.map +1 -1
- package/fesm2022/neural-ui-core-meter-group.mjs +23 -13
- package/fesm2022/neural-ui-core-meter-group.mjs.map +1 -1
- package/fesm2022/neural-ui-core-modal.mjs +16 -11
- package/fesm2022/neural-ui-core-modal.mjs.map +1 -1
- package/fesm2022/neural-ui-core-multiselect.mjs +72 -39
- package/fesm2022/neural-ui-core-multiselect.mjs.map +1 -1
- package/fesm2022/neural-ui-core-nav.mjs +22 -13
- package/fesm2022/neural-ui-core-nav.mjs.map +1 -1
- package/fesm2022/neural-ui-core-notification-center.mjs +27 -10
- package/fesm2022/neural-ui-core-notification-center.mjs.map +1 -1
- package/fesm2022/neural-ui-core-number-input.mjs +35 -19
- package/fesm2022/neural-ui-core-number-input.mjs.map +1 -1
- package/fesm2022/neural-ui-core-pagination.mjs +15 -9
- package/fesm2022/neural-ui-core-pagination.mjs.map +1 -1
- package/fesm2022/neural-ui-core-popover.mjs +22 -14
- package/fesm2022/neural-ui-core-popover.mjs.map +1 -1
- package/fesm2022/neural-ui-core-progress-bar.mjs +19 -11
- package/fesm2022/neural-ui-core-progress-bar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-radio.mjs +24 -15
- package/fesm2022/neural-ui-core-radio.mjs.map +1 -1
- package/fesm2022/neural-ui-core-rating.mjs +13 -8
- package/fesm2022/neural-ui-core-rating.mjs.map +1 -1
- package/fesm2022/neural-ui-core-rich-text-editor.mjs +773 -0
- package/fesm2022/neural-ui-core-rich-text-editor.mjs.map +1 -0
- package/fesm2022/neural-ui-core-scheduler-gantt.mjs +41 -22
- package/fesm2022/neural-ui-core-scheduler-gantt.mjs.map +1 -1
- package/fesm2022/neural-ui-core-select.mjs +77 -43
- package/fesm2022/neural-ui-core-select.mjs.map +1 -1
- package/fesm2022/neural-ui-core-sidebar.mjs +23 -14
- package/fesm2022/neural-ui-core-sidebar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-skeleton.mjs +11 -7
- package/fesm2022/neural-ui-core-skeleton.mjs.map +1 -1
- package/fesm2022/neural-ui-core-slider.mjs +23 -13
- package/fesm2022/neural-ui-core-slider.mjs.map +1 -1
- package/fesm2022/neural-ui-core-spinner.mjs +17 -10
- package/fesm2022/neural-ui-core-spinner.mjs.map +1 -1
- package/fesm2022/neural-ui-core-split-button.mjs +27 -15
- package/fesm2022/neural-ui-core-split-button.mjs.map +1 -1
- package/fesm2022/neural-ui-core-splitter.mjs +9 -6
- package/fesm2022/neural-ui-core-splitter.mjs.map +1 -1
- package/fesm2022/neural-ui-core-stats-card.mjs +19 -11
- package/fesm2022/neural-ui-core-stats-card.mjs.map +1 -1
- package/fesm2022/neural-ui-core-stepper.mjs +13 -8
- package/fesm2022/neural-ui-core-stepper.mjs.map +1 -1
- package/fesm2022/neural-ui-core-switch.mjs +15 -9
- package/fesm2022/neural-ui-core-switch.mjs.map +1 -1
- package/fesm2022/neural-ui-core-table.mjs +242 -124
- package/fesm2022/neural-ui-core-table.mjs.map +1 -1
- package/fesm2022/neural-ui-core-tabs.mjs +30 -18
- package/fesm2022/neural-ui-core-tabs.mjs.map +1 -1
- package/fesm2022/neural-ui-core-textarea.mjs +43 -23
- package/fesm2022/neural-ui-core-textarea.mjs.map +1 -1
- package/fesm2022/neural-ui-core-timeline-grid.mjs +21 -12
- package/fesm2022/neural-ui-core-timeline-grid.mjs.map +1 -1
- package/fesm2022/neural-ui-core-timeline.mjs +5 -4
- package/fesm2022/neural-ui-core-timeline.mjs.map +1 -1
- package/fesm2022/neural-ui-core-toast.mjs +25 -9
- package/fesm2022/neural-ui-core-toast.mjs.map +1 -1
- package/fesm2022/neural-ui-core-toggle-button-group.mjs +17 -10
- package/fesm2022/neural-ui-core-toggle-button-group.mjs.map +1 -1
- package/fesm2022/neural-ui-core-toolbar.mjs +13 -8
- package/fesm2022/neural-ui-core-toolbar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-tooltip.mjs +16 -11
- package/fesm2022/neural-ui-core-tooltip.mjs.map +1 -1
- package/fesm2022/neural-ui-core-tree-table.mjs +57 -30
- package/fesm2022/neural-ui-core-tree-table.mjs.map +1 -1
- package/fesm2022/neural-ui-core-tree.mjs +31 -17
- package/fesm2022/neural-ui-core-tree.mjs.map +1 -1
- package/fesm2022/neural-ui-core-uploader.mjs +91 -47
- package/fesm2022/neural-ui-core-uploader.mjs.map +1 -1
- package/fesm2022/neural-ui-core-url-state.mjs +7 -5
- package/fesm2022/neural-ui-core-url-state.mjs.map +1 -1
- package/fesm2022/neural-ui-core-virtual-list.mjs +32 -19
- package/fesm2022/neural-ui-core-virtual-list.mjs.map +1 -1
- package/package.json +5 -1
- package/types/neural-ui-core-notification-center.d.ts +2 -0
- package/types/neural-ui-core-rich-text-editor.d.ts +97 -0
- package/types/neural-ui-core-toast.d.ts +2 -0
|
@@ -15,9 +15,12 @@ import { NeuIconComponent } from '@neural-ui/core/icon';
|
|
|
15
15
|
*/
|
|
16
16
|
class NeuToastService {
|
|
17
17
|
/** Lista reactiva de toasts activos / Reactive list of active toasts */
|
|
18
|
-
toasts = signal([],
|
|
18
|
+
toasts = signal([], /* @ts-ignore */
|
|
19
|
+
...(ngDevMode ? [{ debugName: "toasts" }] : /* istanbul ignore next */ []));
|
|
19
20
|
/** Posición del contenedor de toasts / Toast container position */
|
|
20
|
-
position = signal('top-right',
|
|
21
|
+
position = signal('top-right', /* @ts-ignore */
|
|
22
|
+
...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
23
|
+
timers = new Map();
|
|
21
24
|
setPosition(position) {
|
|
22
25
|
this.position.set(position);
|
|
23
26
|
}
|
|
@@ -33,7 +36,8 @@ class NeuToastService {
|
|
|
33
36
|
};
|
|
34
37
|
this.toasts.update((list) => [...list, item]);
|
|
35
38
|
if (duration > 0) {
|
|
36
|
-
setTimeout(() => this.dismiss(id), duration);
|
|
39
|
+
const timer = setTimeout(() => this.dismiss(id), duration);
|
|
40
|
+
this.timers.set(id, timer);
|
|
37
41
|
}
|
|
38
42
|
return id;
|
|
39
43
|
}
|
|
@@ -50,15 +54,27 @@ class NeuToastService {
|
|
|
50
54
|
return this.show({ ...opts, message, type: 'warning' });
|
|
51
55
|
}
|
|
52
56
|
dismiss(id) {
|
|
57
|
+
this.clearTimer(id);
|
|
53
58
|
this.toasts.update((list) => list.filter((t) => t.id !== id));
|
|
54
59
|
}
|
|
55
60
|
clear() {
|
|
61
|
+
for (const timer of this.timers.values()) {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
}
|
|
64
|
+
this.timers.clear();
|
|
56
65
|
this.toasts.set([]);
|
|
57
66
|
}
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
clearTimer(id) {
|
|
68
|
+
const timer = this.timers.get(id);
|
|
69
|
+
if (!timer)
|
|
70
|
+
return;
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
this.timers.delete(id);
|
|
73
|
+
}
|
|
74
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
75
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuToastService, providedIn: 'root' });
|
|
60
76
|
}
|
|
61
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
77
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuToastService, decorators: [{
|
|
62
78
|
type: Injectable,
|
|
63
79
|
args: [{ providedIn: 'root' }]
|
|
64
80
|
}] });
|
|
@@ -89,8 +105,8 @@ class NeuToastContainerComponent {
|
|
|
89
105
|
getIcon(type) {
|
|
90
106
|
return TOAST_ICONS[type];
|
|
91
107
|
}
|
|
92
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
93
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
108
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuToastContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
109
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NeuToastContainerComponent, isStandalone: true, selector: "neu-toast-container", host: { attributes: { "aria-live": "polite", "aria-atomic": "false" }, properties: { "class.neu-toast-container--top-right": "toastService.position() === \"top-right\"", "class.neu-toast-container--top-left": "toastService.position() === \"top-left\"", "class.neu-toast-container--bottom-right": "toastService.position() === \"bottom-right\"", "class.neu-toast-container--bottom-left": "toastService.position() === \"bottom-left\"" }, classAttribute: "neu-toast-container" }, ngImport: i0, template: `
|
|
94
110
|
@for (toast of toastService.toasts(); track toast.id) {
|
|
95
111
|
<div
|
|
96
112
|
class="neu-toast"
|
|
@@ -121,7 +137,7 @@ class NeuToastContainerComponent {
|
|
|
121
137
|
}
|
|
122
138
|
`, isInline: true, styles: [".neu-toast-container{position:fixed;z-index:var(--neu-z-toast);display:flex;flex-direction:column;gap:var(--neu-space-3);pointer-events:none;bottom:var(--neu-space-6);left:50%;transform:translate(-50%);width:calc(100vw - var(--neu-space-8));max-width:400px;align-items:stretch}@media(min-width:400px){.neu-toast-container{bottom:auto;left:auto;transform:none;width:360px;align-items:flex-end}}@media(min-width:400px){.neu-toast-container--top-right{top:calc(var(--neu-header-height, 64px) + var(--neu-space-4));right:var(--neu-space-6);align-items:flex-end}.neu-toast-container--top-left{top:calc(var(--neu-header-height, 64px) + var(--neu-space-4));left:var(--neu-space-6);align-items:flex-start}.neu-toast-container--bottom-right{top:auto;bottom:var(--neu-space-6);right:var(--neu-space-6);align-items:flex-end}.neu-toast-container--bottom-left{top:auto;bottom:var(--neu-space-6);left:var(--neu-space-6);align-items:flex-start}}.neu-toast{display:flex;align-items:flex-start;gap:var(--neu-space-3);padding:var(--neu-space-4);background:var(--neu-toast-bg, var(--neu-surface));border-radius:var(--neu-toast-radius, 10px);box-shadow:var(--neu-toast-shadow, 0 8px 24px rgba(15, 23, 42, .12), 0 2px 6px rgba(15, 23, 42, .06));border-left:3px solid transparent;pointer-events:all;animation:neu-toast-in .25s cubic-bezier(.34,1.56,.64,1) forwards;width:100%}.neu-toast--success{border-color:var(--neu-success)}.neu-toast--success .neu-toast__icon-wrap{color:var(--neu-success)}.neu-toast--error{border-color:var(--neu-error)}.neu-toast--error .neu-toast__icon-wrap{color:var(--neu-error)}.neu-toast--warning{border-color:var(--neu-warning)}.neu-toast--warning .neu-toast__icon-wrap{color:var(--neu-warning)}.neu-toast--info{border-color:var(--neu-info)}.neu-toast--info .neu-toast__icon-wrap{color:var(--neu-info)}.neu-toast__icon-wrap{flex-shrink:0;display:flex;align-items:center;margin-top:1px}.neu-toast__body{flex:1;min-width:0}.neu-toast__title{margin:0 0 var(--neu-space-1);font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);font-weight:600;color:var(--neu-text);line-height:1.3}.neu-toast__message{margin:0;font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);color:var(--neu-text-muted);line-height:1.4;word-break:break-word}.neu-toast__close{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;background:transparent;border:none;border-radius:var(--neu-radius-sm);color:var(--neu-text-muted);cursor:pointer;transition:background-color var(--neu-transition),color var(--neu-transition);margin-top:-2px;margin-right:-4px}.neu-toast__close:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-toast__close:focus-visible{outline:2px solid var(--neu-primary);outline-offset:1px}@keyframes neu-toast-in{0%{opacity:0;transform:translateY(12px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@media(min-width:400px){@keyframes neu-toast-in{0%{opacity:0;transform:translate(20px) scale(.96)}to{opacity:1;transform:translate(0) scale(1)}}}\n"], dependencies: [{ kind: "component", type: NeuIconComponent, selector: "neu-icon", inputs: ["name", "strokeWidth", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
123
139
|
}
|
|
124
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
140
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuToastContainerComponent, decorators: [{
|
|
125
141
|
type: Component,
|
|
126
142
|
args: [{ selector: 'neu-toast-container', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NeuIconComponent], host: {
|
|
127
143
|
class: 'neu-toast-container',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neural-ui-core-toast.mjs","sources":["../../../../projects/ui-core/toast/neu-toast.service.ts","../../../../projects/ui-core/toast/neu-toast.component.ts","../../../../projects/ui-core/toast/neural-ui-core-toast.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport { NeuToastItem, NeuToastOptions, NeuToastPosition } from './neu-toast.types';\n\n/**\n * NeuralUI Toast Service\n *\n * Lanza notificaciones flotantes desde cualquier punto de la app.\n * Requiere que `<neu-toast-container>` esté presente en la raíz del app.\n *\n * Uso:\n * const toast = inject(NeuToastService);\n * toast.success('Guardado correctamente');\n * toast.error('Ha ocurrido un error', { title: 'Error', duration: 8000 });\n */\n@Injectable({ providedIn: 'root' })\nexport class NeuToastService {\n /** Lista reactiva de toasts activos / Reactive list of active toasts */\n readonly toasts = signal<NeuToastItem[]>([]);\n\n /** Posición del contenedor de toasts / Toast container position */\n readonly position = signal<NeuToastPosition>('top-right');\n\n setPosition(position: NeuToastPosition): void {\n this.position.set(position);\n }\n\n show(options: NeuToastOptions): string {\n const id = `neu-toast-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n const duration = options.duration ?? 4000;\n\n const item: NeuToastItem = {\n id,\n message: options.message,\n title: options.title ?? '',\n type: options.type ?? 'info',\n duration,\n };\n\n this.toasts.update((list) => [...list, item]);\n\n if (duration > 0) {\n setTimeout(() => this.dismiss(id), duration);\n }\n\n return id;\n }\n\n success(message: string, opts?: Partial<NeuToastOptions>): string {\n return this.show({ ...opts, message, type: 'success' });\n }\n\n error(message: string, opts?: Partial<NeuToastOptions>): string {\n return this.show({ ...opts, message, type: 'error' });\n }\n\n info(message: string, opts?: Partial<NeuToastOptions>): string {\n return this.show({ ...opts, message, type: 'info' });\n }\n\n warning(message: string, opts?: Partial<NeuToastOptions>): string {\n return this.show({ ...opts, message, type: 'warning' });\n }\n\n dismiss(id: string): void {\n this.toasts.update((list) => list.filter((t) => t.id !== id));\n }\n\n clear(): void {\n this.toasts.set([]);\n }\n}\n","import { ChangeDetectionStrategy, Component, ViewEncapsulation, inject } from '@angular/core';\nimport { NeuToastService } from './neu-toast.service';\nimport { NeuToastType } from './neu-toast.types';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\n\n/** Mapa de iconos Lucide por tipo de toast / Map of Lucide icons by toast type */\nconst TOAST_ICONS: Record<NeuToastType, string> = {\n success: 'lucideCheckCircle',\n error: 'lucideXCircle',\n warning: 'lucideAlertTriangle',\n info: 'lucideInfo',\n};\n\n/**\n * NeuralUI Toast Container Component\n *\n * Renderiza los toasts activos del NeuToastService.\n * Añade este componente una sola vez en la raíz del app (app.html).\n *\n * Diseño mobile-first:\n * - < 400px: banner inferior centrado\n * - ≥ 400px: stack en la esquina superior derecha\n *\n * Uso:\n * <!-- en app.html -->\n * <neu-toast-container />\n */\n@Component({\n selector: 'neu-toast-container',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [NeuIconComponent],\n host: {\n class: 'neu-toast-container',\n 'aria-live': 'polite',\n 'aria-atomic': 'false',\n '[class.neu-toast-container--top-right]': 'toastService.position() === \"top-right\"',\n '[class.neu-toast-container--top-left]': 'toastService.position() === \"top-left\"',\n '[class.neu-toast-container--bottom-right]': 'toastService.position() === \"bottom-right\"',\n '[class.neu-toast-container--bottom-left]': 'toastService.position() === \"bottom-left\"',\n },\n template: `\n @for (toast of toastService.toasts(); track toast.id) {\n <div\n class=\"neu-toast\"\n [class]=\"'neu-toast neu-toast--' + toast.type\"\n [attr.role]=\"toast.type === 'error' || toast.type === 'warning' ? 'alert' : 'status'\"\n [attr.aria-live]=\"\n toast.type === 'error' || toast.type === 'warning' ? 'assertive' : 'polite'\n \"\n >\n <span class=\"neu-toast__icon-wrap\" aria-hidden=\"true\">\n <neu-icon [name]=\"getIcon(toast.type)\" size=\"1rem\" />\n </span>\n <div class=\"neu-toast__body\">\n @if (toast.title) {\n <p class=\"neu-toast__title\">{{ toast.title }}</p>\n }\n <p class=\"neu-toast__message\">{{ toast.message }}</p>\n </div>\n <button\n class=\"neu-toast__close\"\n type=\"button\"\n [attr.aria-label]=\"'Cerrar'\"\n (click)=\"toastService.dismiss(toast.id)\"\n >\n <neu-icon name=\"lucideX\" size=\"1rem\" />\n </button>\n </div>\n }\n `,\n styleUrl: './neu-toast.component.scss',\n})\nexport class NeuToastContainerComponent {\n readonly toastService = inject(NeuToastService);\n\n getIcon(type: NeuToastType): string {\n return TOAST_ICONS[type];\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":";;;;AAGA;;;;;;;;;;AAUG;MAEU,eAAe,CAAA;;
|
|
1
|
+
{"version":3,"file":"neural-ui-core-toast.mjs","sources":["../../../../projects/ui-core/toast/neu-toast.service.ts","../../../../projects/ui-core/toast/neu-toast.component.ts","../../../../projects/ui-core/toast/neural-ui-core-toast.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport { NeuToastItem, NeuToastOptions, NeuToastPosition } from './neu-toast.types';\n\n/**\n * NeuralUI Toast Service\n *\n * Lanza notificaciones flotantes desde cualquier punto de la app.\n * Requiere que `<neu-toast-container>` esté presente en la raíz del app.\n *\n * Uso:\n * const toast = inject(NeuToastService);\n * toast.success('Guardado correctamente');\n * toast.error('Ha ocurrido un error', { title: 'Error', duration: 8000 });\n */\n@Injectable({ providedIn: 'root' })\nexport class NeuToastService {\n /** Lista reactiva de toasts activos / Reactive list of active toasts */\n readonly toasts = signal<NeuToastItem[]>([]);\n\n /** Posición del contenedor de toasts / Toast container position */\n readonly position = signal<NeuToastPosition>('top-right');\n\n private readonly timers = new Map<string, ReturnType<typeof setTimeout>>();\n\n setPosition(position: NeuToastPosition): void {\n this.position.set(position);\n }\n\n show(options: NeuToastOptions): string {\n const id = `neu-toast-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n const duration = options.duration ?? 4000;\n\n const item: NeuToastItem = {\n id,\n message: options.message,\n title: options.title ?? '',\n type: options.type ?? 'info',\n duration,\n };\n\n this.toasts.update((list) => [...list, item]);\n\n if (duration > 0) {\n const timer = setTimeout(() => this.dismiss(id), duration);\n this.timers.set(id, timer);\n }\n\n return id;\n }\n\n success(message: string, opts?: Partial<NeuToastOptions>): string {\n return this.show({ ...opts, message, type: 'success' });\n }\n\n error(message: string, opts?: Partial<NeuToastOptions>): string {\n return this.show({ ...opts, message, type: 'error' });\n }\n\n info(message: string, opts?: Partial<NeuToastOptions>): string {\n return this.show({ ...opts, message, type: 'info' });\n }\n\n warning(message: string, opts?: Partial<NeuToastOptions>): string {\n return this.show({ ...opts, message, type: 'warning' });\n }\n\n dismiss(id: string): void {\n this.clearTimer(id);\n this.toasts.update((list) => list.filter((t) => t.id !== id));\n }\n\n clear(): void {\n for (const timer of this.timers.values()) {\n clearTimeout(timer);\n }\n this.timers.clear();\n this.toasts.set([]);\n }\n\n private clearTimer(id: string): void {\n const timer = this.timers.get(id);\n if (!timer) return;\n clearTimeout(timer);\n this.timers.delete(id);\n }\n}\n","import { ChangeDetectionStrategy, Component, ViewEncapsulation, inject } from '@angular/core';\nimport { NeuToastService } from './neu-toast.service';\nimport { NeuToastType } from './neu-toast.types';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\n\n/** Mapa de iconos Lucide por tipo de toast / Map of Lucide icons by toast type */\nconst TOAST_ICONS: Record<NeuToastType, string> = {\n success: 'lucideCheckCircle',\n error: 'lucideXCircle',\n warning: 'lucideAlertTriangle',\n info: 'lucideInfo',\n};\n\n/**\n * NeuralUI Toast Container Component\n *\n * Renderiza los toasts activos del NeuToastService.\n * Añade este componente una sola vez en la raíz del app (app.html).\n *\n * Diseño mobile-first:\n * - < 400px: banner inferior centrado\n * - ≥ 400px: stack en la esquina superior derecha\n *\n * Uso:\n * <!-- en app.html -->\n * <neu-toast-container />\n */\n@Component({\n selector: 'neu-toast-container',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [NeuIconComponent],\n host: {\n class: 'neu-toast-container',\n 'aria-live': 'polite',\n 'aria-atomic': 'false',\n '[class.neu-toast-container--top-right]': 'toastService.position() === \"top-right\"',\n '[class.neu-toast-container--top-left]': 'toastService.position() === \"top-left\"',\n '[class.neu-toast-container--bottom-right]': 'toastService.position() === \"bottom-right\"',\n '[class.neu-toast-container--bottom-left]': 'toastService.position() === \"bottom-left\"',\n },\n template: `\n @for (toast of toastService.toasts(); track toast.id) {\n <div\n class=\"neu-toast\"\n [class]=\"'neu-toast neu-toast--' + toast.type\"\n [attr.role]=\"toast.type === 'error' || toast.type === 'warning' ? 'alert' : 'status'\"\n [attr.aria-live]=\"\n toast.type === 'error' || toast.type === 'warning' ? 'assertive' : 'polite'\n \"\n >\n <span class=\"neu-toast__icon-wrap\" aria-hidden=\"true\">\n <neu-icon [name]=\"getIcon(toast.type)\" size=\"1rem\" />\n </span>\n <div class=\"neu-toast__body\">\n @if (toast.title) {\n <p class=\"neu-toast__title\">{{ toast.title }}</p>\n }\n <p class=\"neu-toast__message\">{{ toast.message }}</p>\n </div>\n <button\n class=\"neu-toast__close\"\n type=\"button\"\n [attr.aria-label]=\"'Cerrar'\"\n (click)=\"toastService.dismiss(toast.id)\"\n >\n <neu-icon name=\"lucideX\" size=\"1rem\" />\n </button>\n </div>\n }\n `,\n styleUrl: './neu-toast.component.scss',\n})\nexport class NeuToastContainerComponent {\n readonly toastService = inject(NeuToastService);\n\n getIcon(type: NeuToastType): string {\n return TOAST_ICONS[type];\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|
|
@@ -17,26 +17,33 @@ import { NeuIconComponent } from '@neural-ui/core/icon';
|
|
|
17
17
|
*/
|
|
18
18
|
class NeuToggleButtonGroupComponent {
|
|
19
19
|
/** Lista de opciones del grupo / Group option list */
|
|
20
|
-
options = input([],
|
|
20
|
+
options = input([], /* @ts-ignore */
|
|
21
|
+
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
21
22
|
/**
|
|
22
23
|
* Permite seleccionar múltiples opciones.
|
|
23
24
|
* - false (por defecto): valor es `T | null`
|
|
24
25
|
* - true: valor es `T[]`
|
|
25
26
|
*/
|
|
26
|
-
multiple = input(false,
|
|
27
|
+
multiple = input(false, /* @ts-ignore */
|
|
28
|
+
...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
|
|
27
29
|
/** Tamaño visual / Visual size */
|
|
28
|
-
size = input('md',
|
|
30
|
+
size = input('md', /* @ts-ignore */
|
|
31
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
29
32
|
/** Deshabilita todo el grupo / Disables the entire group */
|
|
30
|
-
disabled = input(false,
|
|
33
|
+
disabled = input(false, /* @ts-ignore */
|
|
34
|
+
...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
31
35
|
/** Emite el nuevo valor al cambiar (útil sin formControl) / Emits the new value on change (useful without formControl) */
|
|
32
36
|
neuChange = output();
|
|
33
|
-
_value = signal(null,
|
|
34
|
-
|
|
37
|
+
_value = signal(null, /* @ts-ignore */
|
|
38
|
+
...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
|
|
39
|
+
_isDisabled = signal(false, /* @ts-ignore */
|
|
40
|
+
...(ngDevMode ? [{ debugName: "_isDisabled" }] : /* istanbul ignore next */ []));
|
|
35
41
|
groupClasses = computed(() => ({
|
|
36
42
|
'neu-toggle-group': true,
|
|
37
43
|
[`neu-toggle-group--${this.size()}`]: true,
|
|
38
44
|
'neu-toggle-group--disabled': this._isDisabled(),
|
|
39
|
-
}),
|
|
45
|
+
}), /* @ts-ignore */
|
|
46
|
+
...(ngDevMode ? [{ debugName: "groupClasses" }] : /* istanbul ignore next */ []));
|
|
40
47
|
isSelected(value) {
|
|
41
48
|
const v = this._value();
|
|
42
49
|
if (this.multiple()) {
|
|
@@ -84,8 +91,8 @@ class NeuToggleButtonGroupComponent {
|
|
|
84
91
|
setDisabledState(isDisabled) {
|
|
85
92
|
this._isDisabled.set(isDisabled);
|
|
86
93
|
}
|
|
87
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
88
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
94
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuToggleButtonGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
95
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NeuToggleButtonGroupComponent, isStandalone: true, selector: "neu-toggle-button-group", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { neuChange: "neuChange" }, host: { classAttribute: "neu-toggle-group-host" }, providers: [
|
|
89
96
|
{
|
|
90
97
|
provide: NG_VALUE_ACCESSOR,
|
|
91
98
|
useExisting: forwardRef(() => NeuToggleButtonGroupComponent),
|
|
@@ -118,7 +125,7 @@ class NeuToggleButtonGroupComponent {
|
|
|
118
125
|
</div>
|
|
119
126
|
`, isInline: true, styles: [".neu-toggle-group-host{display:inline-block}.neu-toggle-group{display:inline-flex;border:1px solid var(--neu-border);border-radius:var(--neu-radius);overflow:hidden;background:var(--neu-surface)}.neu-toggle-group__btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--neu-space-2);border:none;border-right:1px solid var(--neu-border);background:transparent;color:var(--neu-text-muted);font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);font-weight:500;line-height:1;white-space:nowrap;cursor:pointer;padding:.5rem var(--neu-space-4);transition:background-color .15s ease,color .15s ease,border-color .15s ease;outline:none;-webkit-user-select:none;user-select:none}.neu-toggle-group__btn:last-child{border-right:none}.neu-toggle-group__btn:hover:not(:disabled):not(.neu-toggle-group__btn--disabled){background:var(--neu-surface-2);color:var(--neu-text)}.neu-toggle-group__btn:focus-visible{position:relative;z-index:1;box-shadow:inset 0 0 0 2px var(--neu-primary)}.neu-toggle-group__btn--active{background:var(--neu-primary-solid, var(--neu-primary-dark, var(--neu-primary)));color:var(--neu-primary-solid-fg, var(--neu-primary-fg));border-right-color:var(--neu-primary-solid-hover, var(--neu-primary-dark))}.neu-toggle-group__btn--active:hover:not(:disabled):not(.neu-toggle-group__btn--disabled){background:var(--neu-primary-solid-hover, var(--neu-primary-dark));color:var(--neu-primary-solid-fg, var(--neu-primary-fg))}.neu-toggle-group__btn--active+.neu-toggle-group__btn{border-left-color:var(--neu-primary-solid-hover, var(--neu-primary-dark))}.neu-toggle-group__btn--disabled{opacity:.45;cursor:not-allowed}.neu-toggle-group--disabled{opacity:.6;pointer-events:none}.neu-toggle-group--sm .neu-toggle-group__btn{font-size:var(--neu-text-xs);padding:.375rem var(--neu-space-3)}.neu-toggle-group--md .neu-toggle-group__btn{font-size:var(--neu-text-sm);padding:.5rem var(--neu-space-4)}.neu-toggle-group--lg .neu-toggle-group__btn{font-size:var(--neu-text-base);padding:.625rem var(--neu-space-5)}\n"], dependencies: [{ kind: "component", type: NeuIconComponent, selector: "neu-icon", inputs: ["name", "strokeWidth", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
120
127
|
}
|
|
121
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
128
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuToggleButtonGroupComponent, decorators: [{
|
|
122
129
|
type: Component,
|
|
123
130
|
args: [{ selector: 'neu-toggle-button-group', imports: [NeuIconComponent], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
124
131
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neural-ui-core-toggle-button-group.mjs","sources":["../../../../projects/ui-core/toggle-button-group/neu-toggle-button-group.component.ts","../../../../projects/ui-core/toggle-button-group/neural-ui-core-toggle-button-group.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n forwardRef,\n input,\n output,\n signal,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { NeuButtonSize } from '@neural-ui/core/button';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\n\nexport interface NeuToggleOption<T = unknown> {\n /** Texto visible del botón / Visible button text */\n label: string;\n /** Valor asociado a esta opción / Value associated with this option */\n value: T;\n /** Nombre de icono Lucide (opcional) / Lucide icon name (optional) */\n icon?: string;\n /** Deshabilita solo esta opción / Disables this option only */\n disabled?: boolean;\n}\n\n/**\n * NeuralUI ToggleButtonGroup Component\n *\n * Grupo de botones de selección (single o múltiple). / Selection button group (single or multiple).\n * Selector segmentado para selección única o múltiple. / Segmented selector for single or multiple selection.\n *\n * Uso (single):\n * <neu-toggle-button-group [options]=\"opts\" [formControl]=\"valueCtrl\" />\n *\n * Uso (múltiple):\n * <neu-toggle-button-group [options]=\"opts\" [multiple]=\"true\" [formControl]=\"valuesCtrl\" />\n */\n@Component({\n selector: 'neu-toggle-button-group',\n imports: [NeuIconComponent],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => NeuToggleButtonGroupComponent),\n multi: true,\n },\n ],\n host: { class: 'neu-toggle-group-host' },\n template: `\n <div\n class=\"neu-toggle-group\"\n [class]=\"groupClasses()\"\n role=\"group\"\n [attr.aria-disabled]=\"_isDisabled() || null\"\n >\n @for (opt of options(); track opt.value) {\n <button\n type=\"button\"\n class=\"neu-toggle-group__btn\"\n [class.neu-toggle-group__btn--active]=\"isSelected(opt.value)\"\n [class.neu-toggle-group__btn--disabled]=\"opt.disabled || _isDisabled()\"\n [attr.aria-pressed]=\"isSelected(opt.value)\"\n [disabled]=\"opt.disabled || _isDisabled() ? '' : null\"\n (click)=\"toggle(opt)\"\n (blur)=\"onBlur()\"\n >\n @if (opt.icon) {\n <neu-icon [name]=\"opt.icon\" size=\"16px\" strokeWidth=\"2\" />\n }\n {{ opt.label }}\n </button>\n }\n </div>\n `,\n styleUrl: './neu-toggle-button-group.component.scss',\n})\nexport class NeuToggleButtonGroupComponent<T = unknown> implements ControlValueAccessor {\n /** Lista de opciones del grupo / Group option list */\n options = input<NeuToggleOption<T>[]>([]);\n\n /**\n * Permite seleccionar múltiples opciones.\n * - false (por defecto): valor es `T | null`\n * - true: valor es `T[]`\n */\n multiple = input<boolean>(false);\n\n /** Tamaño visual / Visual size */\n size = input<NeuButtonSize>('md');\n\n /** Deshabilita todo el grupo / Disables the entire group */\n disabled = input<boolean>(false);\n\n /** Emite el nuevo valor al cambiar (útil sin formControl) / Emits the new value on change (useful without formControl) */\n neuChange = output<T | T[] | null>();\n\n readonly _value = signal<T | T[] | null>(null);\n readonly _isDisabled = signal(false);\n\n readonly groupClasses = computed(() => ({\n 'neu-toggle-group': true,\n [`neu-toggle-group--${this.size()}`]: true,\n 'neu-toggle-group--disabled': this._isDisabled(),\n }));\n\n isSelected(value: T): boolean {\n const v = this._value();\n if (this.multiple()) {\n return Array.isArray(v) && (v as T[]).includes(value);\n }\n return v === value;\n }\n\n toggle(opt: NeuToggleOption<T>): void {\n if (opt.disabled || this._isDisabled()) return;\n\n let next: T | T[] | null;\n\n if (this.multiple()) {\n const current: T[] = Array.isArray(this._value()) ? (this._value() as T[]) : [];\n const idx = current.indexOf(opt.value);\n next = idx >= 0 ? current.filter((_, i) => i !== idx) : [...current, opt.value];\n } else {\n next = this._value() === opt.value ? null : opt.value;\n }\n\n this._value.set(next);\n this._onChange(next);\n this._onTouched();\n this.neuChange.emit(next);\n }\n\n onBlur(): void {\n this._onTouched();\n }\n\n // ---- CVA ----\n\n private _onChange: (v: unknown) => void = () => {};\n private _onTouched: () => void = () => {};\n\n writeValue(val: T | T[] | null): void {\n if (val === null || val === undefined) {\n this._value.set(this.multiple() ? ([] as T[]) : null);\n } else {\n this._value.set(val);\n }\n }\n\n registerOnChange(fn: (v: unknown) => void): void {\n this._onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this._onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this._isDisabled.set(isDisabled);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":";;;;;AAyBA;;;;;;;;;;;AAWG;MA0CU,6BAA6B,CAAA;;
|
|
1
|
+
{"version":3,"file":"neural-ui-core-toggle-button-group.mjs","sources":["../../../../projects/ui-core/toggle-button-group/neu-toggle-button-group.component.ts","../../../../projects/ui-core/toggle-button-group/neural-ui-core-toggle-button-group.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n forwardRef,\n input,\n output,\n signal,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { NeuButtonSize } from '@neural-ui/core/button';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\n\nexport interface NeuToggleOption<T = unknown> {\n /** Texto visible del botón / Visible button text */\n label: string;\n /** Valor asociado a esta opción / Value associated with this option */\n value: T;\n /** Nombre de icono Lucide (opcional) / Lucide icon name (optional) */\n icon?: string;\n /** Deshabilita solo esta opción / Disables this option only */\n disabled?: boolean;\n}\n\n/**\n * NeuralUI ToggleButtonGroup Component\n *\n * Grupo de botones de selección (single o múltiple). / Selection button group (single or multiple).\n * Selector segmentado para selección única o múltiple. / Segmented selector for single or multiple selection.\n *\n * Uso (single):\n * <neu-toggle-button-group [options]=\"opts\" [formControl]=\"valueCtrl\" />\n *\n * Uso (múltiple):\n * <neu-toggle-button-group [options]=\"opts\" [multiple]=\"true\" [formControl]=\"valuesCtrl\" />\n */\n@Component({\n selector: 'neu-toggle-button-group',\n imports: [NeuIconComponent],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => NeuToggleButtonGroupComponent),\n multi: true,\n },\n ],\n host: { class: 'neu-toggle-group-host' },\n template: `\n <div\n class=\"neu-toggle-group\"\n [class]=\"groupClasses()\"\n role=\"group\"\n [attr.aria-disabled]=\"_isDisabled() || null\"\n >\n @for (opt of options(); track opt.value) {\n <button\n type=\"button\"\n class=\"neu-toggle-group__btn\"\n [class.neu-toggle-group__btn--active]=\"isSelected(opt.value)\"\n [class.neu-toggle-group__btn--disabled]=\"opt.disabled || _isDisabled()\"\n [attr.aria-pressed]=\"isSelected(opt.value)\"\n [disabled]=\"opt.disabled || _isDisabled() ? '' : null\"\n (click)=\"toggle(opt)\"\n (blur)=\"onBlur()\"\n >\n @if (opt.icon) {\n <neu-icon [name]=\"opt.icon\" size=\"16px\" strokeWidth=\"2\" />\n }\n {{ opt.label }}\n </button>\n }\n </div>\n `,\n styleUrl: './neu-toggle-button-group.component.scss',\n})\nexport class NeuToggleButtonGroupComponent<T = unknown> implements ControlValueAccessor {\n /** Lista de opciones del grupo / Group option list */\n options = input<NeuToggleOption<T>[]>([]);\n\n /**\n * Permite seleccionar múltiples opciones.\n * - false (por defecto): valor es `T | null`\n * - true: valor es `T[]`\n */\n multiple = input<boolean>(false);\n\n /** Tamaño visual / Visual size */\n size = input<NeuButtonSize>('md');\n\n /** Deshabilita todo el grupo / Disables the entire group */\n disabled = input<boolean>(false);\n\n /** Emite el nuevo valor al cambiar (útil sin formControl) / Emits the new value on change (useful without formControl) */\n neuChange = output<T | T[] | null>();\n\n readonly _value = signal<T | T[] | null>(null);\n readonly _isDisabled = signal(false);\n\n readonly groupClasses = computed(() => ({\n 'neu-toggle-group': true,\n [`neu-toggle-group--${this.size()}`]: true,\n 'neu-toggle-group--disabled': this._isDisabled(),\n }));\n\n isSelected(value: T): boolean {\n const v = this._value();\n if (this.multiple()) {\n return Array.isArray(v) && (v as T[]).includes(value);\n }\n return v === value;\n }\n\n toggle(opt: NeuToggleOption<T>): void {\n if (opt.disabled || this._isDisabled()) return;\n\n let next: T | T[] | null;\n\n if (this.multiple()) {\n const current: T[] = Array.isArray(this._value()) ? (this._value() as T[]) : [];\n const idx = current.indexOf(opt.value);\n next = idx >= 0 ? current.filter((_, i) => i !== idx) : [...current, opt.value];\n } else {\n next = this._value() === opt.value ? null : opt.value;\n }\n\n this._value.set(next);\n this._onChange(next);\n this._onTouched();\n this.neuChange.emit(next);\n }\n\n onBlur(): void {\n this._onTouched();\n }\n\n // ---- CVA ----\n\n private _onChange: (v: unknown) => void = () => {};\n private _onTouched: () => void = () => {};\n\n writeValue(val: T | T[] | null): void {\n if (val === null || val === undefined) {\n this._value.set(this.multiple() ? ([] as T[]) : null);\n } else {\n this._value.set(val);\n }\n }\n\n registerOnChange(fn: (v: unknown) => void): void {\n this._onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this._onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this._isDisabled.set(isDisabled);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|
|
@@ -15,22 +15,27 @@ import { input, computed, ChangeDetectionStrategy, ViewEncapsulation, Component
|
|
|
15
15
|
*/
|
|
16
16
|
class NeuToolbarComponent {
|
|
17
17
|
/** Tamaño de la toolbar / Toolbar size */
|
|
18
|
-
size = input('md',
|
|
18
|
+
size = input('md', /* @ts-ignore */
|
|
19
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
19
20
|
/** Añade sombra en la parte inferior / Adds shadow at the bottom */
|
|
20
|
-
shadow = input(false,
|
|
21
|
+
shadow = input(false, /* @ts-ignore */
|
|
22
|
+
...(ngDevMode ? [{ debugName: "shadow" }] : /* istanbul ignore next */ []));
|
|
21
23
|
/** Añade separador inferior / Adds bottom separator */
|
|
22
|
-
bordered = input(false,
|
|
24
|
+
bordered = input(false, /* @ts-ignore */
|
|
25
|
+
...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
|
|
23
26
|
/** Color de fondo personalizado vía CSS (pasa a la variable local) / Custom background color via CSS */
|
|
24
|
-
surface = input('surface',
|
|
27
|
+
surface = input('surface', /* @ts-ignore */
|
|
28
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
25
29
|
hostClasses = computed(() => ({
|
|
26
30
|
'neu-toolbar': true,
|
|
27
31
|
[`neu-toolbar--${this.size()}`]: true,
|
|
28
32
|
[`neu-toolbar--${this.surface()}`]: true,
|
|
29
33
|
'neu-toolbar--shadow': this.shadow(),
|
|
30
34
|
'neu-toolbar--bordered': this.bordered(),
|
|
31
|
-
}),
|
|
32
|
-
|
|
33
|
-
static
|
|
35
|
+
}), /* @ts-ignore */
|
|
36
|
+
...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
|
|
37
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
38
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: NeuToolbarComponent, isStandalone: true, selector: "neu-toolbar", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, shadow: { classPropertyName: "shadow", publicName: "shadow", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, surface: { classPropertyName: "surface", publicName: "surface", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
|
|
34
39
|
<div class="neu-toolbar__section neu-toolbar__section--start">
|
|
35
40
|
<ng-content select="[neu-toolbar-start]" />
|
|
36
41
|
</div>
|
|
@@ -43,7 +48,7 @@ class NeuToolbarComponent {
|
|
|
43
48
|
<ng-content />
|
|
44
49
|
`, isInline: true, styles: ["@charset \"UTF-8\";.neu-toolbar{display:flex;align-items:center;width:100%;gap:8px;background:var(--neu-toolbar-bg, var(--neu-surface-1, #ffffff));color:var(--neu-toolbar-color, var(--neu-text-primary, #111))}.neu-toolbar--sm{padding:6px 12px;min-height:40px}.neu-toolbar--md{padding:8px 16px;min-height:52px}.neu-toolbar--lg{padding:12px 20px;min-height:64px}.neu-toolbar--primary{background:var(--neu-toolbar-primary-bg, var(--neu-primary-dark, var(--neu-primary)));color:var(--neu-toolbar-primary-color, #fff)}.neu-toolbar--primary .neu-button--ghost{color:#ffffffeb}.neu-toolbar--primary .neu-button--ghost:hover:not(:disabled):not(.neu-button--disabled){background:#ffffff1f;color:#fff}.neu-toolbar--none{background:transparent}.neu-toolbar--shadow{box-shadow:0 1px 4px #0000001a}.neu-toolbar--bordered{border-bottom:1px solid var(--neu-border-color, #e5e7eb)}.neu-toolbar__section{display:flex;align-items:center;gap:8px}.neu-toolbar__section--start{flex:0 0 auto;margin-right:auto}.neu-toolbar__section--center{flex:0 1 auto;justify-content:center}.neu-toolbar__section--end{flex:0 0 auto;margin-left:auto}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
45
50
|
}
|
|
46
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
51
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuToolbarComponent, decorators: [{
|
|
47
52
|
type: Component,
|
|
48
53
|
args: [{ selector: 'neu-toolbar', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'hostClasses()' }, template: `
|
|
49
54
|
<div class="neu-toolbar__section neu-toolbar__section--start">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neural-ui-core-toolbar.mjs","sources":["../../../../projects/ui-core/toolbar/neu-toolbar.component.ts","../../../../projects/ui-core/toolbar/neural-ui-core-toolbar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n input,\n} from '@angular/core';\n\nexport type NeuToolbarSize = 'sm' | 'md' | 'lg';\n\n/**\n * NeuralUI Toolbar Component\n *\n * Barra horizontal con tres zonas de contenido: start (izquierda), center (centro) y end (derecha).\n *\n * Uso:\n * <neu-toolbar>\n * <span neu-toolbar-start>Logo</span>\n * <span neu-toolbar-center>Título</span>\n * <span neu-toolbar-end><neu-button>Acción</neu-button></span>\n * </neu-toolbar>\n */\n@Component({\n selector: 'neu-toolbar',\n imports: [],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { '[class]': 'hostClasses()' },\n template: `\n <div class=\"neu-toolbar__section neu-toolbar__section--start\">\n <ng-content select=\"[neu-toolbar-start]\" />\n </div>\n <div class=\"neu-toolbar__section neu-toolbar__section--center\">\n <ng-content select=\"[neu-toolbar-center]\" />\n </div>\n <div class=\"neu-toolbar__section neu-toolbar__section--end\">\n <ng-content select=\"[neu-toolbar-end]\" />\n </div>\n <ng-content />\n `,\n styleUrl: './neu-toolbar.component.scss',\n})\nexport class NeuToolbarComponent {\n /** Tamaño de la toolbar / Toolbar size */\n readonly size = input<NeuToolbarSize>('md');\n\n /** Añade sombra en la parte inferior / Adds shadow at the bottom */\n readonly shadow = input<boolean>(false);\n\n /** Añade separador inferior / Adds bottom separator */\n readonly bordered = input<boolean>(false);\n\n /** Color de fondo personalizado vía CSS (pasa a la variable local) / Custom background color via CSS */\n readonly surface = input<'primary' | 'surface' | 'none'>('surface');\n\n readonly hostClasses = computed(() => ({\n 'neu-toolbar': true,\n [`neu-toolbar--${this.size()}`]: true,\n [`neu-toolbar--${this.surface()}`]: true,\n 'neu-toolbar--shadow': this.shadow(),\n 'neu-toolbar--bordered': this.bordered(),\n }));\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":";;;AAUA;;;;;;;;;;;AAWG;MAqBU,mBAAmB,CAAA;;
|
|
1
|
+
{"version":3,"file":"neural-ui-core-toolbar.mjs","sources":["../../../../projects/ui-core/toolbar/neu-toolbar.component.ts","../../../../projects/ui-core/toolbar/neural-ui-core-toolbar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n input,\n} from '@angular/core';\n\nexport type NeuToolbarSize = 'sm' | 'md' | 'lg';\n\n/**\n * NeuralUI Toolbar Component\n *\n * Barra horizontal con tres zonas de contenido: start (izquierda), center (centro) y end (derecha).\n *\n * Uso:\n * <neu-toolbar>\n * <span neu-toolbar-start>Logo</span>\n * <span neu-toolbar-center>Título</span>\n * <span neu-toolbar-end><neu-button>Acción</neu-button></span>\n * </neu-toolbar>\n */\n@Component({\n selector: 'neu-toolbar',\n imports: [],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { '[class]': 'hostClasses()' },\n template: `\n <div class=\"neu-toolbar__section neu-toolbar__section--start\">\n <ng-content select=\"[neu-toolbar-start]\" />\n </div>\n <div class=\"neu-toolbar__section neu-toolbar__section--center\">\n <ng-content select=\"[neu-toolbar-center]\" />\n </div>\n <div class=\"neu-toolbar__section neu-toolbar__section--end\">\n <ng-content select=\"[neu-toolbar-end]\" />\n </div>\n <ng-content />\n `,\n styleUrl: './neu-toolbar.component.scss',\n})\nexport class NeuToolbarComponent {\n /** Tamaño de la toolbar / Toolbar size */\n readonly size = input<NeuToolbarSize>('md');\n\n /** Añade sombra en la parte inferior / Adds shadow at the bottom */\n readonly shadow = input<boolean>(false);\n\n /** Añade separador inferior / Adds bottom separator */\n readonly bordered = input<boolean>(false);\n\n /** Color de fondo personalizado vía CSS (pasa a la variable local) / Custom background color via CSS */\n readonly surface = input<'primary' | 'surface' | 'none'>('surface');\n\n readonly hostClasses = computed(() => ({\n 'neu-toolbar': true,\n [`neu-toolbar--${this.size()}`]: true,\n [`neu-toolbar--${this.surface()}`]: true,\n 'neu-toolbar--shadow': this.shadow(),\n 'neu-toolbar--bordered': this.bordered(),\n }));\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":";;;AAUA;;;;;;;;;;;AAWG;MAqBU,mBAAmB,CAAA;;IAErB,IAAI,GAAG,KAAK,CAAiB,IAAI;6EAAC;;IAGlC,MAAM,GAAG,KAAK,CAAU,KAAK;+EAAC;;IAG9B,QAAQ,GAAG,KAAK,CAAU,KAAK;iFAAC;;IAGhC,OAAO,GAAG,KAAK,CAAiC,SAAS;gFAAC;AAE1D,IAAA,WAAW,GAAG,QAAQ,CAAC,OAAO;AACrC,QAAA,aAAa,EAAE,IAAI;QACnB,CAAC,CAAA,aAAA,EAAgB,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE,GAAG,IAAI;QACrC,CAAC,CAAA,aAAA,EAAgB,IAAI,CAAC,OAAO,EAAE,CAAA,CAAE,GAAG,IAAI;AACxC,QAAA,qBAAqB,EAAE,IAAI,CAAC,MAAM,EAAE;AACpC,QAAA,uBAAuB,EAAE,IAAI,CAAC,QAAQ,EAAE;KACzC,CAAC;oFAAC;uGAnBQ,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,mBAAmB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,eAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAdpB;;;;;;;;;;;AAWT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,6lCAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAGU,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBApB/B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,aAAa,WACd,EAAE,EAAA,aAAA,EACI,iBAAiB,CAAC,IAAI,EAAA,eAAA,EACpB,uBAAuB,CAAC,MAAM,QACzC,EAAE,SAAS,EAAE,eAAe,EAAE,EAAA,QAAA,EAC1B;;;;;;;;;;;AAWT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,6lCAAA,CAAA,EAAA;;;ACvCH;;AAEG;;;;"}
|
|
@@ -5,12 +5,14 @@ import { ComponentPortal } from '@angular/cdk/portal';
|
|
|
5
5
|
|
|
6
6
|
/** @internal — componente flotante del tooltip, renderizado vía CDK Portal / floating tooltip component, rendered via CDK Portal */
|
|
7
7
|
class NeuTooltipOverlayComponent {
|
|
8
|
-
text = input.required(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
text = input.required(/* @ts-ignore */
|
|
9
|
+
...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
10
|
+
tooltipId = input('', /* @ts-ignore */
|
|
11
|
+
...(ngDevMode ? [{ debugName: "tooltipId" }] : /* istanbul ignore next */ []));
|
|
12
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuTooltipOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: NeuTooltipOverlayComponent, isStandalone: true, selector: "neu-tooltip-overlay", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, tooltipId: { classPropertyName: "tooltipId", publicName: "tooltipId", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "tooltip" }, properties: { "id": "tooltipId()" }, classAttribute: "neu-tooltip" }, ngImport: i0, template: `<span class="neu-tooltip__text">{{ text() }}</span>`, isInline: true, styles: [".neu-tooltip-panel{pointer-events:none}.neu-tooltip{display:block;animation:neu-tooltip-in .15s ease forwards}.neu-tooltip__text{display:inline-block;padding:var(--neu-space-2) var(--neu-space-3);background:var(--neu-tooltip-bg, #0f172a);color:var(--neu-tooltip-fg, #ffffff);font-family:var(--neu-font-sans);font-size:var(--neu-text-xs);font-weight:500;line-height:1.4;border-radius:var(--neu-tooltip-radius, 6px);box-shadow:var(--neu-tooltip-shadow, 0 4px 12px rgba(15, 23, 42, .24));white-space:nowrap;max-width:280px;overflow:hidden;text-overflow:ellipsis}@keyframes neu-tooltip-in{0%{opacity:0;transform:translateY(4px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
12
14
|
}
|
|
13
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
15
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuTooltipOverlayComponent, decorators: [{
|
|
14
16
|
type: Component,
|
|
15
17
|
args: [{ selector: 'neu-tooltip-overlay', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
16
18
|
class: 'neu-tooltip',
|
|
@@ -30,9 +32,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
30
32
|
* <button [neuTooltip]="'Eliminar'" neuTooltipPosition="bottom">Eliminar</button>
|
|
31
33
|
*/
|
|
32
34
|
class NeuTooltipDirective {
|
|
33
|
-
neuTooltip = input.required(
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
neuTooltip = input.required(/* @ts-ignore */
|
|
36
|
+
...(ngDevMode ? [{ debugName: "neuTooltip" }] : /* istanbul ignore next */ []));
|
|
37
|
+
neuTooltipPosition = input('top', /* @ts-ignore */
|
|
38
|
+
...(ngDevMode ? [{ debugName: "neuTooltipPosition" }] : /* istanbul ignore next */ []));
|
|
39
|
+
neuTooltipDisabled = input(false, /* @ts-ignore */
|
|
40
|
+
...(ngDevMode ? [{ debugName: "neuTooltipDisabled" }] : /* istanbul ignore next */ []));
|
|
36
41
|
_overlay = inject(Overlay);
|
|
37
42
|
_elementRef = inject((ElementRef));
|
|
38
43
|
_injector = inject(Injector);
|
|
@@ -116,10 +121,10 @@ class NeuTooltipDirective {
|
|
|
116
121
|
clearTimeout(this._hideTimeout);
|
|
117
122
|
this._overlayRef?.dispose();
|
|
118
123
|
}
|
|
119
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
120
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
124
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
125
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: NeuTooltipDirective, isStandalone: true, selector: "[neuTooltip]", inputs: { neuTooltip: { classPropertyName: "neuTooltip", publicName: "neuTooltip", isSignal: true, isRequired: true, transformFunction: null }, neuTooltipPosition: { classPropertyName: "neuTooltipPosition", publicName: "neuTooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, neuTooltipDisabled: { classPropertyName: "neuTooltipDisabled", publicName: "neuTooltipDisabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "focus": "show()", "mouseleave": "hide()", "blur": "hide()" }, properties: { "attr.aria-describedby": "_tooltipId", "attr.tabindex": "_needsTabindex() ? \"0\" : null" } }, ngImport: i0 });
|
|
121
126
|
}
|
|
122
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
127
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuTooltipDirective, decorators: [{
|
|
123
128
|
type: Directive,
|
|
124
129
|
args: [{
|
|
125
130
|
selector: '[neuTooltip]',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neural-ui-core-tooltip.mjs","sources":["../../../../projects/ui-core/tooltip/neu-tooltip.component.ts","../../../../projects/ui-core/tooltip/neu-tooltip.directive.ts","../../../../projects/ui-core/tooltip/neural-ui-core-tooltip.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation, input } from '@angular/core';\n\n/** @internal — componente flotante del tooltip, renderizado vía CDK Portal / floating tooltip component, rendered via CDK Portal */\n@Component({\n selector: 'neu-tooltip-overlay',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'neu-tooltip',\n role: 'tooltip',\n '[id]': 'tooltipId()',\n },\n template: `<span class=\"neu-tooltip__text\">{{ text() }}</span>`,\n styleUrl: './neu-tooltip.component.scss',\n})\nexport class NeuTooltipOverlayComponent {\n readonly text = input.required<string>();\n readonly tooltipId = input<string>('');\n}\n","import {\n ComponentRef,\n Directive,\n ElementRef,\n HostListener,\n Injector,\n OnDestroy,\n inject,\n input,\n} from '@angular/core';\nimport { Overlay, OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { ConnectedPosition } from '@angular/cdk/overlay';\nimport { NeuTooltipOverlayComponent } from './neu-tooltip.component';\n\nexport type NeuTooltipPosition = 'top' | 'bottom' | 'left' | 'right';\n\n/**\n * NeuralUI Tooltip Directive\n *\n * Muestra un globo informativo al hacer hover/focus sobre el elemento host.\n * Usa CDK Overlay para posicionamiento robusto.\n *\n * Uso:\n * <button [neuTooltip]=\"'Guardar cambios'\">Guardar</button>\n * <button [neuTooltip]=\"'Eliminar'\" neuTooltipPosition=\"bottom\">Eliminar</button>\n */\n@Directive({\n selector: '[neuTooltip]',\n host: {\n '[attr.aria-describedby]': '_tooltipId',\n // Sólo añadimos tabindex en elementos que no son nativamente focusables\n '[attr.tabindex]': '_needsTabindex() ? \"0\" : null',\n },\n})\nexport class NeuTooltipDirective implements OnDestroy {\n readonly neuTooltip = input.required<string>();\n readonly neuTooltipPosition = input<NeuTooltipPosition>('top');\n readonly neuTooltipDisabled = input<boolean>(false);\n\n private readonly _overlay = inject(Overlay);\n private readonly _elementRef = inject(ElementRef<HTMLElement>);\n private readonly _injector = inject(Injector);\n\n readonly _tooltipId = `neu-tooltip-${Math.random().toString(36).slice(2, 7)}`;\n\n /** Elementos HTML nativamente focusables que no necesitan tabindex extra / Natively focusable HTML elements that don't need extra tabindex */\n private readonly _NATIVE_FOCUSABLE = /^(a|button|input|select|textarea|details|summary)$/i;\n protected readonly _needsTabindex = () =>\n !this._NATIVE_FOCUSABLE.test(this._elementRef.nativeElement.tagName);\n\n private _overlayRef: OverlayRef | null = null;\n private _tooltipRef: ComponentRef<NeuTooltipOverlayComponent> | null = null;\n private _hideTimeout: ReturnType<typeof setTimeout> | null = null;\n\n @HostListener('mouseenter')\n @HostListener('focus')\n show(): void {\n if (this.neuTooltipDisabled() || !this.neuTooltip()) return;\n if (this._hideTimeout) {\n clearTimeout(this._hideTimeout);\n this._hideTimeout = null;\n }\n if (this._overlayRef?.hasAttached()) return;\n\n this._createOverlay();\n const portal = new ComponentPortal(NeuTooltipOverlayComponent, null, this._injector);\n this._tooltipRef = this._overlayRef!.attach(portal);\n this._tooltipRef!.setInput('text', this.neuTooltip());\n this._tooltipRef!.setInput('tooltipId', this._tooltipId);\n }\n\n @HostListener('mouseleave')\n @HostListener('blur')\n hide(): void {\n this._hideTimeout = setTimeout(() => this._detach(), 100);\n }\n\n private _createOverlay(): void {\n if (this._overlayRef) return;\n\n const positionStrategy = this._overlay\n .position()\n .flexibleConnectedTo(this._elementRef)\n .withPositions(this._getPositions());\n\n this._overlayRef = this._overlay.create({\n positionStrategy,\n scrollStrategy: this._overlay.scrollStrategies.reposition(),\n panelClass: 'neu-tooltip-panel',\n });\n }\n\n private _getPositions(): ConnectedPosition[] {\n const map: Record<NeuTooltipPosition, ConnectedPosition> = {\n top: {\n originX: 'center',\n originY: 'top',\n overlayX: 'center',\n overlayY: 'bottom',\n offsetY: -8,\n },\n bottom: {\n originX: 'center',\n originY: 'bottom',\n overlayX: 'center',\n overlayY: 'top',\n offsetY: 8,\n },\n left: {\n originX: 'start',\n originY: 'center',\n overlayX: 'end',\n overlayY: 'center',\n offsetX: -8,\n },\n right: {\n originX: 'end',\n originY: 'center',\n overlayX: 'start',\n overlayY: 'center',\n offsetX: 8,\n },\n };\n return [map[this.neuTooltipPosition()], map['top'], map['bottom']];\n }\n\n private _detach(): void {\n this._overlayRef?.detach();\n this._tooltipRef = null;\n }\n\n ngOnDestroy(): void {\n if (this._hideTimeout) clearTimeout(this._hideTimeout);\n this._overlayRef?.dispose();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":";;;;;AAEA;MAaa,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"neural-ui-core-tooltip.mjs","sources":["../../../../projects/ui-core/tooltip/neu-tooltip.component.ts","../../../../projects/ui-core/tooltip/neu-tooltip.directive.ts","../../../../projects/ui-core/tooltip/neural-ui-core-tooltip.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation, input } from '@angular/core';\n\n/** @internal — componente flotante del tooltip, renderizado vía CDK Portal / floating tooltip component, rendered via CDK Portal */\n@Component({\n selector: 'neu-tooltip-overlay',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'neu-tooltip',\n role: 'tooltip',\n '[id]': 'tooltipId()',\n },\n template: `<span class=\"neu-tooltip__text\">{{ text() }}</span>`,\n styleUrl: './neu-tooltip.component.scss',\n})\nexport class NeuTooltipOverlayComponent {\n readonly text = input.required<string>();\n readonly tooltipId = input<string>('');\n}\n","import {\n ComponentRef,\n Directive,\n ElementRef,\n HostListener,\n Injector,\n OnDestroy,\n inject,\n input,\n} from '@angular/core';\nimport { Overlay, OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { ConnectedPosition } from '@angular/cdk/overlay';\nimport { NeuTooltipOverlayComponent } from './neu-tooltip.component';\n\nexport type NeuTooltipPosition = 'top' | 'bottom' | 'left' | 'right';\n\n/**\n * NeuralUI Tooltip Directive\n *\n * Muestra un globo informativo al hacer hover/focus sobre el elemento host.\n * Usa CDK Overlay para posicionamiento robusto.\n *\n * Uso:\n * <button [neuTooltip]=\"'Guardar cambios'\">Guardar</button>\n * <button [neuTooltip]=\"'Eliminar'\" neuTooltipPosition=\"bottom\">Eliminar</button>\n */\n@Directive({\n selector: '[neuTooltip]',\n host: {\n '[attr.aria-describedby]': '_tooltipId',\n // Sólo añadimos tabindex en elementos que no son nativamente focusables\n '[attr.tabindex]': '_needsTabindex() ? \"0\" : null',\n },\n})\nexport class NeuTooltipDirective implements OnDestroy {\n readonly neuTooltip = input.required<string>();\n readonly neuTooltipPosition = input<NeuTooltipPosition>('top');\n readonly neuTooltipDisabled = input<boolean>(false);\n\n private readonly _overlay = inject(Overlay);\n private readonly _elementRef = inject(ElementRef<HTMLElement>);\n private readonly _injector = inject(Injector);\n\n readonly _tooltipId = `neu-tooltip-${Math.random().toString(36).slice(2, 7)}`;\n\n /** Elementos HTML nativamente focusables que no necesitan tabindex extra / Natively focusable HTML elements that don't need extra tabindex */\n private readonly _NATIVE_FOCUSABLE = /^(a|button|input|select|textarea|details|summary)$/i;\n protected readonly _needsTabindex = () =>\n !this._NATIVE_FOCUSABLE.test(this._elementRef.nativeElement.tagName);\n\n private _overlayRef: OverlayRef | null = null;\n private _tooltipRef: ComponentRef<NeuTooltipOverlayComponent> | null = null;\n private _hideTimeout: ReturnType<typeof setTimeout> | null = null;\n\n @HostListener('mouseenter')\n @HostListener('focus')\n show(): void {\n if (this.neuTooltipDisabled() || !this.neuTooltip()) return;\n if (this._hideTimeout) {\n clearTimeout(this._hideTimeout);\n this._hideTimeout = null;\n }\n if (this._overlayRef?.hasAttached()) return;\n\n this._createOverlay();\n const portal = new ComponentPortal(NeuTooltipOverlayComponent, null, this._injector);\n this._tooltipRef = this._overlayRef!.attach(portal);\n this._tooltipRef!.setInput('text', this.neuTooltip());\n this._tooltipRef!.setInput('tooltipId', this._tooltipId);\n }\n\n @HostListener('mouseleave')\n @HostListener('blur')\n hide(): void {\n this._hideTimeout = setTimeout(() => this._detach(), 100);\n }\n\n private _createOverlay(): void {\n if (this._overlayRef) return;\n\n const positionStrategy = this._overlay\n .position()\n .flexibleConnectedTo(this._elementRef)\n .withPositions(this._getPositions());\n\n this._overlayRef = this._overlay.create({\n positionStrategy,\n scrollStrategy: this._overlay.scrollStrategies.reposition(),\n panelClass: 'neu-tooltip-panel',\n });\n }\n\n private _getPositions(): ConnectedPosition[] {\n const map: Record<NeuTooltipPosition, ConnectedPosition> = {\n top: {\n originX: 'center',\n originY: 'top',\n overlayX: 'center',\n overlayY: 'bottom',\n offsetY: -8,\n },\n bottom: {\n originX: 'center',\n originY: 'bottom',\n overlayX: 'center',\n overlayY: 'top',\n offsetY: 8,\n },\n left: {\n originX: 'start',\n originY: 'center',\n overlayX: 'end',\n overlayY: 'center',\n offsetX: -8,\n },\n right: {\n originX: 'end',\n originY: 'center',\n overlayX: 'start',\n overlayY: 'center',\n offsetX: 8,\n },\n };\n return [map[this.neuTooltipPosition()], map['top'], map['bottom']];\n }\n\n private _detach(): void {\n this._overlayRef?.detach();\n this._tooltipRef = null;\n }\n\n ngOnDestroy(): void {\n if (this._hideTimeout) clearTimeout(this._hideTimeout);\n this._overlayRef?.dispose();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|