@neural-ui/core 1.5.0 → 1.5.2
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-chart.mjs +1 -0
- package/fesm2022/neural-ui-core-chart.mjs.map +1 -1
- package/fesm2022/neural-ui-core-sidebar.mjs +103 -7
- package/fesm2022/neural-ui-core-sidebar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-table.mjs +17 -6
- package/fesm2022/neural-ui-core-table.mjs.map +1 -1
- package/fesm2022/neural-ui-core-tree-table.mjs +1 -1
- package/fesm2022/neural-ui-core-tree-table.mjs.map +1 -1
- package/package.json +1 -1
- package/types/neural-ui-core-chart.d.ts +6 -0
- package/types/neural-ui-core-sidebar.d.ts +18 -1
- package/types/neural-ui-core-table.d.ts +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neural-ui-core-chart.mjs","sources":["../../../../projects/ui-core/chart/neu-chart.component.ts","../../../../projects/ui-core/chart/neural-ui-core-chart.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n input,\n} from '@angular/core';\nimport { ChartComponent } from 'ng-apexcharts';\n\nexport type NeuChartType =\n | 'line'\n | 'area'\n | 'bar'\n | 'bar-stacked'\n | 'bar-horizontal'\n | 'bar-horizontal-stacked'\n | 'pareto'\n | 'donut'\n | 'pie'\n | 'radialBar';\n\nexport interface NeuChartSeries {\n name: string;\n data: number[];\n}\n\n/** Paleta por defecto Neural-Blue / Default Neural-Blue palette */\nconst DEFAULT_COLORS = ['#007aff', '#5856d6', '#34c759', '#ff9f0a', '#ff3b30', '#64748b'];\n\n/** Calcula la línea acumulada porcentual para un diagrama de Pareto. / Calculates the cumulative percentage line for a Pareto chart. */\nfunction computeParetoCumulative(data: number[]): number[] {\n const total = data.reduce((s, v) => s + Math.abs(v), 0);\n if (total === 0) return data.map(() => 0);\n let cum = 0;\n return data.map((v) => {\n cum += Math.abs(v);\n return Math.round((cum / total) * 1000) / 10;\n });\n}\n\n/**\n * NeuChart — Wrapper reactivo de ApexCharts con estética Neural-Blue.\n *\n * Tipos soportados:\n * line · area · bar · bar-stacked · bar-horizontal · bar-horizontal-stacked · pareto · donut · pie · radialBar\n *\n * Uso:\n * <neu-chart\n * type=\"bar-stacked\"\n * [series]=\"series()\"\n * [categories]=\"months()\"\n * height=\"280\"\n * />\n */\n@Component({\n selector: 'neu-chart',\n imports: [ChartComponent],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'neu-chart' },\n template: `\n <apx-chart\n [chart]=\"chartConfig()\"\n [series]=\"resolvedSeries()\"\n [labels]=\"labels()\"\n [xaxis]=\"xaxisConfig()\"\n [yaxis]=\"yaxisConfig()\"\n [colors]=\"resolvedColors()\"\n [stroke]=\"strokeConfig()\"\n [fill]=\"fillConfig()\"\n [dataLabels]=\"dataLabelsConfig()\"\n [grid]=\"gridConfig()\"\n [legend]=\"legendConfig()\"\n [tooltip]=\"tooltipConfig()\"\n [plotOptions]=\"plotOptionsConfig()\"\n />\n `,\n styleUrl: './neu-chart.component.scss',\n})\nexport class NeuChartComponent {\n /** Tipo de gráfica. / Chart type. */\n type = input<NeuChartType>('line');\n /** Series para gráficas de ejes (line, area, bar, pareto…). / Series for axis-based charts (line, area, bar, pareto…). */\n series = input<NeuChartSeries[]>([]);\n /** Series para gráficas sin ejes (donut, pie). / Series for non-axis charts (donut, pie). */\n pieSeries = input<number[]>([]);\n /** Etiquetas del eje X. / X-axis labels. */\n categories = input<string[]>([]);\n /** Etiquetas para donut/pie. / Labels for donut/pie. */\n labels = input<string[]>([]);\n /** Altura en px. / Height in px. */\n height = input<number>(280);\n /** Colores custom. Si no se proveen, usa la paleta Neural-Blue. / Custom colors. If not provided, uses the Neural-Blue palette. */\n colors = input<string[]>([]);\n /** Muestra/oculta las etiquetas de datos. / Shows/hides data labels. */\n showDataLabels = input<boolean>(false);\n /** Título de la gráfica. / Chart title. */\n title = input<string>('');\n\n // --------------------------------------------------\n // Helpers privados\n // --------------------------------------------------\n\n private get _isBar(): boolean {\n return ['bar', 'bar-stacked', 'bar-horizontal', 'bar-horizontal-stacked', 'pareto'].includes(\n this.type(),\n );\n }\n\n private get _isStacked(): boolean {\n return ['bar-stacked', 'bar-horizontal-stacked'].includes(this.type());\n }\n\n private get _isHorizontal(): boolean {\n return ['bar-horizontal', 'bar-horizontal-stacked'].includes(this.type());\n }\n\n // --------------------------------------------------\n // Configs computadas\n // --------------------------------------------------\n\n protected readonly resolvedColors = computed(() =>\n this.colors().length ? this.colors() : DEFAULT_COLORS,\n );\n\n protected readonly resolvedSeries = computed((): any => {\n const t = this.type();\n if (t === 'donut' || t === 'pie' || t === 'radialBar') return this.pieSeries();\n if (t === 'pareto') {\n const first = this.series()[0];\n if (!first) return [];\n const cumulative = computeParetoCumulative(first.data);\n return [\n { name: first.name, type: 'bar', data: first.data },\n { name: 'Acumulado %', type: 'line', data: cumulative },\n ];\n }\n return this.series();\n });\n\n protected readonly chartConfig = computed(() => {\n const t = this.type();\n const apexType: string =\n t === 'bar-stacked' || t === 'bar-horizontal' || t === 'bar-horizontal-stacked'\n ? 'bar'\n : t === 'pareto'\n ? 'bar'\n : t;\n return {\n type: apexType as any,\n height: this.height(),\n stacked: this._isStacked,\n fontFamily: 'Inter, system-ui, -apple-system, sans-serif',\n foreColor: '#64748b',\n background: 'transparent',\n toolbar: { show: false },\n sparkline: { enabled: false },\n zoom: { enabled: false },\n animations: { enabled: true, speed: 500 },\n };\n });\n\n protected readonly xaxisConfig = computed(() => ({\n categories: this.categories(),\n labels: {\n style: { fontSize: '12px', fontFamily: 'inherit', colors: '#94a3b8' },\n },\n axisBorder: { show: false },\n axisTicks: { show: false },\n }));\n\n protected readonly yaxisConfig = computed((): any => {\n const labelStyle = { fontSize: '12px', fontFamily: 'inherit', colors: '#94a3b8' };\n if (this.type() === 'pareto') {\n return [\n { labels: { style: labelStyle } },\n {\n opposite: true,\n min: 0,\n max: 100,\n tickAmount: 5,\n labels: {\n style: labelStyle,\n formatter: (v: number) => `${v}%`,\n },\n },\n ];\n }\n return { labels: { style: labelStyle } };\n });\n\n protected readonly strokeConfig = computed(() => {\n const t = this.type();\n if (t === 'pareto') {\n return {\n show: true,\n width: [0, 2],\n curve: ['straight', 'smooth'] as any,\n lineCap: 'round' as const,\n };\n }\n if (this._isBar || t === 'donut' || t === 'pie' || t === 'radialBar') return { show: false };\n return { curve: 'smooth' as const, width: 2 };\n });\n\n protected readonly fillConfig = computed(() => {\n const t = this.type();\n if (t === 'area') {\n return {\n type: 'gradient' as const,\n gradient: { shadeIntensity: 1, opacityFrom: 0.35, opacityTo: 0.02, stops: [0, 100] },\n };\n }\n return { opacity: 0.85 };\n });\n\n protected readonly dataLabelsConfig = computed(() => ({\n enabled: this.showDataLabels(),\n style: { fontSize: '11px', fontFamily: 'inherit' },\n }));\n\n protected readonly gridConfig = computed(() => ({\n borderColor: '#e2e8f0',\n strokeDashArray: 4,\n xaxis: { lines: { show: false } },\n yaxis: { lines: { show: true } },\n padding: { left: 4, right: 4 },\n }));\n\n protected readonly legendConfig = computed(() => ({\n position: 'bottom' as const,\n fontFamily: 'inherit',\n fontSize: '12px',\n markers: { size: 6 },\n itemMargin: { horizontal: 8 },\n }));\n\n protected readonly tooltipConfig = computed(() => {\n const base = {\n theme: 'light' as const,\n style: { fontSize: '12px', fontFamily: 'inherit' },\n };\n if (this.type() === 'pareto') {\n return {\n ...base,\n y: [\n { formatter: (v: number) => String(v) },\n { formatter: (v: number) => `${v.toFixed(1)}%` },\n ],\n };\n }\n return base;\n });\n\n protected readonly plotOptionsConfig = computed(() => {\n const t = this.type();\n if (t === 'donut' || t === 'pie') {\n return { pie: { donut: { size: '68%' } } };\n }\n if (t === 'radialBar') {\n return {\n radialBar: {\n hollow: { margin: 4, size: '55%' },\n track: { background: 'var(--neu-surface-2, #f1f5f9)', strokeWidth: '100%', margin: 4 },\n dataLabels: {\n name: {\n fontSize: '14px',\n fontFamily: 'inherit',\n color: 'var(--neu-text-secondary, #64748b)',\n offsetY: -6,\n },\n value: {\n fontSize: '20px',\n fontFamily: 'inherit',\n fontWeight: 600,\n color: 'var(--neu-text-primary, #0f172a)',\n offsetY: 4,\n formatter: (v: number) => `${Math.round(v)}%`,\n },\n total: {\n show: true,\n label: 'Promedio',\n fontSize: '13px',\n fontFamily: 'inherit',\n color: 'var(--neu-text-secondary, #64748b)',\n formatter: (w: any) => {\n const vals: number[] = w.globals.series;\n const avg = vals.reduce((s: number, v: number) => s + v, 0) / vals.length;\n return `${Math.round(avg)}%`;\n },\n },\n },\n },\n };\n }\n if (this._isBar || t === 'pareto') {\n return {\n bar: {\n horizontal: this._isHorizontal,\n borderRadius: this._isStacked ? 0 : 4,\n columnWidth: '60%',\n barHeight: '70%',\n dataLabels: { total: { enabled: false } },\n },\n };\n }\n return {};\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-chart.mjs","sources":["../../../../projects/ui-core/chart/neu-chart.component.ts","../../../../projects/ui-core/chart/neural-ui-core-chart.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n input,\n} from '@angular/core';\nimport { ChartComponent } from 'ng-apexcharts';\n\nexport type NeuChartType =\n | 'line'\n | 'area'\n | 'bar'\n | 'bar-stacked'\n | 'bar-horizontal'\n | 'bar-horizontal-stacked'\n | 'pareto'\n | 'donut'\n | 'pie'\n | 'radialBar';\n\nexport interface NeuChartSeries {\n name: string;\n data: number[];\n}\n\n/** Paleta por defecto Neural-Blue / Default Neural-Blue palette */\nconst DEFAULT_COLORS = ['#007aff', '#5856d6', '#34c759', '#ff9f0a', '#ff3b30', '#64748b'];\n\n/** Calcula la línea acumulada porcentual para un diagrama de Pareto. / Calculates the cumulative percentage line for a Pareto chart. */\nfunction computeParetoCumulative(data: number[]): number[] {\n const total = data.reduce((s, v) => s + Math.abs(v), 0);\n if (total === 0) return data.map(() => 0);\n let cum = 0;\n return data.map((v) => {\n cum += Math.abs(v);\n return Math.round((cum / total) * 1000) / 10;\n });\n}\n\n/**\n * NeuChart — Wrapper reactivo de ApexCharts con estética Neural-Blue.\n *\n * Tipos soportados:\n * line · area · bar · bar-stacked · bar-horizontal · bar-horizontal-stacked · pareto · donut · pie · radialBar\n *\n * Uso:\n * <neu-chart\n * type=\"bar-stacked\"\n * [series]=\"series()\"\n * [categories]=\"months()\"\n * height=\"280\"\n * />\n */\n@Component({\n selector: 'neu-chart',\n imports: [ChartComponent],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'neu-chart' },\n template: `\n <apx-chart\n [chart]=\"chartConfig()\"\n [series]=\"resolvedSeries()\"\n [labels]=\"labels()\"\n [xaxis]=\"xaxisConfig()\"\n [yaxis]=\"yaxisConfig()\"\n [colors]=\"resolvedColors()\"\n [stroke]=\"strokeConfig()\"\n [fill]=\"fillConfig()\"\n [dataLabels]=\"dataLabelsConfig()\"\n [grid]=\"gridConfig()\"\n [legend]=\"legendConfig()\"\n [tooltip]=\"tooltipConfig()\"\n [plotOptions]=\"plotOptionsConfig()\"\n />\n `,\n styleUrl: './neu-chart.component.scss',\n})\nexport class NeuChartComponent {\n /** Tipo de gráfica. / Chart type. */\n type = input<NeuChartType>('line');\n /** Series para gráficas de ejes (line, area, bar, pareto…). / Series for axis-based charts (line, area, bar, pareto…). */\n series = input<NeuChartSeries[]>([]);\n /** Series para gráficas sin ejes (donut, pie). / Series for non-axis charts (donut, pie). */\n pieSeries = input<number[]>([]);\n /** Etiquetas del eje X. / X-axis labels. */\n categories = input<string[]>([]);\n /** Etiquetas para donut/pie. / Labels for donut/pie. */\n labels = input<string[]>([]);\n /** Altura en px. / Height in px. */\n height = input<number>(280);\n /** Colores custom. Si no se proveen, usa la paleta Neural-Blue. / Custom colors. If not provided, uses the Neural-Blue palette. */\n colors = input<string[]>([]);\n /** Muestra/oculta las etiquetas de datos. / Shows/hides data labels. */\n showDataLabels = input<boolean>(false);\n /** Título de la gráfica. / Chart title. */\n title = input<string>('');\n\n // --------------------------------------------------\n // Helpers privados\n // --------------------------------------------------\n\n private get _isBar(): boolean {\n return ['bar', 'bar-stacked', 'bar-horizontal', 'bar-horizontal-stacked', 'pareto'].includes(\n this.type(),\n );\n }\n\n private get _isStacked(): boolean {\n return ['bar-stacked', 'bar-horizontal-stacked'].includes(this.type());\n }\n\n private get _isHorizontal(): boolean {\n return ['bar-horizontal', 'bar-horizontal-stacked'].includes(this.type());\n }\n\n // --------------------------------------------------\n // Configs computadas\n // --------------------------------------------------\n\n protected readonly resolvedColors = computed(() =>\n this.colors().length ? this.colors() : DEFAULT_COLORS,\n );\n\n protected readonly resolvedSeries = computed((): any => {\n const t = this.type();\n if (t === 'donut' || t === 'pie' || t === 'radialBar') return this.pieSeries();\n if (t === 'pareto') {\n const first = this.series()[0];\n if (!first) return [];\n const cumulative = computeParetoCumulative(first.data);\n return [\n { name: first.name, type: 'bar', data: first.data },\n { name: 'Acumulado %', type: 'line', data: cumulative },\n ];\n }\n return this.series();\n });\n\n protected readonly chartConfig = computed(() => {\n const t = this.type();\n const apexType: string =\n t === 'bar-stacked' || t === 'bar-horizontal' || t === 'bar-horizontal-stacked'\n ? 'bar'\n : t === 'pareto'\n ? 'bar'\n : t;\n return {\n type: apexType as any,\n height: this.height(),\n stacked: this._isStacked,\n fontFamily: 'Inter, system-ui, -apple-system, sans-serif',\n foreColor: '#64748b',\n background: 'transparent',\n toolbar: { show: false },\n sparkline: { enabled: false },\n zoom: { enabled: false },\n animations: { enabled: true, speed: 500 },\n };\n });\n\n protected readonly xaxisConfig = computed(() => ({\n categories: this.categories(),\n labels: {\n style: { fontSize: '12px', fontFamily: 'inherit', colors: '#94a3b8' },\n },\n axisBorder: { show: false },\n axisTicks: { show: false },\n }));\n\n protected readonly yaxisConfig = computed((): any => {\n const labelStyle = { fontSize: '12px', fontFamily: 'inherit', colors: '#94a3b8' };\n if (this.type() === 'pareto') {\n return [\n { labels: { style: labelStyle } },\n {\n opposite: true,\n min: 0,\n max: 100,\n tickAmount: 5,\n labels: {\n style: labelStyle,\n formatter: (v: number) => `${v}%`,\n },\n },\n ];\n }\n return { labels: { style: labelStyle } };\n });\n\n protected readonly strokeConfig = computed(() => {\n const t = this.type();\n if (t === 'pareto') {\n return {\n show: true,\n width: [0, 2],\n curve: ['straight', 'smooth'] as any,\n lineCap: 'round' as const,\n };\n }\n if (this._isBar || t === 'donut' || t === 'pie' || t === 'radialBar') return { show: false };\n return { curve: 'smooth' as const, width: 2 };\n });\n\n protected readonly fillConfig = computed(() => {\n const t = this.type();\n if (t === 'area') {\n return {\n type: 'gradient' as const,\n gradient: { shadeIntensity: 1, opacityFrom: 0.35, opacityTo: 0.02, stops: [0, 100] },\n };\n }\n return { opacity: 0.85 };\n });\n\n protected readonly dataLabelsConfig = computed(() => ({\n enabled: this.showDataLabels(),\n style: { fontSize: '11px', fontFamily: 'inherit' },\n }));\n\n protected readonly gridConfig = computed(() => ({\n borderColor: '#e2e8f0',\n strokeDashArray: 4,\n xaxis: { lines: { show: false } },\n yaxis: { lines: { show: true } },\n padding: { left: 4, right: 4 },\n }));\n\n protected readonly legendConfig = computed(() => ({\n position: 'bottom' as const,\n fontFamily: 'inherit',\n fontSize: '12px',\n markers: { size: 6 },\n itemMargin: { horizontal: 8 },\n }));\n\n protected readonly tooltipConfig = computed(() => {\n const base = {\n theme: 'light' as const,\n style: { fontSize: '12px', fontFamily: 'inherit' },\n x: { show: true },\n };\n if (this.type() === 'pareto') {\n return {\n ...base,\n y: [\n { formatter: (v: number) => String(v) },\n { formatter: (v: number) => `${v.toFixed(1)}%` },\n ],\n };\n }\n return base;\n });\n\n protected readonly plotOptionsConfig = computed(() => {\n const t = this.type();\n if (t === 'donut' || t === 'pie') {\n return { pie: { donut: { size: '68%' } } };\n }\n if (t === 'radialBar') {\n return {\n radialBar: {\n hollow: { margin: 4, size: '55%' },\n track: { background: 'var(--neu-surface-2, #f1f5f9)', strokeWidth: '100%', margin: 4 },\n dataLabels: {\n name: {\n fontSize: '14px',\n fontFamily: 'inherit',\n color: 'var(--neu-text-secondary, #64748b)',\n offsetY: -6,\n },\n value: {\n fontSize: '20px',\n fontFamily: 'inherit',\n fontWeight: 600,\n color: 'var(--neu-text-primary, #0f172a)',\n offsetY: 4,\n formatter: (v: number) => `${Math.round(v)}%`,\n },\n total: {\n show: true,\n label: 'Promedio',\n fontSize: '13px',\n fontFamily: 'inherit',\n color: 'var(--neu-text-secondary, #64748b)',\n formatter: (w: any) => {\n const vals: number[] = w.globals.series;\n const avg = vals.reduce((s: number, v: number) => s + v, 0) / vals.length;\n return `${Math.round(avg)}%`;\n },\n },\n },\n },\n };\n }\n if (this._isBar || t === 'pareto') {\n return {\n bar: {\n horizontal: this._isHorizontal,\n borderRadius: this._isStacked ? 0 : 4,\n columnWidth: '60%',\n barHeight: '70%',\n dataLabels: { total: { enabled: false } },\n },\n };\n }\n return {};\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, computed, input, output, effect, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
|
|
2
|
+
import { inject, ElementRef, computed, input, output, effect, HostListener, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
|
|
3
3
|
import { DOCUMENT } from '@angular/common';
|
|
4
4
|
import { NeuUrlStateService } from '@neural-ui/core/url-state';
|
|
5
5
|
import { NeuIconComponent } from '@neural-ui/core/icon';
|
|
@@ -48,8 +48,10 @@ function unlockDocumentScroll(document) {
|
|
|
48
48
|
*/
|
|
49
49
|
class NeuSidebarComponent {
|
|
50
50
|
document = inject(DOCUMENT);
|
|
51
|
+
elementRef = inject(ElementRef);
|
|
51
52
|
urlState = inject(NeuUrlStateService);
|
|
52
53
|
openParam = computed(() => this.urlState.getParam(this.urlParam()), ...(ngDevMode ? [{ debugName: "openParam" }] : /* istanbul ignore next */ []));
|
|
54
|
+
previousActiveElement = null;
|
|
53
55
|
/** Posición del sidebar: izquierda o derecha de la pantalla / Sidebar position: left or right of the screen */
|
|
54
56
|
side = input('left', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
|
|
55
57
|
/** QueryParam que controla el estado. Default: 'menu' (?menu=open) / QueryParam that controls the state. Default: 'menu' (?menu=open) */
|
|
@@ -68,8 +70,15 @@ class NeuSidebarComponent {
|
|
|
68
70
|
ariaLabel = input('Menú de navegación', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
69
71
|
/** Etiqueta accesible para el botón cerrar / Accessible label for the close button */
|
|
70
72
|
closeLabel = input('Cerrar menú de navegación', ...(ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []));
|
|
73
|
+
/**
|
|
74
|
+
* Modo colapsado: el sidebar muestra solo iconos (icon-only en desktop).
|
|
75
|
+
* Útil para sidebars persistentes en modo compact / Collapsed mode: sidebar shows only icons.
|
|
76
|
+
*/
|
|
77
|
+
collapsed = input(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
71
78
|
/** Emite cuando el usuario cierra el sidebar (overlay click o botón) / Emits when the user closes the sidebar (overlay click or button) */
|
|
72
79
|
closeRequested = output();
|
|
80
|
+
/** Emite cuando el estado collapsed cambia / Emits when collapsed state changes */
|
|
81
|
+
collapsedChange = output();
|
|
73
82
|
/** Signal reactivo: true si el sidebar debe mostrarse / Reactive signal: true if the sidebar should be shown */
|
|
74
83
|
isOpen = computed(() => {
|
|
75
84
|
if (this.persistent())
|
|
@@ -87,6 +96,27 @@ class NeuSidebarComponent {
|
|
|
87
96
|
unlockDocumentScroll(this.document);
|
|
88
97
|
});
|
|
89
98
|
});
|
|
99
|
+
// Focus management: save previous element and move focus to sidebar when opening in drawer mode
|
|
100
|
+
effect(() => {
|
|
101
|
+
const isOpenNow = this.isOpen();
|
|
102
|
+
const isPersistent = this.persistent();
|
|
103
|
+
if (isPersistent) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (isOpenNow) {
|
|
107
|
+
// Save the current active element
|
|
108
|
+
this.previousActiveElement = this.document.activeElement;
|
|
109
|
+
// Move focus to first focusable element inside the sidebar
|
|
110
|
+
this.focusFirstElement();
|
|
111
|
+
}
|
|
112
|
+
else if (this.previousActiveElement && this.previousActiveElement.focus) {
|
|
113
|
+
// Restore focus to the element that had it before opening
|
|
114
|
+
setTimeout(() => {
|
|
115
|
+
this.previousActiveElement?.focus();
|
|
116
|
+
this.previousActiveElement = null;
|
|
117
|
+
}, 0);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
90
120
|
}
|
|
91
121
|
/** Abre el sidebar — añade ?{urlParam}=open a la URL / Opens the sidebar — adds ?{urlParam}=open to the URL */
|
|
92
122
|
open(replaceUrl = false) {
|
|
@@ -97,8 +127,67 @@ class NeuSidebarComponent {
|
|
|
97
127
|
this.urlState.setParam(this.urlParam(), null, true);
|
|
98
128
|
this.closeRequested.emit();
|
|
99
129
|
}
|
|
130
|
+
/** Alterna el estado collapsed / Toggles collapsed state */
|
|
131
|
+
toggleCollapsed() {
|
|
132
|
+
const newState = !this.collapsed();
|
|
133
|
+
this.collapsedChange.emit(newState);
|
|
134
|
+
}
|
|
135
|
+
/** Obtiene los elementos focusables dentro del sidebar / Gets focusable elements inside sidebar */
|
|
136
|
+
getFocusableElements() {
|
|
137
|
+
const focusableSelectors = [
|
|
138
|
+
'button',
|
|
139
|
+
'a[href]',
|
|
140
|
+
'input:not([disabled])',
|
|
141
|
+
'select:not([disabled])',
|
|
142
|
+
'textarea:not([disabled])',
|
|
143
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
144
|
+
].join(',');
|
|
145
|
+
const aside = this.elementRef.nativeElement.querySelector('aside.neu-sidebar');
|
|
146
|
+
if (!aside) {
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
return Array.from(aside.querySelectorAll(focusableSelectors));
|
|
150
|
+
}
|
|
151
|
+
/** Mueve el foco al primer elemento focusable / Moves focus to first focusable element */
|
|
152
|
+
focusFirstElement() {
|
|
153
|
+
setTimeout(() => {
|
|
154
|
+
const focusable = this.getFocusableElements();
|
|
155
|
+
if (focusable.length > 0) {
|
|
156
|
+
focusable[0].focus();
|
|
157
|
+
}
|
|
158
|
+
}, 0);
|
|
159
|
+
}
|
|
160
|
+
/** Focus trap: cicla entre elementos focusables con Tab/Shift+Tab / Focus trap cycling */
|
|
161
|
+
onKeyDown(event) {
|
|
162
|
+
if (!this.isOpen() || this.persistent()) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (event.key !== 'Tab') {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const focusable = this.getFocusableElements();
|
|
169
|
+
if (focusable.length === 0) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const activeElement = this.document.activeElement;
|
|
173
|
+
const currentIndex = focusable.indexOf(activeElement);
|
|
174
|
+
if (event.shiftKey) {
|
|
175
|
+
// Shift+Tab — go to previous
|
|
176
|
+
if (currentIndex <= 0) {
|
|
177
|
+
event.preventDefault();
|
|
178
|
+
focusable[focusable.length - 1].focus();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// Tab — go to next
|
|
183
|
+
if (currentIndex >= focusable.length - 1) {
|
|
184
|
+
event.preventDefault();
|
|
185
|
+
focusable[0].focus();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
100
189
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
101
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuSidebarComponent, isStandalone: true, selector: "neu-sidebar", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, urlParam: { classPropertyName: "urlParam", publicName: "urlParam", isSignal: true, isRequired: false, transformFunction: null }, persistent: { classPropertyName: "persistent", publicName: "persistent", isSignal: true, isRequired: false, transformFunction: null }, hideHeader: { classPropertyName: "hideHeader", publicName: "hideHeader", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closeRequested: "closeRequested" }, ngImport: i0, template: `
|
|
190
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuSidebarComponent, isStandalone: true, selector: "neu-sidebar", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, urlParam: { classPropertyName: "urlParam", publicName: "urlParam", isSignal: true, isRequired: false, transformFunction: null }, persistent: { classPropertyName: "persistent", publicName: "persistent", isSignal: true, isRequired: false, transformFunction: null }, hideHeader: { classPropertyName: "hideHeader", publicName: "hideHeader", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closeRequested: "closeRequested", collapsedChange: "collapsedChange" }, host: { listeners: { "keydown": "onKeyDown($event)" } }, ngImport: i0, template: `
|
|
102
191
|
<!-- Overlay de fondo — solo visible en modo overlay -->
|
|
103
192
|
@if (!persistent()) {
|
|
104
193
|
<div
|
|
@@ -114,8 +203,10 @@ class NeuSidebarComponent {
|
|
|
114
203
|
class="neu-sidebar"
|
|
115
204
|
[class.neu-sidebar--open]="isOpen()"
|
|
116
205
|
[class.neu-sidebar--persistent]="persistent()"
|
|
206
|
+
[class.neu-sidebar--collapsed]="collapsed()"
|
|
117
207
|
[class.neu-sidebar--right]="side() === 'right'"
|
|
118
|
-
role="navigation"
|
|
208
|
+
[attr.role]="persistent() ? 'navigation' : 'dialog'"
|
|
209
|
+
[attr.aria-modal]="!persistent()"
|
|
119
210
|
[attr.aria-label]="ariaLabel()"
|
|
120
211
|
[attr.aria-hidden]="!isOpen() && !persistent()"
|
|
121
212
|
[attr.inert]="!isOpen() && !persistent() ? '' : null"
|
|
@@ -149,7 +240,7 @@ class NeuSidebarComponent {
|
|
|
149
240
|
<ng-content select="[neu-sidebar-footer]" />
|
|
150
241
|
</div>
|
|
151
242
|
</aside>
|
|
152
|
-
`, isInline: true, styles: [".neu-sidebar__overlay{position:fixed;inset:0;background:var(--neu-overlay-bg-soft);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);z-index:var(--neu-z-overlay);opacity:0;pointer-events:none;transition:opacity var(--neu-transition-slow)}.neu-sidebar__overlay--visible{opacity:1;pointer-events:all}.neu-sidebar{position:fixed;top:0;left:0;height:100dvh;width:100%;background:var(--neu-sidebar-bg, var(--neu-surface));border-right:1px solid var(--neu-border);z-index:var(--neu-z-sidebar);display:flex;flex-direction:column;transform:translate(-100%);transition:transform var(--neu-transition-slow),box-shadow var(--neu-transition-slow);overflow:hidden}@media(min-width:400px){.neu-sidebar{width:var(--neu-sidebar-width, 260px)}}.neu-sidebar--open:not(.neu-sidebar--persistent):not(.neu-sidebar--right){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--right{left:auto;right:0;border-right:none;border-left:1px solid var(--neu-border);transform:translate(100%)}.neu-sidebar--right.neu-sidebar--open:not(.neu-sidebar--persistent){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--persistent{position:sticky;top:var(--neu-header-height);height:calc(100dvh - var(--neu-header-height));transform:none;box-shadow:none;border-right:1px solid var(--neu-border);flex-shrink:0;z-index:var(--neu-z-base)}.neu-sidebar__header{display:flex;align-items:center;justify-content:space-between;padding:0 var(--neu-space-5);min-height:var(--neu-header-height, 64px);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__title{font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);font-weight:700;letter-spacing:-.01em;color:var(--neu-text)}.neu-sidebar__close{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--neu-radius);color:var(--neu-text-muted);cursor:pointer;flex-shrink:0;transition:background-color var(--neu-transition),color var(--neu-transition),border-color var(--neu-transition)}.neu-sidebar__close:hover{background:var(--neu-surface-2);color:var(--neu-text);border-color:var(--neu-border)}.neu-sidebar__close:focus-visible{outline:none;box-shadow:var(--neu-focus-ring-strong)}.neu-sidebar__content{flex:1;overflow-y:auto;overflow-x:hidden;padding:var(--neu-space-3) 0;scrollbar-width:thin;scrollbar-color:var(--neu-surface-3) transparent}.neu-sidebar__content::-webkit-scrollbar{width:4px}.neu-sidebar__content::-webkit-scrollbar-track{background:transparent}.neu-sidebar__content::-webkit-scrollbar-thumb{background:var(--neu-surface-3);border-radius:var(--neu-radius-full)}.neu-sidebar__footer{padding:var(--neu-space-4) var(--neu-space-5);border-top:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__footer:empty{display:none}\n"], dependencies: [{ kind: "component", type: NeuIconComponent, selector: "neu-icon", inputs: ["name", "strokeWidth", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
243
|
+
`, isInline: true, styles: [".neu-sidebar__overlay{position:fixed;inset:0;background:var(--neu-overlay-bg-soft);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);z-index:var(--neu-z-overlay);opacity:0;pointer-events:none;transition:opacity var(--neu-transition-slow)}.neu-sidebar__overlay--visible{opacity:1;pointer-events:all}.neu-sidebar{position:fixed;top:0;left:0;height:100dvh;width:100%;background:var(--neu-sidebar-bg, var(--neu-surface));border-right:1px solid var(--neu-border);z-index:var(--neu-z-sidebar);display:flex;flex-direction:column;transform:translate(-100%);transition:transform var(--neu-transition-slow),box-shadow var(--neu-transition-slow);overflow:hidden}@media(min-width:400px){.neu-sidebar{width:var(--neu-sidebar-width, 260px)}}.neu-sidebar--open:not(.neu-sidebar--persistent):not(.neu-sidebar--right){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--right{left:auto;right:0;border-right:none;border-left:1px solid var(--neu-border);transform:translate(100%)}.neu-sidebar--right.neu-sidebar--open:not(.neu-sidebar--persistent){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--persistent{position:sticky;top:var(--neu-header-height);height:calc(100dvh - var(--neu-header-height));transform:none;box-shadow:none;border-right:1px solid var(--neu-border);flex-shrink:0;z-index:var(--neu-z-base)}.neu-sidebar__header{display:flex;align-items:center;justify-content:space-between;padding:0 var(--neu-space-5);min-height:var(--neu-header-height, 64px);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__title{font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);font-weight:700;letter-spacing:-.01em;color:var(--neu-text)}.neu-sidebar__close{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--neu-radius);color:var(--neu-text-muted);cursor:pointer;flex-shrink:0;transition:background-color var(--neu-transition),color var(--neu-transition),border-color var(--neu-transition)}.neu-sidebar__close:hover{background:var(--neu-surface-2);color:var(--neu-text);border-color:var(--neu-border)}.neu-sidebar__close:focus-visible{outline:none;box-shadow:var(--neu-focus-ring-strong)}.neu-sidebar__content{flex:1;overflow-y:auto;overflow-x:hidden;padding:var(--neu-space-3) 0;scrollbar-width:thin;scrollbar-color:var(--neu-surface-3) transparent}.neu-sidebar__content::-webkit-scrollbar{width:4px}.neu-sidebar__content::-webkit-scrollbar-track{background:transparent}.neu-sidebar__content::-webkit-scrollbar-thumb{background:var(--neu-surface-3);border-radius:var(--neu-radius-full)}.neu-sidebar__footer{padding:var(--neu-space-4) var(--neu-space-5);border-top:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__footer:empty{display:none}.neu-sidebar--collapsed{width:var(--neu-sidebar-collapsed-width, 60px)!important}.neu-sidebar--collapsed .neu-sidebar__header{flex-direction:column;justify-content:center;padding:0;min-height:var(--neu-header-height, 64px)}.neu-sidebar--collapsed .neu-sidebar__header .neu-sidebar__title{display:none}.neu-sidebar--collapsed .neu-sidebar__content{padding:var(--neu-space-2) 0}.neu-sidebar--collapsed a span:not([neu-sidebar-header]),.neu-sidebar--collapsed button span:not([neu-sidebar-header]){max-width:0;overflow:hidden;opacity:0;transition:max-width var(--neu-transition),opacity var(--neu-transition)}.neu-sidebar--collapsed .neu-sidebar__footer{padding:var(--neu-space-2) var(--neu-space-3);min-height:auto}.neu-sidebar--collapsed .neu-sidebar__footer span{display:none}.neu-sidebar--collapsed .neu-sidebar__close{width:40px;height:40px}\n"], dependencies: [{ kind: "component", type: NeuIconComponent, selector: "neu-icon", inputs: ["name", "strokeWidth", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
153
244
|
}
|
|
154
245
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSidebarComponent, decorators: [{
|
|
155
246
|
type: Component,
|
|
@@ -169,8 +260,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
169
260
|
class="neu-sidebar"
|
|
170
261
|
[class.neu-sidebar--open]="isOpen()"
|
|
171
262
|
[class.neu-sidebar--persistent]="persistent()"
|
|
263
|
+
[class.neu-sidebar--collapsed]="collapsed()"
|
|
172
264
|
[class.neu-sidebar--right]="side() === 'right'"
|
|
173
|
-
role="navigation"
|
|
265
|
+
[attr.role]="persistent() ? 'navigation' : 'dialog'"
|
|
266
|
+
[attr.aria-modal]="!persistent()"
|
|
174
267
|
[attr.aria-label]="ariaLabel()"
|
|
175
268
|
[attr.aria-hidden]="!isOpen() && !persistent()"
|
|
176
269
|
[attr.inert]="!isOpen() && !persistent() ? '' : null"
|
|
@@ -204,8 +297,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
204
297
|
<ng-content select="[neu-sidebar-footer]" />
|
|
205
298
|
</div>
|
|
206
299
|
</aside>
|
|
207
|
-
`, styles: [".neu-sidebar__overlay{position:fixed;inset:0;background:var(--neu-overlay-bg-soft);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);z-index:var(--neu-z-overlay);opacity:0;pointer-events:none;transition:opacity var(--neu-transition-slow)}.neu-sidebar__overlay--visible{opacity:1;pointer-events:all}.neu-sidebar{position:fixed;top:0;left:0;height:100dvh;width:100%;background:var(--neu-sidebar-bg, var(--neu-surface));border-right:1px solid var(--neu-border);z-index:var(--neu-z-sidebar);display:flex;flex-direction:column;transform:translate(-100%);transition:transform var(--neu-transition-slow),box-shadow var(--neu-transition-slow);overflow:hidden}@media(min-width:400px){.neu-sidebar{width:var(--neu-sidebar-width, 260px)}}.neu-sidebar--open:not(.neu-sidebar--persistent):not(.neu-sidebar--right){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--right{left:auto;right:0;border-right:none;border-left:1px solid var(--neu-border);transform:translate(100%)}.neu-sidebar--right.neu-sidebar--open:not(.neu-sidebar--persistent){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--persistent{position:sticky;top:var(--neu-header-height);height:calc(100dvh - var(--neu-header-height));transform:none;box-shadow:none;border-right:1px solid var(--neu-border);flex-shrink:0;z-index:var(--neu-z-base)}.neu-sidebar__header{display:flex;align-items:center;justify-content:space-between;padding:0 var(--neu-space-5);min-height:var(--neu-header-height, 64px);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__title{font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);font-weight:700;letter-spacing:-.01em;color:var(--neu-text)}.neu-sidebar__close{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--neu-radius);color:var(--neu-text-muted);cursor:pointer;flex-shrink:0;transition:background-color var(--neu-transition),color var(--neu-transition),border-color var(--neu-transition)}.neu-sidebar__close:hover{background:var(--neu-surface-2);color:var(--neu-text);border-color:var(--neu-border)}.neu-sidebar__close:focus-visible{outline:none;box-shadow:var(--neu-focus-ring-strong)}.neu-sidebar__content{flex:1;overflow-y:auto;overflow-x:hidden;padding:var(--neu-space-3) 0;scrollbar-width:thin;scrollbar-color:var(--neu-surface-3) transparent}.neu-sidebar__content::-webkit-scrollbar{width:4px}.neu-sidebar__content::-webkit-scrollbar-track{background:transparent}.neu-sidebar__content::-webkit-scrollbar-thumb{background:var(--neu-surface-3);border-radius:var(--neu-radius-full)}.neu-sidebar__footer{padding:var(--neu-space-4) var(--neu-space-5);border-top:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__footer:empty{display:none}\n"] }]
|
|
208
|
-
}], ctorParameters: () => [], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], urlParam: [{ type: i0.Input, args: [{ isSignal: true, alias: "urlParam", required: false }] }], persistent: [{ type: i0.Input, args: [{ isSignal: true, alias: "persistent", required: false }] }], hideHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideHeader", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], closeRequested: [{ type: i0.Output, args: ["closeRequested"] }] }
|
|
300
|
+
`, styles: [".neu-sidebar__overlay{position:fixed;inset:0;background:var(--neu-overlay-bg-soft);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);z-index:var(--neu-z-overlay);opacity:0;pointer-events:none;transition:opacity var(--neu-transition-slow)}.neu-sidebar__overlay--visible{opacity:1;pointer-events:all}.neu-sidebar{position:fixed;top:0;left:0;height:100dvh;width:100%;background:var(--neu-sidebar-bg, var(--neu-surface));border-right:1px solid var(--neu-border);z-index:var(--neu-z-sidebar);display:flex;flex-direction:column;transform:translate(-100%);transition:transform var(--neu-transition-slow),box-shadow var(--neu-transition-slow);overflow:hidden}@media(min-width:400px){.neu-sidebar{width:var(--neu-sidebar-width, 260px)}}.neu-sidebar--open:not(.neu-sidebar--persistent):not(.neu-sidebar--right){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--right{left:auto;right:0;border-right:none;border-left:1px solid var(--neu-border);transform:translate(100%)}.neu-sidebar--right.neu-sidebar--open:not(.neu-sidebar--persistent){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--persistent{position:sticky;top:var(--neu-header-height);height:calc(100dvh - var(--neu-header-height));transform:none;box-shadow:none;border-right:1px solid var(--neu-border);flex-shrink:0;z-index:var(--neu-z-base)}.neu-sidebar__header{display:flex;align-items:center;justify-content:space-between;padding:0 var(--neu-space-5);min-height:var(--neu-header-height, 64px);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__title{font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);font-weight:700;letter-spacing:-.01em;color:var(--neu-text)}.neu-sidebar__close{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--neu-radius);color:var(--neu-text-muted);cursor:pointer;flex-shrink:0;transition:background-color var(--neu-transition),color var(--neu-transition),border-color var(--neu-transition)}.neu-sidebar__close:hover{background:var(--neu-surface-2);color:var(--neu-text);border-color:var(--neu-border)}.neu-sidebar__close:focus-visible{outline:none;box-shadow:var(--neu-focus-ring-strong)}.neu-sidebar__content{flex:1;overflow-y:auto;overflow-x:hidden;padding:var(--neu-space-3) 0;scrollbar-width:thin;scrollbar-color:var(--neu-surface-3) transparent}.neu-sidebar__content::-webkit-scrollbar{width:4px}.neu-sidebar__content::-webkit-scrollbar-track{background:transparent}.neu-sidebar__content::-webkit-scrollbar-thumb{background:var(--neu-surface-3);border-radius:var(--neu-radius-full)}.neu-sidebar__footer{padding:var(--neu-space-4) var(--neu-space-5);border-top:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__footer:empty{display:none}.neu-sidebar--collapsed{width:var(--neu-sidebar-collapsed-width, 60px)!important}.neu-sidebar--collapsed .neu-sidebar__header{flex-direction:column;justify-content:center;padding:0;min-height:var(--neu-header-height, 64px)}.neu-sidebar--collapsed .neu-sidebar__header .neu-sidebar__title{display:none}.neu-sidebar--collapsed .neu-sidebar__content{padding:var(--neu-space-2) 0}.neu-sidebar--collapsed a span:not([neu-sidebar-header]),.neu-sidebar--collapsed button span:not([neu-sidebar-header]){max-width:0;overflow:hidden;opacity:0;transition:max-width var(--neu-transition),opacity var(--neu-transition)}.neu-sidebar--collapsed .neu-sidebar__footer{padding:var(--neu-space-2) var(--neu-space-3);min-height:auto}.neu-sidebar--collapsed .neu-sidebar__footer span{display:none}.neu-sidebar--collapsed .neu-sidebar__close{width:40px;height:40px}\n"] }]
|
|
301
|
+
}], ctorParameters: () => [], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], urlParam: [{ type: i0.Input, args: [{ isSignal: true, alias: "urlParam", required: false }] }], persistent: [{ type: i0.Input, args: [{ isSignal: true, alias: "persistent", required: false }] }], hideHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideHeader", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], closeRequested: [{ type: i0.Output, args: ["closeRequested"] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], onKeyDown: [{
|
|
302
|
+
type: HostListener,
|
|
303
|
+
args: ['keydown', ['$event']]
|
|
304
|
+
}] } });
|
|
209
305
|
|
|
210
306
|
/**
|
|
211
307
|
* Generated bundle index. Do not edit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neural-ui-core-sidebar.mjs","sources":["../../../../projects/ui-core/sidebar/neu-sidebar.component.ts","../../../../projects/ui-core/sidebar/neural-ui-core-sidebar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { NeuUrlStateService } from '@neural-ui/core/url-state';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\n\nlet overlayScrollLockCount = 0;\nlet previousHtmlOverflow = '';\nlet previousBodyOverflow = '';\n\nfunction lockDocumentScroll(document: Document): void {\n if (overlayScrollLockCount === 0) {\n previousHtmlOverflow = document.documentElement.style.overflow;\n previousBodyOverflow = document.body.style.overflow;\n document.documentElement.style.overflow = 'hidden';\n document.body.style.overflow = 'hidden';\n }\n\n overlayScrollLockCount += 1;\n}\n\nfunction unlockDocumentScroll(document: Document): void {\n if (overlayScrollLockCount === 0) {\n return;\n }\n\n overlayScrollLockCount -= 1;\n\n if (overlayScrollLockCount === 0) {\n document.documentElement.style.overflow = previousHtmlOverflow;\n document.body.style.overflow = previousBodyOverflow;\n }\n}\n\n/**\n * NeuralUI Sidebar Component\n *\n * El estado abierto/cerrado se gestiona automáticamente desde la URL / The open/closed state is automatically managed from the URL\n * via NeuUrlStateService (?menu=open por defecto). / via NeuUrlStateService (?menu=open by default).\n *\n * Modos:\n * - overlay (default): panel flotante sobre el contenido con backdrop / floating panel above content with backdrop\n * - persistent: sidebar fijo integrado en el layout (desktop) / fixed sidebar integrated in the layout (desktop)\n *\n * Uso:\n * <neu-sidebar urlParam=\"menu\" [persistent]=\"isDesktop()\">\n * <span neu-sidebar-header>Mi App</span>\n * <nav>...</nav>\n * <div neu-sidebar-footer>...</div>\n * </neu-sidebar>\n *\n * Abrir desde cualquier parte: / Open from anywhere:\n * inject(NeuUrlStateService).setParam('menu', 'open', false);\n */\n@Component({\n selector: 'neu-sidebar',\n imports: [NeuIconComponent],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <!-- Overlay de fondo — solo visible en modo overlay -->\n @if (!persistent()) {\n <div\n class=\"neu-sidebar__overlay\"\n [class.neu-sidebar__overlay--visible]=\"isOpen()\"\n (click)=\"close()\"\n aria-hidden=\"true\"\n ></div>\n }\n\n <!-- Panel lateral -->\n <aside\n class=\"neu-sidebar\"\n [class.neu-sidebar--open]=\"isOpen()\"\n [class.neu-sidebar--persistent]=\"persistent()\"\n [class.neu-sidebar--right]=\"side() === 'right'\"\n role=\"navigation\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-hidden]=\"!isOpen() && !persistent()\"\n [attr.inert]=\"!isOpen() && !persistent() ? '' : null\"\n >\n <!-- Cabecera -->\n @if (!hideHeader()) {\n <div class=\"neu-sidebar__header\">\n <div class=\"neu-sidebar__title\">\n <ng-content select=\"[neu-sidebar-header]\" />\n </div>\n @if (!persistent()) {\n <button\n class=\"neu-sidebar__close\"\n (click)=\"close()\"\n [attr.aria-label]=\"closeLabel()\"\n type=\"button\"\n >\n <neu-icon name=\"lucideX\" size=\"18px\" aria-hidden=\"true\" />\n </button>\n }\n </div>\n }\n\n <!-- Contenido -->\n <div class=\"neu-sidebar__content\">\n <ng-content />\n </div>\n\n <!-- Footer -->\n <div class=\"neu-sidebar__footer\">\n <ng-content select=\"[neu-sidebar-footer]\" />\n </div>\n </aside>\n `,\n styleUrl: './neu-sidebar.component.scss',\n})\nexport class NeuSidebarComponent {\n private readonly document = inject(DOCUMENT);\n private readonly urlState = inject(NeuUrlStateService);\n private readonly openParam = computed(() => this.urlState.getParam(this.urlParam()));\n\n /** Posición del sidebar: izquierda o derecha de la pantalla / Sidebar position: left or right of the screen */\n side = input<'left' | 'right'>('left');\n\n /** QueryParam que controla el estado. Default: 'menu' (?menu=open) / QueryParam that controls the state. Default: 'menu' (?menu=open) */\n urlParam = input<string>('menu');\n\n /**\n * Modo persistente: el sidebar está siempre visible como parte del layout.\n * Usar en desktop (≥768px). El overlay y el toggle por URL no aplican.\n */\n persistent = input<boolean>(false);\n\n /**\n * Ocultar la cabecera del sidebar. Útil cuando el header ya está en el layout\n * principal y el sidebar persistente no necesita su propio header.\n */\n hideHeader = input<boolean>(false);\n\n /** Etiqueta accesible para el <aside> / Accessible label for the <aside> */\n ariaLabel = input<string>('Menú de navegación');\n\n /** Etiqueta accesible para el botón cerrar / Accessible label for the close button */\n closeLabel = input<string>('Cerrar menú de navegación');\n\n /** Emite cuando el usuario cierra el sidebar (overlay click o botón) / Emits when the user closes the sidebar (overlay click or button) */\n closeRequested = output<void>();\n\n /** Signal reactivo: true si el sidebar debe mostrarse / Reactive signal: true if the sidebar should be shown */\n readonly isOpen = computed(() => {\n if (this.persistent()) return true;\n return this.openParam()() === 'open';\n });\n\n constructor() {\n effect((onCleanup) => {\n const shouldLockScroll = !this.persistent() && this.isOpen();\n\n if (!shouldLockScroll) {\n return;\n }\n\n lockDocumentScroll(this.document);\n\n onCleanup(() => {\n unlockDocumentScroll(this.document);\n });\n });\n }\n\n /** Abre el sidebar — añade ?{urlParam}=open a la URL / Opens the sidebar — adds ?{urlParam}=open to the URL */\n open(replaceUrl = false): void {\n this.urlState.setParam(this.urlParam(), 'open', replaceUrl);\n }\n\n /** Cierra el sidebar — elimina el parámetro de la URL / Closes the sidebar — removes the URL parameter */\n close(): void {\n this.urlState.setParam(this.urlParam(), null, true);\n this.closeRequested.emit();\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-sidebar.mjs","sources":["../../../../projects/ui-core/sidebar/neu-sidebar.component.ts","../../../../projects/ui-core/sidebar/neural-ui-core-sidebar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n output,\n ElementRef,\n HostListener,\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { NeuUrlStateService } from '@neural-ui/core/url-state';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\n\nlet overlayScrollLockCount = 0;\nlet previousHtmlOverflow = '';\nlet previousBodyOverflow = '';\n\nfunction lockDocumentScroll(document: Document): void {\n if (overlayScrollLockCount === 0) {\n previousHtmlOverflow = document.documentElement.style.overflow;\n previousBodyOverflow = document.body.style.overflow;\n document.documentElement.style.overflow = 'hidden';\n document.body.style.overflow = 'hidden';\n }\n\n overlayScrollLockCount += 1;\n}\n\nfunction unlockDocumentScroll(document: Document): void {\n if (overlayScrollLockCount === 0) {\n return;\n }\n\n overlayScrollLockCount -= 1;\n\n if (overlayScrollLockCount === 0) {\n document.documentElement.style.overflow = previousHtmlOverflow;\n document.body.style.overflow = previousBodyOverflow;\n }\n}\n\n/**\n * NeuralUI Sidebar Component\n *\n * El estado abierto/cerrado se gestiona automáticamente desde la URL / The open/closed state is automatically managed from the URL\n * via NeuUrlStateService (?menu=open por defecto). / via NeuUrlStateService (?menu=open by default).\n *\n * Modos:\n * - overlay (default): panel flotante sobre el contenido con backdrop / floating panel above content with backdrop\n * - persistent: sidebar fijo integrado en el layout (desktop) / fixed sidebar integrated in the layout (desktop)\n *\n * Uso:\n * <neu-sidebar urlParam=\"menu\" [persistent]=\"isDesktop()\">\n * <span neu-sidebar-header>Mi App</span>\n * <nav>...</nav>\n * <div neu-sidebar-footer>...</div>\n * </neu-sidebar>\n *\n * Abrir desde cualquier parte: / Open from anywhere:\n * inject(NeuUrlStateService).setParam('menu', 'open', false);\n */\n@Component({\n selector: 'neu-sidebar',\n imports: [NeuIconComponent],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <!-- Overlay de fondo — solo visible en modo overlay -->\n @if (!persistent()) {\n <div\n class=\"neu-sidebar__overlay\"\n [class.neu-sidebar__overlay--visible]=\"isOpen()\"\n (click)=\"close()\"\n aria-hidden=\"true\"\n ></div>\n }\n\n <!-- Panel lateral -->\n <aside\n class=\"neu-sidebar\"\n [class.neu-sidebar--open]=\"isOpen()\"\n [class.neu-sidebar--persistent]=\"persistent()\"\n [class.neu-sidebar--collapsed]=\"collapsed()\"\n [class.neu-sidebar--right]=\"side() === 'right'\"\n [attr.role]=\"persistent() ? 'navigation' : 'dialog'\"\n [attr.aria-modal]=\"!persistent()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-hidden]=\"!isOpen() && !persistent()\"\n [attr.inert]=\"!isOpen() && !persistent() ? '' : null\"\n >\n <!-- Cabecera -->\n @if (!hideHeader()) {\n <div class=\"neu-sidebar__header\">\n <div class=\"neu-sidebar__title\">\n <ng-content select=\"[neu-sidebar-header]\" />\n </div>\n @if (!persistent()) {\n <button\n class=\"neu-sidebar__close\"\n (click)=\"close()\"\n [attr.aria-label]=\"closeLabel()\"\n type=\"button\"\n >\n <neu-icon name=\"lucideX\" size=\"18px\" aria-hidden=\"true\" />\n </button>\n }\n </div>\n }\n\n <!-- Contenido -->\n <div class=\"neu-sidebar__content\">\n <ng-content />\n </div>\n\n <!-- Footer -->\n <div class=\"neu-sidebar__footer\">\n <ng-content select=\"[neu-sidebar-footer]\" />\n </div>\n </aside>\n `,\n styleUrl: './neu-sidebar.component.scss',\n})\nexport class NeuSidebarComponent {\n private readonly document = inject(DOCUMENT);\n private readonly elementRef = inject(ElementRef);\n private readonly urlState = inject(NeuUrlStateService);\n private readonly openParam = computed(() => this.urlState.getParam(this.urlParam()));\n private previousActiveElement: HTMLElement | null = null;\n\n /** Posición del sidebar: izquierda o derecha de la pantalla / Sidebar position: left or right of the screen */\n side = input<'left' | 'right'>('left');\n\n /** QueryParam que controla el estado. Default: 'menu' (?menu=open) / QueryParam that controls the state. Default: 'menu' (?menu=open) */\n urlParam = input<string>('menu');\n\n /**\n * Modo persistente: el sidebar está siempre visible como parte del layout.\n * Usar en desktop (≥768px). El overlay y el toggle por URL no aplican.\n */\n persistent = input<boolean>(false);\n\n /**\n * Ocultar la cabecera del sidebar. Útil cuando el header ya está en el layout\n * principal y el sidebar persistente no necesita su propio header.\n */\n hideHeader = input<boolean>(false);\n\n /** Etiqueta accesible para el <aside> / Accessible label for the <aside> */\n ariaLabel = input<string>('Menú de navegación');\n\n /** Etiqueta accesible para el botón cerrar / Accessible label for the close button */\n closeLabel = input<string>('Cerrar menú de navegación');\n\n /**\n * Modo colapsado: el sidebar muestra solo iconos (icon-only en desktop).\n * Útil para sidebars persistentes en modo compact / Collapsed mode: sidebar shows only icons.\n */\n collapsed = input<boolean>(false);\n\n /** Emite cuando el usuario cierra el sidebar (overlay click o botón) / Emits when the user closes the sidebar (overlay click or button) */\n closeRequested = output<void>();\n\n /** Emite cuando el estado collapsed cambia / Emits when collapsed state changes */\n collapsedChange = output<boolean>();\n\n /** Signal reactivo: true si el sidebar debe mostrarse / Reactive signal: true if the sidebar should be shown */\n readonly isOpen = computed(() => {\n if (this.persistent()) return true;\n return this.openParam()() === 'open';\n });\n\n constructor() {\n effect((onCleanup) => {\n const shouldLockScroll = !this.persistent() && this.isOpen();\n\n if (!shouldLockScroll) {\n return;\n }\n\n lockDocumentScroll(this.document);\n\n onCleanup(() => {\n unlockDocumentScroll(this.document);\n });\n });\n\n // Focus management: save previous element and move focus to sidebar when opening in drawer mode\n effect(() => {\n const isOpenNow = this.isOpen();\n const isPersistent = this.persistent();\n\n if (isPersistent) {\n return;\n }\n\n if (isOpenNow) {\n // Save the current active element\n this.previousActiveElement = this.document.activeElement as HTMLElement;\n\n // Move focus to first focusable element inside the sidebar\n this.focusFirstElement();\n } else if (this.previousActiveElement && this.previousActiveElement.focus) {\n // Restore focus to the element that had it before opening\n setTimeout(() => {\n this.previousActiveElement?.focus();\n this.previousActiveElement = null;\n }, 0);\n }\n });\n }\n\n /** Abre el sidebar — añade ?{urlParam}=open a la URL / Opens the sidebar — adds ?{urlParam}=open to the URL */\n open(replaceUrl = false): void {\n this.urlState.setParam(this.urlParam(), 'open', replaceUrl);\n }\n\n /** Cierra el sidebar — elimina el parámetro de la URL / Closes the sidebar — removes the URL parameter */\n close(): void {\n this.urlState.setParam(this.urlParam(), null, true);\n this.closeRequested.emit();\n }\n\n /** Alterna el estado collapsed / Toggles collapsed state */\n toggleCollapsed(): void {\n const newState = !this.collapsed();\n this.collapsedChange.emit(newState);\n }\n\n /** Obtiene los elementos focusables dentro del sidebar / Gets focusable elements inside sidebar */\n private getFocusableElements(): HTMLElement[] {\n const focusableSelectors = [\n 'button',\n 'a[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n ].join(',');\n\n const aside = this.elementRef.nativeElement.querySelector('aside.neu-sidebar');\n if (!aside) {\n return [];\n }\n\n return Array.from(aside.querySelectorAll(focusableSelectors)) as HTMLElement[];\n }\n\n /** Mueve el foco al primer elemento focusable / Moves focus to first focusable element */\n private focusFirstElement(): void {\n setTimeout(() => {\n const focusable = this.getFocusableElements();\n if (focusable.length > 0) {\n focusable[0].focus();\n }\n }, 0);\n }\n\n /** Focus trap: cicla entre elementos focusables con Tab/Shift+Tab / Focus trap cycling */\n @HostListener('keydown', ['$event'])\n onKeyDown(event: KeyboardEvent): void {\n if (!this.isOpen() || this.persistent()) {\n return;\n }\n\n if (event.key !== 'Tab') {\n return;\n }\n\n const focusable = this.getFocusableElements();\n if (focusable.length === 0) {\n return;\n }\n\n const activeElement = this.document.activeElement as HTMLElement;\n const currentIndex = focusable.indexOf(activeElement);\n\n if (event.shiftKey) {\n // Shift+Tab — go to previous\n if (currentIndex <= 0) {\n event.preventDefault();\n focusable[focusable.length - 1].focus();\n }\n } else {\n // Tab — go to next\n if (currentIndex >= focusable.length - 1) {\n event.preventDefault();\n focusable[0].focus();\n }\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|