@neural-ui/core 1.6.0 → 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 +63 -30
- package/fesm2022/neural-ui-core-rich-text-editor.mjs.map +1 -1
- 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 +1 -1
- package/types/neural-ui-core-notification-center.d.ts +2 -0
- package/types/neural-ui-core-toast.d.ts +2 -0
|
@@ -12,26 +12,35 @@ class NeuNavComponent {
|
|
|
12
12
|
currentUrl = toSignal(this.router.events.pipe(filter((e) => e instanceof NavigationEnd)), { initialValue: null });
|
|
13
13
|
// ---- Inputs ----
|
|
14
14
|
/** Lista de ítems de navegación / Navigation item list */
|
|
15
|
-
items = input([],
|
|
15
|
+
items = input([], /* @ts-ignore */
|
|
16
|
+
...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
16
17
|
/** Estado inicial colapsado / Initial collapsed state */
|
|
17
|
-
collapsed = input(false,
|
|
18
|
+
collapsed = input(false, /* @ts-ignore */
|
|
19
|
+
...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
18
20
|
/** Muestra el botón de colapsar/expandir / Shows the collapse/expand button */
|
|
19
|
-
collapsible = input(true,
|
|
21
|
+
collapsible = input(true, /* @ts-ignore */
|
|
22
|
+
...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
|
|
20
23
|
/** Etiqueta accesible del <nav> / Accessible label for the <nav> */
|
|
21
|
-
ariaLabel = input('Navegación principal',
|
|
24
|
+
ariaLabel = input('Navegación principal', /* @ts-ignore */
|
|
25
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
22
26
|
/** Aria-label del botón cuando el nav está colapsado / Aria-label for the button when the nav is collapsed */
|
|
23
|
-
expandLabel = input('Expandir menú',
|
|
27
|
+
expandLabel = input('Expandir menú', /* @ts-ignore */
|
|
28
|
+
...(ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []));
|
|
24
29
|
/** Aria-label del botón cuando el nav está expandido / Aria-label for the button when the nav is expanded */
|
|
25
|
-
collapseLabel = input('Colapsar menú',
|
|
30
|
+
collapseLabel = input('Colapsar menú', /* @ts-ignore */
|
|
31
|
+
...(ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []));
|
|
26
32
|
/** Emite cuando cambia el estado colapsado / Emits when the collapsed state changes */
|
|
27
33
|
collapsedChange = output();
|
|
28
34
|
// ---- Estado interno / Internal state ----
|
|
29
35
|
// Sigue el input `collapsed` del padre (permite el configurador)
|
|
30
36
|
// pero puede ser sobreescrito localmente con toggleCollapse()
|
|
31
|
-
isCollapsed = linkedSignal(() => this.collapsed(),
|
|
32
|
-
|
|
37
|
+
isCollapsed = linkedSignal(() => this.collapsed(), /* @ts-ignore */
|
|
38
|
+
...(ngDevMode ? [{ debugName: "isCollapsed" }] : /* istanbul ignore next */ []));
|
|
39
|
+
openGroups = signal(new Set(), /* @ts-ignore */
|
|
40
|
+
...(ngDevMode ? [{ debugName: "openGroups" }] : /* istanbul ignore next */ []));
|
|
33
41
|
// ---- Flyout para modo colapsado / Flyout for collapsed mode ----
|
|
34
|
-
flyoutState = signal(null,
|
|
42
|
+
flyoutState = signal(null, /* @ts-ignore */
|
|
43
|
+
...(ngDevMode ? [{ debugName: "flyoutState" }] : /* istanbul ignore next */ []));
|
|
35
44
|
_flyoutTimer = null;
|
|
36
45
|
constructor() {
|
|
37
46
|
// Abrimos el grupo activo DESPUÉS de que el padre haya pasado los inputs
|
|
@@ -124,8 +133,8 @@ class NeuNavComponent {
|
|
|
124
133
|
this.openGroups.set(toOpen);
|
|
125
134
|
}
|
|
126
135
|
}
|
|
127
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
128
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
136
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
137
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NeuNavComponent, isStandalone: true, selector: "neu-nav", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, expandLabel: { classPropertyName: "expandLabel", publicName: "expandLabel", isSignal: true, isRequired: false, transformFunction: null }, collapseLabel: { classPropertyName: "collapseLabel", publicName: "collapseLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsedChange: "collapsedChange" }, ngImport: i0, template: `
|
|
129
138
|
<div class="neu-nav-wrapper" [class.neu-nav-wrapper--collapsed]="isCollapsed()">
|
|
130
139
|
<nav
|
|
131
140
|
class="neu-nav"
|
|
@@ -530,9 +539,9 @@ class NeuNavComponent {
|
|
|
530
539
|
</button>
|
|
531
540
|
}
|
|
532
541
|
</div>
|
|
533
|
-
`, isInline: true, styles: ["@charset \"UTF-8\";.neu-nav{display:flex;flex-direction:column;width:268px;height:100%;background:var(--neu-surface);border-right:1px solid var(--neu-border);transition:width .28s cubic-bezier(.4,0,.2,1);overflow:hidden;flex-shrink:0;-webkit-user-select:none;user-select:none}.neu-nav--collapsed{width:64px}.neu-nav--collapsed .neu-nav__brand{justify-content:center;padding:0;gap:0}.neu-nav--collapsed .neu-nav__brand-content{flex:0 0 0;width:0;opacity:0;overflow:hidden;pointer-events:none}.neu-nav--collapsed .neu-nav__items{padding-left:0;padding-right:0}.neu-nav--collapsed .neu-nav__item{justify-content:center;width:64px;padding:0;gap:0}.neu-nav--collapsed .neu-nav__item--parent .neu-nav__group-chevron{margin-left:0}.neu-nav--collapsed .neu-nav__item-label,.neu-nav--collapsed .neu-nav__item-badge,.neu-nav--collapsed .neu-nav__group-chevron,.neu-nav--collapsed .neu-nav__external-icon{flex:0 0 0;width:0;margin:0;opacity:0;overflow:hidden;pointer-events:none;white-space:nowrap}.neu-nav--collapsed .neu-nav__footer{height:0;opacity:0;overflow:hidden;pointer-events:none}.neu-nav__brand{display:flex;align-items:center;justify-content:space-between;min-height:64px;padding:0 var(--neu-space-4);border-bottom:1px solid var(--neu-border);flex-shrink:0;gap:var(--neu-space-3)}.neu-nav__brand-content{flex:1;min-width:0;display:flex;align-items:center;gap:10px;transition:opacity .2s ease,width .28s cubic-bezier(.4,0,.2,1);overflow:hidden}.neu-nav__brand-icon{display:none;align-items:center;justify-content:center;width:64px;height:64px;flex-shrink:0;background:none;border:none;cursor:pointer;padding:0;color:inherit}.neu-nav__brand-icon:focus-visible{outline:2px solid var(--neu-primary);outline-offset:-2px}.neu-nav--collapsed .neu-nav__brand-icon{display:flex}.neu-nav-wrapper{position:relative;height:100%;flex-shrink:0;display:flex}.neu-nav__toggle-tab{position:absolute;right:-13px;top:16px;transform:none;width:13px;height:40px;display:flex;align-items:center;justify-content:center;background:var(--neu-surface);border:1px solid var(--neu-border);border-left:none;border-radius:0 6px 6px 0;color:var(--neu-text-muted);cursor:pointer;padding:0;z-index:10;transition:background var(--neu-transition),color var(--neu-transition)}.neu-nav__toggle-tab:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-nav__toggle-tab:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-nav__items{flex:1;overflow-y:auto;overflow-x:hidden;padding:var(--neu-space-3) var(--neu-space-2);display:flex;flex-direction:column;gap:2px}.neu-nav__items::-webkit-scrollbar{width:4px}.neu-nav__items::-webkit-scrollbar-track{background:transparent}.neu-nav__items::-webkit-scrollbar-thumb{background:var(--neu-border);border-radius:4px}.neu-nav__item{position:relative;display:flex;align-items:center;gap:10px;height:40px;padding:0 var(--neu-space-3);border-radius:8px;font-size:var(--neu-text-sm);font-weight:500;color:var(--neu-text-muted);text-decoration:none;cursor:pointer;background:none;border:none;font-family:inherit;width:100%;text-align:left;transition:background var(--neu-transition),color var(--neu-transition);white-space:nowrap;flex-shrink:0}.neu-nav__item:focus-visible{outline:2px solid var(--neu-primary);outline-offset:-2px}.neu-nav__item:hover:not(.neu-nav__item--disabled){background:var(--neu-surface-2);color:var(--neu-text)}.neu-nav__item:hover:not(.neu-nav__item--disabled) .neu-nav__item-icon{color:var(--neu-text)}.neu-nav__item--active{background:var(--neu-primary-50);color:var(--neu-primary-dark, var(--neu-primary));font-weight:600}.neu-nav__item--active .neu-nav__item-icon{color:var(--neu-primary-dark, var(--neu-primary))}.neu-nav__item--active:before{content:\"\";position:absolute;left:0;top:6px;bottom:6px;width:3px;background:var(--neu-primary-dark, var(--neu-primary));border-radius:0 var(--neu-radius-full) var(--neu-radius-full) 0}.neu-nav__item--disabled{opacity:1;color:var(--neu-text-disabled);cursor:not-allowed;pointer-events:none}.neu-nav__item--disabled .neu-nav__item-icon{color:var(--neu-text-disabled)}.neu-nav__item--child{height:36px;padding-left:calc(var(--neu-space-3) + 6px);font-size:.8125rem}.neu-nav__item--parent .neu-nav__group-chevron{margin-left:auto;flex-shrink:0;transition:transform var(--neu-transition);color:var(--neu-text-disabled)}.neu-nav__item-icon{flex-shrink:0;color:var(--neu-text-disabled);transition:color var(--neu-transition)}.neu-nav__item-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease,width .28s cubic-bezier(.4,0,.2,1)}.neu-nav__item-badge{flex-shrink:0;font-size:10px;font-weight:700;line-height:1;padding:2px 6px;border-radius:var(--neu-radius-full);text-transform:uppercase;letter-spacing:.04em;transition:opacity .2s ease}.neu-nav__item-badge--default{background:var(--neu-surface-3);color:var(--neu-text-muted)}.neu-nav__item-badge--success{background:var(--neu-success-bg);color:var(--neu-success-text)}.neu-nav__item-badge--warning{background:var(--neu-warning-bg);color:var(--neu-warning-text)}.neu-nav__item-badge--danger{background:var(--neu-error-bg);color:var(--neu-error-text)}.neu-nav__item-badge--info{background:var(--neu-info-bg);color:var(--neu-info-text)}.neu-nav__group{display:flex;flex-direction:column}.neu-nav__group--open .neu-nav__group-chevron{transform:rotate(90deg)}.neu-nav__group--open>.neu-nav__item--parent{color:var(--neu-text);background:var(--neu-surface-2)}.neu-nav__group--open>.neu-nav__item--parent .neu-nav__item-icon{color:var(--neu-text-muted)}.neu-nav__submenu{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px var(--neu-space-3);margin-top:2px;border-left:2px solid var(--neu-border);margin-left:calc(var(--neu-space-3) + 9px)}.neu-nav__submenu--nested{padding-left:var(--neu-space-2);margin-left:calc(var(--neu-space-2) + 7px);border-color:var(--neu-border);border-left-style:dashed}.neu-nav__item--grandchild{height:32px;padding-left:calc(var(--neu-space-2) + 4px);font-size:.75rem}.neu-nav__external-icon{flex-shrink:0;margin-left:auto;color:var(--neu-text-disabled);opacity:.7;transition:opacity var(--neu-transition),color var(--neu-transition)}.neu-nav__item:hover .neu-nav__external-icon{opacity:1;color:var(--neu-text-muted)}.neu-nav__footer{border-top:1px solid var(--neu-border);padding:var(--neu-space-3) var(--neu-space-4);flex-shrink:0;font-size:var(--neu-text-xs);color:var(--neu-text-muted);transition:opacity .2s ease,height .28s cubic-bezier(.4,0,.2,1)}.neu-nav--collapsed .neu-nav__item--parent:after{content:\"\\203a\";position:absolute;right:8px;top:50%;transform:translateY(-50%);font-size:11px;line-height:1;color:var(--neu-text-disabled);pointer-events:none}.neu-nav__flyout{position:fixed;z-index:1000;min-width:200px;max-width:240px;background:var(--neu-surface);border:1px solid var(--neu-border);border-radius:8px;box-shadow:0 4px 20px #0000001f;padding:6px;margin-left:6px}.neu-nav__flyout-title{font-size:.6875rem;font-weight:700;color:var(--neu-text-muted);text-transform:uppercase;letter-spacing:.06em;padding:4px 8px 6px}.neu-nav__flyout-item{display:flex;align-items:center;gap:8px;height:34px;padding:0 8px;border-radius:6px;font-size:.8125rem;color:var(--neu-text-muted);text-decoration:none;cursor:pointer;white-space:nowrap;transition:background var(--neu-transition),color var(--neu-transition)}.neu-nav__flyout-item:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-nav__flyout-item--active{background:var(--neu-primary-50);color:var(--neu-primary);font-weight:600}.neu-nav__flyout-item .neu-nav__external-icon{margin-left:auto;opacity:.6}.neu-nav__flyout-group{margin-top:4px;padding-top:4px;border-top:1px solid var(--neu-border)}.neu-nav__flyout-group-label{display:block;font-size:.6875rem;font-weight:600;color:var(--neu-text-disabled);text-transform:uppercase;letter-spacing:.05em;padding:2px 8px 4px}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: NeuIconComponent, selector: "neu-icon", inputs: ["name", "strokeWidth", "size"] }, { kind: "directive", type: NeuTooltipDirective, selector: "[neuTooltip]", inputs: ["neuTooltip", "neuTooltipPosition", "neuTooltipDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
542
|
+
`, isInline: true, styles: ["@charset \"UTF-8\";.neu-nav{display:flex;flex-direction:column;width:268px;height:100%;background:var(--neu-surface);border-right:1px solid var(--neu-border);transition:width .28s cubic-bezier(.4,0,.2,1);overflow:hidden;flex-shrink:0;-webkit-user-select:none;user-select:none}.neu-nav--collapsed{width:64px}.neu-nav--collapsed .neu-nav__brand{justify-content:center;padding:0;gap:0}.neu-nav--collapsed .neu-nav__brand-content{flex:0 0 0;width:0;opacity:0;overflow:hidden;pointer-events:none}.neu-nav--collapsed .neu-nav__items{padding-left:0;padding-right:0}.neu-nav--collapsed .neu-nav__item{justify-content:center;width:64px;padding:0;gap:0}.neu-nav--collapsed .neu-nav__item--parent .neu-nav__group-chevron{margin-left:0}.neu-nav--collapsed .neu-nav__item-label,.neu-nav--collapsed .neu-nav__item-badge,.neu-nav--collapsed .neu-nav__group-chevron,.neu-nav--collapsed .neu-nav__external-icon{flex:0 0 0;width:0;margin:0;opacity:0;overflow:hidden;pointer-events:none;white-space:nowrap}.neu-nav--collapsed .neu-nav__footer{height:0;opacity:0;overflow:hidden;pointer-events:none}.neu-nav__brand{display:flex;align-items:center;justify-content:space-between;min-height:64px;padding:0 var(--neu-space-4);border-bottom:1px solid var(--neu-border);flex-shrink:0;gap:var(--neu-space-3)}.neu-nav__brand-content{flex:1;min-width:0;display:flex;align-items:center;gap:10px;transition:opacity .2s ease,width .28s cubic-bezier(.4,0,.2,1);overflow:hidden}.neu-nav__brand-icon{display:none;align-items:center;justify-content:center;width:64px;height:64px;flex-shrink:0;background:none;border:none;cursor:pointer;padding:0;color:inherit}.neu-nav__brand-icon:focus-visible{outline:2px solid var(--neu-primary);outline-offset:-2px}.neu-nav--collapsed .neu-nav__brand-icon{display:flex}.neu-nav-wrapper{position:relative;height:100%;flex-shrink:0;display:flex}.neu-nav__toggle-tab{position:absolute;right:-13px;top:16px;transform:none;width:13px;height:40px;display:flex;align-items:center;justify-content:center;background:var(--neu-surface);border:1px solid var(--neu-border);border-left:none;border-radius:0 6px 6px 0;color:var(--neu-text-muted);cursor:pointer;padding:0;z-index:10;transition:background var(--neu-transition),color var(--neu-transition)}.neu-nav__toggle-tab:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-nav__toggle-tab:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-nav__items{flex:1;overflow-y:auto;overflow-x:hidden;padding:var(--neu-space-3) var(--neu-space-2);display:flex;flex-direction:column;gap:2px}.neu-nav__items::-webkit-scrollbar{width:4px}.neu-nav__items::-webkit-scrollbar-track{background:transparent}.neu-nav__items::-webkit-scrollbar-thumb{background:var(--neu-border);border-radius:4px}.neu-nav__item{position:relative;display:flex;align-items:center;gap:10px;height:40px;padding:0 var(--neu-space-3);border-radius:8px;font-size:var(--neu-text-sm);font-weight:500;color:var(--neu-text-muted);text-decoration:none;cursor:pointer;background:none;border:none;font-family:inherit;width:100%;text-align:left;transition:background var(--neu-transition),color var(--neu-transition);white-space:nowrap;flex-shrink:0}.neu-nav__item:focus-visible{outline:2px solid var(--neu-primary);outline-offset:-2px}.neu-nav__item:hover:not(.neu-nav__item--disabled){background:var(--neu-surface-2);color:var(--neu-text)}.neu-nav__item:hover:not(.neu-nav__item--disabled) .neu-nav__item-icon{color:var(--neu-text)}.neu-nav__item--active{background:var(--neu-primary-50);color:var(--neu-primary-dark, var(--neu-primary));font-weight:600}.neu-nav__item--active .neu-nav__item-icon{color:var(--neu-primary-dark, var(--neu-primary))}.neu-nav__item--active:before{content:\"\";position:absolute;left:0;top:6px;bottom:6px;width:3px;background:var(--neu-primary-dark, var(--neu-primary));border-radius:0 var(--neu-radius-full) var(--neu-radius-full) 0}.neu-nav__item--disabled{opacity:1;color:var(--neu-text-disabled);cursor:not-allowed;pointer-events:none}.neu-nav__item--disabled .neu-nav__item-icon{color:var(--neu-text-disabled)}.neu-nav__item--child{height:36px;padding-left:calc(var(--neu-space-3) + 6px);font-size:.8125rem}.neu-nav__item--parent .neu-nav__group-chevron{margin-left:auto;flex-shrink:0;transition:transform var(--neu-transition);color:var(--neu-text-disabled)}.neu-nav__item-icon{flex-shrink:0;color:var(--neu-text-disabled);transition:color var(--neu-transition)}.neu-nav__item-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease,width .28s cubic-bezier(.4,0,.2,1)}.neu-nav__item-badge{flex-shrink:0;font-size:10px;font-weight:700;line-height:1;padding:2px 6px;border-radius:var(--neu-radius-full);text-transform:uppercase;letter-spacing:.04em;transition:opacity .2s ease}.neu-nav__item-badge--default{background:var(--neu-surface-3);color:var(--neu-text-muted)}.neu-nav__item-badge--success{background:var(--neu-success-bg);color:var(--neu-success-text)}.neu-nav__item-badge--warning{background:var(--neu-warning-bg);color:var(--neu-warning-text)}.neu-nav__item-badge--danger{background:var(--neu-error-bg);color:var(--neu-error-text)}.neu-nav__item-badge--info{background:var(--neu-info-bg);color:var(--neu-info-text)}.neu-nav__group{display:flex;flex-direction:column}.neu-nav__group--open .neu-nav__group-chevron{transform:rotate(90deg)}.neu-nav__group--open>.neu-nav__item--parent{color:var(--neu-text);background:var(--neu-surface-2)}.neu-nav__group--open>.neu-nav__item--parent .neu-nav__item-icon{color:var(--neu-text-muted)}.neu-nav__submenu{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px var(--neu-space-3);margin-top:2px;border-left:2px solid var(--neu-border);margin-left:calc(var(--neu-space-3) + 9px)}.neu-nav__submenu--nested{padding-left:var(--neu-space-2);margin-left:calc(var(--neu-space-2) + 7px);border-color:var(--neu-border);border-left-style:dashed}.neu-nav__item--grandchild{height:32px;padding-left:calc(var(--neu-space-2) + 4px);font-size:.75rem}.neu-nav__external-icon{flex-shrink:0;margin-left:auto;color:var(--neu-text-disabled);opacity:.7;transition:opacity var(--neu-transition),color var(--neu-transition)}.neu-nav__item:hover .neu-nav__external-icon{opacity:1;color:var(--neu-text-muted)}.neu-nav__footer{border-top:1px solid var(--neu-border);padding:var(--neu-space-3) var(--neu-space-4);flex-shrink:0;font-size:var(--neu-text-xs);color:var(--neu-text-muted);transition:opacity .2s ease,height .28s cubic-bezier(.4,0,.2,1)}.neu-nav--collapsed .neu-nav__item--parent:after{content:\"\\203a\";position:absolute;right:8px;top:50%;transform:translateY(-50%);font-size:11px;line-height:1;color:var(--neu-text-disabled);pointer-events:none}.neu-nav__flyout{position:fixed;z-index:1000;min-width:200px;max-width:240px;background:var(--neu-surface);border:1px solid var(--neu-border);border-radius:8px;box-shadow:0 4px 20px #0000001f;padding:6px;margin-left:6px}.neu-nav__flyout-title{font-size:.6875rem;font-weight:700;color:var(--neu-text-muted);text-transform:uppercase;letter-spacing:.06em;padding:4px 8px 6px}.neu-nav__flyout-item{display:flex;align-items:center;gap:8px;height:34px;padding:0 8px;border-radius:6px;font-size:.8125rem;color:var(--neu-text-muted);text-decoration:none;cursor:pointer;white-space:nowrap;transition:background var(--neu-transition),color var(--neu-transition)}.neu-nav__flyout-item:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-nav__flyout-item--active{background:var(--neu-primary-50);color:var(--neu-primary);font-weight:600}.neu-nav__flyout-item .neu-nav__external-icon{margin-left:auto;opacity:.6}.neu-nav__flyout-group{margin-top:4px;padding-top:4px;border-top:1px solid var(--neu-border)}.neu-nav__flyout-group-label{display:block;font-size:.6875rem;font-weight:600;color:var(--neu-text-disabled);text-transform:uppercase;letter-spacing:.05em;padding:2px 8px 4px}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: NeuIconComponent, selector: "neu-icon", inputs: ["name", "strokeWidth", "size"] }, { kind: "directive", type: NeuTooltipDirective, selector: "[neuTooltip]", inputs: ["neuTooltip", "neuTooltipPosition", "neuTooltipDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
534
543
|
}
|
|
535
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
544
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuNavComponent, decorators: [{
|
|
536
545
|
type: Component,
|
|
537
546
|
args: [{ selector: 'neu-nav', imports: [RouterLink, RouterLinkActive, NeuIconComponent, NeuTooltipDirective], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
538
547
|
<div class="neu-nav-wrapper" [class.neu-nav-wrapper--collapsed]="isCollapsed()">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neural-ui-core-nav.mjs","sources":["../../../../projects/ui-core/nav/neu-nav.component.ts","../../../../projects/ui-core/nav/neural-ui-core-nav.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ViewEncapsulation,\n afterNextRender,\n inject,\n input,\n linkedSignal,\n output,\n signal,\n} from '@angular/core';\nimport { RouterLink, RouterLinkActive, Router, NavigationEnd } from '@angular/router';\nimport { filter } from 'rxjs';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\nimport { NeuTooltipDirective } from '@neural-ui/core/tooltip';\n\n// ---- Tipos públicos / Public types ----\n\n/**\n * Ítem de navegación con soporte para 3 niveles de profundidad.\n *\n * Destino del enlace — usa UNO de los dos:\n * - `route` → navegación interna Angular (RouterLink)\n * - `href` → URL externa, se abre en nueva pestaña con rel=\"noopener noreferrer\"\n *\n * Los ítems con `children` actúan como grupo acordeón (sin destino propio).\n * Máximo 3 niveles: raíz → hijos → nietos.\n * Los nietos no pueden tener `children`.\n */\nexport interface NeuNavItem {\n id: string;\n label: string;\n icon: string;\n /** Ruta Angular interna (RouterLink). Excluye `href`. / Internal Angular route (RouterLink). Excludes `href`. */\n route?: string;\n /** URL externa. Se abre en nueva pestaña. Excluye `route`. / External URL. Opens in a new tab. Excludes `route`. */\n href?: string;\n /** Ítems hijo (nivel 2). Cada hijo puede tener sus propios `children` (nivel 3). / Child items (level 2). Each child can have its own `children` (level 3). */\n children?: NeuNavItem[];\n badge?: string;\n badgeVariant?: 'default' | 'success' | 'warning' | 'danger' | 'info';\n disabled?: boolean;\n}\n\n@Component({\n selector: 'neu-nav',\n imports: [RouterLink, RouterLinkActive, NeuIconComponent, NeuTooltipDirective],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"neu-nav-wrapper\" [class.neu-nav-wrapper--collapsed]=\"isCollapsed()\">\n <nav\n class=\"neu-nav\"\n [class.neu-nav--collapsed]=\"isCollapsed()\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n <!-- Brand slot -->\n <div class=\"neu-nav__brand\">\n <!-- Icono visible solo en modo colapsado -->\n <div class=\"neu-nav__brand-icon\">\n <ng-content select=\"[neu-nav-brand-icon]\" />\n </div>\n <!-- Contenido completo visible en modo expandido -->\n <div class=\"neu-nav__brand-content\">\n <ng-content select=\"[neu-nav-brand]\" />\n </div>\n </div>\n\n <!-- Items (nivel 1) -->\n <div class=\"neu-nav__items\" role=\"list\">\n @for (item of items(); track item.id) {\n @if (item.children?.length) {\n <!-- NIVEL 1 — Grupo acordeón -->\n <div\n class=\"neu-nav__group\"\n [class.neu-nav__group--open]=\"isGroupOpen(item.id)\"\n role=\"listitem\"\n (mouseenter)=\"onGroupMouseEnter(item, $event)\"\n (mouseleave)=\"onGroupMouseLeave()\"\n >\n <button\n class=\"neu-nav__item neu-nav__item--parent\"\n type=\"button\"\n [class.neu-nav__item--active]=\"isGroupActive(item)\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [attr.aria-expanded]=\"isGroupOpen(item.id)\"\n [attr.aria-haspopup]=\"true\"\n [attr.disabled]=\"item.disabled ? '' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n (click)=\"!isCollapsed() && toggleGroup(item.id)\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideChevronRight\"\n size=\"14px\"\n class=\"neu-nav__group-chevron\"\n aria-hidden=\"true\"\n />\n </button>\n\n <!-- Submenú nivel 2 -->\n @if (!isCollapsed() && isGroupOpen(item.id)) {\n <div class=\"neu-nav__submenu\" role=\"list\">\n @for (child of item.children; track child.id) {\n @if (child.children?.length) {\n <!-- NIVEL 2 — Subgrupo acordeón -->\n <div\n class=\"neu-nav__group neu-nav__group--nested\"\n [class.neu-nav__group--open]=\"isGroupOpen(child.id)\"\n role=\"listitem\"\n >\n <button\n class=\"neu-nav__item neu-nav__item--child neu-nav__item--parent\"\n type=\"button\"\n [class.neu-nav__item--active]=\"isGroupActive(child)\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [attr.aria-expanded]=\"isGroupOpen(child.id)\"\n [attr.aria-haspopup]=\"true\"\n [attr.disabled]=\"child.disabled ? '' : null\"\n (click)=\"toggleGroup(child.id)\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideChevronRight\"\n size=\"13px\"\n class=\"neu-nav__group-chevron\"\n aria-hidden=\"true\"\n />\n </button>\n\n <!-- Submenú nivel 3 -->\n @if (isGroupOpen(child.id)) {\n <div class=\"neu-nav__submenu neu-nav__submenu--nested\" role=\"list\">\n @for (grand of child.children; track grand.id) {\n @if (grand.href) {\n <!-- NIVEL 3 — Enlace externo -->\n <a\n class=\"neu-nav__item neu-nav__item--grandchild\"\n [class.neu-nav__item--disabled]=\"grand.disabled\"\n [href]=\"grand.disabled ? null : grand.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"grand.disabled ? 'true' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"grand.icon\"\n size=\"14px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ grand.label }}</span>\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"11px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 3 — Enlace interno -->\n <a\n class=\"neu-nav__item neu-nav__item--grandchild\"\n [class.neu-nav__item--disabled]=\"grand.disabled\"\n [routerLink]=\"grand.disabled ? null : (grand.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n [attr.aria-current]=\"\n isCurrentRoute(grand.route ?? '') ? 'page' : null\n \"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"grand.icon\"\n size=\"14px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ grand.label }}</span>\n @if (grand.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n grand.badgeVariant ?? 'default'\n }}\"\n >{{ grand.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n }\n </div>\n } @else if (child.href) {\n <!-- NIVEL 2 — Enlace externo -->\n <a\n class=\"neu-nav__item neu-nav__item--child\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [href]=\"child.disabled ? null : child.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"12px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 2 — Enlace interno -->\n <a\n class=\"neu-nav__item neu-nav__item--child\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [routerLink]=\"child.disabled ? null : (child.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n [attr.aria-current]=\"isCurrentRoute(child.route ?? '') ? 'page' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n }\n </div>\n } @else if (item.href) {\n <!-- NIVEL 1 — Enlace externo -->\n <a\n class=\"neu-nav__item\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [href]=\"item.disabled ? null : item.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"13px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 1 — Enlace interno -->\n <a\n class=\"neu-nav__item\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [routerLink]=\"item.disabled ? null : (item.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: item.route === '/' }\"\n [attr.aria-current]=\"isCurrentRoute(item.route ?? '') ? 'page' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n\n <!-- Footer slot -->\n <div class=\"neu-nav__footer\">\n <ng-content select=\"[neu-nav-footer]\" />\n </div>\n </nav>\n\n <!-- Flyout panel para grupos en modo colapsado -->\n @if (flyoutState(); as flyout) {\n <div\n class=\"neu-nav__flyout\"\n [style.top.px]=\"flyout.top\"\n [style.left.px]=\"flyout.left\"\n role=\"menu\"\n (mouseenter)=\"onFlyoutMouseEnter()\"\n (mouseleave)=\"onFlyoutMouseLeave()\"\n >\n <div class=\"neu-nav__flyout-title\">{{ flyout.item.label }}</div>\n @for (child of flyout.item.children ?? []; track child.id) {\n @if (child.children?.length) {\n <div class=\"neu-nav__flyout-group\">\n <span class=\"neu-nav__flyout-group-label\">{{ child.label }}</span>\n @for (grand of child.children; track grand.id) {\n @if (grand.href) {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [href]=\"grand.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"grand.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ grand.label }}</span>\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"10px\"\n class=\"neu-nav__external-icon\"\n />\n </a>\n } @else {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [routerLink]=\"grand.route\"\n routerLinkActive=\"neu-nav__flyout-item--active\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"grand.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ grand.label }}</span>\n </a>\n }\n }\n </div>\n } @else if (child.href) {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [href]=\"child.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"child.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ child.label }}</span>\n <neu-icon name=\"lucideExternalLink\" size=\"10px\" class=\"neu-nav__external-icon\" />\n </a>\n } @else {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [routerLink]=\"child.route\"\n routerLinkActive=\"neu-nav__flyout-item--active\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"child.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ child.label }}</span>\n </a>\n }\n }\n </div>\n }\n\n <!-- Pestaña collapse/expand — fuera del nav para no ser recortada -->\n @if (collapsible()) {\n <button\n class=\"neu-nav__toggle-tab\"\n type=\"button\"\n [attr.aria-label]=\"isCollapsed() ? expandLabel() : collapseLabel()\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n (click)=\"toggleCollapse()\"\n >\n <neu-icon\n [name]=\"isCollapsed() ? 'lucideChevronRight' : 'lucideChevronLeft'\"\n size=\"12px\"\n aria-hidden=\"true\"\n />\n </button>\n }\n </div>\n `,\n styleUrl: './neu-nav.component.scss',\n})\nexport class NeuNavComponent {\n private readonly router = inject(Router);\n\n // ---- Señal reactiva de ruta activa / Reactive active route signal ----\n private readonly currentUrl = toSignal(\n this.router.events.pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd)),\n { initialValue: null },\n );\n\n // ---- Inputs ----\n\n /** Lista de ítems de navegación / Navigation item list */\n items = input<NeuNavItem[]>([]);\n\n /** Estado inicial colapsado / Initial collapsed state */\n collapsed = input<boolean>(false);\n\n /** Muestra el botón de colapsar/expandir / Shows the collapse/expand button */\n collapsible = input<boolean>(true);\n\n /** Etiqueta accesible del <nav> / Accessible label for the <nav> */\n ariaLabel = input<string>('Navegación principal');\n\n /** Aria-label del botón cuando el nav está colapsado / Aria-label for the button when the nav is collapsed */\n expandLabel = input<string>('Expandir menú');\n\n /** Aria-label del botón cuando el nav está expandido / Aria-label for the button when the nav is expanded */\n collapseLabel = input<string>('Colapsar menú');\n\n /** Emite cuando cambia el estado colapsado / Emits when the collapsed state changes */\n collapsedChange = output<boolean>();\n\n // ---- Estado interno / Internal state ----\n\n // Sigue el input `collapsed` del padre (permite el configurador)\n // pero puede ser sobreescrito localmente con toggleCollapse()\n readonly isCollapsed = linkedSignal(() => this.collapsed());\n private readonly openGroups = signal<Set<string>>(new Set());\n\n // ---- Flyout para modo colapsado / Flyout for collapsed mode ----\n readonly flyoutState = signal<{ item: NeuNavItem; top: number; left: number } | null>(null);\n private _flyoutTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n // Abrimos el grupo activo DESPUÉS de que el padre haya pasado los inputs\n afterNextRender(() => this._openActiveGroup());\n // Limpiamos el timer del flyout al destruir el componente\n inject(DestroyRef).onDestroy(() => {\n if (this._flyoutTimer) clearTimeout(this._flyoutTimer);\n });\n }\n\n // ---- Helpers de estado / State helpers ----\n\n toggleCollapse(): void {\n this.isCollapsed.update((v) => {\n const next = !v;\n this.collapsedChange.emit(next);\n return next;\n });\n }\n\n toggleGroup(id: string): void {\n this.openGroups.update((s) => {\n const next = new Set(s);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }\n\n isGroupOpen(id: string): boolean {\n return this.openGroups().has(id);\n }\n\n isCurrentRoute(route: string): boolean {\n if (!route) return false;\n // Consume la señal para que OnPush re-evalúe tras navegación\n this.currentUrl();\n return this.router.url === route || this.router.url.startsWith(route + '?');\n }\n\n isGroupActive(item: NeuNavItem): boolean {\n if (!item.children?.length) return false;\n return item.children.some(\n (c) =>\n this.isCurrentRoute(c.route ?? '') ||\n (c.children?.some((g) => this.isCurrentRoute(g.route ?? '')) ?? false),\n );\n }\n\n // ---- Flyout handlers ----\n\n onGroupMouseEnter(item: NeuNavItem, event: MouseEvent): void {\n if (!this.isCollapsed() || !item.children?.length) return;\n if (this._flyoutTimer) {\n clearTimeout(this._flyoutTimer);\n this._flyoutTimer = null;\n }\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect();\n this.flyoutState.set({ item, top: rect.top, left: rect.right });\n }\n\n onGroupMouseLeave(): void {\n if (!this.isCollapsed()) return;\n this._flyoutTimer = setTimeout(() => this.flyoutState.set(null), 150);\n }\n\n onFlyoutMouseEnter(): void {\n if (this._flyoutTimer) {\n clearTimeout(this._flyoutTimer);\n this._flyoutTimer = null;\n }\n }\n\n onFlyoutMouseLeave(): void {\n this._flyoutTimer = setTimeout(() => this.flyoutState.set(null), 150);\n }\n\n private _openActiveGroup(): void {\n const toOpen = new Set<string>();\n for (const item of this.items()) {\n if (!item.children) continue;\n for (const child of item.children) {\n if (child.route && this.router.url.startsWith(child.route)) {\n toOpen.add(item.id);\n }\n if (child.children) {\n for (const grand of child.children) {\n if (grand.route && this.router.url.startsWith(grand.route)) {\n toOpen.add(item.id);\n toOpen.add(child.id);\n }\n }\n }\n }\n }\n if (toOpen.size > 0) {\n this.openGroups.set(toOpen);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"neural-ui-core-nav.mjs","sources":["../../../../projects/ui-core/nav/neu-nav.component.ts","../../../../projects/ui-core/nav/neural-ui-core-nav.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ViewEncapsulation,\n afterNextRender,\n inject,\n input,\n linkedSignal,\n output,\n signal,\n} from '@angular/core';\nimport { RouterLink, RouterLinkActive, Router, NavigationEnd } from '@angular/router';\nimport { filter } from 'rxjs';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\nimport { NeuTooltipDirective } from '@neural-ui/core/tooltip';\n\n// ---- Tipos públicos / Public types ----\n\n/**\n * Ítem de navegación con soporte para 3 niveles de profundidad.\n *\n * Destino del enlace — usa UNO de los dos:\n * - `route` → navegación interna Angular (RouterLink)\n * - `href` → URL externa, se abre en nueva pestaña con rel=\"noopener noreferrer\"\n *\n * Los ítems con `children` actúan como grupo acordeón (sin destino propio).\n * Máximo 3 niveles: raíz → hijos → nietos.\n * Los nietos no pueden tener `children`.\n */\nexport interface NeuNavItem {\n id: string;\n label: string;\n icon: string;\n /** Ruta Angular interna (RouterLink). Excluye `href`. / Internal Angular route (RouterLink). Excludes `href`. */\n route?: string;\n /** URL externa. Se abre en nueva pestaña. Excluye `route`. / External URL. Opens in a new tab. Excludes `route`. */\n href?: string;\n /** Ítems hijo (nivel 2). Cada hijo puede tener sus propios `children` (nivel 3). / Child items (level 2). Each child can have its own `children` (level 3). */\n children?: NeuNavItem[];\n badge?: string;\n badgeVariant?: 'default' | 'success' | 'warning' | 'danger' | 'info';\n disabled?: boolean;\n}\n\n@Component({\n selector: 'neu-nav',\n imports: [RouterLink, RouterLinkActive, NeuIconComponent, NeuTooltipDirective],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"neu-nav-wrapper\" [class.neu-nav-wrapper--collapsed]=\"isCollapsed()\">\n <nav\n class=\"neu-nav\"\n [class.neu-nav--collapsed]=\"isCollapsed()\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n <!-- Brand slot -->\n <div class=\"neu-nav__brand\">\n <!-- Icono visible solo en modo colapsado -->\n <div class=\"neu-nav__brand-icon\">\n <ng-content select=\"[neu-nav-brand-icon]\" />\n </div>\n <!-- Contenido completo visible en modo expandido -->\n <div class=\"neu-nav__brand-content\">\n <ng-content select=\"[neu-nav-brand]\" />\n </div>\n </div>\n\n <!-- Items (nivel 1) -->\n <div class=\"neu-nav__items\" role=\"list\">\n @for (item of items(); track item.id) {\n @if (item.children?.length) {\n <!-- NIVEL 1 — Grupo acordeón -->\n <div\n class=\"neu-nav__group\"\n [class.neu-nav__group--open]=\"isGroupOpen(item.id)\"\n role=\"listitem\"\n (mouseenter)=\"onGroupMouseEnter(item, $event)\"\n (mouseleave)=\"onGroupMouseLeave()\"\n >\n <button\n class=\"neu-nav__item neu-nav__item--parent\"\n type=\"button\"\n [class.neu-nav__item--active]=\"isGroupActive(item)\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [attr.aria-expanded]=\"isGroupOpen(item.id)\"\n [attr.aria-haspopup]=\"true\"\n [attr.disabled]=\"item.disabled ? '' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n (click)=\"!isCollapsed() && toggleGroup(item.id)\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideChevronRight\"\n size=\"14px\"\n class=\"neu-nav__group-chevron\"\n aria-hidden=\"true\"\n />\n </button>\n\n <!-- Submenú nivel 2 -->\n @if (!isCollapsed() && isGroupOpen(item.id)) {\n <div class=\"neu-nav__submenu\" role=\"list\">\n @for (child of item.children; track child.id) {\n @if (child.children?.length) {\n <!-- NIVEL 2 — Subgrupo acordeón -->\n <div\n class=\"neu-nav__group neu-nav__group--nested\"\n [class.neu-nav__group--open]=\"isGroupOpen(child.id)\"\n role=\"listitem\"\n >\n <button\n class=\"neu-nav__item neu-nav__item--child neu-nav__item--parent\"\n type=\"button\"\n [class.neu-nav__item--active]=\"isGroupActive(child)\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [attr.aria-expanded]=\"isGroupOpen(child.id)\"\n [attr.aria-haspopup]=\"true\"\n [attr.disabled]=\"child.disabled ? '' : null\"\n (click)=\"toggleGroup(child.id)\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideChevronRight\"\n size=\"13px\"\n class=\"neu-nav__group-chevron\"\n aria-hidden=\"true\"\n />\n </button>\n\n <!-- Submenú nivel 3 -->\n @if (isGroupOpen(child.id)) {\n <div class=\"neu-nav__submenu neu-nav__submenu--nested\" role=\"list\">\n @for (grand of child.children; track grand.id) {\n @if (grand.href) {\n <!-- NIVEL 3 — Enlace externo -->\n <a\n class=\"neu-nav__item neu-nav__item--grandchild\"\n [class.neu-nav__item--disabled]=\"grand.disabled\"\n [href]=\"grand.disabled ? null : grand.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"grand.disabled ? 'true' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"grand.icon\"\n size=\"14px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ grand.label }}</span>\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"11px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 3 — Enlace interno -->\n <a\n class=\"neu-nav__item neu-nav__item--grandchild\"\n [class.neu-nav__item--disabled]=\"grand.disabled\"\n [routerLink]=\"grand.disabled ? null : (grand.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n [attr.aria-current]=\"\n isCurrentRoute(grand.route ?? '') ? 'page' : null\n \"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"grand.icon\"\n size=\"14px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ grand.label }}</span>\n @if (grand.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n grand.badgeVariant ?? 'default'\n }}\"\n >{{ grand.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n }\n </div>\n } @else if (child.href) {\n <!-- NIVEL 2 — Enlace externo -->\n <a\n class=\"neu-nav__item neu-nav__item--child\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [href]=\"child.disabled ? null : child.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"12px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 2 — Enlace interno -->\n <a\n class=\"neu-nav__item neu-nav__item--child\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [routerLink]=\"child.disabled ? null : (child.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n [attr.aria-current]=\"isCurrentRoute(child.route ?? '') ? 'page' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n }\n </div>\n } @else if (item.href) {\n <!-- NIVEL 1 — Enlace externo -->\n <a\n class=\"neu-nav__item\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [href]=\"item.disabled ? null : item.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"13px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 1 — Enlace interno -->\n <a\n class=\"neu-nav__item\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [routerLink]=\"item.disabled ? null : (item.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: item.route === '/' }\"\n [attr.aria-current]=\"isCurrentRoute(item.route ?? '') ? 'page' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n\n <!-- Footer slot -->\n <div class=\"neu-nav__footer\">\n <ng-content select=\"[neu-nav-footer]\" />\n </div>\n </nav>\n\n <!-- Flyout panel para grupos en modo colapsado -->\n @if (flyoutState(); as flyout) {\n <div\n class=\"neu-nav__flyout\"\n [style.top.px]=\"flyout.top\"\n [style.left.px]=\"flyout.left\"\n role=\"menu\"\n (mouseenter)=\"onFlyoutMouseEnter()\"\n (mouseleave)=\"onFlyoutMouseLeave()\"\n >\n <div class=\"neu-nav__flyout-title\">{{ flyout.item.label }}</div>\n @for (child of flyout.item.children ?? []; track child.id) {\n @if (child.children?.length) {\n <div class=\"neu-nav__flyout-group\">\n <span class=\"neu-nav__flyout-group-label\">{{ child.label }}</span>\n @for (grand of child.children; track grand.id) {\n @if (grand.href) {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [href]=\"grand.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"grand.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ grand.label }}</span>\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"10px\"\n class=\"neu-nav__external-icon\"\n />\n </a>\n } @else {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [routerLink]=\"grand.route\"\n routerLinkActive=\"neu-nav__flyout-item--active\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"grand.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ grand.label }}</span>\n </a>\n }\n }\n </div>\n } @else if (child.href) {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [href]=\"child.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"child.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ child.label }}</span>\n <neu-icon name=\"lucideExternalLink\" size=\"10px\" class=\"neu-nav__external-icon\" />\n </a>\n } @else {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [routerLink]=\"child.route\"\n routerLinkActive=\"neu-nav__flyout-item--active\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"child.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ child.label }}</span>\n </a>\n }\n }\n </div>\n }\n\n <!-- Pestaña collapse/expand — fuera del nav para no ser recortada -->\n @if (collapsible()) {\n <button\n class=\"neu-nav__toggle-tab\"\n type=\"button\"\n [attr.aria-label]=\"isCollapsed() ? expandLabel() : collapseLabel()\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n (click)=\"toggleCollapse()\"\n >\n <neu-icon\n [name]=\"isCollapsed() ? 'lucideChevronRight' : 'lucideChevronLeft'\"\n size=\"12px\"\n aria-hidden=\"true\"\n />\n </button>\n }\n </div>\n `,\n styleUrl: './neu-nav.component.scss',\n})\nexport class NeuNavComponent {\n private readonly router = inject(Router);\n\n // ---- Señal reactiva de ruta activa / Reactive active route signal ----\n private readonly currentUrl = toSignal(\n this.router.events.pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd)),\n { initialValue: null },\n );\n\n // ---- Inputs ----\n\n /** Lista de ítems de navegación / Navigation item list */\n items = input<NeuNavItem[]>([]);\n\n /** Estado inicial colapsado / Initial collapsed state */\n collapsed = input<boolean>(false);\n\n /** Muestra el botón de colapsar/expandir / Shows the collapse/expand button */\n collapsible = input<boolean>(true);\n\n /** Etiqueta accesible del <nav> / Accessible label for the <nav> */\n ariaLabel = input<string>('Navegación principal');\n\n /** Aria-label del botón cuando el nav está colapsado / Aria-label for the button when the nav is collapsed */\n expandLabel = input<string>('Expandir menú');\n\n /** Aria-label del botón cuando el nav está expandido / Aria-label for the button when the nav is expanded */\n collapseLabel = input<string>('Colapsar menú');\n\n /** Emite cuando cambia el estado colapsado / Emits when the collapsed state changes */\n collapsedChange = output<boolean>();\n\n // ---- Estado interno / Internal state ----\n\n // Sigue el input `collapsed` del padre (permite el configurador)\n // pero puede ser sobreescrito localmente con toggleCollapse()\n readonly isCollapsed = linkedSignal(() => this.collapsed());\n private readonly openGroups = signal<Set<string>>(new Set());\n\n // ---- Flyout para modo colapsado / Flyout for collapsed mode ----\n readonly flyoutState = signal<{ item: NeuNavItem; top: number; left: number } | null>(null);\n private _flyoutTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n // Abrimos el grupo activo DESPUÉS de que el padre haya pasado los inputs\n afterNextRender(() => this._openActiveGroup());\n // Limpiamos el timer del flyout al destruir el componente\n inject(DestroyRef).onDestroy(() => {\n if (this._flyoutTimer) clearTimeout(this._flyoutTimer);\n });\n }\n\n // ---- Helpers de estado / State helpers ----\n\n toggleCollapse(): void {\n this.isCollapsed.update((v) => {\n const next = !v;\n this.collapsedChange.emit(next);\n return next;\n });\n }\n\n toggleGroup(id: string): void {\n this.openGroups.update((s) => {\n const next = new Set(s);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }\n\n isGroupOpen(id: string): boolean {\n return this.openGroups().has(id);\n }\n\n isCurrentRoute(route: string): boolean {\n if (!route) return false;\n // Consume la señal para que OnPush re-evalúe tras navegación\n this.currentUrl();\n return this.router.url === route || this.router.url.startsWith(route + '?');\n }\n\n isGroupActive(item: NeuNavItem): boolean {\n if (!item.children?.length) return false;\n return item.children.some(\n (c) =>\n this.isCurrentRoute(c.route ?? '') ||\n (c.children?.some((g) => this.isCurrentRoute(g.route ?? '')) ?? false),\n );\n }\n\n // ---- Flyout handlers ----\n\n onGroupMouseEnter(item: NeuNavItem, event: MouseEvent): void {\n if (!this.isCollapsed() || !item.children?.length) return;\n if (this._flyoutTimer) {\n clearTimeout(this._flyoutTimer);\n this._flyoutTimer = null;\n }\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect();\n this.flyoutState.set({ item, top: rect.top, left: rect.right });\n }\n\n onGroupMouseLeave(): void {\n if (!this.isCollapsed()) return;\n this._flyoutTimer = setTimeout(() => this.flyoutState.set(null), 150);\n }\n\n onFlyoutMouseEnter(): void {\n if (this._flyoutTimer) {\n clearTimeout(this._flyoutTimer);\n this._flyoutTimer = null;\n }\n }\n\n onFlyoutMouseLeave(): void {\n this._flyoutTimer = setTimeout(() => this.flyoutState.set(null), 150);\n }\n\n private _openActiveGroup(): void {\n const toOpen = new Set<string>();\n for (const item of this.items()) {\n if (!item.children) continue;\n for (const child of item.children) {\n if (child.route && this.router.url.startsWith(child.route)) {\n toOpen.add(item.id);\n }\n if (child.children) {\n for (const grand of child.children) {\n if (grand.route && this.router.url.startsWith(grand.route)) {\n toOpen.add(item.id);\n toOpen.add(child.id);\n }\n }\n }\n }\n }\n if (toOpen.size > 0) {\n this.openGroups.set(toOpen);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|
|
@@ -19,8 +19,11 @@ let _idSeq = 0;
|
|
|
19
19
|
* inject(NeuNotificationService).push({ type: 'success', message: '¡Guardado!' });
|
|
20
20
|
*/
|
|
21
21
|
class NeuNotificationService {
|
|
22
|
-
notifications = signal([],
|
|
23
|
-
|
|
22
|
+
notifications = signal([], /* @ts-ignore */
|
|
23
|
+
...(ngDevMode ? [{ debugName: "notifications" }] : /* istanbul ignore next */ []));
|
|
24
|
+
unreadCount = computed(() => this.notifications().filter((n) => !n.read).length, /* @ts-ignore */
|
|
25
|
+
...(ngDevMode ? [{ debugName: "unreadCount" }] : /* istanbul ignore next */ []));
|
|
26
|
+
timers = new Map();
|
|
24
27
|
/** Agrega una notificación / Adds a notification */
|
|
25
28
|
push(opts) {
|
|
26
29
|
const id = `neu-notif-${++_idSeq}`;
|
|
@@ -36,12 +39,14 @@ class NeuNotificationService {
|
|
|
36
39
|
};
|
|
37
40
|
this.notifications.update((list) => [n, ...list]);
|
|
38
41
|
if (n.duration && n.duration > 0) {
|
|
39
|
-
setTimeout(() => this.remove(id), n.duration);
|
|
42
|
+
const timer = setTimeout(() => this.remove(id), n.duration);
|
|
43
|
+
this.timers.set(id, timer);
|
|
40
44
|
}
|
|
41
45
|
return id;
|
|
42
46
|
}
|
|
43
47
|
/** Elimina una notificación / Removes a notification */
|
|
44
48
|
remove(id) {
|
|
49
|
+
this.clearTimer(id);
|
|
45
50
|
this.notifications.update((list) => list.filter((n) => n.id !== id));
|
|
46
51
|
}
|
|
47
52
|
/** Marca todas como leídas / Marks all as read */
|
|
@@ -50,12 +55,23 @@ class NeuNotificationService {
|
|
|
50
55
|
}
|
|
51
56
|
/** Elimina todas / Clears all */
|
|
52
57
|
clearAll() {
|
|
58
|
+
for (const timer of this.timers.values()) {
|
|
59
|
+
clearTimeout(timer);
|
|
60
|
+
}
|
|
61
|
+
this.timers.clear();
|
|
53
62
|
this.notifications.set([]);
|
|
54
63
|
}
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
clearTimer(id) {
|
|
65
|
+
const timer = this.timers.get(id);
|
|
66
|
+
if (!timer)
|
|
67
|
+
return;
|
|
68
|
+
clearTimeout(timer);
|
|
69
|
+
this.timers.delete(id);
|
|
70
|
+
}
|
|
71
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuNotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
72
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuNotificationService, providedIn: 'root' });
|
|
57
73
|
}
|
|
58
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
74
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuNotificationService, decorators: [{
|
|
59
75
|
type: Injectable,
|
|
60
76
|
args: [{ providedIn: 'root' }]
|
|
61
77
|
}] });
|
|
@@ -72,7 +88,8 @@ let _panelSeq = 0;
|
|
|
72
88
|
class NeuNotificationCenterComponent {
|
|
73
89
|
_svc = inject(NeuNotificationService);
|
|
74
90
|
overlay = inject(Overlay);
|
|
75
|
-
_isOpen = signal(false,
|
|
91
|
+
_isOpen = signal(false, /* @ts-ignore */
|
|
92
|
+
...(ngDevMode ? [{ debugName: "_isOpen" }] : /* istanbul ignore next */ []));
|
|
76
93
|
_panelId = `neu-nc-panel-${++_panelSeq}`;
|
|
77
94
|
_viewportMargin = 16;
|
|
78
95
|
overlayPositions = [
|
|
@@ -119,8 +136,8 @@ class NeuNotificationCenterComponent {
|
|
|
119
136
|
return `Hace ${hours}h`;
|
|
120
137
|
return `Hace ${Math.floor(hours / 24)}d`;
|
|
121
138
|
}
|
|
122
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
123
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
139
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuNotificationCenterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
140
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NeuNotificationCenterComponent, isStandalone: true, selector: "neu-notification-center", host: { properties: { "attr.aria-label": "\"Centro de notificaciones\"" }, classAttribute: "neu-nc" }, ngImport: i0, template: `
|
|
124
141
|
<!-- Bell button -->
|
|
125
142
|
<button
|
|
126
143
|
cdkOverlayOrigin
|
|
@@ -213,7 +230,7 @@ class NeuNotificationCenterComponent {
|
|
|
213
230
|
</ng-template>
|
|
214
231
|
`, isInline: true, styles: ["@charset \"UTF-8\";.neu-nc{position:relative;display:inline-block}.neu-nc__bell{all:unset;position:relative;display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:var(--neu-radius-lg, 12px);cursor:pointer;transition:background .12s}.neu-nc__bell:hover{background:var(--neu-surface-2, #f3f4f6)}.neu-nc__bell:focus-visible{outline:2px solid var(--neu-focus-ring, #0ea5e9);outline-offset:2px}.neu-nc__bell-icon{font-size:1.2rem}.neu-nc__badge{position:absolute;top:4px;right:4px;min-width:16px;height:16px;padding:0 4px;border-radius:999px;background:var(--neu-error);color:var(--neu-text-inverse);font-size:.625rem;font-weight:700;display:flex;align-items:center;justify-content:center;line-height:1}.neu-nc__panel{position:relative;width:320px;max-height:420px;display:flex;flex-direction:column;background:var(--neu-surface-1, #ffffff);border:1px solid var(--neu-border-color, #e5e7eb);border-radius:var(--neu-radius-xl, 16px);box-shadow:0 12px 28px -6px #00000024;z-index:1001;overflow:hidden;animation:neu-nc-in .1s ease}@keyframes neu-nc-in{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}.neu-nc__panel-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--neu-border-color, #e5e7eb);flex-shrink:0}.neu-nc__panel-title{font-size:.9375rem;font-weight:600;color:var(--neu-text-primary, #111)}.neu-nc__panel-actions{display:flex;gap:8px}.neu-nc__action-btn{all:unset;font-size:.75rem;color:var(--neu-color-primary, #0ea5e9);cursor:pointer;padding:2px 6px;border-radius:var(--neu-radius-sm, 4px)}.neu-nc__action-btn:hover{background:var(--neu-color-primary-alpha, rgba(14, 165, 233, .1))}.neu-nc__list{overflow-y:auto;flex:1;padding:6px}.neu-nc__empty{padding:24px;text-align:center;font-size:.875rem;color:var(--neu-text-secondary, #6b7280)}.neu-nc__item{display:flex;align-items:flex-start;gap:10px;padding:10px 10px 10px 12px;border-radius:var(--neu-radius-lg, 12px);position:relative;transition:background .1s}.neu-nc__item:hover{background:var(--neu-surface-2, #f3f4f6)}.neu-nc__item--unread:before{content:\"\";position:absolute;left:4px;top:50%;transform:translateY(-50%);width:6px;height:6px;border-radius:50%;background:var(--neu-color-primary, #0ea5e9)}.neu-nc__item-icon{font-size:1.1rem;flex-shrink:0;padding-top:2px}.neu-nc__item-body{flex:1;min-width:0}.neu-nc__item-title{margin:0 0 2px;font-size:.8125rem;font-weight:600;color:var(--neu-text-primary, #111)}.neu-nc__item-msg{margin:0 0 4px;font-size:.8125rem;color:var(--neu-text-secondary, #4b5563);line-height:1.4}.neu-nc__item-time{font-size:.6875rem;color:var(--neu-text-secondary, #9ca3af)}.neu-nc__item-close{all:unset;opacity:0;cursor:pointer;padding:2px 6px;border-radius:4px;font-size:1rem;color:var(--neu-text-secondary, #9ca3af);flex-shrink:0;transition:opacity .1s}.neu-nc__item:hover .neu-nc__item-close{opacity:1}.neu-nc__item-close:hover{color:var(--neu-text-primary, #111)}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
215
232
|
}
|
|
216
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
233
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuNotificationCenterComponent, decorators: [{
|
|
217
234
|
type: Component,
|
|
218
235
|
args: [{ selector: 'neu-notification-center', imports: [OverlayModule], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
219
236
|
class: 'neu-nc',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neural-ui-core-notification-center.mjs","sources":["../../../../projects/ui-core/notification-center/neu-notification-center.component.ts","../../../../projects/ui-core/notification-center/neural-ui-core-notification-center.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n Injectable,\n OnDestroy,\n ViewEncapsulation,\n computed,\n inject,\n signal,\n} from '@angular/core';\nimport { ConnectedPosition, Overlay, OverlayModule } from '@angular/cdk/overlay';\n\nexport type NeuNotificationType = 'info' | 'success' | 'warning' | 'error';\n\nexport interface NeuNotification {\n id: string;\n type: NeuNotificationType;\n title?: string;\n message: string;\n /** Auto-dismiss duration in ms (0 = persistent) */\n duration?: number;\n /** Icon text / emoji */\n icon?: string;\n timestamp: Date;\n read: boolean;\n}\n\nexport interface NeuNotificationOptions extends Omit<\n NeuNotification,\n 'id' | 'timestamp' | 'read'\n> {}\n\nconst DEFAULT_ICONS: Record<NeuNotificationType, string> = {\n info: 'ℹ️',\n success: '✅',\n warning: '⚠️',\n error: '❌',\n};\n\nlet _idSeq = 0;\n\n/**\n * NeuralUI NotificationService\n *\n * Servicio inyectable que gestiona la cola de notificaciones.\n *\n * Uso:\n * inject(NeuNotificationService).push({ type: 'success', message: '¡Guardado!' });\n */\n@Injectable({ providedIn: 'root' })\nexport class NeuNotificationService {\n readonly notifications = signal<NeuNotification[]>([]);\n\n readonly unreadCount = computed(() => this.notifications().filter((n) => !n.read).length);\n\n /** Agrega una notificación / Adds a notification */\n push(opts: Partial<NeuNotificationOptions> & Pick<NeuNotificationOptions, 'message'>): string {\n const id = `neu-notif-${++_idSeq}`;\n const n: NeuNotification = {\n id,\n type: opts.type ?? 'info',\n title: opts.title,\n message: opts.message,\n icon: opts.icon ?? DEFAULT_ICONS[opts.type ?? 'info'],\n duration: opts.duration ?? 5000,\n timestamp: new Date(),\n read: false,\n };\n this.notifications.update((list) => [n, ...list]);\n\n if (n.duration && n.duration > 0) {\n setTimeout(() => this.remove(id), n.duration);\n }\n return id;\n }\n\n /** Elimina una notificación / Removes a notification */\n remove(id: string): void {\n this.notifications.update((list) => list.filter((n) => n.id !== id));\n }\n\n /** Marca todas como leídas / Marks all as read */\n markAllRead(): void {\n this.notifications.update((list) => list.map((n) => ({ ...n, read: true })));\n }\n\n /** Elimina todas / Clears all */\n clearAll(): void {\n this.notifications.set([]);\n }\n}\n\nlet _panelSeq = 0;\n\n/**\n * NeuralUI NotificationCenter Component\n *\n * Icono de campana con badge de no leídos y panel de notificaciones\n * deslizante. Consume NeuNotificationService.\n *\n * Uso:\n * <neu-notification-center />\n */\n@Component({\n selector: 'neu-notification-center',\n imports: [OverlayModule],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'neu-nc',\n '[attr.aria-label]': '\"Centro de notificaciones\"',\n },\n template: `\n <!-- Bell button -->\n <button\n cdkOverlayOrigin\n #notificationOrigin=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"neu-nc__bell\"\n [attr.aria-expanded]=\"_isOpen()\"\n [attr.aria-controls]=\"_panelId\"\n [attr.aria-label]=\"'Notificaciones. ' + _svc.unreadCount() + ' sin leer'\"\n (click)=\"_toggle()\"\n >\n <span class=\"neu-nc__bell-icon\" aria-hidden=\"true\">🔔</span>\n @if (_svc.unreadCount() > 0) {\n <span class=\"neu-nc__badge\" aria-hidden=\"true\">{{\n _svc.unreadCount() > 99 ? '99+' : _svc.unreadCount()\n }}</span>\n }\n </button>\n\n <!-- Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"notificationOrigin\"\n [cdkConnectedOverlayOpen]=\"_isOpen()\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"overlayScrollStrategy\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayViewportMargin]=\"_viewportMargin\"\n (backdropClick)=\"_isOpen.set(false)\"\n (detach)=\"_isOpen.set(false)\"\n >\n <div\n class=\"neu-nc__panel\"\n [id]=\"_panelId\"\n role=\"dialog\"\n aria-modal=\"false\"\n aria-label=\"Notificaciones\"\n >\n <div class=\"neu-nc__panel-header\">\n <span class=\"neu-nc__panel-title\">Notificaciones</span>\n <div class=\"neu-nc__panel-actions\">\n @if (_svc.unreadCount() > 0) {\n <button type=\"button\" class=\"neu-nc__action-btn\" (click)=\"_svc.markAllRead()\">\n Leer todo\n </button>\n }\n @if (_svc.notifications().length > 0) {\n <button type=\"button\" class=\"neu-nc__action-btn\" (click)=\"_svc.clearAll()\">\n Limpiar\n </button>\n }\n </div>\n </div>\n\n <div class=\"neu-nc__list\" role=\"list\">\n @if (!_svc.notifications().length) {\n <div class=\"neu-nc__empty\" role=\"status\">No hay notificaciones</div>\n }\n @for (n of _svc.notifications(); track n.id) {\n <div\n class=\"neu-nc__item\"\n role=\"listitem\"\n [class.neu-nc__item--unread]=\"!n.read\"\n [class]=\"'neu-nc__item--' + n.type\"\n >\n <span class=\"neu-nc__item-icon\" aria-hidden=\"true\">{{ n.icon }}</span>\n <div class=\"neu-nc__item-body\">\n @if (n.title) {\n <p class=\"neu-nc__item-title\">{{ n.title }}</p>\n }\n <p class=\"neu-nc__item-msg\">{{ n.message }}</p>\n <time class=\"neu-nc__item-time\" [dateTime]=\"n.timestamp.toISOString()\">\n {{ _relativeTime(n.timestamp) }}\n </time>\n </div>\n <button\n type=\"button\"\n class=\"neu-nc__item-close\"\n [attr.aria-label]=\"'Cerrar notificación'\"\n (click)=\"_svc.remove(n.id)\"\n >\n ×\n </button>\n </div>\n }\n </div>\n </div>\n </ng-template>\n `,\n styleUrl: './neu-notification-center.component.scss',\n})\nexport class NeuNotificationCenterComponent {\n readonly _svc = inject(NeuNotificationService);\n private readonly overlay = inject(Overlay);\n readonly _isOpen = signal(false);\n readonly _panelId = `neu-nc-panel-${++_panelSeq}`;\n readonly _viewportMargin = 16;\n readonly overlayPositions: ConnectedPosition[] = [\n {\n originX: 'end',\n originY: 'bottom',\n overlayX: 'end',\n overlayY: 'top',\n offsetY: 8,\n },\n {\n originX: 'end',\n originY: 'top',\n overlayX: 'end',\n overlayY: 'bottom',\n offsetY: -8,\n },\n {\n originX: 'start',\n originY: 'bottom',\n overlayX: 'start',\n overlayY: 'top',\n offsetY: 8,\n },\n ];\n readonly overlayScrollStrategy = this.overlay.scrollStrategies.reposition();\n\n _toggle(): void {\n const opening = !this._isOpen();\n this._isOpen.set(opening);\n if (opening) {\n // Mark all as read when panel opens\n setTimeout(() => this._svc.markAllRead(), 500);\n }\n }\n\n _relativeTime(date: Date): string {\n const diff = Date.now() - date.getTime();\n const mins = Math.floor(diff / 60000);\n if (mins < 1) return 'Ahora';\n if (mins < 60) return `Hace ${mins} min`;\n const hours = Math.floor(mins / 60);\n if (hours < 24) return `Hace ${hours}h`;\n return `Hace ${Math.floor(hours / 24)}d`;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":";;;;;AAgCA,MAAM,aAAa,GAAwC;AACzD,IAAA,IAAI,EAAE,IAAI;AACV,IAAA,OAAO,EAAE,GAAG;AACZ,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,KAAK,EAAE,GAAG;CACX;AAED,IAAI,MAAM,GAAG,CAAC;AAEd;;;;;;;AAOG;MAEU,sBAAsB,CAAA;AACxB,IAAA,aAAa,GAAG,MAAM,CAAoB,EAAE,oFAAC;IAE7C,WAAW,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,aAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;;AAGzF,IAAA,IAAI,CAAC,IAA+E,EAAA;AAClF,QAAA,MAAM,EAAE,GAAG,CAAA,UAAA,EAAa,EAAE,MAAM,EAAE;AAClC,QAAA,MAAM,CAAC,GAAoB;YACzB,EAAE;AACF,YAAA,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,MAAM;YACzB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;AACrB,YAAA,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC;AACrD,YAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI;YAC/B,SAAS,EAAE,IAAI,IAAI,EAAE;AACrB,YAAA,IAAI,EAAE,KAAK;SACZ;AACD,QAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;QAEjD,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,EAAE;AAChC,YAAA,UAAU,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC;QAC/C;AACA,QAAA,OAAO,EAAE;IACX;;AAGA,IAAA,MAAM,CAAC,EAAU,EAAA;QACf,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE;;IAGA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9E;;IAGA,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;IAC5B;uGAvCW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cADT,MAAM,EAAA,CAAA;;2FACnB,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBADlC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;AA2ClC,IAAI,SAAS,GAAG,CAAC;AAEjB;;;;;;;;AAQG;MAwGU,8BAA8B,CAAA;AAChC,IAAA,IAAI,GAAG,MAAM,CAAC,sBAAsB,CAAC;AAC7B,IAAA,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;AACjC,IAAA,OAAO,GAAG,MAAM,CAAC,KAAK,8EAAC;AACvB,IAAA,QAAQ,GAAG,CAAA,aAAA,EAAgB,EAAE,SAAS,EAAE;IACxC,eAAe,GAAG,EAAE;AACpB,IAAA,gBAAgB,GAAwB;AAC/C,QAAA;AACE,YAAA,OAAO,EAAE,KAAK;AACd,YAAA,OAAO,EAAE,QAAQ;AACjB,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,OAAO,EAAE,CAAC;AACX,SAAA;AACD,QAAA;AACE,YAAA,OAAO,EAAE,KAAK;AACd,YAAA,OAAO,EAAE,KAAK;AACd,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,CAAC,CAAC;AACZ,SAAA;AACD,QAAA;AACE,YAAA,OAAO,EAAE,OAAO;AAChB,YAAA,OAAO,EAAE,QAAQ;AACjB,YAAA,QAAQ,EAAE,OAAO;AACjB,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,OAAO,EAAE,CAAC;AACX,SAAA;KACF;IACQ,qBAAqB,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,UAAU,EAAE;IAE3E,OAAO,GAAA;AACL,QAAA,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE;AAC/B,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QACzB,IAAI,OAAO,EAAE;;AAEX,YAAA,UAAU,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC;QAChD;IACF;AAEA,IAAA,aAAa,CAAC,IAAU,EAAA;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;QACrC,IAAI,IAAI,GAAG,CAAC;AAAE,YAAA,OAAO,OAAO;QAC5B,IAAI,IAAI,GAAG,EAAE;YAAE,OAAO,CAAA,KAAA,EAAQ,IAAI,CAAA,IAAA,CAAM;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC;QACnC,IAAI,KAAK,GAAG,EAAE;YAAE,OAAO,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAA,CAAG;QACvC,OAAO,CAAA,KAAA,EAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAA,CAAA,CAAG;IAC1C;uGAhDW,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA9B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,8BAA8B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,8BAAA,EAAA,EAAA,cAAA,EAAA,QAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA9F/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2FT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,66FAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAlGS,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,mBAAA,EAAA,QAAA,EAAA,qEAAA,EAAA,MAAA,EAAA,CAAA,2BAAA,EAAA,8BAAA,EAAA,qCAAA,EAAA,4BAAA,EAAA,4BAAA,EAAA,0BAAA,EAAA,2BAAA,EAAA,6BAAA,EAAA,8BAAA,EAAA,kCAAA,EAAA,+BAAA,EAAA,mCAAA,EAAA,mCAAA,EAAA,yBAAA,EAAA,iCAAA,EAAA,sCAAA,EAAA,gCAAA,EAAA,iCAAA,EAAA,uCAAA,EAAA,kCAAA,EAAA,yBAAA,EAAA,wCAAA,EAAA,+BAAA,EAAA,+BAAA,EAAA,qBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,4DAAA,EAAA,QAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAqGZ,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBAvG1C,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,yBAAyB,EAAA,OAAA,EAC1B,CAAC,aAAa,CAAC,EAAA,aAAA,EACT,iBAAiB,CAAC,IAAI,EAAA,eAAA,EACpB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,KAAK,EAAE,QAAQ;AACf,wBAAA,mBAAmB,EAAE,4BAA4B;qBAClD,EAAA,QAAA,EACS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2FT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,66FAAA,CAAA,EAAA;;;AC3MH;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"neural-ui-core-notification-center.mjs","sources":["../../../../projects/ui-core/notification-center/neu-notification-center.component.ts","../../../../projects/ui-core/notification-center/neural-ui-core-notification-center.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n Injectable,\n OnDestroy,\n ViewEncapsulation,\n computed,\n inject,\n signal,\n} from '@angular/core';\nimport { ConnectedPosition, Overlay, OverlayModule } from '@angular/cdk/overlay';\n\nexport type NeuNotificationType = 'info' | 'success' | 'warning' | 'error';\n\nexport interface NeuNotification {\n id: string;\n type: NeuNotificationType;\n title?: string;\n message: string;\n /** Auto-dismiss duration in ms (0 = persistent) */\n duration?: number;\n /** Icon text / emoji */\n icon?: string;\n timestamp: Date;\n read: boolean;\n}\n\nexport interface NeuNotificationOptions extends Omit<\n NeuNotification,\n 'id' | 'timestamp' | 'read'\n> {}\n\nconst DEFAULT_ICONS: Record<NeuNotificationType, string> = {\n info: 'ℹ️',\n success: '✅',\n warning: '⚠️',\n error: '❌',\n};\n\nlet _idSeq = 0;\n\n/**\n * NeuralUI NotificationService\n *\n * Servicio inyectable que gestiona la cola de notificaciones.\n *\n * Uso:\n * inject(NeuNotificationService).push({ type: 'success', message: '¡Guardado!' });\n */\n@Injectable({ providedIn: 'root' })\nexport class NeuNotificationService {\n readonly notifications = signal<NeuNotification[]>([]);\n\n readonly unreadCount = computed(() => this.notifications().filter((n) => !n.read).length);\n\n private readonly timers = new Map<string, ReturnType<typeof setTimeout>>();\n\n /** Agrega una notificación / Adds a notification */\n push(opts: Partial<NeuNotificationOptions> & Pick<NeuNotificationOptions, 'message'>): string {\n const id = `neu-notif-${++_idSeq}`;\n const n: NeuNotification = {\n id,\n type: opts.type ?? 'info',\n title: opts.title,\n message: opts.message,\n icon: opts.icon ?? DEFAULT_ICONS[opts.type ?? 'info'],\n duration: opts.duration ?? 5000,\n timestamp: new Date(),\n read: false,\n };\n this.notifications.update((list) => [n, ...list]);\n\n if (n.duration && n.duration > 0) {\n const timer = setTimeout(() => this.remove(id), n.duration);\n this.timers.set(id, timer);\n }\n return id;\n }\n\n /** Elimina una notificación / Removes a notification */\n remove(id: string): void {\n this.clearTimer(id);\n this.notifications.update((list) => list.filter((n) => n.id !== id));\n }\n\n /** Marca todas como leídas / Marks all as read */\n markAllRead(): void {\n this.notifications.update((list) => list.map((n) => ({ ...n, read: true })));\n }\n\n /** Elimina todas / Clears all */\n clearAll(): void {\n for (const timer of this.timers.values()) {\n clearTimeout(timer);\n }\n this.timers.clear();\n this.notifications.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\nlet _panelSeq = 0;\n\n/**\n * NeuralUI NotificationCenter Component\n *\n * Icono de campana con badge de no leídos y panel de notificaciones\n * deslizante. Consume NeuNotificationService.\n *\n * Uso:\n * <neu-notification-center />\n */\n@Component({\n selector: 'neu-notification-center',\n imports: [OverlayModule],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'neu-nc',\n '[attr.aria-label]': '\"Centro de notificaciones\"',\n },\n template: `\n <!-- Bell button -->\n <button\n cdkOverlayOrigin\n #notificationOrigin=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"neu-nc__bell\"\n [attr.aria-expanded]=\"_isOpen()\"\n [attr.aria-controls]=\"_panelId\"\n [attr.aria-label]=\"'Notificaciones. ' + _svc.unreadCount() + ' sin leer'\"\n (click)=\"_toggle()\"\n >\n <span class=\"neu-nc__bell-icon\" aria-hidden=\"true\">🔔</span>\n @if (_svc.unreadCount() > 0) {\n <span class=\"neu-nc__badge\" aria-hidden=\"true\">{{\n _svc.unreadCount() > 99 ? '99+' : _svc.unreadCount()\n }}</span>\n }\n </button>\n\n <!-- Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"notificationOrigin\"\n [cdkConnectedOverlayOpen]=\"_isOpen()\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"overlayScrollStrategy\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayViewportMargin]=\"_viewportMargin\"\n (backdropClick)=\"_isOpen.set(false)\"\n (detach)=\"_isOpen.set(false)\"\n >\n <div\n class=\"neu-nc__panel\"\n [id]=\"_panelId\"\n role=\"dialog\"\n aria-modal=\"false\"\n aria-label=\"Notificaciones\"\n >\n <div class=\"neu-nc__panel-header\">\n <span class=\"neu-nc__panel-title\">Notificaciones</span>\n <div class=\"neu-nc__panel-actions\">\n @if (_svc.unreadCount() > 0) {\n <button type=\"button\" class=\"neu-nc__action-btn\" (click)=\"_svc.markAllRead()\">\n Leer todo\n </button>\n }\n @if (_svc.notifications().length > 0) {\n <button type=\"button\" class=\"neu-nc__action-btn\" (click)=\"_svc.clearAll()\">\n Limpiar\n </button>\n }\n </div>\n </div>\n\n <div class=\"neu-nc__list\" role=\"list\">\n @if (!_svc.notifications().length) {\n <div class=\"neu-nc__empty\" role=\"status\">No hay notificaciones</div>\n }\n @for (n of _svc.notifications(); track n.id) {\n <div\n class=\"neu-nc__item\"\n role=\"listitem\"\n [class.neu-nc__item--unread]=\"!n.read\"\n [class]=\"'neu-nc__item--' + n.type\"\n >\n <span class=\"neu-nc__item-icon\" aria-hidden=\"true\">{{ n.icon }}</span>\n <div class=\"neu-nc__item-body\">\n @if (n.title) {\n <p class=\"neu-nc__item-title\">{{ n.title }}</p>\n }\n <p class=\"neu-nc__item-msg\">{{ n.message }}</p>\n <time class=\"neu-nc__item-time\" [dateTime]=\"n.timestamp.toISOString()\">\n {{ _relativeTime(n.timestamp) }}\n </time>\n </div>\n <button\n type=\"button\"\n class=\"neu-nc__item-close\"\n [attr.aria-label]=\"'Cerrar notificación'\"\n (click)=\"_svc.remove(n.id)\"\n >\n ×\n </button>\n </div>\n }\n </div>\n </div>\n </ng-template>\n `,\n styleUrl: './neu-notification-center.component.scss',\n})\nexport class NeuNotificationCenterComponent {\n readonly _svc = inject(NeuNotificationService);\n private readonly overlay = inject(Overlay);\n readonly _isOpen = signal(false);\n readonly _panelId = `neu-nc-panel-${++_panelSeq}`;\n readonly _viewportMargin = 16;\n readonly overlayPositions: ConnectedPosition[] = [\n {\n originX: 'end',\n originY: 'bottom',\n overlayX: 'end',\n overlayY: 'top',\n offsetY: 8,\n },\n {\n originX: 'end',\n originY: 'top',\n overlayX: 'end',\n overlayY: 'bottom',\n offsetY: -8,\n },\n {\n originX: 'start',\n originY: 'bottom',\n overlayX: 'start',\n overlayY: 'top',\n offsetY: 8,\n },\n ];\n readonly overlayScrollStrategy = this.overlay.scrollStrategies.reposition();\n\n _toggle(): void {\n const opening = !this._isOpen();\n this._isOpen.set(opening);\n if (opening) {\n // Mark all as read when panel opens\n setTimeout(() => this._svc.markAllRead(), 500);\n }\n }\n\n _relativeTime(date: Date): string {\n const diff = Date.now() - date.getTime();\n const mins = Math.floor(diff / 60000);\n if (mins < 1) return 'Ahora';\n if (mins < 60) return `Hace ${mins} min`;\n const hours = Math.floor(mins / 60);\n if (hours < 24) return `Hace ${hours}h`;\n return `Hace ${Math.floor(hours / 24)}d`;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|
|
@@ -16,33 +16,48 @@ let _seq = 0;
|
|
|
16
16
|
*/
|
|
17
17
|
class NeuNumberInputComponent {
|
|
18
18
|
/** Valor mínimo / Min value */
|
|
19
|
-
min = input(-Infinity,
|
|
19
|
+
min = input(-Infinity, /* @ts-ignore */
|
|
20
|
+
...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
|
|
20
21
|
/** Valor máximo / Max value */
|
|
21
|
-
max = input(Infinity,
|
|
22
|
+
max = input(Infinity, /* @ts-ignore */
|
|
23
|
+
...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
|
|
22
24
|
/** Incremento / Step */
|
|
23
|
-
step = input(1,
|
|
25
|
+
step = input(1, /* @ts-ignore */
|
|
26
|
+
...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
|
|
24
27
|
/** Etiqueta para el input (accesibilidad) / Label for the input (accessibility) */
|
|
25
|
-
label = input('',
|
|
28
|
+
label = input('', /* @ts-ignore */
|
|
29
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
26
30
|
/** Muestra el label como flotante dentro del campo. No compatible con vertical=true. / Shows the label as floating inside the field. Not compatible with vertical=true. */
|
|
27
|
-
floatingLabel = input(false,
|
|
31
|
+
floatingLabel = input(false, /* @ts-ignore */
|
|
32
|
+
...(ngDevMode ? [{ debugName: "floatingLabel" }] : /* istanbul ignore next */ []));
|
|
28
33
|
/** Aria-label del botón de decremento */
|
|
29
|
-
decrementLabel = input('Disminuir',
|
|
34
|
+
decrementLabel = input('Disminuir', /* @ts-ignore */
|
|
35
|
+
...(ngDevMode ? [{ debugName: "decrementLabel" }] : /* istanbul ignore next */ []));
|
|
30
36
|
/** Aria-label del botón de incremento */
|
|
31
|
-
incrementLabel = input('Aumentar',
|
|
37
|
+
incrementLabel = input('Aumentar', /* @ts-ignore */
|
|
38
|
+
...(ngDevMode ? [{ debugName: "incrementLabel" }] : /* istanbul ignore next */ []));
|
|
32
39
|
/** Muestra los botones en vertical / Shows buttons vertically */
|
|
33
|
-
vertical = input(false,
|
|
40
|
+
vertical = input(false, /* @ts-ignore */
|
|
41
|
+
...(ngDevMode ? [{ debugName: "vertical" }] : /* istanbul ignore next */ []));
|
|
34
42
|
/** Agrupa ambos botones apilados al final del input / Groups both buttons stacked at input end */
|
|
35
|
-
stacked = input(true,
|
|
43
|
+
stacked = input(true, /* @ts-ignore */
|
|
44
|
+
...(ngDevMode ? [{ debugName: "stacked" }] : /* istanbul ignore next */ []));
|
|
36
45
|
/** Tamaño del campo: 'sm' = 36px | 'md' = 48px | 'lg' = 56px / Field size */
|
|
37
|
-
size = input('md',
|
|
46
|
+
size = input('md', /* @ts-ignore */
|
|
47
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
38
48
|
/** Emitido en cada cambio / Emitted on each change */
|
|
39
49
|
valueChange = output();
|
|
40
50
|
_id = `neu-number-input-${++_seq}`;
|
|
41
|
-
_cvaDisabled = signal(false,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
_cvaDisabled = signal(false, /* @ts-ignore */
|
|
52
|
+
...(ngDevMode ? [{ debugName: "_cvaDisabled" }] : /* istanbul ignore next */ []));
|
|
53
|
+
_value = signal(0, /* @ts-ignore */
|
|
54
|
+
...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
|
|
55
|
+
_focused = signal(false, /* @ts-ignore */
|
|
56
|
+
...(ngDevMode ? [{ debugName: "_focused" }] : /* istanbul ignore next */ []));
|
|
57
|
+
hasValue = computed(() => Number.isFinite(this._value()), /* @ts-ignore */
|
|
58
|
+
...(ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []));
|
|
59
|
+
effectiveFloatingLabel = computed(() => this.floatingLabel() && !this.vertical(), /* @ts-ignore */
|
|
60
|
+
...(ngDevMode ? [{ debugName: "effectiveFloatingLabel" }] : /* istanbul ignore next */ []));
|
|
46
61
|
hostClasses = computed(() => ({
|
|
47
62
|
'neu-number-input': true,
|
|
48
63
|
'neu-number-input--vertical': this.vertical(),
|
|
@@ -51,7 +66,8 @@ class NeuNumberInputComponent {
|
|
|
51
66
|
'neu-number-input--disabled': this._cvaDisabled(),
|
|
52
67
|
'neu-number-input--sm': this.size() === 'sm',
|
|
53
68
|
'neu-number-input--lg': this.size() === 'lg',
|
|
54
|
-
}),
|
|
69
|
+
}), /* @ts-ignore */
|
|
70
|
+
...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
|
|
55
71
|
_onChange = () => { };
|
|
56
72
|
_onTouched = () => { };
|
|
57
73
|
writeValue(val) {
|
|
@@ -91,8 +107,8 @@ class NeuNumberInputComponent {
|
|
|
91
107
|
_clamp(v) {
|
|
92
108
|
return Math.min(this.max(), Math.max(this.min(), v));
|
|
93
109
|
}
|
|
94
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
95
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
110
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuNumberInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
111
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NeuNumberInputComponent, isStandalone: true, selector: "neu-number-input", 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 }, floatingLabel: { classPropertyName: "floatingLabel", publicName: "floatingLabel", isSignal: true, isRequired: false, transformFunction: null }, decrementLabel: { classPropertyName: "decrementLabel", publicName: "decrementLabel", isSignal: true, isRequired: false, transformFunction: null }, incrementLabel: { classPropertyName: "incrementLabel", publicName: "incrementLabel", isSignal: true, isRequired: false, transformFunction: null }, vertical: { classPropertyName: "vertical", publicName: "vertical", isSignal: true, isRequired: false, transformFunction: null }, stacked: { classPropertyName: "stacked", publicName: "stacked", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, host: { properties: { "class": "hostClasses()" } }, providers: [
|
|
96
112
|
{
|
|
97
113
|
provide: NG_VALUE_ACCESSOR,
|
|
98
114
|
useExisting: forwardRef(() => NeuNumberInputComponent),
|
|
@@ -223,7 +239,7 @@ class NeuNumberInputComponent {
|
|
|
223
239
|
</div>
|
|
224
240
|
`, isInline: true, styles: ["@charset \"UTF-8\";.neu-number-input{display:inline-flex;flex-direction:column;align-items:flex-start;gap:6px}.neu-number-input--disabled{opacity:.5;pointer-events:none}.neu-number-input--vertical .neu-number-input__control{flex-direction:column;gap:0;align-items:stretch;border:1px solid var(--neu-border);border-radius:var(--neu-radius-md, 8px);overflow:hidden;width:var(--neu-number-input-width, 80px)}.neu-number-input--vertical .neu-number-input__field{width:100%;border:none;border-top:1px solid var(--neu-border);border-bottom:1px solid var(--neu-border);border-radius:0}.neu-number-input--vertical .neu-number-input__control>.neu-number-input__btn{width:100%;border:none;border-radius:0}.neu-number-input--stacked .neu-number-input__control{align-items:stretch;gap:0}.neu-number-input--stacked .neu-number-input__field{flex:1 1 auto;width:auto;min-width:var(--neu-number-input-stacked-min-width, 120px);border-radius:var(--neu-radius-md, 8px) 0 0 var(--neu-radius-md, 8px);border-right:none;text-align:left;padding:0 10px}.neu-number-input--horizontal .neu-number-input__floating-label{left:calc(var(--neu-number-input-btn-size, 48px) + 12px);max-width:calc(100% - var(--neu-number-input-btn-size, 48px) * 2 - 28px)}.neu-number-input--sm{--neu-number-input-height: 36px;--neu-number-input-btn-size: 36px}.neu-number-input--sm .neu-number-input__field{font-size:var(--neu-text-sm)}.neu-number-input--lg{--neu-number-input-height: 56px;--neu-number-input-btn-size: 56px}.neu-number-input__label{font-size:var(--neu-text-sm, .875rem);font-weight:500;color:var(--neu-text);line-height:1.4;cursor:pointer}.neu-number-input__control{position:relative;display:inline-flex;align-items:center;gap:4px}.neu-number-input__field{width:var(--neu-number-input-width, 80px);height:var(--neu-number-input-height, 48px);padding:0 8px;border:1px solid var(--neu-border);border-radius:var(--neu-radius-md, 8px);background:var(--neu-surface);color:var(--neu-text);font-size:.9375rem;font-variant-numeric:tabular-nums;text-align:center;outline:none;transition:border-color .15s;-moz-appearance:textfield}.neu-number-input__field::-webkit-inner-spin-button,.neu-number-input__field::-webkit-outer-spin-button{display:none}.neu-number-input__field:focus{border-color:var(--neu-primary);box-shadow:var(--neu-focus-ring)}.neu-number-input__floating-label{position:absolute;left:6px;top:50%;z-index:1;transform:translateY(-50%);max-width:calc(100% - var(--neu-number-input-btn-size, 26px) - 18px);padding:0 4px;overflow:hidden;color:var(--neu-text-muted);font-size:var(--neu-text-base, 1rem);line-height:1.2;pointer-events:none;text-overflow:ellipsis;transition:top var(--neu-transition),color var(--neu-transition),font-size var(--neu-transition),transform var(--neu-transition),background var(--neu-transition);white-space:nowrap}.neu-number-input__control--focused .neu-number-input__floating-label,.neu-number-input__control--has-value .neu-number-input__floating-label{top:0;transform:translateY(-50%);background:var(--neu-surface);color:var(--neu-text-muted);font-size:12px;font-weight:600}.neu-number-input__control--focused .neu-number-input__floating-label{color:var(--neu-primary)}.neu-number-input__stack{display:flex;flex-direction:column;border:1px solid var(--neu-border);border-radius:0 var(--neu-radius-md, 8px) var(--neu-radius-md, 8px) 0;overflow:hidden;flex-shrink:0}.neu-number-input__stack .neu-number-input__btn{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;justify-content:center;flex:1;width:var(--neu-number-input-btn-size, 26px);border:none;border-radius:0;background:var(--neu-surface);color:var(--neu-text-muted);font-size:.625rem;font-weight:700;line-height:1;transition:background .1s,color .1s}.neu-number-input__stack .neu-number-input__btn:not(:disabled):hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-number-input__stack .neu-number-input__btn:focus-visible{outline:2px solid var(--neu-primary);outline-offset:-1px}.neu-number-input__stack .neu-number-input__btn:disabled{opacity:.4;cursor:not-allowed}.neu-number-input__stack .neu-number-input__btn--inc{border-bottom:1px solid var(--neu-border)}.neu-number-input__control>.neu-number-input__btn{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;justify-content:center;width:var(--neu-number-input-btn-size, 48px);height:var(--neu-number-input-btn-size, 48px);border:1px solid var(--neu-border);border-radius:var(--neu-radius-md, 8px);background:var(--neu-surface);color:var(--neu-text-muted);font-size:.6875rem;line-height:1;transition:background .12s,color .12s,border-color .12s}.neu-number-input__control>.neu-number-input__btn:not(:disabled):hover{background:var(--neu-surface-2);color:var(--neu-text);border-color:var(--neu-primary)}.neu-number-input__control>.neu-number-input__btn:focus-visible{outline:2px solid var(--neu-primary);outline-offset:1px}.neu-number-input__control>.neu-number-input__btn:disabled{opacity:.4;cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
225
241
|
}
|
|
226
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
242
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NeuNumberInputComponent, decorators: [{
|
|
227
243
|
type: Component,
|
|
228
244
|
args: [{ selector: 'neu-number-input', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'hostClasses()' }, providers: [
|
|
229
245
|
{
|