@devjuliovilla/jv-ui 1.16.0 → 1.17.0

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, computed, Component, inject, signal, Injectable, InjectionToken, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, TemplateRef, Directive, contentChild, output, effect, forwardRef, viewChild, untracked, contentChildren, HostListener, viewChildren, numberAttribute, afterNextRender, Renderer2, ElementRef, DestroyRef } from '@angular/core';
2
+ import { input, computed, Component, inject, Renderer2, ElementRef, HostListener, Directive, signal, Injectable, InjectionToken, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, TemplateRef, contentChild, output, effect, forwardRef, viewChild, untracked, contentChildren, viewChildren, numberAttribute, afterNextRender, DestroyRef } from '@angular/core';
3
3
  import { DOCUMENT, NgTemplateOutlet, CommonModule } from '@angular/common';
4
4
  import * as i1 from '@angular/forms';
5
5
  import { NG_VALUE_ACCESSOR, FormBuilder, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
@@ -18009,6 +18009,193 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
18009
18009
  args: [{ selector: 'jv-button-group', standalone: true, template: `<div class="jv-button-group" role="group"><ng-content></ng-content></div>`, styles: [".jv-button-group{display:inline-flex;flex-wrap:wrap;gap:var(--jv-spacing-sm);align-items:center}\n"] }]
18010
18010
  }] });
18011
18011
 
18012
+ let tooltipSequence = 0;
18013
+ class JvTooltipDirective {
18014
+ document = inject(DOCUMENT);
18015
+ renderer = inject(Renderer2);
18016
+ hostRef = inject((ElementRef));
18017
+ tooltipElement = null;
18018
+ showTimeout = null;
18019
+ hideTimeout = null;
18020
+ tooltipId = `jv-tooltip-${++tooltipSequence}`;
18021
+ originalDescribedBy = null;
18022
+ text = input.required({ ...(ngDevMode ? { debugName: "text" } : /* istanbul ignore next */ {}), alias: 'jvTooltip' });
18023
+ position = input('top', { ...(ngDevMode ? { debugName: "position" } : /* istanbul ignore next */ {}), alias: 'jvTooltipPosition' });
18024
+ show() {
18025
+ if (!this.text().trim()) {
18026
+ return;
18027
+ }
18028
+ this.clearHideTimeout();
18029
+ if (this.tooltipElement) {
18030
+ return;
18031
+ }
18032
+ this.showTimeout = setTimeout(() => {
18033
+ this.renderTooltip();
18034
+ this.positionTooltip();
18035
+ this.attachTooltipDescription();
18036
+ }, 120);
18037
+ }
18038
+ hide() {
18039
+ this.clearShowTimeout();
18040
+ if (!this.tooltipElement) {
18041
+ return;
18042
+ }
18043
+ this.hideTimeout = setTimeout(() => this.destroyTooltip(), 80);
18044
+ }
18045
+ handleDocumentKeydown(event) {
18046
+ if (event.key === 'Escape') {
18047
+ this.destroyTooltip();
18048
+ }
18049
+ }
18050
+ handleViewportChange() {
18051
+ if (this.tooltipElement) {
18052
+ this.positionTooltip();
18053
+ }
18054
+ }
18055
+ ngOnDestroy() {
18056
+ this.clearShowTimeout();
18057
+ this.clearHideTimeout();
18058
+ this.destroyTooltip();
18059
+ }
18060
+ renderTooltip() {
18061
+ if (this.tooltipElement) {
18062
+ return;
18063
+ }
18064
+ const tooltip = this.renderer.createElement('div');
18065
+ tooltip.textContent = this.text();
18066
+ this.renderer.setAttribute(tooltip, 'id', this.tooltipId);
18067
+ this.renderer.setAttribute(tooltip, 'role', 'tooltip');
18068
+ this.renderer.setStyle(tooltip, 'position', 'fixed');
18069
+ this.renderer.setStyle(tooltip, 'z-index', '1400');
18070
+ this.renderer.setStyle(tooltip, 'max-width', '18rem');
18071
+ this.renderer.setStyle(tooltip, 'padding', '0.5rem 0.75rem');
18072
+ this.renderer.setStyle(tooltip, 'border-radius', '0.5rem');
18073
+ this.renderer.setStyle(tooltip, 'background', 'rgb(15 23 42)');
18074
+ this.renderer.setStyle(tooltip, 'color', '#ffffff');
18075
+ this.renderer.setStyle(tooltip, 'font-size', '0.8125rem');
18076
+ this.renderer.setStyle(tooltip, 'line-height', '1.4');
18077
+ this.renderer.setStyle(tooltip, 'box-shadow', 'var(--jv-shadow-md)');
18078
+ this.renderer.setStyle(tooltip, 'pointer-events', 'none');
18079
+ this.renderer.setStyle(tooltip, 'opacity', '0');
18080
+ this.renderer.setStyle(tooltip, 'transition', 'opacity 120ms ease');
18081
+ this.renderer.appendChild(this.document.body, tooltip);
18082
+ this.tooltipElement = tooltip;
18083
+ requestAnimationFrame(() => {
18084
+ if (this.tooltipElement) {
18085
+ this.renderer.setStyle(this.tooltipElement, 'opacity', '1');
18086
+ }
18087
+ });
18088
+ }
18089
+ positionTooltip() {
18090
+ const tooltip = this.tooltipElement;
18091
+ if (!tooltip) {
18092
+ return;
18093
+ }
18094
+ const hostRect = this.anchorElement().getBoundingClientRect();
18095
+ const tooltipRect = tooltip.getBoundingClientRect();
18096
+ const gap = 8;
18097
+ let top = hostRect.top - tooltipRect.height - gap;
18098
+ let left = hostRect.left + hostRect.width / 2 - tooltipRect.width / 2;
18099
+ switch (this.position()) {
18100
+ case 'right':
18101
+ top = hostRect.top + hostRect.height / 2 - tooltipRect.height / 2;
18102
+ left = hostRect.right + gap;
18103
+ break;
18104
+ case 'bottom':
18105
+ top = hostRect.bottom + gap;
18106
+ left = hostRect.left + hostRect.width / 2 - tooltipRect.width / 2;
18107
+ break;
18108
+ case 'left':
18109
+ top = hostRect.top + hostRect.height / 2 - tooltipRect.height / 2;
18110
+ left = hostRect.left - tooltipRect.width - gap;
18111
+ break;
18112
+ }
18113
+ this.renderer.setStyle(tooltip, 'top', `${Math.round(top)}px`);
18114
+ this.renderer.setStyle(tooltip, 'left', `${Math.round(left)}px`);
18115
+ }
18116
+ destroyTooltip() {
18117
+ this.clearHideTimeout();
18118
+ this.clearShowTimeout();
18119
+ if (!this.tooltipElement) {
18120
+ return;
18121
+ }
18122
+ this.restoreTooltipDescription();
18123
+ this.renderer.removeChild(this.document.body, this.tooltipElement);
18124
+ this.tooltipElement = null;
18125
+ }
18126
+ attachTooltipDescription() {
18127
+ const anchor = this.anchorElement();
18128
+ this.originalDescribedBy ??= anchor.getAttribute('aria-describedby');
18129
+ const describedBy = [this.originalDescribedBy, this.tooltipId]
18130
+ .filter((value) => !!value)
18131
+ .join(' ')
18132
+ .trim();
18133
+ this.renderer.setAttribute(anchor, 'aria-describedby', describedBy);
18134
+ }
18135
+ restoreTooltipDescription() {
18136
+ const anchor = this.anchorElement();
18137
+ if (this.originalDescribedBy) {
18138
+ this.renderer.setAttribute(anchor, 'aria-describedby', this.originalDescribedBy);
18139
+ }
18140
+ else {
18141
+ this.renderer.removeAttribute(anchor, 'aria-describedby');
18142
+ }
18143
+ this.originalDescribedBy = null;
18144
+ }
18145
+ anchorElement() {
18146
+ const host = this.hostRef.nativeElement;
18147
+ if (isInteractiveElement(host)) {
18148
+ return host;
18149
+ }
18150
+ return host.querySelector('button, a, input, select, textarea, [tabindex]:not([tabindex="-1"])') ?? host;
18151
+ }
18152
+ clearShowTimeout() {
18153
+ if (this.showTimeout) {
18154
+ clearTimeout(this.showTimeout);
18155
+ this.showTimeout = null;
18156
+ }
18157
+ }
18158
+ clearHideTimeout() {
18159
+ if (this.hideTimeout) {
18160
+ clearTimeout(this.hideTimeout);
18161
+ this.hideTimeout = null;
18162
+ }
18163
+ }
18164
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
18165
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.17", type: JvTooltipDirective, isStandalone: true, selector: "[jvTooltip]", inputs: { text: { classPropertyName: "text", publicName: "jvTooltip", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "jvTooltipPosition", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "focusin": "show()", "mouseleave": "hide()", "blur": "hide()", "document:keydown": "handleDocumentKeydown($event)", "window:scroll": "handleViewportChange()", "window:resize": "handleViewportChange()" } }, ngImport: i0 });
18166
+ }
18167
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTooltipDirective, decorators: [{
18168
+ type: Directive,
18169
+ args: [{
18170
+ selector: '[jvTooltip]',
18171
+ standalone: true,
18172
+ }]
18173
+ }], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "jvTooltip", required: true }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "jvTooltipPosition", required: false }] }], show: [{
18174
+ type: HostListener,
18175
+ args: ['mouseenter']
18176
+ }, {
18177
+ type: HostListener,
18178
+ args: ['focusin']
18179
+ }], hide: [{
18180
+ type: HostListener,
18181
+ args: ['mouseleave']
18182
+ }, {
18183
+ type: HostListener,
18184
+ args: ['blur']
18185
+ }], handleDocumentKeydown: [{
18186
+ type: HostListener,
18187
+ args: ['document:keydown', ['$event']]
18188
+ }], handleViewportChange: [{
18189
+ type: HostListener,
18190
+ args: ['window:scroll']
18191
+ }, {
18192
+ type: HostListener,
18193
+ args: ['window:resize']
18194
+ }] } });
18195
+ function isInteractiveElement(element) {
18196
+ return ['BUTTON', 'A', 'INPUT', 'SELECT', 'TEXTAREA'].includes(element.tagName) || element.tabIndex >= 0;
18197
+ }
18198
+
18012
18199
  class JvIconButtonComponent {
18013
18200
  icon = input.required(...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
18014
18201
  ariaLabel = input.required(...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
@@ -18021,25 +18208,31 @@ class JvIconButtonComponent {
18021
18208
  class="jv-icon-button"
18022
18209
  [class]="'jv-icon-button--' + variant()"
18023
18210
  [attr.aria-label]="ariaLabel()"
18211
+ [attr.title]="ariaLabel()"
18212
+ [jvTooltip]="ariaLabel()"
18024
18213
  [disabled]="disabled()"
18025
18214
  >
18026
18215
  <jv-icon [name]="icon()" [size]="18" />
18216
+ <span class="icon-label">{{ ariaLabel() }}</span>
18027
18217
  </button>
18028
- `, isInline: true, styles: [".jv-icon-button{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border:1px solid transparent;border-radius:999px;cursor:pointer;transition:background-color .16s ease,color .16s ease,border-color .16s ease}.jv-icon-button:disabled{opacity:.6;cursor:not-allowed}.jv-icon-button--primary{background:var(--jv-color-primary);color:#fff}.jv-icon-button--secondary{background:var(--jv-color-secondary);color:#fff}.jv-icon-button--outline{border-color:var(--jv-color-border);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-icon-button--ghost,.jv-icon-button--link{background:transparent;color:var(--jv-color-foreground)}.jv-icon-button--danger{background:var(--jv-color-danger);color:#fff}.jv-icon-button--success{background:var(--jv-color-success);color:#fff}.jv-icon-button--warning{background:var(--jv-color-warning);color:#111827}.jv-icon-button--outline:hover,.jv-icon-button--ghost:hover,.jv-icon-button--link:hover{background:var(--jv-color-surface-muted)}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
18218
+ `, isInline: true, styles: [".jv-icon-button{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border:1px solid transparent;border-radius:999px;cursor:pointer;transition:background-color .16s ease,color .16s ease,border-color .16s ease}.icon-label{font-size:0}.jv-icon-button:disabled{opacity:.6;cursor:not-allowed}.jv-icon-button--primary{background:var(--jv-color-primary);color:#fff}.jv-icon-button--secondary{background:var(--jv-color-secondary);color:#fff}.jv-icon-button--outline{border-color:var(--jv-color-border);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-icon-button--ghost,.jv-icon-button--link{background:transparent;color:var(--jv-color-foreground)}.jv-icon-button--danger{background:var(--jv-color-danger);color:#fff}.jv-icon-button--success{background:var(--jv-color-success);color:#fff}.jv-icon-button--warning{background:var(--jv-color-warning);color:#111827}.jv-icon-button--outline:hover,.jv-icon-button--ghost:hover,.jv-icon-button--link:hover{background:var(--jv-color-surface-muted)}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "directive", type: JvTooltipDirective, selector: "[jvTooltip]", inputs: ["jvTooltip", "jvTooltipPosition"] }] });
18029
18219
  }
18030
18220
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvIconButtonComponent, decorators: [{
18031
18221
  type: Component,
18032
- args: [{ selector: 'jv-icon-button', standalone: true, imports: [JvIconComponent], template: `
18222
+ args: [{ selector: 'jv-icon-button', standalone: true, imports: [JvIconComponent, JvTooltipDirective], template: `
18033
18223
  <button
18034
18224
  type="button"
18035
18225
  class="jv-icon-button"
18036
18226
  [class]="'jv-icon-button--' + variant()"
18037
18227
  [attr.aria-label]="ariaLabel()"
18228
+ [attr.title]="ariaLabel()"
18229
+ [jvTooltip]="ariaLabel()"
18038
18230
  [disabled]="disabled()"
18039
18231
  >
18040
18232
  <jv-icon [name]="icon()" [size]="18" />
18233
+ <span class="icon-label">{{ ariaLabel() }}</span>
18041
18234
  </button>
18042
- `, styles: [".jv-icon-button{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border:1px solid transparent;border-radius:999px;cursor:pointer;transition:background-color .16s ease,color .16s ease,border-color .16s ease}.jv-icon-button:disabled{opacity:.6;cursor:not-allowed}.jv-icon-button--primary{background:var(--jv-color-primary);color:#fff}.jv-icon-button--secondary{background:var(--jv-color-secondary);color:#fff}.jv-icon-button--outline{border-color:var(--jv-color-border);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-icon-button--ghost,.jv-icon-button--link{background:transparent;color:var(--jv-color-foreground)}.jv-icon-button--danger{background:var(--jv-color-danger);color:#fff}.jv-icon-button--success{background:var(--jv-color-success);color:#fff}.jv-icon-button--warning{background:var(--jv-color-warning);color:#111827}.jv-icon-button--outline:hover,.jv-icon-button--ghost:hover,.jv-icon-button--link:hover{background:var(--jv-color-surface-muted)}\n"] }]
18235
+ `, styles: [".jv-icon-button{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border:1px solid transparent;border-radius:999px;cursor:pointer;transition:background-color .16s ease,color .16s ease,border-color .16s ease}.icon-label{font-size:0}.jv-icon-button:disabled{opacity:.6;cursor:not-allowed}.jv-icon-button--primary{background:var(--jv-color-primary);color:#fff}.jv-icon-button--secondary{background:var(--jv-color-secondary);color:#fff}.jv-icon-button--outline{border-color:var(--jv-color-border);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-icon-button--ghost,.jv-icon-button--link{background:transparent;color:var(--jv-color-foreground)}.jv-icon-button--danger{background:var(--jv-color-danger);color:#fff}.jv-icon-button--success{background:var(--jv-color-success);color:#fff}.jv-icon-button--warning{background:var(--jv-color-warning);color:#111827}.jv-icon-button--outline:hover,.jv-icon-button--ghost:hover,.jv-icon-button--link:hover{background:var(--jv-color-surface-muted)}\n"] }]
18043
18236
  }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
18044
18237
 
18045
18238
  const JV_UI_DEFAULT_CONFIG = {
@@ -22969,24 +23162,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22969
23162
  `, styles: [".jv-breadcrumb ol{display:flex;flex-wrap:wrap;gap:var(--jv-spacing-xs);margin:0;padding:0;list-style:none;color:var(--jv-color-foreground-muted);font-size:.875rem}.jv-breadcrumb li{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-breadcrumb a{color:inherit;text-decoration:none}.jv-breadcrumb a:hover{color:var(--jv-color-foreground);text-decoration:underline}.separator{opacity:.7}\n"] }]
22970
23163
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }] } });
22971
23164
 
22972
- class JvSidebarComponent {
22973
- router = inject(Router);
22974
- expandedSections = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedSections" }] : /* istanbul ignore next */ []));
22975
- title = input.required(...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
22976
- subtitle = input('', ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
22977
- brandIcon = input('monitor', ...(ngDevMode ? [{ debugName: "brandIcon" }] : /* istanbul ignore next */ []));
22978
- items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
22979
- collapsed = input(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
22980
- mobileOpen = input(false, ...(ngDevMode ? [{ debugName: "mobileOpen" }] : /* istanbul ignore next */ []));
22981
- ariaLabel = input('Sidebar navigation', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
22982
- currentTheme = input('light', ...(ngDevMode ? [{ debugName: "currentTheme" }] : /* istanbul ignore next */ []));
22983
- themeOptions = input([], ...(ngDevMode ? [{ debugName: "themeOptions" }] : /* istanbul ignore next */ []));
22984
- topbarActions = input([], ...(ngDevMode ? [{ debugName: "topbarActions" }] : /* istanbul ignore next */ []));
22985
- showThemeSelector = input(true, ...(ngDevMode ? [{ debugName: "showThemeSelector" }] : /* istanbul ignore next */ []));
22986
- collapseToggle = output();
22987
- mobileClose = output();
22988
- themeChange = output();
22989
- actionClick = output();
23165
+ class JvNavigationState {
23166
+ items;
23167
+ router;
23168
+ expandActiveSections;
23169
+ sectionOverrides = signal(new Map(), ...(ngDevMode ? [{ debugName: "sectionOverrides" }] : /* istanbul ignore next */ []));
23170
+ normalizedItems = computed(() => this.items().map((item) => ({
23171
+ ...item,
23172
+ children: item.children ?? [],
23173
+ })), ...(ngDevMode ? [{ debugName: "normalizedItems" }] : /* istanbul ignore next */ []));
22990
23174
  activeChildParentIds = computed(() => {
22991
23175
  const url = this.router.url;
22992
23176
  const ids = new Set();
@@ -22999,22 +23183,33 @@ class JvSidebarComponent {
22999
23183
  }
23000
23184
  return ids;
23001
23185
  }, ...(ngDevMode ? [{ debugName: "activeChildParentIds" }] : /* istanbul ignore next */ []));
23002
- normalizedItems = computed(() => this.items().map((item) => ({
23003
- ...item,
23004
- children: item.children ?? [],
23005
- })), ...(ngDevMode ? [{ debugName: "normalizedItems" }] : /* istanbul ignore next */ []));
23006
- isExpanded(id) {
23007
- return this.expandedSections().has(id) || this.activeChildParentIds().has(id);
23186
+ constructor(items, router, expandActiveSections = true) {
23187
+ this.items = items;
23188
+ this.router = router;
23189
+ this.expandActiveSections = expandActiveSections;
23008
23190
  }
23009
- toggleSection(id) {
23010
- this.expandedSections.update((current) => {
23011
- const next = new Set(current);
23012
- if (next.has(id)) {
23013
- next.delete(id);
23014
- }
23015
- else {
23016
- next.add(id);
23191
+ isExpanded(id) {
23192
+ return this.sectionOverrides().get(id) ?? (this.expandActiveSections && this.activeChildParentIds().has(id));
23193
+ }
23194
+ toggleSection(id, exclusive = false) {
23195
+ this.sectionOverrides.update((current) => {
23196
+ const next = new Map(current);
23197
+ const shouldExpand = !this.isExpanded(id);
23198
+ if (exclusive) {
23199
+ for (const item of this.normalizedItems()) {
23200
+ if (item.children.length > 0) {
23201
+ next.set(item.id, false);
23202
+ }
23203
+ }
23017
23204
  }
23205
+ next.set(id, shouldExpand);
23206
+ return next;
23207
+ });
23208
+ }
23209
+ closeSection(id) {
23210
+ this.sectionOverrides.update((current) => {
23211
+ const next = new Map(current);
23212
+ next.set(id, false);
23018
23213
  return next;
23019
23214
  });
23020
23215
  }
@@ -23028,6 +23223,38 @@ class JvSidebarComponent {
23028
23223
  const target = document.querySelector(href);
23029
23224
  target?.scrollIntoView({ block: 'start', behavior: 'smooth' });
23030
23225
  }
23226
+ }
23227
+
23228
+ class JvSidebarComponent {
23229
+ title = input.required(...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
23230
+ subtitle = input('', ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
23231
+ brandIcon = input('monitor', ...(ngDevMode ? [{ debugName: "brandIcon" }] : /* istanbul ignore next */ []));
23232
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
23233
+ collapsed = input(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
23234
+ mobileOpen = input(false, ...(ngDevMode ? [{ debugName: "mobileOpen" }] : /* istanbul ignore next */ []));
23235
+ ariaLabel = input('Sidebar navigation', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
23236
+ currentTheme = input('light', ...(ngDevMode ? [{ debugName: "currentTheme" }] : /* istanbul ignore next */ []));
23237
+ themeOptions = input([], ...(ngDevMode ? [{ debugName: "themeOptions" }] : /* istanbul ignore next */ []));
23238
+ topbarActions = input([], ...(ngDevMode ? [{ debugName: "topbarActions" }] : /* istanbul ignore next */ []));
23239
+ showThemeSelector = input(true, ...(ngDevMode ? [{ debugName: "showThemeSelector" }] : /* istanbul ignore next */ []));
23240
+ navigation = new JvNavigationState(this.items, inject(Router));
23241
+ collapseToggle = output();
23242
+ mobileClose = output();
23243
+ themeChange = output();
23244
+ actionClick = output();
23245
+ normalizedItems = this.navigation.normalizedItems;
23246
+ isExpanded(id) {
23247
+ return this.navigation.isExpanded(id);
23248
+ }
23249
+ toggleSection(id) {
23250
+ this.navigation.toggleSection(id);
23251
+ }
23252
+ isHashLink(href) {
23253
+ return this.navigation.isHashLink(href);
23254
+ }
23255
+ navigateTo(href) {
23256
+ this.navigation.navigateTo(href);
23257
+ }
23031
23258
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23032
23259
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvSidebarComponent, isStandalone: true, selector: "jv-sidebar", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, brandIcon: { classPropertyName: "brandIcon", publicName: "brandIcon", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, mobileOpen: { classPropertyName: "mobileOpen", publicName: "mobileOpen", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, currentTheme: { classPropertyName: "currentTheme", publicName: "currentTheme", isSignal: true, isRequired: false, transformFunction: null }, themeOptions: { classPropertyName: "themeOptions", publicName: "themeOptions", isSignal: true, isRequired: false, transformFunction: null }, topbarActions: { classPropertyName: "topbarActions", publicName: "topbarActions", isSignal: true, isRequired: false, transformFunction: null }, showThemeSelector: { classPropertyName: "showThemeSelector", publicName: "showThemeSelector", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapseToggle: "collapseToggle", mobileClose: "mobileClose", themeChange: "themeChange", actionClick: "actionClick" }, ngImport: i0, template: `
23033
23260
  @if (mobileOpen()) {
@@ -23176,19 +23403,20 @@ class JvSidebarComponent {
23176
23403
 
23177
23404
  <div class="mobile-actions">
23178
23405
  @for (action of topbarActions(); track action.id) {
23179
- <button type="button" class="icon-button" [attr.aria-label]="action.label" (click)="actionClick.emit(action.id); mobileClose.emit()">
23406
+ <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id); mobileClose.emit()">
23180
23407
  <jv-icon [name]="action.icon" [size]="18" />
23408
+ <span>{{ action.label }}</span>
23181
23409
  </button>
23182
23410
  }
23183
23411
  </div>
23184
23412
  </div>
23185
23413
  </div>
23186
23414
  </aside>
23187
- `, isInline: true, styles: [".jv-sidebar-backdrop{display:none}.jv-sidebar{display:grid;grid-template-rows:auto 1fr auto;gap:var(--jv-spacing-lg);width:280px;min-width:280px;height:100vh;padding:var(--jv-spacing-lg);overflow-y:auto;border-right:1px solid var(--jv-color-border);background:var(--jv-color-surface);scrollbar-width:none;-ms-overflow-style:none}.jv-sidebar::-webkit-scrollbar{width:0;height:0;display:none}.jv-sidebar.is-collapsed{width:96px;min-width:96px;padding-inline:var(--jv-spacing-md)}.jv-sidebar-footer{display:grid;gap:var(--jv-spacing-md)}.jv-sidebar-mobile-extras{display:none}.jv-sidebar-brand,.jv-sidebar-link,.jv-sidebar-toggle{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.brand-mark{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border-radius:var(--jv-radius-md);background:color-mix(in srgb,var(--jv-color-primary) 16%,var(--jv-color-surface));color:var(--jv-color-primary);flex:0 0 auto}.brand-copy{display:grid;gap:.1rem}.brand-copy span{color:var(--jv-color-foreground-muted);font-size:.875rem}.jv-sidebar-item{display:grid;gap:var(--jv-spacing-xs);list-style:none}.jv-sidebar-list{display:grid;gap:var(--jv-spacing-xs);margin:0;padding:0}.jv-sidebar-nav{display:grid;gap:var(--jv-spacing-xs);align-content:start}.jv-sidebar-link,.jv-sidebar-child-link,.jv-sidebar-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground-muted);text-decoration:none;cursor:pointer}.jv-sidebar-link-main{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-sidebar-link:hover,.jv-sidebar-child-link:hover,.jv-sidebar-toggle:hover{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-sidebar-link.is-active,.jv-sidebar-child-link.is-active{border-color:color-mix(in srgb,var(--jv-color-primary) 25%,var(--jv-color-border));background:color-mix(in srgb,var(--jv-color-primary) 12%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-sidebar-children{display:grid;gap:var(--jv-spacing-xs);margin-left:var(--jv-spacing-xl);padding-left:var(--jv-spacing-sm);border-left:1px solid var(--jv-color-border)}.jv-sidebar-child-link{display:flex;align-items:center;min-height:calc(var(--jv-density-control-height) - .25rem);font-size:.9rem}.jv-sidebar-toggle{width:100%;background:var(--jv-color-surface-muted);cursor:pointer}@media(max-width:900px){.jv-sidebar-backdrop{display:block;position:fixed;inset:0;z-index:99;background:#0006}.jv-sidebar{position:fixed;top:0;left:0;z-index:100;width:280px;min-width:280px;height:100vh;border-right:1px solid var(--jv-color-border);border-bottom:none;box-shadow:var(--jv-shadow-lg);transform:translate(-100%);visibility:hidden;transition:transform .24s cubic-bezier(.4,0,.2,1),visibility .24s}.jv-sidebar.is-mobile-open{transform:translate(0);visibility:visible}.jv-sidebar.is-collapsed{width:280px;min-width:280px}.jv-sidebar-mobile-extras{display:flex;flex-direction:column;gap:var(--jv-spacing-md);padding-top:var(--jv-spacing-md);border-top:1px solid var(--jv-color-border)}.jv-sidebar-mobile-extras .theme-group{display:flex;flex-wrap:wrap;gap:var(--jv-spacing-xs)}.jv-sidebar-mobile-extras .theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);cursor:pointer;font:inherit}.jv-sidebar-mobile-extras .theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}.jv-sidebar-mobile-extras .mobile-actions{display:flex;gap:var(--jv-spacing-sm)}.jv-sidebar-mobile-extras .icon-button{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border:1px solid var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);cursor:pointer}}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] });
23415
+ `, isInline: true, styles: [".jv-sidebar-backdrop{display:none}.jv-sidebar{display:grid;grid-template-rows:auto 1fr auto;gap:var(--jv-spacing-lg);width:280px;min-width:280px;height:100vh;padding:var(--jv-spacing-lg);overflow-y:auto;border-right:1px solid var(--jv-color-border);background:var(--jv-color-surface);scrollbar-width:none;-ms-overflow-style:none}.jv-sidebar::-webkit-scrollbar{width:0;height:0;display:none}.jv-sidebar.is-collapsed{width:96px;min-width:96px;padding-inline:var(--jv-spacing-md)}.jv-sidebar-footer{display:grid;gap:var(--jv-spacing-md)}.jv-sidebar-mobile-extras{display:none}.jv-sidebar-brand,.jv-sidebar-link,.jv-sidebar-toggle{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.brand-mark{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border-radius:var(--jv-radius-md);background:color-mix(in srgb,var(--jv-color-primary) 16%,var(--jv-color-surface));color:var(--jv-color-primary);flex:0 0 auto}.brand-copy{display:grid;gap:.1rem}.brand-copy span{color:var(--jv-color-foreground-muted);font-size:.875rem}.jv-sidebar-item{display:grid;gap:var(--jv-spacing-xs);list-style:none}.jv-sidebar-list{display:grid;gap:var(--jv-spacing-xs);margin:0;padding:0}.jv-sidebar-nav{display:grid;gap:var(--jv-spacing-xs);align-content:start}.jv-sidebar-link,.jv-sidebar-child-link,.jv-sidebar-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground-muted);text-decoration:none;cursor:pointer}.jv-sidebar-link-main{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-sidebar-link:hover,.jv-sidebar-child-link:hover,.jv-sidebar-toggle:hover{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-sidebar-link.is-active,.jv-sidebar-child-link.is-active{border-color:color-mix(in srgb,var(--jv-color-primary) 25%,var(--jv-color-border));background:color-mix(in srgb,var(--jv-color-primary) 12%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-sidebar-children{display:grid;gap:var(--jv-spacing-xs);margin-left:var(--jv-spacing-xl);padding-left:var(--jv-spacing-sm);border-left:1px solid var(--jv-color-border)}.jv-sidebar-child-link{display:flex;align-items:center;min-height:calc(var(--jv-density-control-height) - .25rem);font-size:.9rem}.jv-sidebar-toggle{width:100%;background:var(--jv-color-surface-muted);cursor:pointer}@media(max-width:900px){.jv-sidebar-backdrop{display:block;position:fixed;inset:0;z-index:99;background:#0006}.jv-sidebar{position:fixed;top:0;left:0;z-index:100;width:280px;min-width:280px;height:100vh;border-right:1px solid var(--jv-color-border);border-bottom:none;box-shadow:var(--jv-shadow-lg);transform:translate(-100%);visibility:hidden;transition:transform .24s cubic-bezier(.4,0,.2,1),visibility .24s}.jv-sidebar.is-mobile-open{transform:translate(0);visibility:visible}.jv-sidebar.is-collapsed{width:280px;min-width:280px}.jv-sidebar-mobile-extras{display:flex;flex-direction:column;gap:var(--jv-spacing-md);padding-top:var(--jv-spacing-md);border-top:1px solid var(--jv-color-border)}.jv-sidebar-mobile-extras .theme-group{display:flex;flex-wrap:wrap;gap:var(--jv-spacing-xs)}.jv-sidebar-mobile-extras .theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);cursor:pointer;font:inherit}.jv-sidebar-mobile-extras .theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}.jv-sidebar-mobile-extras .mobile-actions{display:flex;gap:var(--jv-spacing-sm)}.jv-sidebar-mobile-extras .icon-button{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-width:var(--jv-density-control-height);height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);cursor:pointer}}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: JvTooltipDirective, selector: "[jvTooltip]", inputs: ["jvTooltip", "jvTooltipPosition"] }] });
23188
23416
  }
23189
23417
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSidebarComponent, decorators: [{
23190
23418
  type: Component,
23191
- args: [{ selector: 'jv-sidebar', standalone: true, imports: [JvIconComponent, RouterLink], template: `
23419
+ args: [{ selector: 'jv-sidebar', standalone: true, imports: [JvIconComponent, RouterLink, JvTooltipDirective], template: `
23192
23420
  @if (mobileOpen()) {
23193
23421
  <div class="jv-sidebar-backdrop" tabindex="-1" (click)="mobileClose.emit()" (keydown.escape)="mobileClose.emit()"></div>
23194
23422
  }
@@ -23335,15 +23563,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23335
23563
 
23336
23564
  <div class="mobile-actions">
23337
23565
  @for (action of topbarActions(); track action.id) {
23338
- <button type="button" class="icon-button" [attr.aria-label]="action.label" (click)="actionClick.emit(action.id); mobileClose.emit()">
23566
+ <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id); mobileClose.emit()">
23339
23567
  <jv-icon [name]="action.icon" [size]="18" />
23568
+ <span>{{ action.label }}</span>
23340
23569
  </button>
23341
23570
  }
23342
23571
  </div>
23343
23572
  </div>
23344
23573
  </div>
23345
23574
  </aside>
23346
- `, styles: [".jv-sidebar-backdrop{display:none}.jv-sidebar{display:grid;grid-template-rows:auto 1fr auto;gap:var(--jv-spacing-lg);width:280px;min-width:280px;height:100vh;padding:var(--jv-spacing-lg);overflow-y:auto;border-right:1px solid var(--jv-color-border);background:var(--jv-color-surface);scrollbar-width:none;-ms-overflow-style:none}.jv-sidebar::-webkit-scrollbar{width:0;height:0;display:none}.jv-sidebar.is-collapsed{width:96px;min-width:96px;padding-inline:var(--jv-spacing-md)}.jv-sidebar-footer{display:grid;gap:var(--jv-spacing-md)}.jv-sidebar-mobile-extras{display:none}.jv-sidebar-brand,.jv-sidebar-link,.jv-sidebar-toggle{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.brand-mark{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border-radius:var(--jv-radius-md);background:color-mix(in srgb,var(--jv-color-primary) 16%,var(--jv-color-surface));color:var(--jv-color-primary);flex:0 0 auto}.brand-copy{display:grid;gap:.1rem}.brand-copy span{color:var(--jv-color-foreground-muted);font-size:.875rem}.jv-sidebar-item{display:grid;gap:var(--jv-spacing-xs);list-style:none}.jv-sidebar-list{display:grid;gap:var(--jv-spacing-xs);margin:0;padding:0}.jv-sidebar-nav{display:grid;gap:var(--jv-spacing-xs);align-content:start}.jv-sidebar-link,.jv-sidebar-child-link,.jv-sidebar-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground-muted);text-decoration:none;cursor:pointer}.jv-sidebar-link-main{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-sidebar-link:hover,.jv-sidebar-child-link:hover,.jv-sidebar-toggle:hover{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-sidebar-link.is-active,.jv-sidebar-child-link.is-active{border-color:color-mix(in srgb,var(--jv-color-primary) 25%,var(--jv-color-border));background:color-mix(in srgb,var(--jv-color-primary) 12%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-sidebar-children{display:grid;gap:var(--jv-spacing-xs);margin-left:var(--jv-spacing-xl);padding-left:var(--jv-spacing-sm);border-left:1px solid var(--jv-color-border)}.jv-sidebar-child-link{display:flex;align-items:center;min-height:calc(var(--jv-density-control-height) - .25rem);font-size:.9rem}.jv-sidebar-toggle{width:100%;background:var(--jv-color-surface-muted);cursor:pointer}@media(max-width:900px){.jv-sidebar-backdrop{display:block;position:fixed;inset:0;z-index:99;background:#0006}.jv-sidebar{position:fixed;top:0;left:0;z-index:100;width:280px;min-width:280px;height:100vh;border-right:1px solid var(--jv-color-border);border-bottom:none;box-shadow:var(--jv-shadow-lg);transform:translate(-100%);visibility:hidden;transition:transform .24s cubic-bezier(.4,0,.2,1),visibility .24s}.jv-sidebar.is-mobile-open{transform:translate(0);visibility:visible}.jv-sidebar.is-collapsed{width:280px;min-width:280px}.jv-sidebar-mobile-extras{display:flex;flex-direction:column;gap:var(--jv-spacing-md);padding-top:var(--jv-spacing-md);border-top:1px solid var(--jv-color-border)}.jv-sidebar-mobile-extras .theme-group{display:flex;flex-wrap:wrap;gap:var(--jv-spacing-xs)}.jv-sidebar-mobile-extras .theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);cursor:pointer;font:inherit}.jv-sidebar-mobile-extras .theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}.jv-sidebar-mobile-extras .mobile-actions{display:flex;gap:var(--jv-spacing-sm)}.jv-sidebar-mobile-extras .icon-button{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border:1px solid var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);cursor:pointer}}\n"] }]
23575
+ `, styles: [".jv-sidebar-backdrop{display:none}.jv-sidebar{display:grid;grid-template-rows:auto 1fr auto;gap:var(--jv-spacing-lg);width:280px;min-width:280px;height:100vh;padding:var(--jv-spacing-lg);overflow-y:auto;border-right:1px solid var(--jv-color-border);background:var(--jv-color-surface);scrollbar-width:none;-ms-overflow-style:none}.jv-sidebar::-webkit-scrollbar{width:0;height:0;display:none}.jv-sidebar.is-collapsed{width:96px;min-width:96px;padding-inline:var(--jv-spacing-md)}.jv-sidebar-footer{display:grid;gap:var(--jv-spacing-md)}.jv-sidebar-mobile-extras{display:none}.jv-sidebar-brand,.jv-sidebar-link,.jv-sidebar-toggle{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.brand-mark{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border-radius:var(--jv-radius-md);background:color-mix(in srgb,var(--jv-color-primary) 16%,var(--jv-color-surface));color:var(--jv-color-primary);flex:0 0 auto}.brand-copy{display:grid;gap:.1rem}.brand-copy span{color:var(--jv-color-foreground-muted);font-size:.875rem}.jv-sidebar-item{display:grid;gap:var(--jv-spacing-xs);list-style:none}.jv-sidebar-list{display:grid;gap:var(--jv-spacing-xs);margin:0;padding:0}.jv-sidebar-nav{display:grid;gap:var(--jv-spacing-xs);align-content:start}.jv-sidebar-link,.jv-sidebar-child-link,.jv-sidebar-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground-muted);text-decoration:none;cursor:pointer}.jv-sidebar-link-main{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-sidebar-link:hover,.jv-sidebar-child-link:hover,.jv-sidebar-toggle:hover{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-sidebar-link.is-active,.jv-sidebar-child-link.is-active{border-color:color-mix(in srgb,var(--jv-color-primary) 25%,var(--jv-color-border));background:color-mix(in srgb,var(--jv-color-primary) 12%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-sidebar-children{display:grid;gap:var(--jv-spacing-xs);margin-left:var(--jv-spacing-xl);padding-left:var(--jv-spacing-sm);border-left:1px solid var(--jv-color-border)}.jv-sidebar-child-link{display:flex;align-items:center;min-height:calc(var(--jv-density-control-height) - .25rem);font-size:.9rem}.jv-sidebar-toggle{width:100%;background:var(--jv-color-surface-muted);cursor:pointer}@media(max-width:900px){.jv-sidebar-backdrop{display:block;position:fixed;inset:0;z-index:99;background:#0006}.jv-sidebar{position:fixed;top:0;left:0;z-index:100;width:280px;min-width:280px;height:100vh;border-right:1px solid var(--jv-color-border);border-bottom:none;box-shadow:var(--jv-shadow-lg);transform:translate(-100%);visibility:hidden;transition:transform .24s cubic-bezier(.4,0,.2,1),visibility .24s}.jv-sidebar.is-mobile-open{transform:translate(0);visibility:visible}.jv-sidebar.is-collapsed{width:280px;min-width:280px}.jv-sidebar-mobile-extras{display:flex;flex-direction:column;gap:var(--jv-spacing-md);padding-top:var(--jv-spacing-md);border-top:1px solid var(--jv-color-border)}.jv-sidebar-mobile-extras .theme-group{display:flex;flex-wrap:wrap;gap:var(--jv-spacing-xs)}.jv-sidebar-mobile-extras .theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);cursor:pointer;font:inherit}.jv-sidebar-mobile-extras .theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}.jv-sidebar-mobile-extras .mobile-actions{display:flex;gap:var(--jv-spacing-sm)}.jv-sidebar-mobile-extras .icon-button{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-width:var(--jv-density-control-height);height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);cursor:pointer}}\n"] }]
23347
23576
  }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], brandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandIcon", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], mobileOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileOpen", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], currentTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentTheme", required: false }] }], themeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "themeOptions", required: false }] }], topbarActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarActions", required: false }] }], showThemeSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThemeSelector", required: false }] }], collapseToggle: [{ type: i0.Output, args: ["collapseToggle"] }], mobileClose: [{ type: i0.Output, args: ["mobileClose"] }], themeChange: [{ type: i0.Output, args: ["themeChange"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }] } });
23348
23577
 
23349
23578
  class JvTopbarComponent {
@@ -23397,17 +23626,18 @@ class JvTopbarComponent {
23397
23626
  }
23398
23627
 
23399
23628
  @for (action of visibleActions(); track action.id) {
23400
- <button type="button" class="icon-button" [attr.aria-label]="action.label" (click)="actionClick.emit(action.id)">
23629
+ <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id)">
23401
23630
  <jv-icon [name]="action.icon" [size]="18" />
23631
+ <span class="action-label">{{ action.label }}</span>
23402
23632
  </button>
23403
23633
  }
23404
23634
  </div>
23405
23635
  </header>
23406
- `, isInline: true, styles: [".jv-topbar{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md) var(--jv-spacing-lg);border-bottom:1px solid var(--jv-color-border);background:var(--jv-color-surface)}.jv-topbar-start,.jv-topbar-end,.theme-group{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-topbar-end{flex-wrap:wrap;justify-content:flex-end}.title-block{display:grid;gap:.1rem}.title-block span{color:var(--jv-color-foreground-muted);font-size:.875rem}.icon-button,.theme-pill{border:1px solid var(--jv-color-border);background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.icon-button{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border-radius:999px}.theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border-radius:999px}.theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}@media(max-width:900px){.jv-topbar{align-items:center;flex-direction:row;justify-content:flex-start}.jv-topbar-end{display:none}}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
23636
+ `, isInline: true, styles: [".jv-topbar{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md) var(--jv-spacing-lg);border-bottom:1px solid var(--jv-color-border);background:var(--jv-color-surface)}.jv-topbar-start,.jv-topbar-end,.theme-group{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-topbar-end{flex-wrap:wrap;justify-content:flex-end}.title-block{display:grid;gap:.1rem}.title-block span{color:var(--jv-color-foreground-muted);font-size:.875rem}.icon-button,.theme-pill{border:1px solid var(--jv-color-border);background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.icon-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--jv-spacing-xs);min-width:var(--jv-density-control-height);height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border-radius:999px;cursor:pointer}.theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border-radius:999px}.theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}@media(max-width:900px){.jv-topbar{align-items:center;flex-direction:row;justify-content:flex-start}.jv-topbar-end{display:none}}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "directive", type: JvTooltipDirective, selector: "[jvTooltip]", inputs: ["jvTooltip", "jvTooltipPosition"] }] });
23407
23637
  }
23408
23638
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTopbarComponent, decorators: [{
23409
23639
  type: Component,
23410
- args: [{ selector: 'jv-topbar', standalone: true, imports: [JvIconComponent], template: `
23640
+ args: [{ selector: 'jv-topbar', standalone: true, imports: [JvIconComponent, JvTooltipDirective], template: `
23411
23641
  <header class="jv-topbar">
23412
23642
  <div class="jv-topbar-start">
23413
23643
  <button type="button" class="icon-button" (click)="menuClick.emit()" aria-label="Toggle navigation menu">
@@ -23446,24 +23676,272 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23446
23676
  }
23447
23677
 
23448
23678
  @for (action of visibleActions(); track action.id) {
23449
- <button type="button" class="icon-button" [attr.aria-label]="action.label" (click)="actionClick.emit(action.id)">
23679
+ <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id)">
23450
23680
  <jv-icon [name]="action.icon" [size]="18" />
23681
+ <span class="action-label">{{ action.label }}</span>
23451
23682
  </button>
23452
23683
  }
23453
23684
  </div>
23454
23685
  </header>
23455
- `, styles: [".jv-topbar{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md) var(--jv-spacing-lg);border-bottom:1px solid var(--jv-color-border);background:var(--jv-color-surface)}.jv-topbar-start,.jv-topbar-end,.theme-group{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-topbar-end{flex-wrap:wrap;justify-content:flex-end}.title-block{display:grid;gap:.1rem}.title-block span{color:var(--jv-color-foreground-muted);font-size:.875rem}.icon-button,.theme-pill{border:1px solid var(--jv-color-border);background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.icon-button{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border-radius:999px}.theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border-radius:999px}.theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}@media(max-width:900px){.jv-topbar{align-items:center;flex-direction:row;justify-content:flex-start}.jv-topbar-end{display:none}}\n"] }]
23686
+ `, styles: [".jv-topbar{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md) var(--jv-spacing-lg);border-bottom:1px solid var(--jv-color-border);background:var(--jv-color-surface)}.jv-topbar-start,.jv-topbar-end,.theme-group{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-topbar-end{flex-wrap:wrap;justify-content:flex-end}.title-block{display:grid;gap:.1rem}.title-block span{color:var(--jv-color-foreground-muted);font-size:.875rem}.icon-button,.theme-pill{border:1px solid var(--jv-color-border);background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.icon-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--jv-spacing-xs);min-width:var(--jv-density-control-height);height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border-radius:999px;cursor:pointer}.theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border-radius:999px}.theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}@media(max-width:900px){.jv-topbar{align-items:center;flex-direction:row;justify-content:flex-start}.jv-topbar-end{display:none}}\n"] }]
23456
23687
  }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], currentTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentTheme", required: false }] }], themeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "themeOptions", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], showThemeSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThemeSelector", required: false }] }], menuClick: [{ type: i0.Output, args: ["menuClick"] }], themeChange: [{ type: i0.Output, args: ["themeChange"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }] } });
23457
23688
 
23458
- class JvDashboardShellComponent {
23689
+ class JvTopbarMenuComponent {
23459
23690
  title = input.required(...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
23460
- sidebarSubtitle = input('', ...(ngDevMode ? [{ debugName: "sidebarSubtitle" }] : /* istanbul ignore next */ []));
23691
+ subtitle = input('', ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
23461
23692
  brandIcon = input('monitor', ...(ngDevMode ? [{ debugName: "brandIcon" }] : /* istanbul ignore next */ []));
23462
- navItems = input([], ...(ngDevMode ? [{ debugName: "navItems" }] : /* istanbul ignore next */ []));
23463
- sidebarCollapsed = input(false, ...(ngDevMode ? [{ debugName: "sidebarCollapsed" }] : /* istanbul ignore next */ []));
23464
- mobileSidebarOpen = input(false, ...(ngDevMode ? [{ debugName: "mobileSidebarOpen" }] : /* istanbul ignore next */ []));
23465
- topbarTitle = input('', ...(ngDevMode ? [{ debugName: "topbarTitle" }] : /* istanbul ignore next */ []));
23466
- topbarSubtitle = input('', ...(ngDevMode ? [{ debugName: "topbarSubtitle" }] : /* istanbul ignore next */ []));
23693
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
23694
+ mobileOpen = input(false, ...(ngDevMode ? [{ debugName: "mobileOpen" }] : /* istanbul ignore next */ []));
23695
+ ariaLabel = input('Topbar navigation', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
23696
+ currentTheme = input('light', ...(ngDevMode ? [{ debugName: "currentTheme" }] : /* istanbul ignore next */ []));
23697
+ themeOptions = input([], ...(ngDevMode ? [{ debugName: "themeOptions" }] : /* istanbul ignore next */ []));
23698
+ actions = input([], ...(ngDevMode ? [{ debugName: "actions" }] : /* istanbul ignore next */ []));
23699
+ showThemeSelector = input(true, ...(ngDevMode ? [{ debugName: "showThemeSelector" }] : /* istanbul ignore next */ []));
23700
+ menuClick = output();
23701
+ mobileClose = output();
23702
+ themeChange = output();
23703
+ actionClick = output();
23704
+ navigation = new JvNavigationState(this.items, inject(Router), false);
23705
+ normalizedItems = this.navigation.normalizedItems;
23706
+ isExpanded(id) {
23707
+ return this.navigation.isExpanded(id);
23708
+ }
23709
+ toggleSection(id) {
23710
+ this.navigation.toggleSection(id, true);
23711
+ }
23712
+ isHashLink(href) {
23713
+ return this.navigation.isHashLink(href);
23714
+ }
23715
+ navigateTo(href, parentId) {
23716
+ this.navigation.navigateTo(href);
23717
+ if (parentId) {
23718
+ this.navigation.closeSection(parentId);
23719
+ }
23720
+ this.mobileClose.emit();
23721
+ }
23722
+ closeSection(id) {
23723
+ this.navigation.closeSection(id);
23724
+ }
23725
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTopbarMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23726
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvTopbarMenuComponent, isStandalone: true, selector: "jv-topbar-menu", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, brandIcon: { classPropertyName: "brandIcon", publicName: "brandIcon", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, mobileOpen: { classPropertyName: "mobileOpen", publicName: "mobileOpen", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, currentTheme: { classPropertyName: "currentTheme", publicName: "currentTheme", isSignal: true, isRequired: false, transformFunction: null }, themeOptions: { classPropertyName: "themeOptions", publicName: "themeOptions", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, showThemeSelector: { classPropertyName: "showThemeSelector", publicName: "showThemeSelector", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuClick: "menuClick", mobileClose: "mobileClose", themeChange: "themeChange", actionClick: "actionClick" }, ngImport: i0, template: `
23727
+ @if (mobileOpen()) {
23728
+ <div class="jv-topbar-menu-backdrop" tabindex="-1" (click)="mobileClose.emit()" (keydown.escape)="mobileClose.emit()"></div>
23729
+ }
23730
+
23731
+ <header class="jv-topbar-menu" [class.is-mobile-open]="mobileOpen()">
23732
+ <div class="jv-topbar-menu-brand">
23733
+ <div class="brand-mark">
23734
+ <jv-icon [name]="brandIcon()" [size]="18" />
23735
+ </div>
23736
+ <div class="brand-copy">
23737
+ <strong>{{ title() }}</strong>
23738
+ @if (subtitle()) {
23739
+ <span>{{ subtitle() }}</span>
23740
+ }
23741
+ </div>
23742
+ </div>
23743
+
23744
+ <button type="button" class="mobile-menu-button" aria-label="Toggle navigation menu" (click)="menuClick.emit()">
23745
+ <jv-icon name="menu" [size]="18" />
23746
+ </button>
23747
+
23748
+ <nav class="jv-topbar-menu-nav" [attr.aria-label]="ariaLabel()">
23749
+ <ul class="jv-topbar-menu-list">
23750
+ @for (item of normalizedItems(); track item.id) {
23751
+ <li class="jv-topbar-menu-item">
23752
+ @if (item.children.length > 0) {
23753
+ <button
23754
+ type="button"
23755
+ class="jv-topbar-menu-link"
23756
+ [class.is-active]="item.active"
23757
+ [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
23758
+ [attr.aria-controls]="'jv-topbar-menu-section-' + item.id"
23759
+ (click)="toggleSection(item.id)"
23760
+ >
23761
+ @if (item.icon) {
23762
+ <jv-icon [name]="item.icon" [size]="17" />
23763
+ }
23764
+ <span>{{ item.label }}</span>
23765
+ <jv-icon [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'" [size]="15" />
23766
+ </button>
23767
+
23768
+ @if (isExpanded(item.id)) {
23769
+ <div class="jv-topbar-menu-dropdown" [id]="'jv-topbar-menu-section-' + item.id">
23770
+ @for (child of item.children; track child.id) {
23771
+ @if (isHashLink(child.href)) {
23772
+ <button type="button" class="jv-topbar-menu-child" [class.is-active]="child.active" (click)="navigateTo(child.href, item.id)">
23773
+ {{ child.label }}
23774
+ </button>
23775
+ } @else {
23776
+ <a class="jv-topbar-menu-child" [class.is-active]="child.active" [routerLink]="child.href" [attr.aria-current]="child.active ? 'page' : null" (click)="closeSection(item.id); mobileClose.emit()">
23777
+ {{ child.label }}
23778
+ </a>
23779
+ }
23780
+ }
23781
+ </div>
23782
+ }
23783
+ } @else {
23784
+ @if (isHashLink(item.href)) {
23785
+ <button type="button" class="jv-topbar-menu-link" [class.is-active]="item.active" (click)="navigateTo(item.href)">
23786
+ @if (item.icon) {
23787
+ <jv-icon [name]="item.icon" [size]="17" />
23788
+ }
23789
+ <span>{{ item.label }}</span>
23790
+ </button>
23791
+ } @else {
23792
+ <a class="jv-topbar-menu-link" [class.is-active]="item.active" [routerLink]="item.href" [attr.aria-current]="item.active ? 'page' : null" (click)="mobileClose.emit()">
23793
+ @if (item.icon) {
23794
+ <jv-icon [name]="item.icon" [size]="17" />
23795
+ }
23796
+ <span>{{ item.label }}</span>
23797
+ </a>
23798
+ }
23799
+ }
23800
+ </li>
23801
+ }
23802
+ </ul>
23803
+ </nav>
23804
+
23805
+ <div class="jv-topbar-menu-actions">
23806
+ @if (showThemeSelector()) {
23807
+ <div class="theme-group" aria-label="Theme selector">
23808
+ @for (option of themeOptions(); track option.value) {
23809
+ <button type="button" class="theme-pill" [class.is-active]="currentTheme() === option.value" (click)="themeChange.emit(option.value)">
23810
+ @if (option.icon) {
23811
+ <jv-icon [name]="option.icon" [size]="16" />
23812
+ }
23813
+ <span>{{ option.label }}</span>
23814
+ </button>
23815
+ }
23816
+ </div>
23817
+ }
23818
+
23819
+ @for (action of actions(); track action.id) {
23820
+ <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id)">
23821
+ <jv-icon [name]="action.icon" [size]="18" />
23822
+ <span class="action-label">{{ action.label }}</span>
23823
+ </button>
23824
+ }
23825
+ </div>
23826
+ </header>
23827
+ `, isInline: true, styles: [":host{display:block;position:relative;z-index:20}.jv-topbar-menu,.jv-topbar-menu-brand,.jv-topbar-menu-list,.jv-topbar-menu-actions,.theme-group{display:flex;align-items:center}.jv-topbar-menu{gap:var(--jv-spacing-lg);min-height:4.5rem;padding:var(--jv-spacing-md) var(--jv-spacing-xl);min-width:0;border-bottom:1px solid var(--jv-color-border);background:var(--jv-color-surface)}.jv-topbar-menu-brand{gap:var(--jv-spacing-sm);flex:0 0 auto}.brand-mark{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border-radius:var(--jv-radius-md);background:color-mix(in srgb,var(--jv-color-primary) 16%,var(--jv-color-surface));color:var(--jv-color-primary)}.brand-copy{display:grid;gap:.1rem}.brand-copy span{color:var(--jv-color-foreground-muted);font-size:.8125rem}.jv-topbar-menu-nav{min-width:0;flex:1 1 0}.jv-topbar-menu-list{gap:var(--jv-spacing-xs);margin:0;padding:0;list-style:none;min-width:0;flex-wrap:wrap}.jv-topbar-menu-item{position:relative;min-width:0;flex:0 1 auto}.jv-topbar-menu-link,.jv-topbar-menu-child,.icon-button,.theme-pill,.mobile-menu-button{border:1px solid transparent;background:transparent;color:var(--jv-color-foreground-muted);cursor:pointer;font:inherit;text-decoration:none}.jv-topbar-menu-link{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);min-width:0;width:100%;max-width:15rem;padding:0 var(--jv-spacing-sm);border-radius:var(--jv-radius-md);white-space:nowrap}.jv-topbar-menu-link span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.jv-topbar-menu-link:hover,.jv-topbar-menu-child:hover,.jv-topbar-menu-link.is-active,.jv-topbar-menu-child.is-active{background:color-mix(in srgb,var(--jv-color-primary) 12%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-topbar-menu-dropdown{position:absolute;top:calc(100% + var(--jv-spacing-xs));left:0;display:grid;min-width:14rem;max-height:min(70vh,32rem);gap:var(--jv-spacing-xs);padding:var(--jv-spacing-sm);overflow-y:auto;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);box-shadow:var(--jv-shadow-lg);z-index:30}.jv-topbar-menu-child{display:block;padding:var(--jv-spacing-sm) var(--jv-spacing-md);border-radius:var(--jv-radius-sm);text-align:left;white-space:nowrap}.jv-topbar-menu-actions{justify-content:flex-end;gap:var(--jv-spacing-sm);flex:0 0 auto}.theme-group{gap:var(--jv-spacing-xs)}.icon-button,.mobile-menu-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--jv-spacing-xs);min-width:var(--jv-density-control-height);height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border-color:var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.icon-button{cursor:pointer}.theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border-color:var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);font-size:.8125rem}.theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}.mobile-menu-button,.jv-topbar-menu-backdrop{display:none}@media(max-width:1100px){.jv-topbar-menu{gap:var(--jv-spacing-md);padding-inline:var(--jv-spacing-lg)}.jv-topbar-menu-link{max-width:12rem;padding-inline:var(--jv-spacing-xs)}}@media(max-width:1400px){.jv-topbar-menu-actions .theme-group{display:none}}@media(max-width:900px){.jv-topbar-menu-backdrop{display:block;position:fixed;inset:0;z-index:19;background:#0006}.jv-topbar-menu{position:relative;justify-content:space-between;min-height:4rem;padding:var(--jv-spacing-sm) var(--jv-spacing-md)}.mobile-menu-button{display:inline-grid;order:3}.jv-topbar-menu-nav{position:fixed;top:4rem;right:0;bottom:0;z-index:21;width:min(22rem,88vw);padding:var(--jv-spacing-lg);overflow-y:auto;border-left:1px solid var(--jv-color-border);background:var(--jv-color-surface);box-shadow:var(--jv-shadow-lg);transform:translate(100%);visibility:hidden;transition:transform .24s ease,visibility .24s}.jv-topbar-menu.is-mobile-open .jv-topbar-menu-nav{transform:translate(0);visibility:visible}.jv-topbar-menu-list{display:grid;align-items:stretch}.jv-topbar-menu-link{width:100%;justify-content:flex-start;padding-inline:var(--jv-spacing-md)}.jv-topbar-menu-dropdown{position:static;min-width:0;margin-left:var(--jv-spacing-md);box-shadow:none}.jv-topbar-menu-actions{margin-left:auto}}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: JvTooltipDirective, selector: "[jvTooltip]", inputs: ["jvTooltip", "jvTooltipPosition"] }] });
23828
+ }
23829
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTopbarMenuComponent, decorators: [{
23830
+ type: Component,
23831
+ args: [{ selector: 'jv-topbar-menu', standalone: true, imports: [JvIconComponent, RouterLink, JvTooltipDirective], template: `
23832
+ @if (mobileOpen()) {
23833
+ <div class="jv-topbar-menu-backdrop" tabindex="-1" (click)="mobileClose.emit()" (keydown.escape)="mobileClose.emit()"></div>
23834
+ }
23835
+
23836
+ <header class="jv-topbar-menu" [class.is-mobile-open]="mobileOpen()">
23837
+ <div class="jv-topbar-menu-brand">
23838
+ <div class="brand-mark">
23839
+ <jv-icon [name]="brandIcon()" [size]="18" />
23840
+ </div>
23841
+ <div class="brand-copy">
23842
+ <strong>{{ title() }}</strong>
23843
+ @if (subtitle()) {
23844
+ <span>{{ subtitle() }}</span>
23845
+ }
23846
+ </div>
23847
+ </div>
23848
+
23849
+ <button type="button" class="mobile-menu-button" aria-label="Toggle navigation menu" (click)="menuClick.emit()">
23850
+ <jv-icon name="menu" [size]="18" />
23851
+ </button>
23852
+
23853
+ <nav class="jv-topbar-menu-nav" [attr.aria-label]="ariaLabel()">
23854
+ <ul class="jv-topbar-menu-list">
23855
+ @for (item of normalizedItems(); track item.id) {
23856
+ <li class="jv-topbar-menu-item">
23857
+ @if (item.children.length > 0) {
23858
+ <button
23859
+ type="button"
23860
+ class="jv-topbar-menu-link"
23861
+ [class.is-active]="item.active"
23862
+ [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
23863
+ [attr.aria-controls]="'jv-topbar-menu-section-' + item.id"
23864
+ (click)="toggleSection(item.id)"
23865
+ >
23866
+ @if (item.icon) {
23867
+ <jv-icon [name]="item.icon" [size]="17" />
23868
+ }
23869
+ <span>{{ item.label }}</span>
23870
+ <jv-icon [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'" [size]="15" />
23871
+ </button>
23872
+
23873
+ @if (isExpanded(item.id)) {
23874
+ <div class="jv-topbar-menu-dropdown" [id]="'jv-topbar-menu-section-' + item.id">
23875
+ @for (child of item.children; track child.id) {
23876
+ @if (isHashLink(child.href)) {
23877
+ <button type="button" class="jv-topbar-menu-child" [class.is-active]="child.active" (click)="navigateTo(child.href, item.id)">
23878
+ {{ child.label }}
23879
+ </button>
23880
+ } @else {
23881
+ <a class="jv-topbar-menu-child" [class.is-active]="child.active" [routerLink]="child.href" [attr.aria-current]="child.active ? 'page' : null" (click)="closeSection(item.id); mobileClose.emit()">
23882
+ {{ child.label }}
23883
+ </a>
23884
+ }
23885
+ }
23886
+ </div>
23887
+ }
23888
+ } @else {
23889
+ @if (isHashLink(item.href)) {
23890
+ <button type="button" class="jv-topbar-menu-link" [class.is-active]="item.active" (click)="navigateTo(item.href)">
23891
+ @if (item.icon) {
23892
+ <jv-icon [name]="item.icon" [size]="17" />
23893
+ }
23894
+ <span>{{ item.label }}</span>
23895
+ </button>
23896
+ } @else {
23897
+ <a class="jv-topbar-menu-link" [class.is-active]="item.active" [routerLink]="item.href" [attr.aria-current]="item.active ? 'page' : null" (click)="mobileClose.emit()">
23898
+ @if (item.icon) {
23899
+ <jv-icon [name]="item.icon" [size]="17" />
23900
+ }
23901
+ <span>{{ item.label }}</span>
23902
+ </a>
23903
+ }
23904
+ }
23905
+ </li>
23906
+ }
23907
+ </ul>
23908
+ </nav>
23909
+
23910
+ <div class="jv-topbar-menu-actions">
23911
+ @if (showThemeSelector()) {
23912
+ <div class="theme-group" aria-label="Theme selector">
23913
+ @for (option of themeOptions(); track option.value) {
23914
+ <button type="button" class="theme-pill" [class.is-active]="currentTheme() === option.value" (click)="themeChange.emit(option.value)">
23915
+ @if (option.icon) {
23916
+ <jv-icon [name]="option.icon" [size]="16" />
23917
+ }
23918
+ <span>{{ option.label }}</span>
23919
+ </button>
23920
+ }
23921
+ </div>
23922
+ }
23923
+
23924
+ @for (action of actions(); track action.id) {
23925
+ <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id)">
23926
+ <jv-icon [name]="action.icon" [size]="18" />
23927
+ <span class="action-label">{{ action.label }}</span>
23928
+ </button>
23929
+ }
23930
+ </div>
23931
+ </header>
23932
+ `, styles: [":host{display:block;position:relative;z-index:20}.jv-topbar-menu,.jv-topbar-menu-brand,.jv-topbar-menu-list,.jv-topbar-menu-actions,.theme-group{display:flex;align-items:center}.jv-topbar-menu{gap:var(--jv-spacing-lg);min-height:4.5rem;padding:var(--jv-spacing-md) var(--jv-spacing-xl);min-width:0;border-bottom:1px solid var(--jv-color-border);background:var(--jv-color-surface)}.jv-topbar-menu-brand{gap:var(--jv-spacing-sm);flex:0 0 auto}.brand-mark{display:inline-grid;place-items:center;width:var(--jv-density-control-height);height:var(--jv-density-control-height);border-radius:var(--jv-radius-md);background:color-mix(in srgb,var(--jv-color-primary) 16%,var(--jv-color-surface));color:var(--jv-color-primary)}.brand-copy{display:grid;gap:.1rem}.brand-copy span{color:var(--jv-color-foreground-muted);font-size:.8125rem}.jv-topbar-menu-nav{min-width:0;flex:1 1 0}.jv-topbar-menu-list{gap:var(--jv-spacing-xs);margin:0;padding:0;list-style:none;min-width:0;flex-wrap:wrap}.jv-topbar-menu-item{position:relative;min-width:0;flex:0 1 auto}.jv-topbar-menu-link,.jv-topbar-menu-child,.icon-button,.theme-pill,.mobile-menu-button{border:1px solid transparent;background:transparent;color:var(--jv-color-foreground-muted);cursor:pointer;font:inherit;text-decoration:none}.jv-topbar-menu-link{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);min-width:0;width:100%;max-width:15rem;padding:0 var(--jv-spacing-sm);border-radius:var(--jv-radius-md);white-space:nowrap}.jv-topbar-menu-link span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.jv-topbar-menu-link:hover,.jv-topbar-menu-child:hover,.jv-topbar-menu-link.is-active,.jv-topbar-menu-child.is-active{background:color-mix(in srgb,var(--jv-color-primary) 12%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-topbar-menu-dropdown{position:absolute;top:calc(100% + var(--jv-spacing-xs));left:0;display:grid;min-width:14rem;max-height:min(70vh,32rem);gap:var(--jv-spacing-xs);padding:var(--jv-spacing-sm);overflow-y:auto;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);box-shadow:var(--jv-shadow-lg);z-index:30}.jv-topbar-menu-child{display:block;padding:var(--jv-spacing-sm) var(--jv-spacing-md);border-radius:var(--jv-radius-sm);text-align:left;white-space:nowrap}.jv-topbar-menu-actions{justify-content:flex-end;gap:var(--jv-spacing-sm);flex:0 0 auto}.theme-group{gap:var(--jv-spacing-xs)}.icon-button,.mobile-menu-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--jv-spacing-xs);min-width:var(--jv-density-control-height);height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border-color:var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.icon-button{cursor:pointer}.theme-pill{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs);min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border-color:var(--jv-color-border);border-radius:999px;background:var(--jv-color-surface-muted);color:var(--jv-color-foreground);font-size:.8125rem}.theme-pill.is-active{border-color:var(--jv-color-primary);background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface))}.mobile-menu-button,.jv-topbar-menu-backdrop{display:none}@media(max-width:1100px){.jv-topbar-menu{gap:var(--jv-spacing-md);padding-inline:var(--jv-spacing-lg)}.jv-topbar-menu-link{max-width:12rem;padding-inline:var(--jv-spacing-xs)}}@media(max-width:1400px){.jv-topbar-menu-actions .theme-group{display:none}}@media(max-width:900px){.jv-topbar-menu-backdrop{display:block;position:fixed;inset:0;z-index:19;background:#0006}.jv-topbar-menu{position:relative;justify-content:space-between;min-height:4rem;padding:var(--jv-spacing-sm) var(--jv-spacing-md)}.mobile-menu-button{display:inline-grid;order:3}.jv-topbar-menu-nav{position:fixed;top:4rem;right:0;bottom:0;z-index:21;width:min(22rem,88vw);padding:var(--jv-spacing-lg);overflow-y:auto;border-left:1px solid var(--jv-color-border);background:var(--jv-color-surface);box-shadow:var(--jv-shadow-lg);transform:translate(100%);visibility:hidden;transition:transform .24s ease,visibility .24s}.jv-topbar-menu.is-mobile-open .jv-topbar-menu-nav{transform:translate(0);visibility:visible}.jv-topbar-menu-list{display:grid;align-items:stretch}.jv-topbar-menu-link{width:100%;justify-content:flex-start;padding-inline:var(--jv-spacing-md)}.jv-topbar-menu-dropdown{position:static;min-width:0;margin-left:var(--jv-spacing-md);box-shadow:none}.jv-topbar-menu-actions{margin-left:auto}}\n"] }]
23933
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], brandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandIcon", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], mobileOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileOpen", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], currentTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentTheme", required: false }] }], themeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "themeOptions", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], showThemeSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThemeSelector", required: false }] }], menuClick: [{ type: i0.Output, args: ["menuClick"] }], mobileClose: [{ type: i0.Output, args: ["mobileClose"] }], themeChange: [{ type: i0.Output, args: ["themeChange"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }] } });
23934
+
23935
+ class JvDashboardShellComponent {
23936
+ title = input.required(...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
23937
+ navigationMode = input('sidebar', ...(ngDevMode ? [{ debugName: "navigationMode" }] : /* istanbul ignore next */ []));
23938
+ sidebarSubtitle = input('', ...(ngDevMode ? [{ debugName: "sidebarSubtitle" }] : /* istanbul ignore next */ []));
23939
+ brandIcon = input('monitor', ...(ngDevMode ? [{ debugName: "brandIcon" }] : /* istanbul ignore next */ []));
23940
+ navItems = input([], ...(ngDevMode ? [{ debugName: "navItems" }] : /* istanbul ignore next */ []));
23941
+ sidebarCollapsed = input(false, ...(ngDevMode ? [{ debugName: "sidebarCollapsed" }] : /* istanbul ignore next */ []));
23942
+ mobileSidebarOpen = input(false, ...(ngDevMode ? [{ debugName: "mobileSidebarOpen" }] : /* istanbul ignore next */ []));
23943
+ topbarTitle = input('', ...(ngDevMode ? [{ debugName: "topbarTitle" }] : /* istanbul ignore next */ []));
23944
+ topbarSubtitle = input('', ...(ngDevMode ? [{ debugName: "topbarSubtitle" }] : /* istanbul ignore next */ []));
23467
23945
  currentTheme = input('light', ...(ngDevMode ? [{ debugName: "currentTheme" }] : /* istanbul ignore next */ []));
23468
23946
  themeOptions = input([], ...(ngDevMode ? [{ debugName: "themeOptions" }] : /* istanbul ignore next */ []));
23469
23947
  topbarActions = input([], ...(ngDevMode ? [{ debugName: "topbarActions" }] : /* istanbul ignore next */ []));
@@ -23474,90 +23952,130 @@ class JvDashboardShellComponent {
23474
23952
  themeChange = output();
23475
23953
  topbarActionClick = output();
23476
23954
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDashboardShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23477
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvDashboardShellComponent, isStandalone: true, selector: "jv-dashboard-shell", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, sidebarSubtitle: { classPropertyName: "sidebarSubtitle", publicName: "sidebarSubtitle", isSignal: true, isRequired: false, transformFunction: null }, brandIcon: { classPropertyName: "brandIcon", publicName: "brandIcon", isSignal: true, isRequired: false, transformFunction: null }, navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, sidebarCollapsed: { classPropertyName: "sidebarCollapsed", publicName: "sidebarCollapsed", isSignal: true, isRequired: false, transformFunction: null }, mobileSidebarOpen: { classPropertyName: "mobileSidebarOpen", publicName: "mobileSidebarOpen", isSignal: true, isRequired: false, transformFunction: null }, topbarTitle: { classPropertyName: "topbarTitle", publicName: "topbarTitle", isSignal: true, isRequired: false, transformFunction: null }, topbarSubtitle: { classPropertyName: "topbarSubtitle", publicName: "topbarSubtitle", isSignal: true, isRequired: false, transformFunction: null }, currentTheme: { classPropertyName: "currentTheme", publicName: "currentTheme", isSignal: true, isRequired: false, transformFunction: null }, themeOptions: { classPropertyName: "themeOptions", publicName: "themeOptions", isSignal: true, isRequired: false, transformFunction: null }, topbarActions: { classPropertyName: "topbarActions", publicName: "topbarActions", isSignal: true, isRequired: false, transformFunction: null }, showThemeSelector: { classPropertyName: "showThemeSelector", publicName: "showThemeSelector", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuClick: "menuClick", mobileClose: "mobileClose", sidebarCollapseToggle: "sidebarCollapseToggle", themeChange: "themeChange", topbarActionClick: "topbarActionClick" }, ngImport: i0, template: `
23478
- <div class="jv-dashboard-shell" [class.is-sidebar-collapsed]="sidebarCollapsed()">
23479
- <jv-sidebar
23480
- [title]="title()"
23481
- [subtitle]="sidebarSubtitle()"
23482
- [brandIcon]="brandIcon()"
23483
- [items]="navItems()"
23484
- [collapsed]="sidebarCollapsed()"
23485
- [mobileOpen]="mobileSidebarOpen()"
23486
- [currentTheme]="currentTheme()"
23487
- [themeOptions]="themeOptions()"
23488
- [topbarActions]="topbarActions()"
23489
- [showThemeSelector]="showThemeSelector()"
23490
- (collapseToggle)="sidebarCollapseToggle.emit()"
23491
- (mobileClose)="mobileClose.emit()"
23492
- (themeChange)="themeChange.emit($event)"
23493
- (actionClick)="topbarActionClick.emit($event)"
23494
- />
23495
-
23496
- <div class="jv-dashboard-main">
23497
- <jv-topbar
23498
- [title]="topbarTitle()"
23499
- [subtitle]="topbarSubtitle()"
23955
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvDashboardShellComponent, isStandalone: true, selector: "jv-dashboard-shell", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, navigationMode: { classPropertyName: "navigationMode", publicName: "navigationMode", isSignal: true, isRequired: false, transformFunction: null }, sidebarSubtitle: { classPropertyName: "sidebarSubtitle", publicName: "sidebarSubtitle", isSignal: true, isRequired: false, transformFunction: null }, brandIcon: { classPropertyName: "brandIcon", publicName: "brandIcon", isSignal: true, isRequired: false, transformFunction: null }, navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, sidebarCollapsed: { classPropertyName: "sidebarCollapsed", publicName: "sidebarCollapsed", isSignal: true, isRequired: false, transformFunction: null }, mobileSidebarOpen: { classPropertyName: "mobileSidebarOpen", publicName: "mobileSidebarOpen", isSignal: true, isRequired: false, transformFunction: null }, topbarTitle: { classPropertyName: "topbarTitle", publicName: "topbarTitle", isSignal: true, isRequired: false, transformFunction: null }, topbarSubtitle: { classPropertyName: "topbarSubtitle", publicName: "topbarSubtitle", isSignal: true, isRequired: false, transformFunction: null }, currentTheme: { classPropertyName: "currentTheme", publicName: "currentTheme", isSignal: true, isRequired: false, transformFunction: null }, themeOptions: { classPropertyName: "themeOptions", publicName: "themeOptions", isSignal: true, isRequired: false, transformFunction: null }, topbarActions: { classPropertyName: "topbarActions", publicName: "topbarActions", isSignal: true, isRequired: false, transformFunction: null }, showThemeSelector: { classPropertyName: "showThemeSelector", publicName: "showThemeSelector", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuClick: "menuClick", mobileClose: "mobileClose", sidebarCollapseToggle: "sidebarCollapseToggle", themeChange: "themeChange", topbarActionClick: "topbarActionClick" }, ngImport: i0, template: `
23956
+ <div class="jv-dashboard-shell" [class.is-sidebar-collapsed]="sidebarCollapsed()" [class.is-topbar-navigation]="navigationMode() === 'topbar'">
23957
+ @if (navigationMode() === 'sidebar') {
23958
+ <jv-sidebar
23959
+ [title]="title()"
23960
+ [subtitle]="sidebarSubtitle()"
23961
+ [brandIcon]="brandIcon()"
23962
+ [items]="navItems()"
23963
+ [collapsed]="sidebarCollapsed()"
23964
+ [mobileOpen]="mobileSidebarOpen()"
23500
23965
  [currentTheme]="currentTheme()"
23501
23966
  [themeOptions]="themeOptions()"
23502
- [actions]="topbarActions()"
23967
+ [topbarActions]="topbarActions()"
23503
23968
  [showThemeSelector]="showThemeSelector()"
23504
- (menuClick)="menuClick.emit()"
23969
+ (collapseToggle)="sidebarCollapseToggle.emit()"
23970
+ (mobileClose)="mobileClose.emit()"
23505
23971
  (themeChange)="themeChange.emit($event)"
23506
23972
  (actionClick)="topbarActionClick.emit($event)"
23507
- >
23508
- <ng-content select="[topbar-actions]" topbar-actions></ng-content>
23509
- </jv-topbar>
23973
+ />
23974
+ }
23975
+
23976
+ <div class="jv-dashboard-main">
23977
+ @if (navigationMode() === 'topbar') {
23978
+ <jv-topbar-menu
23979
+ [title]="title()"
23980
+ [subtitle]="sidebarSubtitle()"
23981
+ [brandIcon]="brandIcon()"
23982
+ [items]="navItems()"
23983
+ [mobileOpen]="mobileSidebarOpen()"
23984
+ [currentTheme]="currentTheme()"
23985
+ [themeOptions]="themeOptions()"
23986
+ [actions]="topbarActions()"
23987
+ [showThemeSelector]="showThemeSelector()"
23988
+ (menuClick)="menuClick.emit()"
23989
+ (mobileClose)="mobileClose.emit()"
23990
+ (themeChange)="themeChange.emit($event)"
23991
+ (actionClick)="topbarActionClick.emit($event)"
23992
+ />
23993
+ } @else {
23994
+ <jv-topbar
23995
+ [title]="topbarTitle()"
23996
+ [subtitle]="topbarSubtitle()"
23997
+ [currentTheme]="currentTheme()"
23998
+ [themeOptions]="themeOptions()"
23999
+ [actions]="topbarActions()"
24000
+ [showThemeSelector]="showThemeSelector()"
24001
+ (menuClick)="menuClick.emit()"
24002
+ (themeChange)="themeChange.emit($event)"
24003
+ (actionClick)="topbarActionClick.emit($event)"
24004
+ >
24005
+ <ng-content select="[topbar-actions]" topbar-actions></ng-content>
24006
+ </jv-topbar>
24007
+ }
23510
24008
 
23511
24009
  <main class="jv-dashboard-content">
23512
24010
  <ng-content></ng-content>
23513
24011
  </main>
23514
24012
  </div>
23515
24013
  </div>
23516
- `, isInline: true, styles: [":host{display:block;height:100dvh;overflow:hidden}.jv-dashboard-shell{display:grid;height:100%;grid-template-columns:auto 1fr;background:var(--jv-color-background);overflow:hidden}.jv-dashboard-main{display:grid;grid-template-rows:auto 1fr;min-width:0;min-height:0;overflow:hidden}.jv-dashboard-content{overflow:auto;min-width:0;min-height:0;padding:var(--jv-spacing-xl);scrollbar-width:none;-ms-overflow-style:none}.jv-dashboard-content::-webkit-scrollbar{width:0;height:0;display:none}@media(max-width:900px){.jv-dashboard-shell{grid-template-columns:1fr}.jv-dashboard-content{padding:var(--jv-spacing-lg)}}\n"], dependencies: [{ kind: "component", type: JvSidebarComponent, selector: "jv-sidebar", inputs: ["title", "subtitle", "brandIcon", "items", "collapsed", "mobileOpen", "ariaLabel", "currentTheme", "themeOptions", "topbarActions", "showThemeSelector"], outputs: ["collapseToggle", "mobileClose", "themeChange", "actionClick"] }, { kind: "component", type: JvTopbarComponent, selector: "jv-topbar", inputs: ["title", "subtitle", "currentTheme", "themeOptions", "actions", "showThemeSelector"], outputs: ["menuClick", "themeChange", "actionClick"] }] });
24014
+ `, isInline: true, styles: [":host{display:block;height:100dvh;overflow:hidden}.jv-dashboard-shell{display:grid;height:100%;grid-template-columns:auto 1fr;background:var(--jv-color-background);overflow:hidden}.jv-dashboard-shell.is-topbar-navigation{grid-template-columns:1fr}.jv-dashboard-main{display:grid;grid-template-rows:auto 1fr;min-width:0;min-height:0;overflow:hidden}.jv-dashboard-content{overflow:auto;min-width:0;min-height:0;padding:var(--jv-spacing-xl);scrollbar-width:none;-ms-overflow-style:none}.jv-dashboard-content::-webkit-scrollbar{width:0;height:0;display:none}@media(max-width:900px){.jv-dashboard-shell{grid-template-columns:1fr}.jv-dashboard-content{padding:var(--jv-spacing-lg)}}\n"], dependencies: [{ kind: "component", type: JvSidebarComponent, selector: "jv-sidebar", inputs: ["title", "subtitle", "brandIcon", "items", "collapsed", "mobileOpen", "ariaLabel", "currentTheme", "themeOptions", "topbarActions", "showThemeSelector"], outputs: ["collapseToggle", "mobileClose", "themeChange", "actionClick"] }, { kind: "component", type: JvTopbarComponent, selector: "jv-topbar", inputs: ["title", "subtitle", "currentTheme", "themeOptions", "actions", "showThemeSelector"], outputs: ["menuClick", "themeChange", "actionClick"] }, { kind: "component", type: JvTopbarMenuComponent, selector: "jv-topbar-menu", inputs: ["title", "subtitle", "brandIcon", "items", "mobileOpen", "ariaLabel", "currentTheme", "themeOptions", "actions", "showThemeSelector"], outputs: ["menuClick", "mobileClose", "themeChange", "actionClick"] }] });
23517
24015
  }
23518
24016
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDashboardShellComponent, decorators: [{
23519
24017
  type: Component,
23520
- args: [{ selector: 'jv-dashboard-shell', standalone: true, imports: [JvSidebarComponent, JvTopbarComponent], template: `
23521
- <div class="jv-dashboard-shell" [class.is-sidebar-collapsed]="sidebarCollapsed()">
23522
- <jv-sidebar
23523
- [title]="title()"
23524
- [subtitle]="sidebarSubtitle()"
23525
- [brandIcon]="brandIcon()"
23526
- [items]="navItems()"
23527
- [collapsed]="sidebarCollapsed()"
23528
- [mobileOpen]="mobileSidebarOpen()"
23529
- [currentTheme]="currentTheme()"
23530
- [themeOptions]="themeOptions()"
23531
- [topbarActions]="topbarActions()"
23532
- [showThemeSelector]="showThemeSelector()"
23533
- (collapseToggle)="sidebarCollapseToggle.emit()"
23534
- (mobileClose)="mobileClose.emit()"
23535
- (themeChange)="themeChange.emit($event)"
23536
- (actionClick)="topbarActionClick.emit($event)"
23537
- />
23538
-
23539
- <div class="jv-dashboard-main">
23540
- <jv-topbar
23541
- [title]="topbarTitle()"
23542
- [subtitle]="topbarSubtitle()"
24018
+ args: [{ selector: 'jv-dashboard-shell', standalone: true, imports: [JvSidebarComponent, JvTopbarComponent, JvTopbarMenuComponent], template: `
24019
+ <div class="jv-dashboard-shell" [class.is-sidebar-collapsed]="sidebarCollapsed()" [class.is-topbar-navigation]="navigationMode() === 'topbar'">
24020
+ @if (navigationMode() === 'sidebar') {
24021
+ <jv-sidebar
24022
+ [title]="title()"
24023
+ [subtitle]="sidebarSubtitle()"
24024
+ [brandIcon]="brandIcon()"
24025
+ [items]="navItems()"
24026
+ [collapsed]="sidebarCollapsed()"
24027
+ [mobileOpen]="mobileSidebarOpen()"
23543
24028
  [currentTheme]="currentTheme()"
23544
24029
  [themeOptions]="themeOptions()"
23545
- [actions]="topbarActions()"
24030
+ [topbarActions]="topbarActions()"
23546
24031
  [showThemeSelector]="showThemeSelector()"
23547
- (menuClick)="menuClick.emit()"
24032
+ (collapseToggle)="sidebarCollapseToggle.emit()"
24033
+ (mobileClose)="mobileClose.emit()"
23548
24034
  (themeChange)="themeChange.emit($event)"
23549
24035
  (actionClick)="topbarActionClick.emit($event)"
23550
- >
23551
- <ng-content select="[topbar-actions]" topbar-actions></ng-content>
23552
- </jv-topbar>
24036
+ />
24037
+ }
24038
+
24039
+ <div class="jv-dashboard-main">
24040
+ @if (navigationMode() === 'topbar') {
24041
+ <jv-topbar-menu
24042
+ [title]="title()"
24043
+ [subtitle]="sidebarSubtitle()"
24044
+ [brandIcon]="brandIcon()"
24045
+ [items]="navItems()"
24046
+ [mobileOpen]="mobileSidebarOpen()"
24047
+ [currentTheme]="currentTheme()"
24048
+ [themeOptions]="themeOptions()"
24049
+ [actions]="topbarActions()"
24050
+ [showThemeSelector]="showThemeSelector()"
24051
+ (menuClick)="menuClick.emit()"
24052
+ (mobileClose)="mobileClose.emit()"
24053
+ (themeChange)="themeChange.emit($event)"
24054
+ (actionClick)="topbarActionClick.emit($event)"
24055
+ />
24056
+ } @else {
24057
+ <jv-topbar
24058
+ [title]="topbarTitle()"
24059
+ [subtitle]="topbarSubtitle()"
24060
+ [currentTheme]="currentTheme()"
24061
+ [themeOptions]="themeOptions()"
24062
+ [actions]="topbarActions()"
24063
+ [showThemeSelector]="showThemeSelector()"
24064
+ (menuClick)="menuClick.emit()"
24065
+ (themeChange)="themeChange.emit($event)"
24066
+ (actionClick)="topbarActionClick.emit($event)"
24067
+ >
24068
+ <ng-content select="[topbar-actions]" topbar-actions></ng-content>
24069
+ </jv-topbar>
24070
+ }
23553
24071
 
23554
24072
  <main class="jv-dashboard-content">
23555
24073
  <ng-content></ng-content>
23556
24074
  </main>
23557
24075
  </div>
23558
24076
  </div>
23559
- `, styles: [":host{display:block;height:100dvh;overflow:hidden}.jv-dashboard-shell{display:grid;height:100%;grid-template-columns:auto 1fr;background:var(--jv-color-background);overflow:hidden}.jv-dashboard-main{display:grid;grid-template-rows:auto 1fr;min-width:0;min-height:0;overflow:hidden}.jv-dashboard-content{overflow:auto;min-width:0;min-height:0;padding:var(--jv-spacing-xl);scrollbar-width:none;-ms-overflow-style:none}.jv-dashboard-content::-webkit-scrollbar{width:0;height:0;display:none}@media(max-width:900px){.jv-dashboard-shell{grid-template-columns:1fr}.jv-dashboard-content{padding:var(--jv-spacing-lg)}}\n"] }]
23560
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], sidebarSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarSubtitle", required: false }] }], brandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandIcon", required: false }] }], navItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "navItems", required: false }] }], sidebarCollapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarCollapsed", required: false }] }], mobileSidebarOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileSidebarOpen", required: false }] }], topbarTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarTitle", required: false }] }], topbarSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarSubtitle", required: false }] }], currentTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentTheme", required: false }] }], themeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "themeOptions", required: false }] }], topbarActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarActions", required: false }] }], showThemeSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThemeSelector", required: false }] }], menuClick: [{ type: i0.Output, args: ["menuClick"] }], mobileClose: [{ type: i0.Output, args: ["mobileClose"] }], sidebarCollapseToggle: [{ type: i0.Output, args: ["sidebarCollapseToggle"] }], themeChange: [{ type: i0.Output, args: ["themeChange"] }], topbarActionClick: [{ type: i0.Output, args: ["topbarActionClick"] }] } });
24077
+ `, styles: [":host{display:block;height:100dvh;overflow:hidden}.jv-dashboard-shell{display:grid;height:100%;grid-template-columns:auto 1fr;background:var(--jv-color-background);overflow:hidden}.jv-dashboard-shell.is-topbar-navigation{grid-template-columns:1fr}.jv-dashboard-main{display:grid;grid-template-rows:auto 1fr;min-width:0;min-height:0;overflow:hidden}.jv-dashboard-content{overflow:auto;min-width:0;min-height:0;padding:var(--jv-spacing-xl);scrollbar-width:none;-ms-overflow-style:none}.jv-dashboard-content::-webkit-scrollbar{width:0;height:0;display:none}@media(max-width:900px){.jv-dashboard-shell{grid-template-columns:1fr}.jv-dashboard-content{padding:var(--jv-spacing-lg)}}\n"] }]
24078
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], navigationMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigationMode", required: false }] }], sidebarSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarSubtitle", required: false }] }], brandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandIcon", required: false }] }], navItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "navItems", required: false }] }], sidebarCollapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarCollapsed", required: false }] }], mobileSidebarOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileSidebarOpen", required: false }] }], topbarTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarTitle", required: false }] }], topbarSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarSubtitle", required: false }] }], currentTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentTheme", required: false }] }], themeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "themeOptions", required: false }] }], topbarActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarActions", required: false }] }], showThemeSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThemeSelector", required: false }] }], menuClick: [{ type: i0.Output, args: ["menuClick"] }], mobileClose: [{ type: i0.Output, args: ["mobileClose"] }], sidebarCollapseToggle: [{ type: i0.Output, args: ["sidebarCollapseToggle"] }], themeChange: [{ type: i0.Output, args: ["themeChange"] }], topbarActionClick: [{ type: i0.Output, args: ["topbarActionClick"] }] } });
23561
24079
 
23562
24080
  class JvPageComponent {
23563
24081
  eyebrow = input('', ...(ngDevMode ? [{ debugName: "eyebrow" }] : /* istanbul ignore next */ []));
@@ -24093,193 +24611,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24093
24611
  args: ['window:resize']
24094
24612
  }] } });
24095
24613
 
24096
- let tooltipSequence = 0;
24097
- class JvTooltipDirective {
24098
- document = inject(DOCUMENT);
24099
- renderer = inject(Renderer2);
24100
- hostRef = inject((ElementRef));
24101
- tooltipElement = null;
24102
- showTimeout = null;
24103
- hideTimeout = null;
24104
- tooltipId = `jv-tooltip-${++tooltipSequence}`;
24105
- originalDescribedBy = null;
24106
- text = input.required({ ...(ngDevMode ? { debugName: "text" } : /* istanbul ignore next */ {}), alias: 'jvTooltip' });
24107
- position = input('top', { ...(ngDevMode ? { debugName: "position" } : /* istanbul ignore next */ {}), alias: 'jvTooltipPosition' });
24108
- show() {
24109
- if (!this.text().trim()) {
24110
- return;
24111
- }
24112
- this.clearHideTimeout();
24113
- if (this.tooltipElement) {
24114
- return;
24115
- }
24116
- this.showTimeout = setTimeout(() => {
24117
- this.renderTooltip();
24118
- this.positionTooltip();
24119
- this.attachTooltipDescription();
24120
- }, 120);
24121
- }
24122
- hide() {
24123
- this.clearShowTimeout();
24124
- if (!this.tooltipElement) {
24125
- return;
24126
- }
24127
- this.hideTimeout = setTimeout(() => this.destroyTooltip(), 80);
24128
- }
24129
- handleDocumentKeydown(event) {
24130
- if (event.key === 'Escape') {
24131
- this.destroyTooltip();
24132
- }
24133
- }
24134
- handleViewportChange() {
24135
- if (this.tooltipElement) {
24136
- this.positionTooltip();
24137
- }
24138
- }
24139
- ngOnDestroy() {
24140
- this.clearShowTimeout();
24141
- this.clearHideTimeout();
24142
- this.destroyTooltip();
24143
- }
24144
- renderTooltip() {
24145
- if (this.tooltipElement) {
24146
- return;
24147
- }
24148
- const tooltip = this.renderer.createElement('div');
24149
- tooltip.textContent = this.text();
24150
- this.renderer.setAttribute(tooltip, 'id', this.tooltipId);
24151
- this.renderer.setAttribute(tooltip, 'role', 'tooltip');
24152
- this.renderer.setStyle(tooltip, 'position', 'fixed');
24153
- this.renderer.setStyle(tooltip, 'z-index', '1400');
24154
- this.renderer.setStyle(tooltip, 'max-width', '18rem');
24155
- this.renderer.setStyle(tooltip, 'padding', '0.5rem 0.75rem');
24156
- this.renderer.setStyle(tooltip, 'border-radius', '0.5rem');
24157
- this.renderer.setStyle(tooltip, 'background', 'rgb(15 23 42)');
24158
- this.renderer.setStyle(tooltip, 'color', '#ffffff');
24159
- this.renderer.setStyle(tooltip, 'font-size', '0.8125rem');
24160
- this.renderer.setStyle(tooltip, 'line-height', '1.4');
24161
- this.renderer.setStyle(tooltip, 'box-shadow', 'var(--jv-shadow-md)');
24162
- this.renderer.setStyle(tooltip, 'pointer-events', 'none');
24163
- this.renderer.setStyle(tooltip, 'opacity', '0');
24164
- this.renderer.setStyle(tooltip, 'transition', 'opacity 120ms ease');
24165
- this.renderer.appendChild(this.document.body, tooltip);
24166
- this.tooltipElement = tooltip;
24167
- requestAnimationFrame(() => {
24168
- if (this.tooltipElement) {
24169
- this.renderer.setStyle(this.tooltipElement, 'opacity', '1');
24170
- }
24171
- });
24172
- }
24173
- positionTooltip() {
24174
- const tooltip = this.tooltipElement;
24175
- if (!tooltip) {
24176
- return;
24177
- }
24178
- const hostRect = this.anchorElement().getBoundingClientRect();
24179
- const tooltipRect = tooltip.getBoundingClientRect();
24180
- const gap = 8;
24181
- let top = hostRect.top - tooltipRect.height - gap;
24182
- let left = hostRect.left + hostRect.width / 2 - tooltipRect.width / 2;
24183
- switch (this.position()) {
24184
- case 'right':
24185
- top = hostRect.top + hostRect.height / 2 - tooltipRect.height / 2;
24186
- left = hostRect.right + gap;
24187
- break;
24188
- case 'bottom':
24189
- top = hostRect.bottom + gap;
24190
- left = hostRect.left + hostRect.width / 2 - tooltipRect.width / 2;
24191
- break;
24192
- case 'left':
24193
- top = hostRect.top + hostRect.height / 2 - tooltipRect.height / 2;
24194
- left = hostRect.left - tooltipRect.width - gap;
24195
- break;
24196
- }
24197
- this.renderer.setStyle(tooltip, 'top', `${Math.round(top)}px`);
24198
- this.renderer.setStyle(tooltip, 'left', `${Math.round(left)}px`);
24199
- }
24200
- destroyTooltip() {
24201
- this.clearHideTimeout();
24202
- this.clearShowTimeout();
24203
- if (!this.tooltipElement) {
24204
- return;
24205
- }
24206
- this.restoreTooltipDescription();
24207
- this.renderer.removeChild(this.document.body, this.tooltipElement);
24208
- this.tooltipElement = null;
24209
- }
24210
- attachTooltipDescription() {
24211
- const anchor = this.anchorElement();
24212
- this.originalDescribedBy ??= anchor.getAttribute('aria-describedby');
24213
- const describedBy = [this.originalDescribedBy, this.tooltipId]
24214
- .filter((value) => !!value)
24215
- .join(' ')
24216
- .trim();
24217
- this.renderer.setAttribute(anchor, 'aria-describedby', describedBy);
24218
- }
24219
- restoreTooltipDescription() {
24220
- const anchor = this.anchorElement();
24221
- if (this.originalDescribedBy) {
24222
- this.renderer.setAttribute(anchor, 'aria-describedby', this.originalDescribedBy);
24223
- }
24224
- else {
24225
- this.renderer.removeAttribute(anchor, 'aria-describedby');
24226
- }
24227
- this.originalDescribedBy = null;
24228
- }
24229
- anchorElement() {
24230
- const host = this.hostRef.nativeElement;
24231
- if (isInteractiveElement(host)) {
24232
- return host;
24233
- }
24234
- return host.querySelector('button, a, input, select, textarea, [tabindex]:not([tabindex="-1"])') ?? host;
24235
- }
24236
- clearShowTimeout() {
24237
- if (this.showTimeout) {
24238
- clearTimeout(this.showTimeout);
24239
- this.showTimeout = null;
24240
- }
24241
- }
24242
- clearHideTimeout() {
24243
- if (this.hideTimeout) {
24244
- clearTimeout(this.hideTimeout);
24245
- this.hideTimeout = null;
24246
- }
24247
- }
24248
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
24249
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.17", type: JvTooltipDirective, isStandalone: true, selector: "[jvTooltip]", inputs: { text: { classPropertyName: "text", publicName: "jvTooltip", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "jvTooltipPosition", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "focusin": "show()", "mouseleave": "hide()", "blur": "hide()", "document:keydown": "handleDocumentKeydown($event)", "window:scroll": "handleViewportChange()", "window:resize": "handleViewportChange()" } }, ngImport: i0 });
24250
- }
24251
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTooltipDirective, decorators: [{
24252
- type: Directive,
24253
- args: [{
24254
- selector: '[jvTooltip]',
24255
- standalone: true,
24256
- }]
24257
- }], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "jvTooltip", required: true }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "jvTooltipPosition", required: false }] }], show: [{
24258
- type: HostListener,
24259
- args: ['mouseenter']
24260
- }, {
24261
- type: HostListener,
24262
- args: ['focusin']
24263
- }], hide: [{
24264
- type: HostListener,
24265
- args: ['mouseleave']
24266
- }, {
24267
- type: HostListener,
24268
- args: ['blur']
24269
- }], handleDocumentKeydown: [{
24270
- type: HostListener,
24271
- args: ['document:keydown', ['$event']]
24272
- }], handleViewportChange: [{
24273
- type: HostListener,
24274
- args: ['window:scroll']
24275
- }, {
24276
- type: HostListener,
24277
- args: ['window:resize']
24278
- }] } });
24279
- function isInteractiveElement(element) {
24280
- return ['BUTTON', 'A', 'INPUT', 'SELECT', 'TEXTAREA'].includes(element.tagName) || element.tabIndex >= 0;
24281
- }
24282
-
24283
24614
  const JV_GRID_DEFAULT_OPTIONS = {
24284
24615
  searchable: true,
24285
24616
  sortable: true,
@@ -25625,5 +25956,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
25625
25956
  * Generated bundle index. Do not edit.
25626
25957
  */
25627
25958
 
25628
- export { EN, ES, JV_DEFAULT_LOCALE, JV_FALLBACK_ICON_NAME, JV_GRID_DEFAULT_OPTIONS, JV_LOCALE_DICTIONARIES, JV_LUCIDE_ICON_REGISTRY, JV_UI_CONFIG, JV_UI_CONFIG_DEFAULTS, JV_UI_DEFAULT_CONFIG, JvAccordionComponent, JvAccordionPanelDirective, JvAlertComponent, JvAnnouncementService, JvBadgeComponent, JvBreadcrumbComponent, JvButtonComponent, JvButtonGroupComponent, JvCardComponent, JvChangePasswordPageComponent, JvCheckboxComponent, JvCodeComponent, JvCollapsiblePanelComponent, JvConfirmDialogComponent, JvDashboardShellComponent, JvDatePickerComponent, JvDayPlannerComponent, JvDayPlannerDetailDirective, JvDayPlannerItemDirective, JvDialogComponent, JvDialogService, JvDividerComponent, JvFileInputComponent, JvForgotPasswordPageComponent, JvFormContainerComponent, JvFormatService, JvGridComponent, JvIconButtonComponent, JvIconComponent, JvImageGalleryComponent, JvImageSliderComponent, JvInputComponent, JvListComponent, JvListItemComponent, JvLoaderComponent, JvLoaderService, JvLoginPageComponent, JvModalSelectorComponent, JvMonthCalendarComponent, JvMonthCalendarDayDirective, JvPageComponent, JvPaginationComponent, JvRadioComponent, JvSectionComponent, JvSelectComponent, JvSidebarComponent, JvSwitchComponent, JvTabPanelDirective, JvTabsComponent, JvTextareaComponent, JvThemeService, JvToastComponent, JvToastService, JvTooltipDirective, JvTopbarComponent, JvTranslationService, JvWindowModalComponent, provideJvUi };
25959
+ export { EN, ES, JV_DEFAULT_LOCALE, JV_FALLBACK_ICON_NAME, JV_GRID_DEFAULT_OPTIONS, JV_LOCALE_DICTIONARIES, JV_LUCIDE_ICON_REGISTRY, JV_UI_CONFIG, JV_UI_CONFIG_DEFAULTS, JV_UI_DEFAULT_CONFIG, JvAccordionComponent, JvAccordionPanelDirective, JvAlertComponent, JvAnnouncementService, JvBadgeComponent, JvBreadcrumbComponent, JvButtonComponent, JvButtonGroupComponent, JvCardComponent, JvChangePasswordPageComponent, JvCheckboxComponent, JvCodeComponent, JvCollapsiblePanelComponent, JvConfirmDialogComponent, JvDashboardShellComponent, JvDatePickerComponent, JvDayPlannerComponent, JvDayPlannerDetailDirective, JvDayPlannerItemDirective, JvDialogComponent, JvDialogService, JvDividerComponent, JvFileInputComponent, JvForgotPasswordPageComponent, JvFormContainerComponent, JvFormatService, JvGridComponent, JvIconButtonComponent, JvIconComponent, JvImageGalleryComponent, JvImageSliderComponent, JvInputComponent, JvListComponent, JvListItemComponent, JvLoaderComponent, JvLoaderService, JvLoginPageComponent, JvModalSelectorComponent, JvMonthCalendarComponent, JvMonthCalendarDayDirective, JvPageComponent, JvPaginationComponent, JvRadioComponent, JvSectionComponent, JvSelectComponent, JvSidebarComponent, JvSwitchComponent, JvTabPanelDirective, JvTabsComponent, JvTextareaComponent, JvThemeService, JvToastComponent, JvToastService, JvTooltipDirective, JvTopbarComponent, JvTopbarMenuComponent, JvTranslationService, JvWindowModalComponent, provideJvUi };
25629
25960
  //# sourceMappingURL=devjuliovilla-jv-ui.mjs.map