@devjuliovilla/jv-ui 1.11.2 → 1.13.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,8 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, computed, Component, forwardRef, inject, output, Directive, Injectable, signal, InjectionToken, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, effect, contentChildren, HostListener, viewChild, viewChildren, numberAttribute, afterNextRender, Renderer2, ElementRef } from '@angular/core';
2
+ import { input, computed, Component, inject, signal, Injectable, InjectionToken, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, Directive, contentChild, output, effect, forwardRef, viewChild, untracked, contentChildren, HostListener, viewChildren, numberAttribute, afterNextRender, Renderer2, ElementRef } from '@angular/core';
3
+ import { DOCUMENT, NgTemplateOutlet, CommonModule } from '@angular/common';
3
4
  import * as i1 from '@angular/forms';
4
5
  import { NG_VALUE_ACCESSOR, FormBuilder, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
5
- import { CommonModule, DOCUMENT, NgTemplateOutlet } from '@angular/common';
6
6
  import { Router, RouterLink } from '@angular/router';
7
7
 
8
8
  // This file is auto-generated by tools/generate-icons.mjs
@@ -18042,927 +18042,93 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
18042
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"] }]
18043
18043
  }], 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
18044
 
18045
- class JvAlertComponent {
18046
- tone = input('info', ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
18047
- title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
18048
- role = input('status', ...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
18049
- alertClass = computed(() => `jv-alert--${this.tone()}`, ...(ngDevMode ? [{ debugName: "alertClass" }] : /* istanbul ignore next */ []));
18050
- iconName = computed(() => {
18051
- switch (this.tone()) {
18052
- case 'success':
18053
- return 'check';
18054
- case 'warning':
18055
- return 'triangle-alert';
18056
- case 'danger':
18057
- return 'circle-alert';
18058
- case 'primary':
18059
- return 'sparkles';
18060
- case 'secondary':
18061
- case 'neutral':
18062
- return 'info';
18063
- default:
18064
- return 'info';
18065
- }
18066
- }, ...(ngDevMode ? [{ debugName: "iconName" }] : /* istanbul ignore next */ []));
18067
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18068
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvAlertComponent, isStandalone: true, selector: "jv-alert", inputs: { tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
18069
- <div class="jv-alert" [class]="alertClass()" [attr.role]="role()">
18070
- <div class="jv-alert-icon">
18071
- <jv-icon [name]="iconName()" [size]="18" />
18072
- </div>
18073
- <div class="jv-alert-content">
18074
- @if (title()) {
18075
- <strong>{{ title() }}</strong>
18076
- }
18077
- <div><ng-content></ng-content></div>
18078
- </div>
18079
- </div>
18080
- `, isInline: true, styles: [".jv-alert{display:grid;grid-template-columns:auto 1fr;gap:var(--jv-spacing-sm);padding:var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md)}.jv-alert-content{display:grid;gap:var(--jv-spacing-xs)}.jv-alert--primary{background:color-mix(in srgb,var(--jv-color-primary) 10%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-alert--secondary,.jv-alert--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-alert--success{background:color-mix(in srgb,var(--jv-color-success) 12%,var(--jv-color-surface))}.jv-alert--warning{background:color-mix(in srgb,var(--jv-color-warning) 16%,var(--jv-color-surface))}.jv-alert--danger{background:color-mix(in srgb,var(--jv-color-danger) 12%,var(--jv-color-surface))}.jv-alert--info{background:color-mix(in srgb,var(--jv-color-info) 12%,var(--jv-color-surface))}strong{font-size:.95rem}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
18081
- }
18082
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAlertComponent, decorators: [{
18083
- type: Component,
18084
- args: [{ selector: 'jv-alert', standalone: true, imports: [JvIconComponent], template: `
18085
- <div class="jv-alert" [class]="alertClass()" [attr.role]="role()">
18086
- <div class="jv-alert-icon">
18087
- <jv-icon [name]="iconName()" [size]="18" />
18088
- </div>
18089
- <div class="jv-alert-content">
18090
- @if (title()) {
18091
- <strong>{{ title() }}</strong>
18092
- }
18093
- <div><ng-content></ng-content></div>
18094
- </div>
18095
- </div>
18096
- `, styles: [".jv-alert{display:grid;grid-template-columns:auto 1fr;gap:var(--jv-spacing-sm);padding:var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md)}.jv-alert-content{display:grid;gap:var(--jv-spacing-xs)}.jv-alert--primary{background:color-mix(in srgb,var(--jv-color-primary) 10%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-alert--secondary,.jv-alert--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-alert--success{background:color-mix(in srgb,var(--jv-color-success) 12%,var(--jv-color-surface))}.jv-alert--warning{background:color-mix(in srgb,var(--jv-color-warning) 16%,var(--jv-color-surface))}.jv-alert--danger{background:color-mix(in srgb,var(--jv-color-danger) 12%,var(--jv-color-surface))}.jv-alert--info{background:color-mix(in srgb,var(--jv-color-info) 12%,var(--jv-color-surface))}strong{font-size:.95rem}\n"] }]
18097
- }], propDecorators: { tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }] } });
18098
-
18099
- class JvCardComponent {
18100
- elevated = input(true, ...(ngDevMode ? [{ debugName: "elevated" }] : /* istanbul ignore next */ []));
18101
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18102
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvCardComponent, isStandalone: true, selector: "jv-card", inputs: { elevated: { classPropertyName: "elevated", publicName: "elevated", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
18103
- <article class="jv-card" [class]="elevated() ? 'jv-card--elevated' : 'jv-card--flat'">
18104
- <ng-content></ng-content>
18105
- </article>
18106
- `, isInline: true, styles: [".jv-card{padding:var(--jv-spacing-lg);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-lg);background:var(--jv-color-surface)}.jv-card--elevated{box-shadow:var(--jv-shadow-md)}\n"] });
18107
- }
18108
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCardComponent, decorators: [{
18109
- type: Component,
18110
- args: [{ selector: 'jv-card', standalone: true, template: `
18111
- <article class="jv-card" [class]="elevated() ? 'jv-card--elevated' : 'jv-card--flat'">
18112
- <ng-content></ng-content>
18113
- </article>
18114
- `, styles: [".jv-card{padding:var(--jv-spacing-lg);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-lg);background:var(--jv-color-surface)}.jv-card--elevated{box-shadow:var(--jv-shadow-md)}\n"] }]
18115
- }], propDecorators: { elevated: [{ type: i0.Input, args: [{ isSignal: true, alias: "elevated", required: false }] }] } });
18116
-
18117
- class JvFormContainerComponent {
18118
- label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
18119
- hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
18120
- error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
18121
- inputId = input('', ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
18122
- hintId = input('', ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
18123
- errorId = input('', ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
18124
- required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
18125
- invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
18126
- resolvedHintId = computed(() => this.hintId() || (this.inputId() ? `${this.inputId()}-hint` : ''), ...(ngDevMode ? [{ debugName: "resolvedHintId" }] : /* istanbul ignore next */ []));
18127
- resolvedErrorId = computed(() => this.errorId() || (this.inputId() ? `${this.inputId()}-error` : ''), ...(ngDevMode ? [{ debugName: "resolvedErrorId" }] : /* istanbul ignore next */ []));
18128
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18129
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvFormContainerComponent, isStandalone: true, selector: "jv-form-container", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, hintId: { classPropertyName: "hintId", publicName: "hintId", isSignal: true, isRequired: false, transformFunction: null }, errorId: { classPropertyName: "errorId", publicName: "errorId", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
18130
- <div class="jv-form-container" [class.is-invalid]="invalid()">
18131
- @if (label()) {
18132
- <label class="jv-form-label" [attr.for]="inputId() || null">
18133
- <span>{{ label() }}</span>
18134
- @if (required()) {
18135
- <span class="required-indicator" aria-hidden="true">*</span>
18136
- }
18137
- </label>
18138
- }
18139
-
18140
- <ng-content></ng-content>
18141
-
18142
- @if (hint() && !invalid()) {
18143
- <p class="jv-form-hint" [id]="resolvedHintId() || null">{{ hint() }}</p>
18144
- }
18145
-
18146
- @if (error() && invalid()) {
18147
- <p class="jv-form-error" [id]="resolvedErrorId() || null" role="alert" aria-live="assertive">{{ error() }}</p>
18148
- }
18149
- </div>
18150
- `, isInline: true, styles: [".jv-form-container{display:grid;gap:var(--jv-spacing-xs)}.jv-form-label{display:inline-flex;align-items:center;gap:.35rem;font-weight:600;color:var(--jv-color-foreground)}.required-indicator,.jv-form-error{color:var(--jv-color-danger)}.jv-form-hint,.jv-form-error{margin:0;font-size:.875rem}.jv-form-hint{color:var(--jv-color-foreground-muted)}\n"] });
18151
- }
18152
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormContainerComponent, decorators: [{
18153
- type: Component,
18154
- args: [{ selector: 'jv-form-container', standalone: true, template: `
18155
- <div class="jv-form-container" [class.is-invalid]="invalid()">
18156
- @if (label()) {
18157
- <label class="jv-form-label" [attr.for]="inputId() || null">
18158
- <span>{{ label() }}</span>
18159
- @if (required()) {
18160
- <span class="required-indicator" aria-hidden="true">*</span>
18161
- }
18162
- </label>
18163
- }
18164
-
18165
- <ng-content></ng-content>
18166
-
18167
- @if (hint() && !invalid()) {
18168
- <p class="jv-form-hint" [id]="resolvedHintId() || null">{{ hint() }}</p>
18169
- }
18170
-
18171
- @if (error() && invalid()) {
18172
- <p class="jv-form-error" [id]="resolvedErrorId() || null" role="alert" aria-live="assertive">{{ error() }}</p>
18173
- }
18174
- </div>
18175
- `, styles: [".jv-form-container{display:grid;gap:var(--jv-spacing-xs)}.jv-form-label{display:inline-flex;align-items:center;gap:.35rem;font-weight:600;color:var(--jv-color-foreground)}.required-indicator,.jv-form-error{color:var(--jv-color-danger)}.jv-form-hint,.jv-form-error{margin:0;font-size:.875rem}.jv-form-hint{color:var(--jv-color-foreground-muted)}\n"] }]
18176
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], hintId: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintId", required: false }] }], errorId: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorId", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }] } });
18045
+ const JV_UI_DEFAULT_CONFIG = {
18046
+ theme: 'light',
18047
+ density: 'normal',
18048
+ language: 'es-MX',
18049
+ locale: 'es',
18050
+ messagesLocale: 'es',
18051
+ formatLocale: 'es-MX',
18052
+ formats: {
18053
+ date: { day: '2-digit', month: '2-digit', year: 'numeric' },
18054
+ time: { hour: '2-digit', minute: '2-digit' },
18055
+ datetime: { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' },
18056
+ integer: { maximumFractionDigits: 0 },
18057
+ number: { minimumFractionDigits: 0, maximumFractionDigits: 2 },
18058
+ currency: { style: 'currency', currency: 'MXN', minimumFractionDigits: 2, maximumFractionDigits: 2 },
18059
+ percent: { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 2 },
18060
+ },
18061
+ toastPosition: 'bottom-right',
18062
+ tabsTransition: 'none',
18063
+ };
18177
18064
 
18178
- let inputIdSequence = 0;
18179
- class JvInputComponent {
18180
- type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
18181
- placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
18182
- required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
18183
- invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
18184
- describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
18185
- inputId = input(`jv-input-${++inputIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
18186
- value = '';
18187
- disabled = false;
18188
- onChange = () => undefined;
18189
- onTouched = () => undefined;
18190
- writeValue(value) {
18191
- this.value = value ?? '';
18065
+ class JvThemeService {
18066
+ document = inject(DOCUMENT);
18067
+ config = inject(JvUiConfigService);
18068
+ storageKey = 'jv-ui-theme';
18069
+ theme = signal(this.config.snapshot.theme, ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
18070
+ density = signal(this.config.snapshot.density, ...(ngDevMode ? [{ debugName: "density" }] : /* istanbul ignore next */ []));
18071
+ initialize() {
18072
+ const initialConfig = this.config.snapshot;
18073
+ const theme = this.resolveInitialTheme(initialConfig.theme);
18074
+ this.applyTheme(theme);
18075
+ this.applyDensity(initialConfig.density);
18076
+ this.applyLanguage(initialConfig.language);
18192
18077
  }
18193
- registerOnChange(fn) {
18194
- this.onChange = fn;
18078
+ setTheme(theme) {
18079
+ this.applyTheme(theme);
18080
+ try {
18081
+ this.document.defaultView?.localStorage.setItem(this.storageKey, theme);
18082
+ }
18083
+ catch {
18084
+ // Ignore storage failures in restricted environments.
18085
+ }
18195
18086
  }
18196
- registerOnTouched(fn) {
18197
- this.onTouched = fn;
18087
+ setDensity(density) {
18088
+ this.applyDensity(density);
18198
18089
  }
18199
- setDisabledState(isDisabled) {
18200
- this.disabled = isDisabled;
18090
+ applyTheme(theme) {
18091
+ this.theme.set(theme);
18092
+ const root = this.document.documentElement;
18093
+ root.dataset['theme'] = theme;
18094
+ root.style.colorScheme = theme === 'dark' ? 'dark' : 'light';
18201
18095
  }
18202
- handleInput(event) {
18203
- const nextValue = event.target.value;
18204
- this.value = nextValue;
18205
- this.onChange(nextValue);
18096
+ applyDensity(density) {
18097
+ this.density.set(density);
18098
+ this.document.documentElement.dataset['density'] = density;
18206
18099
  }
18207
- handleBlur() {
18208
- this.onTouched();
18100
+ applyLanguage(language) {
18101
+ this.document.documentElement.lang = language;
18209
18102
  }
18210
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18211
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvInputComponent, isStandalone: true, selector: "jv-input", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "describedBy", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
18212
- {
18213
- provide: NG_VALUE_ACCESSOR,
18214
- useExisting: forwardRef(() => JvInputComponent),
18215
- multi: true,
18216
- },
18217
- ], ngImport: i0, template: `
18218
- <input
18219
- class="jv-input"
18220
- [class.is-invalid]="invalid()"
18221
- [id]="inputId()"
18222
- [type]="type()"
18223
- [value]="value"
18224
- [placeholder]="placeholder()"
18225
- [required]="required()"
18226
- [disabled]="disabled"
18227
- [attr.aria-invalid]="invalid() ? 'true' : null"
18228
- [attr.aria-describedby]="describedBy() || null"
18229
- (input)="handleInput($event)"
18230
- (blur)="handleBlur()"
18231
- />
18232
- `, isInline: true, styles: [".jv-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-input::placeholder{color:var(--jv-color-foreground-muted)}.jv-input.is-invalid{border-color:var(--jv-color-danger)}.jv-input:disabled{opacity:.7;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
18233
- }
18234
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvInputComponent, decorators: [{
18235
- type: Component,
18236
- args: [{ selector: 'jv-input', standalone: true, imports: [CommonModule], providers: [
18237
- {
18238
- provide: NG_VALUE_ACCESSOR,
18239
- useExisting: forwardRef(() => JvInputComponent),
18240
- multi: true,
18241
- },
18242
- ], template: `
18243
- <input
18244
- class="jv-input"
18245
- [class.is-invalid]="invalid()"
18246
- [id]="inputId()"
18247
- [type]="type()"
18248
- [value]="value"
18249
- [placeholder]="placeholder()"
18250
- [required]="required()"
18251
- [disabled]="disabled"
18252
- [attr.aria-invalid]="invalid() ? 'true' : null"
18253
- [attr.aria-describedby]="describedBy() || null"
18254
- (input)="handleInput($event)"
18255
- (blur)="handleBlur()"
18256
- />
18257
- `, styles: [".jv-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-input::placeholder{color:var(--jv-color-foreground-muted)}.jv-input.is-invalid{border-color:var(--jv-color-danger)}.jv-input:disabled{opacity:.7;cursor:not-allowed}\n"] }]
18258
- }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }] } });
18259
-
18260
- class JvSectionComponent {
18261
- title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
18262
- description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
18263
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18264
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvSectionComponent, isStandalone: true, selector: "jv-section", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
18265
- <section class="jv-section">
18266
- @if (title() || description()) {
18267
- <header class="jv-section-header">
18268
- @if (title()) {
18269
- <h2>{{ title() }}</h2>
18270
- }
18271
- @if (description()) {
18272
- <p>{{ description() }}</p>
18273
- }
18274
- </header>
18275
- }
18276
- <div class="jv-section-content"><ng-content></ng-content></div>
18277
- </section>
18278
- `, isInline: true, styles: [".jv-section{display:grid;gap:var(--jv-spacing-md)}.jv-section-header{display:grid;gap:var(--jv-spacing-xs)}h2,p{margin:0}p{color:var(--jv-color-foreground-muted)}\n"] });
18279
- }
18280
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSectionComponent, decorators: [{
18281
- type: Component,
18282
- args: [{ selector: 'jv-section', standalone: true, template: `
18283
- <section class="jv-section">
18284
- @if (title() || description()) {
18285
- <header class="jv-section-header">
18286
- @if (title()) {
18287
- <h2>{{ title() }}</h2>
18288
- }
18289
- @if (description()) {
18290
- <p>{{ description() }}</p>
18291
- }
18292
- </header>
18293
- }
18294
- <div class="jv-section-content"><ng-content></ng-content></div>
18295
- </section>
18296
- `, styles: [".jv-section{display:grid;gap:var(--jv-spacing-md)}.jv-section-header{display:grid;gap:var(--jv-spacing-xs)}h2,p{margin:0}p{color:var(--jv-color-foreground-muted)}\n"] }]
18297
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
18298
-
18299
- function passwordMatchValidator(control) {
18300
- const newPassword = control.get('newPassword')?.value;
18301
- const confirmPassword = control.get('confirmPassword')?.value;
18302
- if (!newPassword || !confirmPassword) {
18303
- return null;
18304
- }
18305
- return newPassword === confirmPassword ? null : { passwordMismatch: true };
18306
- }
18307
- class JvChangePasswordPageComponent {
18308
- formBuilder = inject(FormBuilder);
18309
- title = input('Change password', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
18310
- description = input('Update your password and keep your account secure.', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
18311
- submitLabel = input('Update password', ...(ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []));
18312
- cancelLabel = input('Cancel', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []));
18313
- loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
18314
- error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
18315
- changePasswordSubmit = output();
18316
- cancel = output();
18317
- form = this.formBuilder.group({
18318
- currentPassword: ['', Validators.required],
18319
- newPassword: ['', Validators.required],
18320
- confirmPassword: ['', Validators.required],
18321
- }, { validators: passwordMatchValidator });
18322
- currentInvalid = computed(() => {
18323
- const control = this.form.controls.currentPassword;
18324
- return control.invalid && (control.touched || control.dirty);
18325
- }, ...(ngDevMode ? [{ debugName: "currentInvalid" }] : /* istanbul ignore next */ []));
18326
- newInvalid = computed(() => {
18327
- const control = this.form.controls.newPassword;
18328
- return control.invalid && (control.touched || control.dirty);
18329
- }, ...(ngDevMode ? [{ debugName: "newInvalid" }] : /* istanbul ignore next */ []));
18330
- confirmInvalid = computed(() => {
18331
- const control = this.form.controls.confirmPassword;
18332
- return (control.invalid && (control.touched || control.dirty)) || ((control.touched || control.dirty) && this.form.hasError('passwordMismatch'));
18333
- }, ...(ngDevMode ? [{ debugName: "confirmInvalid" }] : /* istanbul ignore next */ []));
18334
- submit() {
18335
- if (this.form.invalid) {
18336
- this.form.markAllAsTouched();
18337
- return;
18103
+ resolveInitialTheme(fallbackTheme) {
18104
+ const savedTheme = this.readSavedTheme();
18105
+ if (savedTheme) {
18106
+ return savedTheme;
18338
18107
  }
18339
- this.changePasswordSubmit.emit(this.form.getRawValue());
18340
- }
18341
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvChangePasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18342
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvChangePasswordPageComponent, isStandalone: true, selector: "jv-change-password-page", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, submitLabel: { classPropertyName: "submitLabel", publicName: "submitLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changePasswordSubmit: "changePasswordSubmit", cancel: "cancel" }, ngImport: i0, template: `
18343
- <jv-card>
18344
- <jv-section [title]="title()" [description]="description()">
18345
- @if (error()) {
18346
- <jv-alert tone="danger" title="Password change error" role="alert">{{ error() }}</jv-alert>
18347
- }
18348
-
18349
- <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
18350
- <jv-form-container label="Current password" inputId="jv-current-password" error="Current password is required" [required]="true" [invalid]="currentInvalid()">
18351
- <jv-input inputId="jv-current-password" type="password" formControlName="currentPassword" [invalid]="currentInvalid()" />
18352
- </jv-form-container>
18353
-
18354
- <jv-form-container label="New password" inputId="jv-new-password" error="New password is required" [required]="true" [invalid]="newInvalid()">
18355
- <jv-input inputId="jv-new-password" type="password" formControlName="newPassword" [invalid]="newInvalid()" />
18356
- </jv-form-container>
18357
-
18358
- <jv-form-container label="Confirm new password" inputId="jv-confirm-password" error="Passwords must match" [required]="true" [invalid]="confirmInvalid()">
18359
- <jv-input inputId="jv-confirm-password" type="password" formControlName="confirmPassword" [invalid]="confirmInvalid()" />
18360
- </jv-form-container>
18361
-
18362
- <div class="auth-actions">
18363
- <jv-button variant="outline" (click)="cancel.emit()">{{ cancelLabel() }}</jv-button>
18364
- <jv-button variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
18365
- </div>
18366
- </form>
18367
- </jv-section>
18368
- </jv-card>
18369
- `, isInline: true, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: JvAlertComponent, selector: "jv-alert", inputs: ["tone", "title", "role"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvCardComponent, selector: "jv-card", inputs: ["elevated"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvSectionComponent, selector: "jv-section", inputs: ["title", "description"] }] });
18370
- }
18371
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvChangePasswordPageComponent, decorators: [{
18372
- type: Component,
18373
- args: [{ selector: 'jv-change-password-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
18374
- <jv-card>
18375
- <jv-section [title]="title()" [description]="description()">
18376
- @if (error()) {
18377
- <jv-alert tone="danger" title="Password change error" role="alert">{{ error() }}</jv-alert>
18378
- }
18379
-
18380
- <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
18381
- <jv-form-container label="Current password" inputId="jv-current-password" error="Current password is required" [required]="true" [invalid]="currentInvalid()">
18382
- <jv-input inputId="jv-current-password" type="password" formControlName="currentPassword" [invalid]="currentInvalid()" />
18383
- </jv-form-container>
18384
-
18385
- <jv-form-container label="New password" inputId="jv-new-password" error="New password is required" [required]="true" [invalid]="newInvalid()">
18386
- <jv-input inputId="jv-new-password" type="password" formControlName="newPassword" [invalid]="newInvalid()" />
18387
- </jv-form-container>
18388
-
18389
- <jv-form-container label="Confirm new password" inputId="jv-confirm-password" error="Passwords must match" [required]="true" [invalid]="confirmInvalid()">
18390
- <jv-input inputId="jv-confirm-password" type="password" formControlName="confirmPassword" [invalid]="confirmInvalid()" />
18391
- </jv-form-container>
18392
-
18393
- <div class="auth-actions">
18394
- <jv-button variant="outline" (click)="cancel.emit()">{{ cancelLabel() }}</jv-button>
18395
- <jv-button variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
18396
- </div>
18397
- </form>
18398
- </jv-section>
18399
- </jv-card>
18400
- `, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"] }]
18401
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], submitLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitLabel", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], changePasswordSubmit: [{ type: i0.Output, args: ["changePasswordSubmit"] }], cancel: [{ type: i0.Output, args: ["cancel"] }] } });
18402
-
18403
- class JvForgotPasswordPageComponent {
18404
- formBuilder = inject(FormBuilder);
18405
- title = input('Reset your password', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
18406
- description = input('We will send reset instructions to your email address.', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
18407
- submitLabel = input('Send reset link', ...(ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []));
18408
- backLabel = input('Back to login', ...(ngDevMode ? [{ debugName: "backLabel" }] : /* istanbul ignore next */ []));
18409
- loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
18410
- error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
18411
- forgotPasswordSubmit = output();
18412
- backToLogin = output();
18413
- form = this.formBuilder.group({
18414
- email: ['', [Validators.required, Validators.email]],
18415
- });
18416
- emailInvalid = computed(() => {
18417
- const control = this.form.controls.email;
18418
- return control.invalid && (control.touched || control.dirty);
18419
- }, ...(ngDevMode ? [{ debugName: "emailInvalid" }] : /* istanbul ignore next */ []));
18420
- submit() {
18421
- if (this.form.invalid) {
18422
- this.form.markAllAsTouched();
18423
- return;
18108
+ if (fallbackTheme === 'high-contrast') {
18109
+ return fallbackTheme;
18424
18110
  }
18425
- this.forgotPasswordSubmit.emit(this.form.getRawValue());
18426
- }
18427
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvForgotPasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18428
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvForgotPasswordPageComponent, isStandalone: true, selector: "jv-forgot-password-page", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, submitLabel: { classPropertyName: "submitLabel", publicName: "submitLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { forgotPasswordSubmit: "forgotPasswordSubmit", backToLogin: "backToLogin" }, ngImport: i0, template: `
18429
- <jv-card>
18430
- <jv-section [title]="title()" [description]="description()">
18431
- @if (error()) {
18432
- <jv-alert tone="danger" title="Reset error" role="alert">{{ error() }}</jv-alert>
18433
- }
18434
-
18435
- <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
18436
- <jv-form-container label="Email" inputId="jv-forgot-email" error="Enter a valid email" [required]="true" [invalid]="emailInvalid()">
18437
- <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" placeholder="you@example.com" />
18438
- </jv-form-container>
18439
-
18440
- <div class="auth-actions">
18441
- <jv-button variant="outline" (click)="backToLogin.emit()">{{ backLabel() }}</jv-button>
18442
- <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
18443
- </div>
18444
- </form>
18445
- </jv-section>
18446
- </jv-card>
18447
- `, isInline: true, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: JvAlertComponent, selector: "jv-alert", inputs: ["tone", "title", "role"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvCardComponent, selector: "jv-card", inputs: ["elevated"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvSectionComponent, selector: "jv-section", inputs: ["title", "description"] }] });
18448
- }
18449
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvForgotPasswordPageComponent, decorators: [{
18450
- type: Component,
18451
- args: [{ selector: 'jv-forgot-password-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
18452
- <jv-card>
18453
- <jv-section [title]="title()" [description]="description()">
18454
- @if (error()) {
18455
- <jv-alert tone="danger" title="Reset error" role="alert">{{ error() }}</jv-alert>
18456
- }
18457
-
18458
- <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
18459
- <jv-form-container label="Email" inputId="jv-forgot-email" error="Enter a valid email" [required]="true" [invalid]="emailInvalid()">
18460
- <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" placeholder="you@example.com" />
18461
- </jv-form-container>
18462
-
18463
- <div class="auth-actions">
18464
- <jv-button variant="outline" (click)="backToLogin.emit()">{{ backLabel() }}</jv-button>
18465
- <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
18466
- </div>
18467
- </form>
18468
- </jv-section>
18469
- </jv-card>
18470
- `, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"] }]
18471
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], submitLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitLabel", required: false }] }], backLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "backLabel", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], forgotPasswordSubmit: [{ type: i0.Output, args: ["forgotPasswordSubmit"] }], backToLogin: [{ type: i0.Output, args: ["backToLogin"] }] } });
18472
-
18473
- let checkboxIdSequence = 0;
18474
- class JvCheckboxComponent {
18475
- label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
18476
- describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
18477
- inputId = input(`jv-checkbox-${++checkboxIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
18478
- value = false;
18479
- disabled = false;
18480
- onChange = () => undefined;
18481
- onTouched = () => undefined;
18482
- writeValue(value) {
18483
- this.value = value ?? false;
18484
- }
18485
- registerOnChange(fn) {
18486
- this.onChange = fn;
18111
+ return this.prefersDarkMode() ? 'dark' : fallbackTheme;
18487
18112
  }
18488
- registerOnTouched(fn) {
18489
- this.onTouched = fn;
18113
+ readSavedTheme() {
18114
+ try {
18115
+ const saved = this.document.defaultView?.localStorage.getItem(this.storageKey);
18116
+ return this.isTheme(saved) ? saved : null;
18117
+ }
18118
+ catch {
18119
+ return null;
18120
+ }
18490
18121
  }
18491
- setDisabledState(isDisabled) {
18492
- this.disabled = isDisabled;
18122
+ prefersDarkMode() {
18123
+ return this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
18493
18124
  }
18494
- handleChange(event) {
18495
- const nextValue = event.target.checked;
18496
- this.value = nextValue;
18497
- this.onChange(nextValue);
18125
+ isTheme(value) {
18126
+ return value === 'light' || value === 'dark' || value === 'high-contrast';
18498
18127
  }
18499
- handleBlur() {
18500
- this.onTouched();
18501
- }
18502
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18503
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvCheckboxComponent, isStandalone: true, selector: "jv-checkbox", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "describedBy", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
18504
- {
18505
- provide: NG_VALUE_ACCESSOR,
18506
- useExisting: forwardRef(() => JvCheckboxComponent),
18507
- multi: true,
18508
- },
18509
- ], ngImport: i0, template: `
18510
- <label class="jv-checkbox" [class.is-disabled]="disabled">
18511
- <input
18512
- type="checkbox"
18513
- [id]="inputId()"
18514
- [checked]="value"
18515
- [disabled]="disabled"
18516
- [attr.aria-describedby]="describedBy() || null"
18517
- (change)="handleChange($event)"
18518
- (blur)="handleBlur()"
18519
- />
18520
- <span>{{ label() }}</span>
18521
- </label>
18522
- `, isInline: true, styles: [".jv-checkbox{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);min-height:var(--jv-density-control-height);color:var(--jv-color-foreground)}.jv-checkbox.is-disabled{opacity:.7}\n"] });
18523
- }
18524
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCheckboxComponent, decorators: [{
18525
- type: Component,
18526
- args: [{ selector: 'jv-checkbox', standalone: true, providers: [
18527
- {
18528
- provide: NG_VALUE_ACCESSOR,
18529
- useExisting: forwardRef(() => JvCheckboxComponent),
18530
- multi: true,
18531
- },
18532
- ], template: `
18533
- <label class="jv-checkbox" [class.is-disabled]="disabled">
18534
- <input
18535
- type="checkbox"
18536
- [id]="inputId()"
18537
- [checked]="value"
18538
- [disabled]="disabled"
18539
- [attr.aria-describedby]="describedBy() || null"
18540
- (change)="handleChange($event)"
18541
- (blur)="handleBlur()"
18542
- />
18543
- <span>{{ label() }}</span>
18544
- </label>
18545
- `, styles: [".jv-checkbox{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);min-height:var(--jv-density-control-height);color:var(--jv-color-foreground)}.jv-checkbox.is-disabled{opacity:.7}\n"] }]
18546
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }] } });
18547
-
18548
- class JvLoginPageComponent {
18549
- formBuilder = inject(FormBuilder);
18550
- title = input('Welcome back', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
18551
- description = input('Use your account credentials to continue.', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
18552
- submitLabel = input('Sign in', ...(ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []));
18553
- rememberMeLabel = input('Remember me', ...(ngDevMode ? [{ debugName: "rememberMeLabel" }] : /* istanbul ignore next */ []));
18554
- forgotPasswordLabel = input('Forgot password?', ...(ngDevMode ? [{ debugName: "forgotPasswordLabel" }] : /* istanbul ignore next */ []));
18555
- loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
18556
- error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
18557
- loginSubmit = output();
18558
- forgotPasswordClick = output();
18559
- form = this.formBuilder.group({
18560
- identifier: ['', Validators.required],
18561
- password: ['', Validators.required],
18562
- rememberMe: [false],
18563
- });
18564
- identifierInvalid = computed(() => {
18565
- const control = this.form.controls.identifier;
18566
- return control.invalid && (control.touched || control.dirty);
18567
- }, ...(ngDevMode ? [{ debugName: "identifierInvalid" }] : /* istanbul ignore next */ []));
18568
- passwordInvalid = computed(() => {
18569
- const control = this.form.controls.password;
18570
- return control.invalid && (control.touched || control.dirty);
18571
- }, ...(ngDevMode ? [{ debugName: "passwordInvalid" }] : /* istanbul ignore next */ []));
18572
- submit() {
18573
- if (this.form.invalid) {
18574
- this.form.markAllAsTouched();
18575
- return;
18576
- }
18577
- this.loginSubmit.emit(this.form.getRawValue());
18578
- }
18579
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvLoginPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18580
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvLoginPageComponent, isStandalone: true, selector: "jv-login-page", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, submitLabel: { classPropertyName: "submitLabel", publicName: "submitLabel", isSignal: true, isRequired: false, transformFunction: null }, rememberMeLabel: { classPropertyName: "rememberMeLabel", publicName: "rememberMeLabel", isSignal: true, isRequired: false, transformFunction: null }, forgotPasswordLabel: { classPropertyName: "forgotPasswordLabel", publicName: "forgotPasswordLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loginSubmit: "loginSubmit", forgotPasswordClick: "forgotPasswordClick" }, ngImport: i0, template: `
18581
- <jv-card>
18582
- <jv-section [title]="title()" [description]="description()">
18583
- @if (error()) {
18584
- <jv-alert tone="danger" title="Sign-in error" role="alert">{{ error() }}</jv-alert>
18585
- }
18586
-
18587
- <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
18588
- <jv-form-container label="Email or username" inputId="jv-login-identifier" error="This field is required" [required]="true" [invalid]="identifierInvalid()">
18589
- <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" placeholder="you@example.com" />
18590
- </jv-form-container>
18591
-
18592
- <jv-form-container label="Password" inputId="jv-login-password" error="Password is required" [required]="true" [invalid]="passwordInvalid()">
18593
- <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" placeholder="Enter your password" />
18594
- </jv-form-container>
18595
-
18596
- <div class="auth-inline-row">
18597
- <jv-checkbox formControlName="rememberMe" label="{{ rememberMeLabel() }}" />
18598
- <button type="button" class="auth-link" (click)="forgotPasswordClick.emit()">{{ forgotPasswordLabel() }}</button>
18599
- </div>
18600
-
18601
- <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
18602
- </form>
18603
- </jv-section>
18604
- </jv-card>
18605
- `, isInline: true, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-inline-row{display:flex;justify-content:space-between;align-items:center;gap:var(--jv-spacing-md);flex-wrap:wrap}.auth-link{border:0;padding:0;background:transparent;color:var(--jv-color-primary);text-decoration:underline;text-underline-offset:.18em}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: JvAlertComponent, selector: "jv-alert", inputs: ["tone", "title", "role"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvCardComponent, selector: "jv-card", inputs: ["elevated"] }, { kind: "component", type: JvCheckboxComponent, selector: "jv-checkbox", inputs: ["label", "describedBy", "inputId"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvSectionComponent, selector: "jv-section", inputs: ["title", "description"] }] });
18606
- }
18607
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvLoginPageComponent, decorators: [{
18608
- type: Component,
18609
- args: [{ selector: 'jv-login-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvCheckboxComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
18610
- <jv-card>
18611
- <jv-section [title]="title()" [description]="description()">
18612
- @if (error()) {
18613
- <jv-alert tone="danger" title="Sign-in error" role="alert">{{ error() }}</jv-alert>
18614
- }
18615
-
18616
- <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
18617
- <jv-form-container label="Email or username" inputId="jv-login-identifier" error="This field is required" [required]="true" [invalid]="identifierInvalid()">
18618
- <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" placeholder="you@example.com" />
18619
- </jv-form-container>
18620
-
18621
- <jv-form-container label="Password" inputId="jv-login-password" error="Password is required" [required]="true" [invalid]="passwordInvalid()">
18622
- <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" placeholder="Enter your password" />
18623
- </jv-form-container>
18624
-
18625
- <div class="auth-inline-row">
18626
- <jv-checkbox formControlName="rememberMe" label="{{ rememberMeLabel() }}" />
18627
- <button type="button" class="auth-link" (click)="forgotPasswordClick.emit()">{{ forgotPasswordLabel() }}</button>
18628
- </div>
18629
-
18630
- <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
18631
- </form>
18632
- </jv-section>
18633
- </jv-card>
18634
- `, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-inline-row{display:flex;justify-content:space-between;align-items:center;gap:var(--jv-spacing-md);flex-wrap:wrap}.auth-link{border:0;padding:0;background:transparent;color:var(--jv-color-primary);text-decoration:underline;text-underline-offset:.18em}\n"] }]
18635
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], submitLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitLabel", required: false }] }], rememberMeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rememberMeLabel", required: false }] }], forgotPasswordLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "forgotPasswordLabel", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], loginSubmit: [{ type: i0.Output, args: ["loginSubmit"] }], forgotPasswordClick: [{ type: i0.Output, args: ["forgotPasswordClick"] }] } });
18636
-
18637
- class JvDividerComponent {
18638
- vertical = input(false, ...(ngDevMode ? [{ debugName: "vertical" }] : /* istanbul ignore next */ []));
18639
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDividerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18640
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvDividerComponent, isStandalone: true, selector: "jv-divider", inputs: { vertical: { classPropertyName: "vertical", publicName: "vertical", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
18641
- <div
18642
- class="jv-divider"
18643
- [class.jv-divider--vertical]="vertical()"
18644
- [attr.role]="'separator'"
18645
- [attr.aria-orientation]="vertical() ? 'vertical' : 'horizontal'"
18646
- ></div>
18647
- `, isInline: true, styles: [".jv-divider{width:100%;height:1px;background:var(--jv-color-border)}.jv-divider--vertical{width:1px;height:100%;min-height:1.5rem}\n"] });
18648
- }
18649
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDividerComponent, decorators: [{
18650
- type: Component,
18651
- args: [{ selector: 'jv-divider', standalone: true, template: `
18652
- <div
18653
- class="jv-divider"
18654
- [class.jv-divider--vertical]="vertical()"
18655
- [attr.role]="'separator'"
18656
- [attr.aria-orientation]="vertical() ? 'vertical' : 'horizontal'"
18657
- ></div>
18658
- `, styles: [".jv-divider{width:100%;height:1px;background:var(--jv-color-border)}.jv-divider--vertical{width:1px;height:100%;min-height:1.5rem}\n"] }]
18659
- }], propDecorators: { vertical: [{ type: i0.Input, args: [{ isSignal: true, alias: "vertical", required: false }] }] } });
18660
-
18661
- class JvAccordionPanelDirective {
18662
- templateRef;
18663
- id = input.required({ ...(ngDevMode ? { debugName: "id" } : /* istanbul ignore next */ {}), alias: 'jvAccordionPanel' });
18664
- constructor(templateRef) {
18665
- this.templateRef = templateRef;
18666
- }
18667
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAccordionPanelDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
18668
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.17", type: JvAccordionPanelDirective, isStandalone: true, selector: "ng-template[jvAccordionPanel]", inputs: { id: { classPropertyName: "id", publicName: "jvAccordionPanel", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
18669
- }
18670
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAccordionPanelDirective, decorators: [{
18671
- type: Directive,
18672
- args: [{
18673
- selector: 'ng-template[jvAccordionPanel]',
18674
- standalone: true,
18675
- }]
18676
- }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "jvAccordionPanel", required: true }] }] } });
18677
-
18678
- class JvAnnouncementService {
18679
- document = inject(DOCUMENT);
18680
- region = null;
18681
- announce(message, politeness = 'polite') {
18682
- if (!message.trim()) {
18683
- return;
18684
- }
18685
- const region = this.ensureRegion(politeness);
18686
- region.textContent = '';
18687
- // Clear and reinsert so NVDA reliably reads repeated updates.
18688
- setTimeout(() => {
18689
- region.textContent = message;
18690
- }, 20);
18691
- }
18692
- ensureRegion(politeness) {
18693
- if (!this.region) {
18694
- const region = this.document.createElement('div');
18695
- region.className = 'sr-only';
18696
- region.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');
18697
- region.setAttribute('aria-live', politeness);
18698
- region.setAttribute('aria-atomic', 'true');
18699
- this.document.body.appendChild(region);
18700
- this.region = region;
18701
- return region;
18702
- }
18703
- this.region.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');
18704
- this.region.setAttribute('aria-live', politeness);
18705
- return this.region;
18706
- }
18707
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAnnouncementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18708
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAnnouncementService, providedIn: 'root' });
18128
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18129
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvThemeService, providedIn: 'root' });
18709
18130
  }
18710
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAnnouncementService, decorators: [{
18711
- type: Injectable,
18712
- args: [{ providedIn: 'root' }]
18713
- }] });
18714
-
18715
- const JV_UI_DEFAULT_CONFIG = {
18716
- theme: 'light',
18717
- density: 'normal',
18718
- language: 'es-MX',
18719
- locale: 'es',
18720
- messagesLocale: 'es',
18721
- formatLocale: 'es-MX',
18722
- formats: {
18723
- date: { day: '2-digit', month: '2-digit', year: 'numeric' },
18724
- time: { hour: '2-digit', minute: '2-digit' },
18725
- datetime: { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' },
18726
- integer: { maximumFractionDigits: 0 },
18727
- number: { minimumFractionDigits: 0, maximumFractionDigits: 2 },
18728
- currency: { style: 'currency', currency: 'MXN', minimumFractionDigits: 2, maximumFractionDigits: 2 },
18729
- percent: { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 2 },
18730
- },
18731
- toastPosition: 'bottom-right',
18732
- tabsTransition: 'none',
18733
- };
18734
-
18735
- class JvFormatService {
18736
- config = inject(JvUiConfigService);
18737
- formatLocale = signal(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX', ...(ngDevMode ? [{ debugName: "formatLocale" }] : /* istanbul ignore next */ []));
18738
- formats = signal(this.resolveFormats(this.config.snapshot.formats), ...(ngDevMode ? [{ debugName: "formats" }] : /* istanbul ignore next */ []));
18739
- firstDayOfWeek = computed(() => this.resolveFirstDayOfWeek(this.formatLocale()), ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
18740
- initialize() {
18741
- this.formatLocale.set(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX');
18742
- this.formats.set(this.resolveFormats(this.config.snapshot.formats));
18743
- }
18744
- setFormatLocale(locale) {
18745
- this.formatLocale.set(locale);
18746
- }
18747
- setFormats(formats) {
18748
- this.formats.update((current) => this.resolveFormats({ ...current, ...formats }));
18749
- }
18750
- format(kind, value, overrides) {
18751
- if (value == null || value === '')
18752
- return '';
18753
- if (kind === 'date' || kind === 'time' || kind === 'datetime') {
18754
- const date = this.toDate(value);
18755
- if (!date)
18756
- return String(value);
18757
- return new Intl.DateTimeFormat(this.formatLocale(), this.resolveDateOptions(kind, overrides)).format(date);
18758
- }
18759
- const number = this.toNumber(value);
18760
- if (number === null)
18761
- return String(value);
18762
- return new Intl.NumberFormat(this.formatLocale(), this.resolveNumberOptions(kind, overrides)).format(number);
18763
- }
18764
- toComparable(kind, value) {
18765
- if (value == null || value === '')
18766
- return null;
18767
- if (kind === 'date' || kind === 'time' || kind === 'datetime') {
18768
- const date = this.toDate(value);
18769
- return date ? date.getTime() : String(value);
18770
- }
18771
- if (kind === 'integer' || kind === 'number' || kind === 'currency' || kind === 'percent') {
18772
- const number = this.toNumber(value);
18773
- return number ?? String(value);
18774
- }
18775
- return String(value);
18776
- }
18777
- toDate(value) {
18778
- if (value instanceof Date) {
18779
- return Number.isNaN(value.getTime()) ? null : value;
18780
- }
18781
- if (typeof value === 'number' || typeof value === 'string') {
18782
- const date = new Date(value);
18783
- return Number.isNaN(date.getTime()) ? null : date;
18784
- }
18785
- return null;
18786
- }
18787
- toNumber(value) {
18788
- if (typeof value === 'number') {
18789
- return Number.isFinite(value) ? value : null;
18790
- }
18791
- if (typeof value === 'string') {
18792
- const normalized = value.trim().replace(/[%,$\s]/g, '').replace(/,/g, '');
18793
- if (!normalized)
18794
- return null;
18795
- const parsed = Number(normalized);
18796
- return Number.isFinite(parsed) ? parsed : null;
18797
- }
18798
- return null;
18799
- }
18800
- toSearchValue(kind, value) {
18801
- if (value == null)
18802
- return '';
18803
- if (kind === 'date' || kind === 'time' || kind === 'datetime') {
18804
- const date = this.toDate(value);
18805
- if (!date)
18806
- return String(value).toLowerCase();
18807
- return date.toISOString().toLowerCase();
18808
- }
18809
- return String(value).toLowerCase();
18810
- }
18811
- resolveFormats(formats) {
18812
- const defaults = this.config.snapshot.formats;
18813
- return {
18814
- date: { ...defaults.date, ...formats?.date },
18815
- time: { ...defaults.time, ...formats?.time },
18816
- datetime: { ...defaults.datetime, ...formats?.datetime },
18817
- integer: { ...defaults.integer, ...formats?.integer },
18818
- number: { ...defaults.number, ...formats?.number },
18819
- currency: { ...defaults.currency, ...formats?.currency },
18820
- percent: { ...defaults.percent, ...formats?.percent },
18821
- };
18822
- }
18823
- resolveDateOptions(kind, overrides) {
18824
- return { ...this.formats()[kind], ...overrides };
18825
- }
18826
- resolveNumberOptions(kind, overrides) {
18827
- return { ...this.formats()[kind], ...overrides };
18828
- }
18829
- resolveFirstDayOfWeek(locale) {
18830
- try {
18831
- const intlLocale = new Intl.Locale(locale);
18832
- const firstDay = intlLocale.weekInfo?.firstDay;
18833
- if (typeof firstDay === 'number') {
18834
- return firstDay % 7;
18835
- }
18836
- }
18837
- catch {
18838
- // Ignore unsupported Intl.Locale implementations.
18839
- }
18840
- return 0;
18841
- }
18842
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18843
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, providedIn: 'root' });
18844
- }
18845
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, decorators: [{
18846
- type: Injectable,
18847
- args: [{ providedIn: 'root' }]
18848
- }] });
18849
-
18850
- class JvThemeService {
18851
- document = inject(DOCUMENT);
18852
- config = inject(JvUiConfigService);
18853
- storageKey = 'jv-ui-theme';
18854
- theme = signal(this.config.snapshot.theme, ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
18855
- density = signal(this.config.snapshot.density, ...(ngDevMode ? [{ debugName: "density" }] : /* istanbul ignore next */ []));
18856
- initialize() {
18857
- const initialConfig = this.config.snapshot;
18858
- const theme = this.resolveInitialTheme(initialConfig.theme);
18859
- this.applyTheme(theme);
18860
- this.applyDensity(initialConfig.density);
18861
- this.applyLanguage(initialConfig.language);
18862
- }
18863
- setTheme(theme) {
18864
- this.applyTheme(theme);
18865
- try {
18866
- this.document.defaultView?.localStorage.setItem(this.storageKey, theme);
18867
- }
18868
- catch {
18869
- // Ignore storage failures in restricted environments.
18870
- }
18871
- }
18872
- setDensity(density) {
18873
- this.applyDensity(density);
18874
- }
18875
- applyTheme(theme) {
18876
- this.theme.set(theme);
18877
- const root = this.document.documentElement;
18878
- root.dataset['theme'] = theme;
18879
- root.style.colorScheme = theme === 'dark' ? 'dark' : 'light';
18880
- }
18881
- applyDensity(density) {
18882
- this.density.set(density);
18883
- this.document.documentElement.dataset['density'] = density;
18884
- }
18885
- applyLanguage(language) {
18886
- this.document.documentElement.lang = language;
18887
- }
18888
- resolveInitialTheme(fallbackTheme) {
18889
- const savedTheme = this.readSavedTheme();
18890
- if (savedTheme) {
18891
- return savedTheme;
18892
- }
18893
- if (fallbackTheme === 'high-contrast') {
18894
- return fallbackTheme;
18895
- }
18896
- return this.prefersDarkMode() ? 'dark' : fallbackTheme;
18897
- }
18898
- readSavedTheme() {
18899
- try {
18900
- const saved = this.document.defaultView?.localStorage.getItem(this.storageKey);
18901
- return this.isTheme(saved) ? saved : null;
18902
- }
18903
- catch {
18904
- return null;
18905
- }
18906
- }
18907
- prefersDarkMode() {
18908
- return this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
18909
- }
18910
- isTheme(value) {
18911
- return value === 'light' || value === 'dark' || value === 'high-contrast';
18912
- }
18913
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18914
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvThemeService, providedIn: 'root' });
18915
- }
18916
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvThemeService, decorators: [{
18917
- type: Injectable,
18918
- args: [{ providedIn: 'root' }]
18919
- }] });
18920
-
18921
- const JV_UI_CONFIG = new InjectionToken('JV_UI_CONFIG');
18922
- const JV_UI_CONFIG_DEFAULTS = new InjectionToken('JV_UI_CONFIG_DEFAULTS', {
18923
- providedIn: 'root',
18924
- factory: () => JV_UI_DEFAULT_CONFIG,
18925
- });
18926
- function provideJvUi(config = {}) {
18927
- const configProvider = {
18928
- provide: JV_UI_CONFIG,
18929
- useValue: config,
18930
- multi: true,
18931
- };
18932
- return makeEnvironmentProviders([
18933
- configProvider,
18934
- {
18935
- provide: ENVIRONMENT_INITIALIZER,
18936
- multi: true,
18937
- useValue: () => {
18938
- inject(JvThemeService).initialize();
18939
- inject(JvTranslationService).initialize();
18940
- inject(JvFormatService).initialize();
18941
- },
18942
- },
18943
- ]);
18944
- }
18945
-
18946
- class JvUiConfigService {
18947
- defaults = inject(JV_UI_CONFIG_DEFAULTS);
18948
- configLayers = (inject(JV_UI_CONFIG, { optional: true }) ?? []);
18949
- get snapshot() {
18950
- return this.configLayers.reduce((merged, layer) => ({
18951
- ...merged,
18952
- ...layer,
18953
- formats: {
18954
- ...merged.formats,
18955
- ...(layer.formats ?? {}),
18956
- },
18957
- }), {
18958
- ...this.defaults,
18959
- formats: { ...this.defaults.formats },
18960
- });
18961
- }
18962
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18963
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, providedIn: 'root' });
18964
- }
18965
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, decorators: [{
18131
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvThemeService, decorators: [{
18966
18132
  type: Injectable,
18967
18133
  args: [{ providedIn: 'root' }]
18968
18134
  }] });
@@ -19008,6 +18174,12 @@ const ES = {
19008
18174
  'datePicker.prevMonth': 'Mes anterior',
19009
18175
  'datePicker.nextMonth': 'Mes siguiente',
19010
18176
  'datePicker.selectionCleared': 'Seleccion de fecha limpiada',
18177
+ 'monthCalendar.title': 'Calendario mensual',
18178
+ 'monthCalendar.today': 'Hoy',
18179
+ 'monthCalendar.prevMonth': 'Mes anterior',
18180
+ 'monthCalendar.nextMonth': 'Mes siguiente',
18181
+ 'monthCalendar.prevYear': 'Ano anterior',
18182
+ 'monthCalendar.nextYear': 'Ano siguiente',
19011
18183
  'modalSelector.placeholder': 'Seleccione una opcion',
19012
18184
  'modalSelector.searchPlaceholder': 'Buscar',
19013
18185
  'modalSelector.emptyMessage': 'No se encontraron resultados',
@@ -19027,6 +18199,11 @@ const ES = {
19027
18199
  'dialog.cancel': 'Cancelar',
19028
18200
  'common.expanded': 'Expandido',
19029
18201
  'common.collapsed': 'Colapsado',
18202
+ 'planner.title': 'Planificador',
18203
+ 'planner.emptyMessage': 'No hay elementos programados',
18204
+ 'planner.expand': 'Expandir detalles',
18205
+ 'planner.collapse': 'Colapsar detalles',
18206
+ 'planner.unscheduled': 'Sin programar',
19030
18207
  'slider.prevImage': 'Imagen anterior',
19031
18208
  'slider.nextImage': 'Imagen siguiente',
19032
18209
  'slider.thumbnailList': 'Miniaturas de imagenes',
@@ -19076,6 +18253,12 @@ const EN = {
19076
18253
  'datePicker.prevMonth': 'Previous month',
19077
18254
  'datePicker.nextMonth': 'Next month',
19078
18255
  'datePicker.selectionCleared': 'Date selection cleared',
18256
+ 'monthCalendar.title': 'Month calendar',
18257
+ 'monthCalendar.today': 'Today',
18258
+ 'monthCalendar.prevMonth': 'Previous month',
18259
+ 'monthCalendar.nextMonth': 'Next month',
18260
+ 'monthCalendar.prevYear': 'Previous year',
18261
+ 'monthCalendar.nextYear': 'Next year',
19079
18262
  'modalSelector.placeholder': 'Select an option',
19080
18263
  'modalSelector.searchPlaceholder': 'Search',
19081
18264
  'modalSelector.emptyMessage': 'No results found',
@@ -19095,6 +18278,11 @@ const EN = {
19095
18278
  'dialog.cancel': 'Cancel',
19096
18279
  'common.expanded': 'Expanded',
19097
18280
  'common.collapsed': 'Collapsed',
18281
+ 'planner.title': 'Schedule planner',
18282
+ 'planner.emptyMessage': 'No scheduled items',
18283
+ 'planner.expand': 'Expand details',
18284
+ 'planner.collapse': 'Collapse details',
18285
+ 'planner.unscheduled': 'Unscheduled',
19098
18286
  'slider.prevImage': 'Previous image',
19099
18287
  'slider.nextImage': 'Next image',
19100
18288
  'slider.thumbnailList': 'Image thumbnails',
@@ -19103,49 +18291,1798 @@ const EN = {
19103
18291
  'gallery.nextImage': 'Next image',
19104
18292
  };
19105
18293
 
19106
- const JV_LOCALE_DICTIONARIES = {
19107
- es: ES,
19108
- en: EN,
19109
- };
19110
- const JV_DEFAULT_LOCALE = 'es';
18294
+ const JV_LOCALE_DICTIONARIES = {
18295
+ es: ES,
18296
+ en: EN,
18297
+ };
18298
+ const JV_DEFAULT_LOCALE = 'es';
18299
+
18300
+ class JvTranslationService {
18301
+ config = inject(JvUiConfigService);
18302
+ locale = signal(this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale), ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
18303
+ initialize() {
18304
+ const locale = this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale);
18305
+ this.locale.set(locale);
18306
+ }
18307
+ setLocale(locale) {
18308
+ this.locale.set(locale);
18309
+ }
18310
+ setMessagesLocale(locale) {
18311
+ this.setLocale(locale);
18312
+ }
18313
+ translate(key, params) {
18314
+ const dict = JV_LOCALE_DICTIONARIES[this.locale()] ?? JV_LOCALE_DICTIONARIES[JV_DEFAULT_LOCALE];
18315
+ let value = dict[key];
18316
+ if (value === undefined) {
18317
+ value = JV_LOCALE_DICTIONARIES[JV_DEFAULT_LOCALE][key] ?? key;
18318
+ }
18319
+ if (params) {
18320
+ for (const [k, v] of Object.entries(params)) {
18321
+ value = value.replace(`{${k}}`, String(v));
18322
+ }
18323
+ }
18324
+ return value;
18325
+ }
18326
+ resolveLocale(locale) {
18327
+ if (!locale)
18328
+ return JV_DEFAULT_LOCALE;
18329
+ if (locale === 'es' || locale === 'en')
18330
+ return locale;
18331
+ return locale.startsWith('es') ? 'es' : 'en';
18332
+ }
18333
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18334
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, providedIn: 'root' });
18335
+ }
18336
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, decorators: [{
18337
+ type: Injectable,
18338
+ args: [{ providedIn: 'root' }]
18339
+ }] });
18340
+
18341
+ const JV_UI_CONFIG = new InjectionToken('JV_UI_CONFIG');
18342
+ const JV_UI_CONFIG_DEFAULTS = new InjectionToken('JV_UI_CONFIG_DEFAULTS', {
18343
+ providedIn: 'root',
18344
+ factory: () => JV_UI_DEFAULT_CONFIG,
18345
+ });
18346
+ function provideJvUi(config = {}) {
18347
+ const configProvider = {
18348
+ provide: JV_UI_CONFIG,
18349
+ useValue: config,
18350
+ multi: true,
18351
+ };
18352
+ return makeEnvironmentProviders([
18353
+ configProvider,
18354
+ {
18355
+ provide: ENVIRONMENT_INITIALIZER,
18356
+ multi: true,
18357
+ useValue: () => {
18358
+ inject(JvThemeService).initialize();
18359
+ inject(JvTranslationService).initialize();
18360
+ inject(JvFormatService).initialize();
18361
+ },
18362
+ },
18363
+ ]);
18364
+ }
18365
+
18366
+ class JvUiConfigService {
18367
+ defaults = inject(JV_UI_CONFIG_DEFAULTS);
18368
+ configLayers = (inject(JV_UI_CONFIG, { optional: true }) ?? []);
18369
+ get snapshot() {
18370
+ return this.configLayers.reduce((merged, layer) => ({
18371
+ ...merged,
18372
+ ...layer,
18373
+ formats: {
18374
+ ...merged.formats,
18375
+ ...(layer.formats ?? {}),
18376
+ },
18377
+ }), {
18378
+ ...this.defaults,
18379
+ formats: { ...this.defaults.formats },
18380
+ });
18381
+ }
18382
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18383
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, providedIn: 'root' });
18384
+ }
18385
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, decorators: [{
18386
+ type: Injectable,
18387
+ args: [{ providedIn: 'root' }]
18388
+ }] });
18389
+
18390
+ class JvFormatService {
18391
+ config = inject(JvUiConfigService);
18392
+ formatLocale = signal(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX', ...(ngDevMode ? [{ debugName: "formatLocale" }] : /* istanbul ignore next */ []));
18393
+ formats = signal(this.resolveFormats(this.config.snapshot.formats), ...(ngDevMode ? [{ debugName: "formats" }] : /* istanbul ignore next */ []));
18394
+ firstDayOfWeek = computed(() => this.resolveFirstDayOfWeek(this.formatLocale()), ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
18395
+ initialize() {
18396
+ this.formatLocale.set(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX');
18397
+ this.formats.set(this.resolveFormats(this.config.snapshot.formats));
18398
+ }
18399
+ setFormatLocale(locale) {
18400
+ this.formatLocale.set(locale);
18401
+ }
18402
+ setFormats(formats) {
18403
+ this.formats.update((current) => this.resolveFormats({ ...current, ...formats }));
18404
+ }
18405
+ format(kind, value, overrides) {
18406
+ if (value == null || value === '')
18407
+ return '';
18408
+ if (kind === 'date' || kind === 'time' || kind === 'datetime') {
18409
+ const date = this.toDate(value);
18410
+ if (!date)
18411
+ return String(value);
18412
+ return new Intl.DateTimeFormat(this.formatLocale(), this.resolveDateOptions(kind, overrides)).format(date);
18413
+ }
18414
+ const number = this.toNumber(value);
18415
+ if (number === null)
18416
+ return String(value);
18417
+ return new Intl.NumberFormat(this.formatLocale(), this.resolveNumberOptions(kind, overrides)).format(number);
18418
+ }
18419
+ toComparable(kind, value) {
18420
+ if (value == null || value === '')
18421
+ return null;
18422
+ if (kind === 'date' || kind === 'time' || kind === 'datetime') {
18423
+ const date = this.toDate(value);
18424
+ return date ? date.getTime() : String(value);
18425
+ }
18426
+ if (kind === 'integer' || kind === 'number' || kind === 'currency' || kind === 'percent') {
18427
+ const number = this.toNumber(value);
18428
+ return number ?? String(value);
18429
+ }
18430
+ return String(value);
18431
+ }
18432
+ toDate(value) {
18433
+ if (value instanceof Date) {
18434
+ return Number.isNaN(value.getTime()) ? null : value;
18435
+ }
18436
+ if (typeof value === 'number' || typeof value === 'string') {
18437
+ const date = new Date(value);
18438
+ return Number.isNaN(date.getTime()) ? null : date;
18439
+ }
18440
+ return null;
18441
+ }
18442
+ toNumber(value) {
18443
+ if (typeof value === 'number') {
18444
+ return Number.isFinite(value) ? value : null;
18445
+ }
18446
+ if (typeof value === 'string') {
18447
+ const normalized = value.trim().replace(/[%,$\s]/g, '').replace(/,/g, '');
18448
+ if (!normalized)
18449
+ return null;
18450
+ const parsed = Number(normalized);
18451
+ return Number.isFinite(parsed) ? parsed : null;
18452
+ }
18453
+ return null;
18454
+ }
18455
+ toSearchValue(kind, value) {
18456
+ if (value == null)
18457
+ return '';
18458
+ if (kind === 'date' || kind === 'time' || kind === 'datetime') {
18459
+ const date = this.toDate(value);
18460
+ if (!date)
18461
+ return String(value).toLowerCase();
18462
+ return date.toISOString().toLowerCase();
18463
+ }
18464
+ return String(value).toLowerCase();
18465
+ }
18466
+ resolveFormats(formats) {
18467
+ const defaults = this.config.snapshot.formats;
18468
+ return {
18469
+ date: { ...defaults.date, ...formats?.date },
18470
+ time: { ...defaults.time, ...formats?.time },
18471
+ datetime: { ...defaults.datetime, ...formats?.datetime },
18472
+ integer: { ...defaults.integer, ...formats?.integer },
18473
+ number: { ...defaults.number, ...formats?.number },
18474
+ currency: { ...defaults.currency, ...formats?.currency },
18475
+ percent: { ...defaults.percent, ...formats?.percent },
18476
+ };
18477
+ }
18478
+ resolveDateOptions(kind, overrides) {
18479
+ return { ...this.formats()[kind], ...overrides };
18480
+ }
18481
+ resolveNumberOptions(kind, overrides) {
18482
+ return { ...this.formats()[kind], ...overrides };
18483
+ }
18484
+ resolveFirstDayOfWeek(locale) {
18485
+ try {
18486
+ const intlLocale = new Intl.Locale(locale);
18487
+ const firstDay = intlLocale.weekInfo?.firstDay;
18488
+ if (typeof firstDay === 'number') {
18489
+ return firstDay % 7;
18490
+ }
18491
+ }
18492
+ catch {
18493
+ // Ignore unsupported Intl.Locale implementations.
18494
+ }
18495
+ return 0;
18496
+ }
18497
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18498
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, providedIn: 'root' });
18499
+ }
18500
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, decorators: [{
18501
+ type: Injectable,
18502
+ args: [{ providedIn: 'root' }]
18503
+ }] });
18504
+
18505
+ class JvBadgeComponent {
18506
+ tone = input('primary', ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
18507
+ badgeClass = computed(() => `jv-badge--${this.tone()}`, ...(ngDevMode ? [{ debugName: "badgeClass" }] : /* istanbul ignore next */ []));
18508
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18509
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvBadgeComponent, isStandalone: true, selector: "jv-badge", inputs: { tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `<span class="jv-badge" [class]="badgeClass()"><ng-content></ng-content></span>`, isInline: true, styles: [".jv-badge{display:inline-flex;align-items:center;justify-content:center;min-height:1.75rem;padding:0 var(--jv-spacing-sm);border-radius:999px;font-size:.8rem;font-weight:700;line-height:1;white-space:nowrap}.jv-badge--primary{background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface));color:var(--jv-color-primary)}.jv-badge--secondary,.jv-badge--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-badge--success{background:color-mix(in srgb,var(--jv-color-success) 16%,var(--jv-color-surface));color:var(--jv-color-success)}.jv-badge--warning{background:color-mix(in srgb,var(--jv-color-warning) 20%,var(--jv-color-surface));color:#8a4b00}.jv-badge--danger{background:color-mix(in srgb,var(--jv-color-danger) 16%,var(--jv-color-surface));color:var(--jv-color-danger)}.jv-badge--info{background:color-mix(in srgb,var(--jv-color-info) 16%,var(--jv-color-surface));color:var(--jv-color-info)}\n"] });
18510
+ }
18511
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvBadgeComponent, decorators: [{
18512
+ type: Component,
18513
+ args: [{ selector: 'jv-badge', standalone: true, template: `<span class="jv-badge" [class]="badgeClass()"><ng-content></ng-content></span>`, styles: [".jv-badge{display:inline-flex;align-items:center;justify-content:center;min-height:1.75rem;padding:0 var(--jv-spacing-sm);border-radius:999px;font-size:.8rem;font-weight:700;line-height:1;white-space:nowrap}.jv-badge--primary{background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface));color:var(--jv-color-primary)}.jv-badge--secondary,.jv-badge--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-badge--success{background:color-mix(in srgb,var(--jv-color-success) 16%,var(--jv-color-surface));color:var(--jv-color-success)}.jv-badge--warning{background:color-mix(in srgb,var(--jv-color-warning) 20%,var(--jv-color-surface));color:#8a4b00}.jv-badge--danger{background:color-mix(in srgb,var(--jv-color-danger) 16%,var(--jv-color-surface));color:var(--jv-color-danger)}.jv-badge--info{background:color-mix(in srgb,var(--jv-color-info) 16%,var(--jv-color-surface));color:var(--jv-color-info)}\n"] }]
18514
+ }], propDecorators: { tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }] } });
18515
+
18516
+ class JvDayPlannerDetailDirective {
18517
+ templateRef;
18518
+ constructor(templateRef) {
18519
+ this.templateRef = templateRef;
18520
+ }
18521
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerDetailDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
18522
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: JvDayPlannerDetailDirective, isStandalone: true, selector: "ng-template[jvDayPlannerDetail]", ngImport: i0 });
18523
+ }
18524
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerDetailDirective, decorators: [{
18525
+ type: Directive,
18526
+ args: [{
18527
+ selector: 'ng-template[jvDayPlannerDetail]',
18528
+ standalone: true,
18529
+ }]
18530
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
18531
+
18532
+ class JvDayPlannerItemDirective {
18533
+ templateRef;
18534
+ constructor(templateRef) {
18535
+ this.templateRef = templateRef;
18536
+ }
18537
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerItemDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
18538
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: JvDayPlannerItemDirective, isStandalone: true, selector: "ng-template[jvDayPlannerItem]", ngImport: i0 });
18539
+ }
18540
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerItemDirective, decorators: [{
18541
+ type: Directive,
18542
+ args: [{
18543
+ selector: 'ng-template[jvDayPlannerItem]',
18544
+ standalone: true,
18545
+ }]
18546
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
18547
+
18548
+ class JvDayPlannerComponent {
18549
+ translation = inject(JvTranslationService);
18550
+ formatService = inject(JvFormatService);
18551
+ customItemTemplate = contentChild(JvDayPlannerItemDirective, ...(ngDevMode ? [{ debugName: "customItemTemplate" }] : /* istanbul ignore next */ []));
18552
+ customDetailTemplate = contentChild(JvDayPlannerDetailDirective, ...(ngDevMode ? [{ debugName: "customDetailTemplate" }] : /* istanbul ignore next */ []));
18553
+ expandedIds = signal([], ...(ngDevMode ? [{ debugName: "expandedIds" }] : /* istanbul ignore next */ []));
18554
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
18555
+ groupByDate = input(false, ...(ngDevMode ? [{ debugName: "groupByDate" }] : /* istanbul ignore next */ []));
18556
+ emptyMessage = input('', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
18557
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
18558
+ defaultExpandedItemIds = input([], ...(ngDevMode ? [{ debugName: "defaultExpandedItemIds" }] : /* istanbul ignore next */ []));
18559
+ itemSelect = output();
18560
+ resolvedAriaLabel = computed(() => this.ariaLabel() || this.translation.translate('planner.title'), ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
18561
+ resolvedItems = computed(() => {
18562
+ return this.items()
18563
+ .map((item) => {
18564
+ const date = normalizeDate$1(item.date ?? item.start ?? null);
18565
+ const start = normalizeDateTime(item.start ?? item.date ?? null);
18566
+ const end = normalizeDateTime(item.end ?? null);
18567
+ return {
18568
+ id: String(item.id),
18569
+ raw: item,
18570
+ date,
18571
+ start,
18572
+ end,
18573
+ sortValue: start?.getTime() ?? date?.getTime() ?? Number.MAX_SAFE_INTEGER,
18574
+ hasDetails: Boolean(item.details) || Boolean(this.customDetailTemplate()),
18575
+ };
18576
+ })
18577
+ .sort((left, right) => left.sortValue - right.sortValue);
18578
+ }, ...(ngDevMode ? [{ debugName: "resolvedItems" }] : /* istanbul ignore next */ []));
18579
+ groupedItems = computed(() => {
18580
+ const items = this.resolvedItems();
18581
+ if (!this.groupByDate()) {
18582
+ return [{ key: 'all', label: '', items }];
18583
+ }
18584
+ const groups = new Map();
18585
+ for (const item of items) {
18586
+ const key = item.date ? toDateKey$1(item.date) : 'unscheduled';
18587
+ const bucket = groups.get(key) ?? [];
18588
+ bucket.push(item);
18589
+ groups.set(key, bucket);
18590
+ }
18591
+ return Array.from(groups.entries()).map(([key, groupItems]) => ({
18592
+ key,
18593
+ label: key === 'unscheduled' ? this.translation.translate('planner.unscheduled') : this.formatDateLabel(groupItems[0]?.date),
18594
+ items: groupItems,
18595
+ }));
18596
+ }, ...(ngDevMode ? [{ debugName: "groupedItems" }] : /* istanbul ignore next */ []));
18597
+ constructor() {
18598
+ effect(() => {
18599
+ this.expandedIds.set(this.defaultExpandedItemIds().map((id) => String(id)));
18600
+ });
18601
+ }
18602
+ itemTemplate() {
18603
+ return this.customItemTemplate();
18604
+ }
18605
+ detailTemplate() {
18606
+ return this.customDetailTemplate();
18607
+ }
18608
+ itemContext(item) {
18609
+ return { $implicit: item.raw, item: item.raw, expanded: this.isExpanded(item.id) };
18610
+ }
18611
+ detailContext(item) {
18612
+ return { $implicit: item.raw, item: item.raw };
18613
+ }
18614
+ selectItem(item) {
18615
+ this.itemSelect.emit(item);
18616
+ }
18617
+ toggleExpanded(itemId) {
18618
+ this.expandedIds.update((current) => current.includes(itemId)
18619
+ ? current.filter((id) => id !== itemId)
18620
+ : [...current, itemId]);
18621
+ }
18622
+ isExpanded(itemId) {
18623
+ return this.expandedIds().includes(itemId);
18624
+ }
18625
+ timeLabel(item) {
18626
+ if (!item.start && !item.end) {
18627
+ return '';
18628
+ }
18629
+ const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), {
18630
+ hour: 'numeric',
18631
+ minute: '2-digit',
18632
+ });
18633
+ if (item.start && item.end) {
18634
+ return `${formatter.format(item.start)} - ${formatter.format(item.end)}`;
18635
+ }
18636
+ return formatter.format(item.start ?? item.end);
18637
+ }
18638
+ formatDateLabel(date) {
18639
+ if (!date) {
18640
+ return this.translation.translate('planner.unscheduled');
18641
+ }
18642
+ return new Intl.DateTimeFormat(this.formatService.formatLocale(), {
18643
+ weekday: 'long',
18644
+ day: 'numeric',
18645
+ month: 'long',
18646
+ year: 'numeric',
18647
+ }).format(date);
18648
+ }
18649
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18650
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvDayPlannerComponent, isStandalone: true, selector: "jv-day-planner", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, groupByDate: { classPropertyName: "groupByDate", publicName: "groupByDate", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, defaultExpandedItemIds: { classPropertyName: "defaultExpandedItemIds", publicName: "defaultExpandedItemIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelect: "itemSelect" }, queries: [{ propertyName: "customItemTemplate", first: true, predicate: JvDayPlannerItemDirective, descendants: true, isSignal: true }, { propertyName: "customDetailTemplate", first: true, predicate: JvDayPlannerDetailDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
18651
+ <section class="jv-day-planner" [attr.aria-label]="resolvedAriaLabel()">
18652
+ @if (groupedItems().length === 0) {
18653
+ <div class="jv-day-planner-empty">{{ emptyMessage() || translation.translate('planner.emptyMessage') }}</div>
18654
+ } @else {
18655
+ <div class="jv-day-planner-groups">
18656
+ @for (group of groupedItems(); track group.key) {
18657
+ <section class="jv-day-planner-group">
18658
+ @if (groupByDate()) {
18659
+ <header class="jv-day-planner-group-header">{{ group.label }}</header>
18660
+ }
18661
+
18662
+ <div class="jv-day-planner-items">
18663
+ @for (item of group.items; track item.id) {
18664
+ <article class="jv-day-planner-item" [class.jv-day-planner-item--completed]="item.raw.completed">
18665
+ <div class="jv-day-planner-item-header">
18666
+ <button type="button" class="jv-day-planner-item-button" (click)="selectItem(item.raw)">
18667
+ @if (itemTemplate()) {
18668
+ <ng-container
18669
+ [ngTemplateOutlet]="itemTemplate()!.templateRef"
18670
+ [ngTemplateOutletContext]="itemContext(item)"
18671
+ />
18672
+ } @else {
18673
+ <div class="jv-day-planner-item-content">
18674
+ <div class="jv-day-planner-item-topline">
18675
+ <strong>{{ item.raw.title }}</strong>
18676
+ <span class="jv-day-planner-item-time">{{ timeLabel(item) }}</span>
18677
+ </div>
18678
+
18679
+ <div class="jv-day-planner-item-badges">
18680
+ @if (item.raw.status) {
18681
+ <jv-badge [tone]="item.raw.statusTone ?? 'secondary'">{{ item.raw.status }}</jv-badge>
18682
+ }
18683
+ @if (item.raw.type) {
18684
+ <jv-badge [tone]="item.raw.typeTone ?? 'primary'">{{ item.raw.type }}</jv-badge>
18685
+ }
18686
+ </div>
18687
+
18688
+ <div class="jv-day-planner-item-meta">
18689
+ @if (item.raw.responsible) {
18690
+ <span>{{ item.raw.responsible }}</span>
18691
+ }
18692
+ @if (item.raw.location) {
18693
+ <span>{{ item.raw.location }}</span>
18694
+ }
18695
+ </div>
18696
+ </div>
18697
+ }
18698
+ </button>
18699
+
18700
+ @if (item.hasDetails) {
18701
+ <button
18702
+ type="button"
18703
+ class="jv-day-planner-toggle"
18704
+ [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
18705
+ [attr.aria-label]="isExpanded(item.id) ? translation.translate('planner.collapse') : translation.translate('planner.expand')"
18706
+ (click)="toggleExpanded(item.id)"
18707
+ >
18708
+ {{ isExpanded(item.id) ? '−' : '+' }}
18709
+ </button>
18710
+ }
18711
+ </div>
18712
+
18713
+ @if (item.hasDetails && isExpanded(item.id)) {
18714
+ <div class="jv-day-planner-detail">
18715
+ @if (detailTemplate()) {
18716
+ <ng-container
18717
+ [ngTemplateOutlet]="detailTemplate()!.templateRef"
18718
+ [ngTemplateOutletContext]="detailContext(item)"
18719
+ />
18720
+ } @else {
18721
+ <p>{{ item.raw.details }}</p>
18722
+ }
18723
+ </div>
18724
+ }
18725
+ </article>
18726
+ }
18727
+ </div>
18728
+ </section>
18729
+ }
18730
+ </div>
18731
+ }
18732
+ </section>
18733
+ `, isInline: true, styles: [".jv-day-planner,.jv-day-planner-groups,.jv-day-planner-group,.jv-day-planner-items{display:grid;gap:var(--jv-spacing-md)}.jv-day-planner-empty{padding:var(--jv-spacing-lg);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-lg);color:var(--jv-color-foreground-muted);text-align:center}.jv-day-planner-group-header{font-size:.875rem;font-weight:700;color:var(--jv-color-foreground-muted);text-transform:uppercase;letter-spacing:.04em}.jv-day-planner-item{display:grid;gap:var(--jv-spacing-sm);padding:var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-lg);background:var(--jv-color-surface)}.jv-day-planner-item--completed{opacity:.72}.jv-day-planner-item-header{display:grid;grid-template-columns:1fr auto;gap:var(--jv-spacing-sm);align-items:start}.jv-day-planner-item-button,.jv-day-planner-toggle{border:0;background:transparent;color:inherit;font:inherit}.jv-day-planner-item-button{padding:0;text-align:left;cursor:pointer}.jv-day-planner-item-button:focus-visible,.jv-day-planner-toggle:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:2px;border-radius:var(--jv-radius-sm)}.jv-day-planner-toggle{width:2rem;height:2rem;border-radius:999px;cursor:pointer;color:var(--jv-color-foreground-muted)}.jv-day-planner-toggle:hover{background:var(--jv-color-surface-muted)}.jv-day-planner-item-content,.jv-day-planner-item-badges,.jv-day-planner-item-meta{display:grid;gap:var(--jv-spacing-xs)}.jv-day-planner-item-topline{display:flex;flex-wrap:wrap;gap:var(--jv-spacing-sm);align-items:baseline;justify-content:space-between}.jv-day-planner-item-time{color:var(--jv-color-foreground-muted);font-size:.875rem}.jv-day-planner-item-badges,.jv-day-planner-item-meta{grid-auto-flow:column;grid-auto-columns:max-content;align-items:center;justify-content:start;column-gap:var(--jv-spacing-sm);row-gap:var(--jv-spacing-xs);flex-wrap:wrap}.jv-day-planner-item-meta{color:var(--jv-color-foreground-muted);font-size:.875rem}.jv-day-planner-detail{padding-top:var(--jv-spacing-sm);border-top:1px solid var(--jv-color-border);color:var(--jv-color-foreground-muted)}.jv-day-planner-detail p{margin:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: JvBadgeComponent, selector: "jv-badge", inputs: ["tone"] }] });
18734
+ }
18735
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerComponent, decorators: [{
18736
+ type: Component,
18737
+ args: [{ selector: 'jv-day-planner', standalone: true, imports: [NgTemplateOutlet, JvBadgeComponent], template: `
18738
+ <section class="jv-day-planner" [attr.aria-label]="resolvedAriaLabel()">
18739
+ @if (groupedItems().length === 0) {
18740
+ <div class="jv-day-planner-empty">{{ emptyMessage() || translation.translate('planner.emptyMessage') }}</div>
18741
+ } @else {
18742
+ <div class="jv-day-planner-groups">
18743
+ @for (group of groupedItems(); track group.key) {
18744
+ <section class="jv-day-planner-group">
18745
+ @if (groupByDate()) {
18746
+ <header class="jv-day-planner-group-header">{{ group.label }}</header>
18747
+ }
18748
+
18749
+ <div class="jv-day-planner-items">
18750
+ @for (item of group.items; track item.id) {
18751
+ <article class="jv-day-planner-item" [class.jv-day-planner-item--completed]="item.raw.completed">
18752
+ <div class="jv-day-planner-item-header">
18753
+ <button type="button" class="jv-day-planner-item-button" (click)="selectItem(item.raw)">
18754
+ @if (itemTemplate()) {
18755
+ <ng-container
18756
+ [ngTemplateOutlet]="itemTemplate()!.templateRef"
18757
+ [ngTemplateOutletContext]="itemContext(item)"
18758
+ />
18759
+ } @else {
18760
+ <div class="jv-day-planner-item-content">
18761
+ <div class="jv-day-planner-item-topline">
18762
+ <strong>{{ item.raw.title }}</strong>
18763
+ <span class="jv-day-planner-item-time">{{ timeLabel(item) }}</span>
18764
+ </div>
18765
+
18766
+ <div class="jv-day-planner-item-badges">
18767
+ @if (item.raw.status) {
18768
+ <jv-badge [tone]="item.raw.statusTone ?? 'secondary'">{{ item.raw.status }}</jv-badge>
18769
+ }
18770
+ @if (item.raw.type) {
18771
+ <jv-badge [tone]="item.raw.typeTone ?? 'primary'">{{ item.raw.type }}</jv-badge>
18772
+ }
18773
+ </div>
18774
+
18775
+ <div class="jv-day-planner-item-meta">
18776
+ @if (item.raw.responsible) {
18777
+ <span>{{ item.raw.responsible }}</span>
18778
+ }
18779
+ @if (item.raw.location) {
18780
+ <span>{{ item.raw.location }}</span>
18781
+ }
18782
+ </div>
18783
+ </div>
18784
+ }
18785
+ </button>
18786
+
18787
+ @if (item.hasDetails) {
18788
+ <button
18789
+ type="button"
18790
+ class="jv-day-planner-toggle"
18791
+ [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
18792
+ [attr.aria-label]="isExpanded(item.id) ? translation.translate('planner.collapse') : translation.translate('planner.expand')"
18793
+ (click)="toggleExpanded(item.id)"
18794
+ >
18795
+ {{ isExpanded(item.id) ? '−' : '+' }}
18796
+ </button>
18797
+ }
18798
+ </div>
18799
+
18800
+ @if (item.hasDetails && isExpanded(item.id)) {
18801
+ <div class="jv-day-planner-detail">
18802
+ @if (detailTemplate()) {
18803
+ <ng-container
18804
+ [ngTemplateOutlet]="detailTemplate()!.templateRef"
18805
+ [ngTemplateOutletContext]="detailContext(item)"
18806
+ />
18807
+ } @else {
18808
+ <p>{{ item.raw.details }}</p>
18809
+ }
18810
+ </div>
18811
+ }
18812
+ </article>
18813
+ }
18814
+ </div>
18815
+ </section>
18816
+ }
18817
+ </div>
18818
+ }
18819
+ </section>
18820
+ `, styles: [".jv-day-planner,.jv-day-planner-groups,.jv-day-planner-group,.jv-day-planner-items{display:grid;gap:var(--jv-spacing-md)}.jv-day-planner-empty{padding:var(--jv-spacing-lg);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-lg);color:var(--jv-color-foreground-muted);text-align:center}.jv-day-planner-group-header{font-size:.875rem;font-weight:700;color:var(--jv-color-foreground-muted);text-transform:uppercase;letter-spacing:.04em}.jv-day-planner-item{display:grid;gap:var(--jv-spacing-sm);padding:var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-lg);background:var(--jv-color-surface)}.jv-day-planner-item--completed{opacity:.72}.jv-day-planner-item-header{display:grid;grid-template-columns:1fr auto;gap:var(--jv-spacing-sm);align-items:start}.jv-day-planner-item-button,.jv-day-planner-toggle{border:0;background:transparent;color:inherit;font:inherit}.jv-day-planner-item-button{padding:0;text-align:left;cursor:pointer}.jv-day-planner-item-button:focus-visible,.jv-day-planner-toggle:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:2px;border-radius:var(--jv-radius-sm)}.jv-day-planner-toggle{width:2rem;height:2rem;border-radius:999px;cursor:pointer;color:var(--jv-color-foreground-muted)}.jv-day-planner-toggle:hover{background:var(--jv-color-surface-muted)}.jv-day-planner-item-content,.jv-day-planner-item-badges,.jv-day-planner-item-meta{display:grid;gap:var(--jv-spacing-xs)}.jv-day-planner-item-topline{display:flex;flex-wrap:wrap;gap:var(--jv-spacing-sm);align-items:baseline;justify-content:space-between}.jv-day-planner-item-time{color:var(--jv-color-foreground-muted);font-size:.875rem}.jv-day-planner-item-badges,.jv-day-planner-item-meta{grid-auto-flow:column;grid-auto-columns:max-content;align-items:center;justify-content:start;column-gap:var(--jv-spacing-sm);row-gap:var(--jv-spacing-xs);flex-wrap:wrap}.jv-day-planner-item-meta{color:var(--jv-color-foreground-muted);font-size:.875rem}.jv-day-planner-detail{padding-top:var(--jv-spacing-sm);border-top:1px solid var(--jv-color-border);color:var(--jv-color-foreground-muted)}.jv-day-planner-detail p{margin:0}\n"] }]
18821
+ }], ctorParameters: () => [], propDecorators: { customItemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => JvDayPlannerItemDirective), { isSignal: true }] }], customDetailTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => JvDayPlannerDetailDirective), { isSignal: true }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], groupByDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupByDate", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], defaultExpandedItemIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultExpandedItemIds", required: false }] }], itemSelect: [{ type: i0.Output, args: ["itemSelect"] }] } });
18822
+ function normalizeDate$1(value) {
18823
+ if (!value) {
18824
+ return null;
18825
+ }
18826
+ const date = value instanceof Date ? value : new Date(value);
18827
+ return Number.isNaN(date.getTime()) ? null : new Date(date.getFullYear(), date.getMonth(), date.getDate());
18828
+ }
18829
+ function normalizeDateTime(value) {
18830
+ if (!value) {
18831
+ return null;
18832
+ }
18833
+ const date = value instanceof Date ? value : new Date(value);
18834
+ return Number.isNaN(date.getTime()) ? null : date;
18835
+ }
18836
+ function toDateKey$1(date) {
18837
+ const year = date.getFullYear();
18838
+ const month = String(date.getMonth() + 1).padStart(2, '0');
18839
+ const day = String(date.getDate()).padStart(2, '0');
18840
+ return `${year}-${month}-${day}`;
18841
+ }
18842
+
18843
+ let selectIdSequence = 0;
18844
+ class JvSelectComponent {
18845
+ options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
18846
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
18847
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
18848
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
18849
+ describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
18850
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
18851
+ inputId = input(`jv-select-${++selectIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
18852
+ modelValue = input('', ...(ngDevMode ? [{ debugName: "modelValue" }] : /* istanbul ignore next */ []));
18853
+ selectionChange = output();
18854
+ value = '';
18855
+ disabled = false;
18856
+ onChange = () => undefined;
18857
+ onTouched = () => undefined;
18858
+ currentValue = computed(() => this.modelValue() || this.value, ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
18859
+ writeValue(value) {
18860
+ this.value = value ?? '';
18861
+ }
18862
+ registerOnChange(fn) {
18863
+ this.onChange = fn;
18864
+ }
18865
+ registerOnTouched(fn) {
18866
+ this.onTouched = fn;
18867
+ }
18868
+ setDisabledState(isDisabled) {
18869
+ this.disabled = isDisabled;
18870
+ }
18871
+ handleChange(event) {
18872
+ const nextValue = event.target.value;
18873
+ this.value = nextValue;
18874
+ this.onChange(nextValue);
18875
+ this.selectionChange.emit(nextValue);
18876
+ }
18877
+ handleBlur() {
18878
+ this.onTouched();
18879
+ }
18880
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18881
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvSelectComponent, isStandalone: true, selector: "jv-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "describedBy", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, modelValue: { classPropertyName: "modelValue", publicName: "modelValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, providers: [
18882
+ {
18883
+ provide: NG_VALUE_ACCESSOR,
18884
+ useExisting: forwardRef(() => JvSelectComponent),
18885
+ multi: true,
18886
+ },
18887
+ ], ngImport: i0, template: `
18888
+ <select
18889
+ class="jv-select"
18890
+ [class.is-invalid]="invalid()"
18891
+ [id]="inputId()"
18892
+ [disabled]="disabled"
18893
+ [required]="required()"
18894
+ [attr.aria-invalid]="invalid() ? 'true' : null"
18895
+ [attr.aria-describedby]="describedBy() || null"
18896
+ [attr.aria-label]="ariaLabel() || null"
18897
+ (change)="handleChange($event)"
18898
+ (blur)="handleBlur()"
18899
+ >
18900
+ @if (placeholder()) {
18901
+ <option value="" [disabled]="required()" [selected]="currentValue() === ''">{{ placeholder() }}</option>
18902
+ }
18903
+
18904
+ @for (option of options(); track option.label + ':' + option.value) {
18905
+ <option [value]="option.value" [disabled]="option.disabled ?? false" [selected]="option.value === currentValue()">{{ option.label }}</option>
18906
+ }
18907
+ </select>
18908
+ `, isInline: true, styles: [".jv-select{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-select.is-invalid{border-color:var(--jv-color-danger)}\n"] });
18909
+ }
18910
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSelectComponent, decorators: [{
18911
+ type: Component,
18912
+ args: [{ selector: 'jv-select', standalone: true, providers: [
18913
+ {
18914
+ provide: NG_VALUE_ACCESSOR,
18915
+ useExisting: forwardRef(() => JvSelectComponent),
18916
+ multi: true,
18917
+ },
18918
+ ], template: `
18919
+ <select
18920
+ class="jv-select"
18921
+ [class.is-invalid]="invalid()"
18922
+ [id]="inputId()"
18923
+ [disabled]="disabled"
18924
+ [required]="required()"
18925
+ [attr.aria-invalid]="invalid() ? 'true' : null"
18926
+ [attr.aria-describedby]="describedBy() || null"
18927
+ [attr.aria-label]="ariaLabel() || null"
18928
+ (change)="handleChange($event)"
18929
+ (blur)="handleBlur()"
18930
+ >
18931
+ @if (placeholder()) {
18932
+ <option value="" [disabled]="required()" [selected]="currentValue() === ''">{{ placeholder() }}</option>
18933
+ }
18934
+
18935
+ @for (option of options(); track option.label + ':' + option.value) {
18936
+ <option [value]="option.value" [disabled]="option.disabled ?? false" [selected]="option.value === currentValue()">{{ option.label }}</option>
18937
+ }
18938
+ </select>
18939
+ `, styles: [".jv-select{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-select.is-invalid{border-color:var(--jv-color-danger)}\n"] }]
18940
+ }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], modelValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelValue", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
18941
+
18942
+ class JvMonthCalendarDayDirective {
18943
+ templateRef;
18944
+ constructor(templateRef) {
18945
+ this.templateRef = templateRef;
18946
+ }
18947
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvMonthCalendarDayDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
18948
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: JvMonthCalendarDayDirective, isStandalone: true, selector: "ng-template[jvMonthCalendarDay]", ngImport: i0 });
18949
+ }
18950
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvMonthCalendarDayDirective, decorators: [{
18951
+ type: Directive,
18952
+ args: [{
18953
+ selector: 'ng-template[jvMonthCalendarDay]',
18954
+ standalone: true,
18955
+ }]
18956
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
18957
+
18958
+ class JvMonthCalendarComponent {
18959
+ translation = inject(JvTranslationService);
18960
+ formatService = inject(JvFormatService);
18961
+ gridRootRef = viewChild('gridRoot', ...(ngDevMode ? [{ debugName: "gridRootRef" }] : /* istanbul ignore next */ []));
18962
+ customDayTemplate = contentChild(JvMonthCalendarDayDirective, ...(ngDevMode ? [{ debugName: "customDayTemplate" }] : /* istanbul ignore next */ []));
18963
+ valueInput = input(undefined, { ...(ngDevMode ? { debugName: "valueInput" } : /* istanbul ignore next */ {}), alias: 'value' });
18964
+ visibleMonthInput = input(undefined, { ...(ngDevMode ? { debugName: "visibleMonthInput" } : /* istanbul ignore next */ {}), alias: 'visibleMonth' });
18965
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
18966
+ monthLabel = input('', ...(ngDevMode ? [{ debugName: "monthLabel" }] : /* istanbul ignore next */ []));
18967
+ yearLabel = input('', ...(ngDevMode ? [{ debugName: "yearLabel" }] : /* istanbul ignore next */ []));
18968
+ minYear = input(undefined, ...(ngDevMode ? [{ debugName: "minYear" }] : /* istanbul ignore next */ []));
18969
+ maxYear = input(undefined, ...(ngDevMode ? [{ debugName: "maxYear" }] : /* istanbul ignore next */ []));
18970
+ navigation = input(null, ...(ngDevMode ? [{ debugName: "navigation" }] : /* istanbul ignore next */ []));
18971
+ dayMeta = input([], ...(ngDevMode ? [{ debugName: "dayMeta" }] : /* istanbul ignore next */ []));
18972
+ selectionChange = output();
18973
+ visibleMonthChange = output();
18974
+ visibleMonth = signal(firstOfMonth$1(new Date()), ...(ngDevMode ? [{ debugName: "visibleMonth" }] : /* istanbul ignore next */ []));
18975
+ focusedDate = signal(startOfDay$1(new Date()), ...(ngDevMode ? [{ debugName: "focusedDate" }] : /* istanbul ignore next */ []));
18976
+ resolvedAriaLabel = computed(() => this.ariaLabel() || this.translation.translate('monthCalendar.title'), ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
18977
+ resolvedMonthLabel = computed(() => this.monthLabel() || 'Month', ...(ngDevMode ? [{ debugName: "resolvedMonthLabel" }] : /* istanbul ignore next */ []));
18978
+ resolvedYearLabel = computed(() => this.yearLabel() || 'Year', ...(ngDevMode ? [{ debugName: "resolvedYearLabel" }] : /* istanbul ignore next */ []));
18979
+ resolvedNavigation = computed(() => ({
18980
+ previousMonth: this.navigation()?.previousMonth ?? true,
18981
+ nextMonth: this.navigation()?.nextMonth ?? true,
18982
+ previousYear: this.navigation()?.previousYear ?? false,
18983
+ nextYear: this.navigation()?.nextYear ?? false,
18984
+ }), ...(ngDevMode ? [{ debugName: "resolvedNavigation" }] : /* istanbul ignore next */ []));
18985
+ monthOptions = computed(() => {
18986
+ const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), { month: 'long' });
18987
+ return Array.from({ length: 12 }, (_, month) => ({
18988
+ label: capitalize$1(formatter.format(new Date(2026, month, 1))),
18989
+ value: String(month),
18990
+ }));
18991
+ }, ...(ngDevMode ? [{ debugName: "monthOptions" }] : /* istanbul ignore next */ []));
18992
+ yearOptions = computed(() => {
18993
+ const [startYear, endYear] = this.yearBounds();
18994
+ return Array.from({ length: endYear - startYear + 1 }, (_, index) => {
18995
+ const year = startYear + index;
18996
+ return { label: String(year), value: String(year) };
18997
+ });
18998
+ }, ...(ngDevMode ? [{ debugName: "yearOptions" }] : /* istanbul ignore next */ []));
18999
+ weekdayLabels = computed(() => {
19000
+ const startDay = this.formatService.firstDayOfWeek();
19001
+ const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), { weekday: 'short' });
19002
+ return Array.from({ length: 7 }, (_, index) => capitalize$1(formatter.format(addDays$1(new Date(2026, 5, 7), startDay + index))));
19003
+ }, ...(ngDevMode ? [{ debugName: "weekdayLabels" }] : /* istanbul ignore next */ []));
19004
+ metaMap = computed(() => {
19005
+ const entries = this.dayMeta()
19006
+ .map((meta) => {
19007
+ const date = normalizeDate(meta.date);
19008
+ return date ? [toDateKey(date), {
19009
+ count: Math.max(0, meta.count ?? 0),
19010
+ tone: meta.tone ?? 'primary',
19011
+ label: meta.label ?? '',
19012
+ }] : null;
19013
+ })
19014
+ .filter((entry) => entry !== null);
19015
+ return new Map(entries);
19016
+ }, ...(ngDevMode ? [{ debugName: "metaMap" }] : /* istanbul ignore next */ []));
19017
+ calendarCells = computed(() => {
19018
+ const month = this.visibleMonth();
19019
+ const firstDay = firstOfMonth$1(month);
19020
+ const startOffset = (firstDay.getDay() - this.formatService.firstDayOfWeek() + 7) % 7;
19021
+ const daysInCurrentMonth = daysInMonth$1(month.getFullYear(), month.getMonth());
19022
+ const gridStart = addDays$1(firstDay, -startOffset);
19023
+ const selectedDate = this.selectedDate();
19024
+ const today = startOfDay$1(new Date());
19025
+ return Array.from({ length: Math.ceil((startOffset + daysInCurrentMonth) / 7) * 7 }, (_, index) => {
19026
+ const date = addDays$1(gridStart, index);
19027
+ return {
19028
+ date,
19029
+ currentMonth: date.getMonth() === month.getMonth(),
19030
+ isToday: sameDate$1(date, today),
19031
+ isSelected: sameDate$1(date, selectedDate),
19032
+ meta: this.metaMap().get(toDateKey(date)) ?? null,
19033
+ };
19034
+ });
19035
+ }, ...(ngDevMode ? [{ debugName: "calendarCells" }] : /* istanbul ignore next */ []));
19036
+ selectedDate = computed(() => normalizeDate(this.valueInput()), ...(ngDevMode ? [{ debugName: "selectedDate" }] : /* istanbul ignore next */ []));
19037
+ visibleMonthValue = computed(() => normalizeMonth(this.visibleMonthInput()), ...(ngDevMode ? [{ debugName: "visibleMonthValue" }] : /* istanbul ignore next */ []));
19038
+ yearBounds = computed(() => {
19039
+ const fallbackYear = new Date().getFullYear();
19040
+ const minYear = this.minYear() ?? fallbackYear - 10;
19041
+ const maxYear = this.maxYear() ?? fallbackYear + 10;
19042
+ return minYear <= maxYear ? [minYear, maxYear] : [maxYear, minYear];
19043
+ }, ...(ngDevMode ? [{ debugName: "yearBounds" }] : /* istanbul ignore next */ []));
19044
+ constructor() {
19045
+ effect(() => {
19046
+ const explicitVisibleMonth = this.visibleMonthValue();
19047
+ const selectedDate = this.selectedDate();
19048
+ if (explicitVisibleMonth) {
19049
+ this.focusedDate.set(this.focusDateForMonth(explicitVisibleMonth, untracked(() => this.focusedDate())));
19050
+ this.visibleMonth.set(explicitVisibleMonth);
19051
+ return;
19052
+ }
19053
+ if (!selectedDate) {
19054
+ return;
19055
+ }
19056
+ this.focusedDate.set(selectedDate);
19057
+ this.visibleMonth.set(firstOfMonth$1(selectedDate));
19058
+ });
19059
+ }
19060
+ dayTemplate() {
19061
+ return this.customDayTemplate();
19062
+ }
19063
+ dayContext(cell) {
19064
+ return { $implicit: cell, cell };
19065
+ }
19066
+ shiftMonth(offset) {
19067
+ this.setVisibleMonth(new Date(this.visibleMonth().getFullYear(), this.visibleMonth().getMonth() + offset, 1));
19068
+ this.focusDateWithinVisibleMonth(this.focusedDate());
19069
+ }
19070
+ shiftYear(offset) {
19071
+ this.setVisibleMonth(new Date(this.visibleMonth().getFullYear() + offset, this.visibleMonth().getMonth(), 1));
19072
+ this.focusDateWithinVisibleMonth(this.focusedDate());
19073
+ }
19074
+ handleMonthChange(value) {
19075
+ const current = this.visibleMonth();
19076
+ this.setVisibleMonth(new Date(current.getFullYear(), Number(value), 1));
19077
+ this.focusDateWithinVisibleMonth(this.focusedDate());
19078
+ }
19079
+ handleYearChange(value) {
19080
+ const current = this.visibleMonth();
19081
+ this.setVisibleMonth(new Date(Number(value), current.getMonth(), 1));
19082
+ this.focusDateWithinVisibleMonth(this.focusedDate());
19083
+ }
19084
+ selectToday() {
19085
+ const today = startOfDay$1(new Date());
19086
+ this.setVisibleMonth(today);
19087
+ this.selectDate(today);
19088
+ }
19089
+ selectDate(date) {
19090
+ const nextValue = startOfDay$1(date);
19091
+ this.focusedDate.set(nextValue);
19092
+ this.setVisibleMonth(nextValue);
19093
+ this.selectionChange.emit(nextValue);
19094
+ }
19095
+ handleDayKeydown(event, date) {
19096
+ let nextDate = null;
19097
+ switch (event.key) {
19098
+ case 'ArrowRight':
19099
+ nextDate = addDays$1(date, 1);
19100
+ break;
19101
+ case 'ArrowLeft':
19102
+ nextDate = addDays$1(date, -1);
19103
+ break;
19104
+ case 'ArrowDown':
19105
+ nextDate = addDays$1(date, 7);
19106
+ break;
19107
+ case 'ArrowUp':
19108
+ nextDate = addDays$1(date, -7);
19109
+ break;
19110
+ case 'Home':
19111
+ nextDate = addDays$1(date, -((date.getDay() - this.formatService.firstDayOfWeek() + 7) % 7));
19112
+ break;
19113
+ case 'End':
19114
+ nextDate = addDays$1(date, 6 - ((date.getDay() - this.formatService.firstDayOfWeek() + 7) % 7));
19115
+ break;
19116
+ case 'Enter':
19117
+ case ' ':
19118
+ event.preventDefault();
19119
+ this.selectDate(date);
19120
+ return;
19121
+ }
19122
+ if (!nextDate) {
19123
+ return;
19124
+ }
19125
+ event.preventDefault();
19126
+ this.focusedDate.set(nextDate);
19127
+ this.setVisibleMonth(nextDate);
19128
+ queueMicrotask(() => this.focusDateButton(nextDate));
19129
+ }
19130
+ isFocusedDate(date) {
19131
+ return sameDate$1(date, this.focusedDate());
19132
+ }
19133
+ dayAriaLabel(cell) {
19134
+ const parts = [new Intl.DateTimeFormat(this.formatService.formatLocale(), {
19135
+ weekday: 'long',
19136
+ day: 'numeric',
19137
+ month: 'long',
19138
+ year: 'numeric',
19139
+ }).format(cell.date)];
19140
+ if (cell.meta?.count) {
19141
+ parts.push(`${cell.meta.count}`);
19142
+ }
19143
+ if (cell.meta?.label) {
19144
+ parts.push(cell.meta.label);
19145
+ }
19146
+ return parts.join('. ');
19147
+ }
19148
+ markerClass(tone) {
19149
+ return `jv-month-calendar-marker--${tone}`;
19150
+ }
19151
+ isoDate(date) {
19152
+ return toDateKey(date);
19153
+ }
19154
+ setVisibleMonth(date) {
19155
+ const month = firstOfMonth$1(date);
19156
+ this.visibleMonth.set(month);
19157
+ this.visibleMonthChange.emit(month);
19158
+ }
19159
+ focusDateWithinVisibleMonth(date) {
19160
+ const nextDate = this.focusDateForMonth(this.visibleMonth(), date);
19161
+ this.focusedDate.set(nextDate);
19162
+ queueMicrotask(() => this.focusDateButton(nextDate));
19163
+ }
19164
+ focusDateForMonth(month, date) {
19165
+ return startOfDay$1(new Date(month.getFullYear(), month.getMonth(), Math.min(date.getDate(), daysInMonth$1(month.getFullYear(), month.getMonth()))));
19166
+ }
19167
+ focusDateButton(date) {
19168
+ const button = this.gridRootRef()?.nativeElement
19169
+ .querySelector(`[data-jv-date="${toDateKey(date)}"]`);
19170
+ button?.focus();
19171
+ }
19172
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvMonthCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19173
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvMonthCalendarComponent, isStandalone: true, selector: "jv-month-calendar", inputs: { valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, visibleMonthInput: { classPropertyName: "visibleMonthInput", publicName: "visibleMonth", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, monthLabel: { classPropertyName: "monthLabel", publicName: "monthLabel", isSignal: true, isRequired: false, transformFunction: null }, yearLabel: { classPropertyName: "yearLabel", publicName: "yearLabel", isSignal: true, isRequired: false, transformFunction: null }, minYear: { classPropertyName: "minYear", publicName: "minYear", isSignal: true, isRequired: false, transformFunction: null }, maxYear: { classPropertyName: "maxYear", publicName: "maxYear", isSignal: true, isRequired: false, transformFunction: null }, navigation: { classPropertyName: "navigation", publicName: "navigation", isSignal: true, isRequired: false, transformFunction: null }, dayMeta: { classPropertyName: "dayMeta", publicName: "dayMeta", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", visibleMonthChange: "visibleMonthChange" }, queries: [{ propertyName: "customDayTemplate", first: true, predicate: JvMonthCalendarDayDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "gridRootRef", first: true, predicate: ["gridRoot"], descendants: true, isSignal: true }], ngImport: i0, template: `
19174
+ <section class="jv-month-calendar" [attr.aria-label]="resolvedAriaLabel()">
19175
+ <div class="jv-month-calendar-toolbar">
19176
+ <div class="jv-month-calendar-nav-group jv-month-calendar-nav-group--start">
19177
+ @if (resolvedNavigation().previousYear) {
19178
+ <jv-icon-button
19179
+ icon="chevrons-left"
19180
+ variant="ghost"
19181
+ [ariaLabel]="translation.translate('monthCalendar.prevYear')"
19182
+ (click)="shiftYear(-1)"
19183
+ />
19184
+ }
19185
+
19186
+ @if (resolvedNavigation().previousMonth) {
19187
+ <jv-icon-button
19188
+ icon="chevron-left"
19189
+ variant="ghost"
19190
+ [ariaLabel]="translation.translate('monthCalendar.prevMonth')"
19191
+ (click)="shiftMonth(-1)"
19192
+ />
19193
+ }
19194
+ </div>
19195
+
19196
+ <div class="jv-month-calendar-selects">
19197
+ <jv-select
19198
+ [options]="monthOptions()"
19199
+ [ariaLabel]="resolvedMonthLabel()"
19200
+ [modelValue]="visibleMonth().getMonth().toString()"
19201
+ (selectionChange)="handleMonthChange($event)"
19202
+ />
19203
+ <jv-select
19204
+ [options]="yearOptions()"
19205
+ [ariaLabel]="resolvedYearLabel()"
19206
+ [modelValue]="visibleMonth().getFullYear().toString()"
19207
+ (selectionChange)="handleYearChange($event)"
19208
+ />
19209
+ </div>
19210
+
19211
+ <div class="jv-month-calendar-nav-group jv-month-calendar-nav-group--end">
19212
+ @if (resolvedNavigation().nextMonth) {
19213
+ <jv-icon-button
19214
+ icon="chevron-right"
19215
+ variant="ghost"
19216
+ [ariaLabel]="translation.translate('monthCalendar.nextMonth')"
19217
+ (click)="shiftMonth(1)"
19218
+ />
19219
+ }
19220
+
19221
+ @if (resolvedNavigation().nextYear) {
19222
+ <jv-icon-button
19223
+ icon="chevrons-right"
19224
+ variant="ghost"
19225
+ [ariaLabel]="translation.translate('monthCalendar.nextYear')"
19226
+ (click)="shiftYear(1)"
19227
+ />
19228
+ }
19229
+ </div>
19230
+ </div>
19231
+
19232
+ <div class="jv-month-calendar-actions">
19233
+ <button type="button" class="jv-month-calendar-today" (click)="selectToday()">
19234
+ {{ translation.translate('monthCalendar.today') }}
19235
+ </button>
19236
+ </div>
19237
+
19238
+ <div class="jv-month-calendar-weekdays" aria-hidden="true">
19239
+ @for (weekday of weekdayLabels(); track weekday) {
19240
+ <span>{{ weekday }}</span>
19241
+ }
19242
+ </div>
19243
+
19244
+ <div #gridRoot class="jv-month-calendar-grid" role="grid" [attr.aria-label]="resolvedAriaLabel()">
19245
+ @for (cell of calendarCells(); track isoDate(cell.date)) {
19246
+ <button
19247
+ type="button"
19248
+ class="jv-month-calendar-day"
19249
+ [class.jv-month-calendar-day--outside]="!cell.currentMonth"
19250
+ [class.jv-month-calendar-day--today]="cell.isToday"
19251
+ [class.jv-month-calendar-day--selected]="cell.isSelected"
19252
+ [attr.aria-selected]="cell.isSelected ? 'true' : 'false'"
19253
+ [attr.aria-label]="dayAriaLabel(cell)"
19254
+ [attr.data-jv-date]="isoDate(cell.date)"
19255
+ [attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
19256
+ (click)="selectDate(cell.date)"
19257
+ (keydown)="handleDayKeydown($event, cell.date)"
19258
+ >
19259
+ @if (dayTemplate()) {
19260
+ <ng-container [ngTemplateOutlet]="dayTemplate()!.templateRef" [ngTemplateOutletContext]="dayContext(cell)" />
19261
+ } @else {
19262
+ <span class="jv-month-calendar-day-number">{{ cell.date.getDate() }}</span>
19263
+ @if (cell.meta?.count) {
19264
+ <span class="jv-month-calendar-day-count" [class]="markerClass(cell.meta!.tone)">{{ cell.meta?.count }}</span>
19265
+ } @else if (cell.meta) {
19266
+ <span class="jv-month-calendar-day-dot" [class]="markerClass(cell.meta.tone)"></span>
19267
+ }
19268
+ }
19269
+ </button>
19270
+ }
19271
+ </div>
19272
+ </section>
19273
+ `, isInline: true, styles: [".jv-month-calendar{display:grid;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-lg);background:var(--jv-color-surface)}.jv-month-calendar-toolbar,.jv-month-calendar-nav-group,.jv-month-calendar-selects,.jv-month-calendar-weekdays,.jv-month-calendar-grid,.jv-month-calendar-actions{display:grid;gap:var(--jv-spacing-sm)}.jv-month-calendar-toolbar{grid-template-columns:auto 1fr auto;align-items:center}.jv-month-calendar-nav-group{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-month-calendar-nav-group--end{justify-content:end}.jv-month-calendar-selects{grid-template-columns:1fr 1fr}.jv-month-calendar-actions{justify-content:end}.jv-month-calendar-today{min-height:2.25rem;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);font:inherit;cursor:pointer}.jv-month-calendar-today:hover,.jv-month-calendar-today:focus-visible{border-color:var(--jv-color-primary);outline:none}.jv-month-calendar-weekdays,.jv-month-calendar-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.jv-month-calendar-weekdays span{text-align:center;font-size:.8125rem;font-weight:600;color:var(--jv-color-foreground-muted)}.jv-month-calendar-day{position:relative;min-height:5rem;display:grid;align-content:start;justify-items:start;gap:var(--jv-spacing-xs);padding:var(--jv-spacing-sm);border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease}.jv-month-calendar-day:hover,.jv-month-calendar-day:focus-visible{background:var(--jv-color-surface-muted);outline:none}.jv-month-calendar-day--outside{color:var(--jv-color-foreground-muted)}.jv-month-calendar-day--today{border-color:var(--jv-color-primary)}.jv-month-calendar-day--selected{background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface));border-color:var(--jv-color-primary)}.jv-month-calendar-day-number{font-weight:700}.jv-month-calendar-day-count,.jv-month-calendar-day-dot{display:inline-flex;align-items:center;justify-content:center;border-radius:999px}.jv-month-calendar-day-count{min-width:1.5rem;min-height:1.5rem;padding:0 .375rem;font-size:.75rem;font-weight:700}.jv-month-calendar-day-dot{width:.5rem;height:.5rem;margin-top:auto}.jv-month-calendar-marker--primary{background:color-mix(in srgb,var(--jv-color-primary) 18%,var(--jv-color-surface));color:var(--jv-color-primary)}.jv-month-calendar-marker--secondary,.jv-month-calendar-marker--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-month-calendar-marker--success{background:color-mix(in srgb,var(--jv-color-success) 18%,var(--jv-color-surface));color:var(--jv-color-success)}.jv-month-calendar-marker--warning{background:color-mix(in srgb,var(--jv-color-warning) 20%,var(--jv-color-surface));color:#8a4b00}.jv-month-calendar-marker--danger{background:color-mix(in srgb,var(--jv-color-danger) 18%,var(--jv-color-surface));color:var(--jv-color-danger)}.jv-month-calendar-marker--info{background:color-mix(in srgb,var(--jv-color-info) 18%,var(--jv-color-surface));color:var(--jv-color-info)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: JvIconButtonComponent, selector: "jv-icon-button", inputs: ["icon", "ariaLabel", "variant", "disabled"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
19274
+ }
19275
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvMonthCalendarComponent, decorators: [{
19276
+ type: Component,
19277
+ args: [{ selector: 'jv-month-calendar', standalone: true, imports: [NgTemplateOutlet, JvIconButtonComponent, JvSelectComponent], template: `
19278
+ <section class="jv-month-calendar" [attr.aria-label]="resolvedAriaLabel()">
19279
+ <div class="jv-month-calendar-toolbar">
19280
+ <div class="jv-month-calendar-nav-group jv-month-calendar-nav-group--start">
19281
+ @if (resolvedNavigation().previousYear) {
19282
+ <jv-icon-button
19283
+ icon="chevrons-left"
19284
+ variant="ghost"
19285
+ [ariaLabel]="translation.translate('monthCalendar.prevYear')"
19286
+ (click)="shiftYear(-1)"
19287
+ />
19288
+ }
19289
+
19290
+ @if (resolvedNavigation().previousMonth) {
19291
+ <jv-icon-button
19292
+ icon="chevron-left"
19293
+ variant="ghost"
19294
+ [ariaLabel]="translation.translate('monthCalendar.prevMonth')"
19295
+ (click)="shiftMonth(-1)"
19296
+ />
19297
+ }
19298
+ </div>
19299
+
19300
+ <div class="jv-month-calendar-selects">
19301
+ <jv-select
19302
+ [options]="monthOptions()"
19303
+ [ariaLabel]="resolvedMonthLabel()"
19304
+ [modelValue]="visibleMonth().getMonth().toString()"
19305
+ (selectionChange)="handleMonthChange($event)"
19306
+ />
19307
+ <jv-select
19308
+ [options]="yearOptions()"
19309
+ [ariaLabel]="resolvedYearLabel()"
19310
+ [modelValue]="visibleMonth().getFullYear().toString()"
19311
+ (selectionChange)="handleYearChange($event)"
19312
+ />
19313
+ </div>
19314
+
19315
+ <div class="jv-month-calendar-nav-group jv-month-calendar-nav-group--end">
19316
+ @if (resolvedNavigation().nextMonth) {
19317
+ <jv-icon-button
19318
+ icon="chevron-right"
19319
+ variant="ghost"
19320
+ [ariaLabel]="translation.translate('monthCalendar.nextMonth')"
19321
+ (click)="shiftMonth(1)"
19322
+ />
19323
+ }
19324
+
19325
+ @if (resolvedNavigation().nextYear) {
19326
+ <jv-icon-button
19327
+ icon="chevrons-right"
19328
+ variant="ghost"
19329
+ [ariaLabel]="translation.translate('monthCalendar.nextYear')"
19330
+ (click)="shiftYear(1)"
19331
+ />
19332
+ }
19333
+ </div>
19334
+ </div>
19335
+
19336
+ <div class="jv-month-calendar-actions">
19337
+ <button type="button" class="jv-month-calendar-today" (click)="selectToday()">
19338
+ {{ translation.translate('monthCalendar.today') }}
19339
+ </button>
19340
+ </div>
19341
+
19342
+ <div class="jv-month-calendar-weekdays" aria-hidden="true">
19343
+ @for (weekday of weekdayLabels(); track weekday) {
19344
+ <span>{{ weekday }}</span>
19345
+ }
19346
+ </div>
19347
+
19348
+ <div #gridRoot class="jv-month-calendar-grid" role="grid" [attr.aria-label]="resolvedAriaLabel()">
19349
+ @for (cell of calendarCells(); track isoDate(cell.date)) {
19350
+ <button
19351
+ type="button"
19352
+ class="jv-month-calendar-day"
19353
+ [class.jv-month-calendar-day--outside]="!cell.currentMonth"
19354
+ [class.jv-month-calendar-day--today]="cell.isToday"
19355
+ [class.jv-month-calendar-day--selected]="cell.isSelected"
19356
+ [attr.aria-selected]="cell.isSelected ? 'true' : 'false'"
19357
+ [attr.aria-label]="dayAriaLabel(cell)"
19358
+ [attr.data-jv-date]="isoDate(cell.date)"
19359
+ [attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
19360
+ (click)="selectDate(cell.date)"
19361
+ (keydown)="handleDayKeydown($event, cell.date)"
19362
+ >
19363
+ @if (dayTemplate()) {
19364
+ <ng-container [ngTemplateOutlet]="dayTemplate()!.templateRef" [ngTemplateOutletContext]="dayContext(cell)" />
19365
+ } @else {
19366
+ <span class="jv-month-calendar-day-number">{{ cell.date.getDate() }}</span>
19367
+ @if (cell.meta?.count) {
19368
+ <span class="jv-month-calendar-day-count" [class]="markerClass(cell.meta!.tone)">{{ cell.meta?.count }}</span>
19369
+ } @else if (cell.meta) {
19370
+ <span class="jv-month-calendar-day-dot" [class]="markerClass(cell.meta.tone)"></span>
19371
+ }
19372
+ }
19373
+ </button>
19374
+ }
19375
+ </div>
19376
+ </section>
19377
+ `, styles: [".jv-month-calendar{display:grid;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-lg);background:var(--jv-color-surface)}.jv-month-calendar-toolbar,.jv-month-calendar-nav-group,.jv-month-calendar-selects,.jv-month-calendar-weekdays,.jv-month-calendar-grid,.jv-month-calendar-actions{display:grid;gap:var(--jv-spacing-sm)}.jv-month-calendar-toolbar{grid-template-columns:auto 1fr auto;align-items:center}.jv-month-calendar-nav-group{display:inline-flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-month-calendar-nav-group--end{justify-content:end}.jv-month-calendar-selects{grid-template-columns:1fr 1fr}.jv-month-calendar-actions{justify-content:end}.jv-month-calendar-today{min-height:2.25rem;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);font:inherit;cursor:pointer}.jv-month-calendar-today:hover,.jv-month-calendar-today:focus-visible{border-color:var(--jv-color-primary);outline:none}.jv-month-calendar-weekdays,.jv-month-calendar-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.jv-month-calendar-weekdays span{text-align:center;font-size:.8125rem;font-weight:600;color:var(--jv-color-foreground-muted)}.jv-month-calendar-day{position:relative;min-height:5rem;display:grid;align-content:start;justify-items:start;gap:var(--jv-spacing-xs);padding:var(--jv-spacing-sm);border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease}.jv-month-calendar-day:hover,.jv-month-calendar-day:focus-visible{background:var(--jv-color-surface-muted);outline:none}.jv-month-calendar-day--outside{color:var(--jv-color-foreground-muted)}.jv-month-calendar-day--today{border-color:var(--jv-color-primary)}.jv-month-calendar-day--selected{background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface));border-color:var(--jv-color-primary)}.jv-month-calendar-day-number{font-weight:700}.jv-month-calendar-day-count,.jv-month-calendar-day-dot{display:inline-flex;align-items:center;justify-content:center;border-radius:999px}.jv-month-calendar-day-count{min-width:1.5rem;min-height:1.5rem;padding:0 .375rem;font-size:.75rem;font-weight:700}.jv-month-calendar-day-dot{width:.5rem;height:.5rem;margin-top:auto}.jv-month-calendar-marker--primary{background:color-mix(in srgb,var(--jv-color-primary) 18%,var(--jv-color-surface));color:var(--jv-color-primary)}.jv-month-calendar-marker--secondary,.jv-month-calendar-marker--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-month-calendar-marker--success{background:color-mix(in srgb,var(--jv-color-success) 18%,var(--jv-color-surface));color:var(--jv-color-success)}.jv-month-calendar-marker--warning{background:color-mix(in srgb,var(--jv-color-warning) 20%,var(--jv-color-surface));color:#8a4b00}.jv-month-calendar-marker--danger{background:color-mix(in srgb,var(--jv-color-danger) 18%,var(--jv-color-surface));color:var(--jv-color-danger)}.jv-month-calendar-marker--info{background:color-mix(in srgb,var(--jv-color-info) 18%,var(--jv-color-surface));color:var(--jv-color-info)}\n"] }]
19378
+ }], ctorParameters: () => [], propDecorators: { gridRootRef: [{ type: i0.ViewChild, args: ['gridRoot', { isSignal: true }] }], customDayTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => JvMonthCalendarDayDirective), { isSignal: true }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], visibleMonthInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleMonth", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], monthLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthLabel", required: false }] }], yearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "yearLabel", required: false }] }], minYear: [{ type: i0.Input, args: [{ isSignal: true, alias: "minYear", required: false }] }], maxYear: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxYear", required: false }] }], navigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigation", required: false }] }], dayMeta: [{ type: i0.Input, args: [{ isSignal: true, alias: "dayMeta", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], visibleMonthChange: [{ type: i0.Output, args: ["visibleMonthChange"] }] } });
19379
+ function normalizeDate(value) {
19380
+ if (!value) {
19381
+ return null;
19382
+ }
19383
+ const date = value instanceof Date ? value : new Date(value);
19384
+ return Number.isNaN(date.getTime()) ? null : startOfDay$1(date);
19385
+ }
19386
+ function normalizeMonth(value) {
19387
+ const date = normalizeDate(value);
19388
+ return date ? firstOfMonth$1(date) : null;
19389
+ }
19390
+ function daysInMonth$1(year, month) {
19391
+ return new Date(year, month + 1, 0).getDate();
19392
+ }
19393
+ function firstOfMonth$1(date) {
19394
+ return new Date(date.getFullYear(), date.getMonth(), 1);
19395
+ }
19396
+ function startOfDay$1(date) {
19397
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
19398
+ }
19399
+ function addDays$1(date, amount) {
19400
+ return startOfDay$1(new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount));
19401
+ }
19402
+ function sameDate$1(left, right) {
19403
+ if (!left || !right) {
19404
+ return false;
19405
+ }
19406
+ return left.getFullYear() === right.getFullYear()
19407
+ && left.getMonth() === right.getMonth()
19408
+ && left.getDate() === right.getDate();
19409
+ }
19410
+ function toDateKey(date) {
19411
+ const year = date.getFullYear();
19412
+ const month = String(date.getMonth() + 1).padStart(2, '0');
19413
+ const day = String(date.getDate()).padStart(2, '0');
19414
+ return `${year}-${month}-${day}`;
19415
+ }
19416
+ function capitalize$1(value) {
19417
+ return value.charAt(0).toUpperCase() + value.slice(1);
19418
+ }
19419
+
19420
+ class JvAlertComponent {
19421
+ tone = input('info', ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
19422
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
19423
+ role = input('status', ...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
19424
+ alertClass = computed(() => `jv-alert--${this.tone()}`, ...(ngDevMode ? [{ debugName: "alertClass" }] : /* istanbul ignore next */ []));
19425
+ iconName = computed(() => {
19426
+ switch (this.tone()) {
19427
+ case 'success':
19428
+ return 'check';
19429
+ case 'warning':
19430
+ return 'triangle-alert';
19431
+ case 'danger':
19432
+ return 'circle-alert';
19433
+ case 'primary':
19434
+ return 'sparkles';
19435
+ case 'secondary':
19436
+ case 'neutral':
19437
+ return 'info';
19438
+ default:
19439
+ return 'info';
19440
+ }
19441
+ }, ...(ngDevMode ? [{ debugName: "iconName" }] : /* istanbul ignore next */ []));
19442
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19443
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvAlertComponent, isStandalone: true, selector: "jv-alert", inputs: { tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
19444
+ <div class="jv-alert" [class]="alertClass()" [attr.role]="role()">
19445
+ <div class="jv-alert-icon">
19446
+ <jv-icon [name]="iconName()" [size]="18" />
19447
+ </div>
19448
+ <div class="jv-alert-content">
19449
+ @if (title()) {
19450
+ <strong>{{ title() }}</strong>
19451
+ }
19452
+ <div><ng-content></ng-content></div>
19453
+ </div>
19454
+ </div>
19455
+ `, isInline: true, styles: [".jv-alert{display:grid;grid-template-columns:auto 1fr;gap:var(--jv-spacing-sm);padding:var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md)}.jv-alert-content{display:grid;gap:var(--jv-spacing-xs)}.jv-alert--primary{background:color-mix(in srgb,var(--jv-color-primary) 10%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-alert--secondary,.jv-alert--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-alert--success{background:color-mix(in srgb,var(--jv-color-success) 12%,var(--jv-color-surface))}.jv-alert--warning{background:color-mix(in srgb,var(--jv-color-warning) 16%,var(--jv-color-surface))}.jv-alert--danger{background:color-mix(in srgb,var(--jv-color-danger) 12%,var(--jv-color-surface))}.jv-alert--info{background:color-mix(in srgb,var(--jv-color-info) 12%,var(--jv-color-surface))}strong{font-size:.95rem}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
19456
+ }
19457
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAlertComponent, decorators: [{
19458
+ type: Component,
19459
+ args: [{ selector: 'jv-alert', standalone: true, imports: [JvIconComponent], template: `
19460
+ <div class="jv-alert" [class]="alertClass()" [attr.role]="role()">
19461
+ <div class="jv-alert-icon">
19462
+ <jv-icon [name]="iconName()" [size]="18" />
19463
+ </div>
19464
+ <div class="jv-alert-content">
19465
+ @if (title()) {
19466
+ <strong>{{ title() }}</strong>
19467
+ }
19468
+ <div><ng-content></ng-content></div>
19469
+ </div>
19470
+ </div>
19471
+ `, styles: [".jv-alert{display:grid;grid-template-columns:auto 1fr;gap:var(--jv-spacing-sm);padding:var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md)}.jv-alert-content{display:grid;gap:var(--jv-spacing-xs)}.jv-alert--primary{background:color-mix(in srgb,var(--jv-color-primary) 10%,var(--jv-color-surface));color:var(--jv-color-foreground)}.jv-alert--secondary,.jv-alert--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-alert--success{background:color-mix(in srgb,var(--jv-color-success) 12%,var(--jv-color-surface))}.jv-alert--warning{background:color-mix(in srgb,var(--jv-color-warning) 16%,var(--jv-color-surface))}.jv-alert--danger{background:color-mix(in srgb,var(--jv-color-danger) 12%,var(--jv-color-surface))}.jv-alert--info{background:color-mix(in srgb,var(--jv-color-info) 12%,var(--jv-color-surface))}strong{font-size:.95rem}\n"] }]
19472
+ }], propDecorators: { tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }] } });
19473
+
19474
+ class JvCardComponent {
19475
+ elevated = input(true, ...(ngDevMode ? [{ debugName: "elevated" }] : /* istanbul ignore next */ []));
19476
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19477
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvCardComponent, isStandalone: true, selector: "jv-card", inputs: { elevated: { classPropertyName: "elevated", publicName: "elevated", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
19478
+ <article class="jv-card" [class]="elevated() ? 'jv-card--elevated' : 'jv-card--flat'">
19479
+ <ng-content></ng-content>
19480
+ </article>
19481
+ `, isInline: true, styles: [".jv-card{padding:var(--jv-spacing-lg);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-lg);background:var(--jv-color-surface)}.jv-card--elevated{box-shadow:var(--jv-shadow-md)}\n"] });
19482
+ }
19483
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCardComponent, decorators: [{
19484
+ type: Component,
19485
+ args: [{ selector: 'jv-card', standalone: true, template: `
19486
+ <article class="jv-card" [class]="elevated() ? 'jv-card--elevated' : 'jv-card--flat'">
19487
+ <ng-content></ng-content>
19488
+ </article>
19489
+ `, styles: [".jv-card{padding:var(--jv-spacing-lg);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-lg);background:var(--jv-color-surface)}.jv-card--elevated{box-shadow:var(--jv-shadow-md)}\n"] }]
19490
+ }], propDecorators: { elevated: [{ type: i0.Input, args: [{ isSignal: true, alias: "elevated", required: false }] }] } });
19491
+
19492
+ class JvFormContainerComponent {
19493
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
19494
+ hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
19495
+ error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
19496
+ inputId = input('', ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
19497
+ hintId = input('', ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
19498
+ errorId = input('', ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
19499
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
19500
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
19501
+ resolvedHintId = computed(() => this.hintId() || (this.inputId() ? `${this.inputId()}-hint` : ''), ...(ngDevMode ? [{ debugName: "resolvedHintId" }] : /* istanbul ignore next */ []));
19502
+ resolvedErrorId = computed(() => this.errorId() || (this.inputId() ? `${this.inputId()}-error` : ''), ...(ngDevMode ? [{ debugName: "resolvedErrorId" }] : /* istanbul ignore next */ []));
19503
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19504
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvFormContainerComponent, isStandalone: true, selector: "jv-form-container", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, hintId: { classPropertyName: "hintId", publicName: "hintId", isSignal: true, isRequired: false, transformFunction: null }, errorId: { classPropertyName: "errorId", publicName: "errorId", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
19505
+ <div class="jv-form-container" [class.is-invalid]="invalid()">
19506
+ @if (label()) {
19507
+ <label class="jv-form-label" [attr.for]="inputId() || null">
19508
+ <span>{{ label() }}</span>
19509
+ @if (required()) {
19510
+ <span class="required-indicator" aria-hidden="true">*</span>
19511
+ }
19512
+ </label>
19513
+ }
19514
+
19515
+ <ng-content></ng-content>
19516
+
19517
+ @if (hint() && !invalid()) {
19518
+ <p class="jv-form-hint" [id]="resolvedHintId() || null">{{ hint() }}</p>
19519
+ }
19520
+
19521
+ @if (error() && invalid()) {
19522
+ <p class="jv-form-error" [id]="resolvedErrorId() || null" role="alert" aria-live="assertive">{{ error() }}</p>
19523
+ }
19524
+ </div>
19525
+ `, isInline: true, styles: [".jv-form-container{display:grid;gap:var(--jv-spacing-xs)}.jv-form-label{display:inline-flex;align-items:center;gap:.35rem;font-weight:600;color:var(--jv-color-foreground)}.required-indicator,.jv-form-error{color:var(--jv-color-danger)}.jv-form-hint,.jv-form-error{margin:0;font-size:.875rem}.jv-form-hint{color:var(--jv-color-foreground-muted)}\n"] });
19526
+ }
19527
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormContainerComponent, decorators: [{
19528
+ type: Component,
19529
+ args: [{ selector: 'jv-form-container', standalone: true, template: `
19530
+ <div class="jv-form-container" [class.is-invalid]="invalid()">
19531
+ @if (label()) {
19532
+ <label class="jv-form-label" [attr.for]="inputId() || null">
19533
+ <span>{{ label() }}</span>
19534
+ @if (required()) {
19535
+ <span class="required-indicator" aria-hidden="true">*</span>
19536
+ }
19537
+ </label>
19538
+ }
19539
+
19540
+ <ng-content></ng-content>
19541
+
19542
+ @if (hint() && !invalid()) {
19543
+ <p class="jv-form-hint" [id]="resolvedHintId() || null">{{ hint() }}</p>
19544
+ }
19545
+
19546
+ @if (error() && invalid()) {
19547
+ <p class="jv-form-error" [id]="resolvedErrorId() || null" role="alert" aria-live="assertive">{{ error() }}</p>
19548
+ }
19549
+ </div>
19550
+ `, styles: [".jv-form-container{display:grid;gap:var(--jv-spacing-xs)}.jv-form-label{display:inline-flex;align-items:center;gap:.35rem;font-weight:600;color:var(--jv-color-foreground)}.required-indicator,.jv-form-error{color:var(--jv-color-danger)}.jv-form-hint,.jv-form-error{margin:0;font-size:.875rem}.jv-form-hint{color:var(--jv-color-foreground-muted)}\n"] }]
19551
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], hintId: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintId", required: false }] }], errorId: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorId", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }] } });
19552
+
19553
+ let inputIdSequence = 0;
19554
+ class JvInputComponent {
19555
+ type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
19556
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
19557
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
19558
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
19559
+ describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
19560
+ inputId = input(`jv-input-${++inputIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
19561
+ value = '';
19562
+ disabled = false;
19563
+ onChange = () => undefined;
19564
+ onTouched = () => undefined;
19565
+ writeValue(value) {
19566
+ this.value = value ?? '';
19567
+ }
19568
+ registerOnChange(fn) {
19569
+ this.onChange = fn;
19570
+ }
19571
+ registerOnTouched(fn) {
19572
+ this.onTouched = fn;
19573
+ }
19574
+ setDisabledState(isDisabled) {
19575
+ this.disabled = isDisabled;
19576
+ }
19577
+ handleInput(event) {
19578
+ const nextValue = event.target.value;
19579
+ this.value = nextValue;
19580
+ this.onChange(nextValue);
19581
+ }
19582
+ handleBlur() {
19583
+ this.onTouched();
19584
+ }
19585
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19586
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvInputComponent, isStandalone: true, selector: "jv-input", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "describedBy", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
19587
+ {
19588
+ provide: NG_VALUE_ACCESSOR,
19589
+ useExisting: forwardRef(() => JvInputComponent),
19590
+ multi: true,
19591
+ },
19592
+ ], ngImport: i0, template: `
19593
+ <input
19594
+ class="jv-input"
19595
+ [class.is-invalid]="invalid()"
19596
+ [id]="inputId()"
19597
+ [type]="type()"
19598
+ [value]="value"
19599
+ [placeholder]="placeholder()"
19600
+ [required]="required()"
19601
+ [disabled]="disabled"
19602
+ [attr.aria-invalid]="invalid() ? 'true' : null"
19603
+ [attr.aria-describedby]="describedBy() || null"
19604
+ (input)="handleInput($event)"
19605
+ (blur)="handleBlur()"
19606
+ />
19607
+ `, isInline: true, styles: [".jv-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-input::placeholder{color:var(--jv-color-foreground-muted)}.jv-input.is-invalid{border-color:var(--jv-color-danger)}.jv-input:disabled{opacity:.7;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
19608
+ }
19609
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvInputComponent, decorators: [{
19610
+ type: Component,
19611
+ args: [{ selector: 'jv-input', standalone: true, imports: [CommonModule], providers: [
19612
+ {
19613
+ provide: NG_VALUE_ACCESSOR,
19614
+ useExisting: forwardRef(() => JvInputComponent),
19615
+ multi: true,
19616
+ },
19617
+ ], template: `
19618
+ <input
19619
+ class="jv-input"
19620
+ [class.is-invalid]="invalid()"
19621
+ [id]="inputId()"
19622
+ [type]="type()"
19623
+ [value]="value"
19624
+ [placeholder]="placeholder()"
19625
+ [required]="required()"
19626
+ [disabled]="disabled"
19627
+ [attr.aria-invalid]="invalid() ? 'true' : null"
19628
+ [attr.aria-describedby]="describedBy() || null"
19629
+ (input)="handleInput($event)"
19630
+ (blur)="handleBlur()"
19631
+ />
19632
+ `, styles: [".jv-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-input::placeholder{color:var(--jv-color-foreground-muted)}.jv-input.is-invalid{border-color:var(--jv-color-danger)}.jv-input:disabled{opacity:.7;cursor:not-allowed}\n"] }]
19633
+ }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }] } });
19634
+
19635
+ class JvSectionComponent {
19636
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
19637
+ description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
19638
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19639
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvSectionComponent, isStandalone: true, selector: "jv-section", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
19640
+ <section class="jv-section">
19641
+ @if (title() || description()) {
19642
+ <header class="jv-section-header">
19643
+ @if (title()) {
19644
+ <h2>{{ title() }}</h2>
19645
+ }
19646
+ @if (description()) {
19647
+ <p>{{ description() }}</p>
19648
+ }
19649
+ </header>
19650
+ }
19651
+ <div class="jv-section-content"><ng-content></ng-content></div>
19652
+ </section>
19653
+ `, isInline: true, styles: [".jv-section{display:grid;gap:var(--jv-spacing-md)}.jv-section-header{display:grid;gap:var(--jv-spacing-xs)}h2,p{margin:0}p{color:var(--jv-color-foreground-muted)}\n"] });
19654
+ }
19655
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSectionComponent, decorators: [{
19656
+ type: Component,
19657
+ args: [{ selector: 'jv-section', standalone: true, template: `
19658
+ <section class="jv-section">
19659
+ @if (title() || description()) {
19660
+ <header class="jv-section-header">
19661
+ @if (title()) {
19662
+ <h2>{{ title() }}</h2>
19663
+ }
19664
+ @if (description()) {
19665
+ <p>{{ description() }}</p>
19666
+ }
19667
+ </header>
19668
+ }
19669
+ <div class="jv-section-content"><ng-content></ng-content></div>
19670
+ </section>
19671
+ `, styles: [".jv-section{display:grid;gap:var(--jv-spacing-md)}.jv-section-header{display:grid;gap:var(--jv-spacing-xs)}h2,p{margin:0}p{color:var(--jv-color-foreground-muted)}\n"] }]
19672
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
19673
+
19674
+ function passwordMatchValidator(control) {
19675
+ const newPassword = control.get('newPassword')?.value;
19676
+ const confirmPassword = control.get('confirmPassword')?.value;
19677
+ if (!newPassword || !confirmPassword) {
19678
+ return null;
19679
+ }
19680
+ return newPassword === confirmPassword ? null : { passwordMismatch: true };
19681
+ }
19682
+ class JvChangePasswordPageComponent {
19683
+ formBuilder = inject(FormBuilder);
19684
+ title = input('Change password', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
19685
+ description = input('Update your password and keep your account secure.', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
19686
+ submitLabel = input('Update password', ...(ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []));
19687
+ cancelLabel = input('Cancel', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []));
19688
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
19689
+ error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
19690
+ changePasswordSubmit = output();
19691
+ cancel = output();
19692
+ form = this.formBuilder.group({
19693
+ currentPassword: ['', Validators.required],
19694
+ newPassword: ['', Validators.required],
19695
+ confirmPassword: ['', Validators.required],
19696
+ }, { validators: passwordMatchValidator });
19697
+ currentInvalid = computed(() => {
19698
+ const control = this.form.controls.currentPassword;
19699
+ return control.invalid && (control.touched || control.dirty);
19700
+ }, ...(ngDevMode ? [{ debugName: "currentInvalid" }] : /* istanbul ignore next */ []));
19701
+ newInvalid = computed(() => {
19702
+ const control = this.form.controls.newPassword;
19703
+ return control.invalid && (control.touched || control.dirty);
19704
+ }, ...(ngDevMode ? [{ debugName: "newInvalid" }] : /* istanbul ignore next */ []));
19705
+ confirmInvalid = computed(() => {
19706
+ const control = this.form.controls.confirmPassword;
19707
+ return (control.invalid && (control.touched || control.dirty)) || ((control.touched || control.dirty) && this.form.hasError('passwordMismatch'));
19708
+ }, ...(ngDevMode ? [{ debugName: "confirmInvalid" }] : /* istanbul ignore next */ []));
19709
+ submit() {
19710
+ if (this.form.invalid) {
19711
+ this.form.markAllAsTouched();
19712
+ return;
19713
+ }
19714
+ this.changePasswordSubmit.emit(this.form.getRawValue());
19715
+ }
19716
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvChangePasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19717
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvChangePasswordPageComponent, isStandalone: true, selector: "jv-change-password-page", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, submitLabel: { classPropertyName: "submitLabel", publicName: "submitLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changePasswordSubmit: "changePasswordSubmit", cancel: "cancel" }, ngImport: i0, template: `
19718
+ <jv-card>
19719
+ <jv-section [title]="title()" [description]="description()">
19720
+ @if (error()) {
19721
+ <jv-alert tone="danger" title="Password change error" role="alert">{{ error() }}</jv-alert>
19722
+ }
19723
+
19724
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19725
+ <jv-form-container label="Current password" inputId="jv-current-password" error="Current password is required" [required]="true" [invalid]="currentInvalid()">
19726
+ <jv-input inputId="jv-current-password" type="password" formControlName="currentPassword" [invalid]="currentInvalid()" />
19727
+ </jv-form-container>
19728
+
19729
+ <jv-form-container label="New password" inputId="jv-new-password" error="New password is required" [required]="true" [invalid]="newInvalid()">
19730
+ <jv-input inputId="jv-new-password" type="password" formControlName="newPassword" [invalid]="newInvalid()" />
19731
+ </jv-form-container>
19732
+
19733
+ <jv-form-container label="Confirm new password" inputId="jv-confirm-password" error="Passwords must match" [required]="true" [invalid]="confirmInvalid()">
19734
+ <jv-input inputId="jv-confirm-password" type="password" formControlName="confirmPassword" [invalid]="confirmInvalid()" />
19735
+ </jv-form-container>
19736
+
19737
+ <div class="auth-actions">
19738
+ <jv-button variant="outline" (click)="cancel.emit()">{{ cancelLabel() }}</jv-button>
19739
+ <jv-button variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19740
+ </div>
19741
+ </form>
19742
+ </jv-section>
19743
+ </jv-card>
19744
+ `, isInline: true, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: JvAlertComponent, selector: "jv-alert", inputs: ["tone", "title", "role"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvCardComponent, selector: "jv-card", inputs: ["elevated"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvSectionComponent, selector: "jv-section", inputs: ["title", "description"] }] });
19745
+ }
19746
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvChangePasswordPageComponent, decorators: [{
19747
+ type: Component,
19748
+ args: [{ selector: 'jv-change-password-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
19749
+ <jv-card>
19750
+ <jv-section [title]="title()" [description]="description()">
19751
+ @if (error()) {
19752
+ <jv-alert tone="danger" title="Password change error" role="alert">{{ error() }}</jv-alert>
19753
+ }
19754
+
19755
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19756
+ <jv-form-container label="Current password" inputId="jv-current-password" error="Current password is required" [required]="true" [invalid]="currentInvalid()">
19757
+ <jv-input inputId="jv-current-password" type="password" formControlName="currentPassword" [invalid]="currentInvalid()" />
19758
+ </jv-form-container>
19759
+
19760
+ <jv-form-container label="New password" inputId="jv-new-password" error="New password is required" [required]="true" [invalid]="newInvalid()">
19761
+ <jv-input inputId="jv-new-password" type="password" formControlName="newPassword" [invalid]="newInvalid()" />
19762
+ </jv-form-container>
19763
+
19764
+ <jv-form-container label="Confirm new password" inputId="jv-confirm-password" error="Passwords must match" [required]="true" [invalid]="confirmInvalid()">
19765
+ <jv-input inputId="jv-confirm-password" type="password" formControlName="confirmPassword" [invalid]="confirmInvalid()" />
19766
+ </jv-form-container>
19767
+
19768
+ <div class="auth-actions">
19769
+ <jv-button variant="outline" (click)="cancel.emit()">{{ cancelLabel() }}</jv-button>
19770
+ <jv-button variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19771
+ </div>
19772
+ </form>
19773
+ </jv-section>
19774
+ </jv-card>
19775
+ `, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"] }]
19776
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], submitLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitLabel", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], changePasswordSubmit: [{ type: i0.Output, args: ["changePasswordSubmit"] }], cancel: [{ type: i0.Output, args: ["cancel"] }] } });
19777
+
19778
+ class JvForgotPasswordPageComponent {
19779
+ formBuilder = inject(FormBuilder);
19780
+ title = input('Reset your password', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
19781
+ description = input('We will send reset instructions to your email address.', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
19782
+ submitLabel = input('Send reset link', ...(ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []));
19783
+ backLabel = input('Back to login', ...(ngDevMode ? [{ debugName: "backLabel" }] : /* istanbul ignore next */ []));
19784
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
19785
+ error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
19786
+ forgotPasswordSubmit = output();
19787
+ backToLogin = output();
19788
+ form = this.formBuilder.group({
19789
+ email: ['', [Validators.required, Validators.email]],
19790
+ });
19791
+ emailInvalid = computed(() => {
19792
+ const control = this.form.controls.email;
19793
+ return control.invalid && (control.touched || control.dirty);
19794
+ }, ...(ngDevMode ? [{ debugName: "emailInvalid" }] : /* istanbul ignore next */ []));
19795
+ submit() {
19796
+ if (this.form.invalid) {
19797
+ this.form.markAllAsTouched();
19798
+ return;
19799
+ }
19800
+ this.forgotPasswordSubmit.emit(this.form.getRawValue());
19801
+ }
19802
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvForgotPasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19803
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvForgotPasswordPageComponent, isStandalone: true, selector: "jv-forgot-password-page", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, submitLabel: { classPropertyName: "submitLabel", publicName: "submitLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { forgotPasswordSubmit: "forgotPasswordSubmit", backToLogin: "backToLogin" }, ngImport: i0, template: `
19804
+ <jv-card>
19805
+ <jv-section [title]="title()" [description]="description()">
19806
+ @if (error()) {
19807
+ <jv-alert tone="danger" title="Reset error" role="alert">{{ error() }}</jv-alert>
19808
+ }
19809
+
19810
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19811
+ <jv-form-container label="Email" inputId="jv-forgot-email" error="Enter a valid email" [required]="true" [invalid]="emailInvalid()">
19812
+ <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" placeholder="you@example.com" />
19813
+ </jv-form-container>
19814
+
19815
+ <div class="auth-actions">
19816
+ <jv-button variant="outline" (click)="backToLogin.emit()">{{ backLabel() }}</jv-button>
19817
+ <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19818
+ </div>
19819
+ </form>
19820
+ </jv-section>
19821
+ </jv-card>
19822
+ `, isInline: true, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: JvAlertComponent, selector: "jv-alert", inputs: ["tone", "title", "role"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvCardComponent, selector: "jv-card", inputs: ["elevated"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvSectionComponent, selector: "jv-section", inputs: ["title", "description"] }] });
19823
+ }
19824
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvForgotPasswordPageComponent, decorators: [{
19825
+ type: Component,
19826
+ args: [{ selector: 'jv-forgot-password-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
19827
+ <jv-card>
19828
+ <jv-section [title]="title()" [description]="description()">
19829
+ @if (error()) {
19830
+ <jv-alert tone="danger" title="Reset error" role="alert">{{ error() }}</jv-alert>
19831
+ }
19832
+
19833
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19834
+ <jv-form-container label="Email" inputId="jv-forgot-email" error="Enter a valid email" [required]="true" [invalid]="emailInvalid()">
19835
+ <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" placeholder="you@example.com" />
19836
+ </jv-form-container>
19837
+
19838
+ <div class="auth-actions">
19839
+ <jv-button variant="outline" (click)="backToLogin.emit()">{{ backLabel() }}</jv-button>
19840
+ <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19841
+ </div>
19842
+ </form>
19843
+ </jv-section>
19844
+ </jv-card>
19845
+ `, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"] }]
19846
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], submitLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitLabel", required: false }] }], backLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "backLabel", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], forgotPasswordSubmit: [{ type: i0.Output, args: ["forgotPasswordSubmit"] }], backToLogin: [{ type: i0.Output, args: ["backToLogin"] }] } });
19847
+
19848
+ let checkboxIdSequence = 0;
19849
+ class JvCheckboxComponent {
19850
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
19851
+ describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
19852
+ inputId = input(`jv-checkbox-${++checkboxIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
19853
+ value = false;
19854
+ disabled = false;
19855
+ onChange = () => undefined;
19856
+ onTouched = () => undefined;
19857
+ writeValue(value) {
19858
+ this.value = value ?? false;
19859
+ }
19860
+ registerOnChange(fn) {
19861
+ this.onChange = fn;
19862
+ }
19863
+ registerOnTouched(fn) {
19864
+ this.onTouched = fn;
19865
+ }
19866
+ setDisabledState(isDisabled) {
19867
+ this.disabled = isDisabled;
19868
+ }
19869
+ handleChange(event) {
19870
+ const nextValue = event.target.checked;
19871
+ this.value = nextValue;
19872
+ this.onChange(nextValue);
19873
+ }
19874
+ handleBlur() {
19875
+ this.onTouched();
19876
+ }
19877
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19878
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvCheckboxComponent, isStandalone: true, selector: "jv-checkbox", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "describedBy", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
19879
+ {
19880
+ provide: NG_VALUE_ACCESSOR,
19881
+ useExisting: forwardRef(() => JvCheckboxComponent),
19882
+ multi: true,
19883
+ },
19884
+ ], ngImport: i0, template: `
19885
+ <label class="jv-checkbox" [class.is-disabled]="disabled">
19886
+ <input
19887
+ type="checkbox"
19888
+ [id]="inputId()"
19889
+ [checked]="value"
19890
+ [disabled]="disabled"
19891
+ [attr.aria-describedby]="describedBy() || null"
19892
+ (change)="handleChange($event)"
19893
+ (blur)="handleBlur()"
19894
+ />
19895
+ <span>{{ label() }}</span>
19896
+ </label>
19897
+ `, isInline: true, styles: [".jv-checkbox{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);min-height:var(--jv-density-control-height);color:var(--jv-color-foreground)}.jv-checkbox.is-disabled{opacity:.7}\n"] });
19898
+ }
19899
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCheckboxComponent, decorators: [{
19900
+ type: Component,
19901
+ args: [{ selector: 'jv-checkbox', standalone: true, providers: [
19902
+ {
19903
+ provide: NG_VALUE_ACCESSOR,
19904
+ useExisting: forwardRef(() => JvCheckboxComponent),
19905
+ multi: true,
19906
+ },
19907
+ ], template: `
19908
+ <label class="jv-checkbox" [class.is-disabled]="disabled">
19909
+ <input
19910
+ type="checkbox"
19911
+ [id]="inputId()"
19912
+ [checked]="value"
19913
+ [disabled]="disabled"
19914
+ [attr.aria-describedby]="describedBy() || null"
19915
+ (change)="handleChange($event)"
19916
+ (blur)="handleBlur()"
19917
+ />
19918
+ <span>{{ label() }}</span>
19919
+ </label>
19920
+ `, styles: [".jv-checkbox{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);min-height:var(--jv-density-control-height);color:var(--jv-color-foreground)}.jv-checkbox.is-disabled{opacity:.7}\n"] }]
19921
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }] } });
19922
+
19923
+ class JvLoginPageComponent {
19924
+ formBuilder = inject(FormBuilder);
19925
+ title = input('Welcome back', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
19926
+ description = input('Use your account credentials to continue.', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
19927
+ submitLabel = input('Sign in', ...(ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []));
19928
+ rememberMeLabel = input('Remember me', ...(ngDevMode ? [{ debugName: "rememberMeLabel" }] : /* istanbul ignore next */ []));
19929
+ forgotPasswordLabel = input('Forgot password?', ...(ngDevMode ? [{ debugName: "forgotPasswordLabel" }] : /* istanbul ignore next */ []));
19930
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
19931
+ error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
19932
+ loginSubmit = output();
19933
+ forgotPasswordClick = output();
19934
+ form = this.formBuilder.group({
19935
+ identifier: ['', Validators.required],
19936
+ password: ['', Validators.required],
19937
+ rememberMe: [false],
19938
+ });
19939
+ identifierInvalid = computed(() => {
19940
+ const control = this.form.controls.identifier;
19941
+ return control.invalid && (control.touched || control.dirty);
19942
+ }, ...(ngDevMode ? [{ debugName: "identifierInvalid" }] : /* istanbul ignore next */ []));
19943
+ passwordInvalid = computed(() => {
19944
+ const control = this.form.controls.password;
19945
+ return control.invalid && (control.touched || control.dirty);
19946
+ }, ...(ngDevMode ? [{ debugName: "passwordInvalid" }] : /* istanbul ignore next */ []));
19947
+ submit() {
19948
+ if (this.form.invalid) {
19949
+ this.form.markAllAsTouched();
19950
+ return;
19951
+ }
19952
+ this.loginSubmit.emit(this.form.getRawValue());
19953
+ }
19954
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvLoginPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19955
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvLoginPageComponent, isStandalone: true, selector: "jv-login-page", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, submitLabel: { classPropertyName: "submitLabel", publicName: "submitLabel", isSignal: true, isRequired: false, transformFunction: null }, rememberMeLabel: { classPropertyName: "rememberMeLabel", publicName: "rememberMeLabel", isSignal: true, isRequired: false, transformFunction: null }, forgotPasswordLabel: { classPropertyName: "forgotPasswordLabel", publicName: "forgotPasswordLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loginSubmit: "loginSubmit", forgotPasswordClick: "forgotPasswordClick" }, ngImport: i0, template: `
19956
+ <jv-card>
19957
+ <jv-section [title]="title()" [description]="description()">
19958
+ @if (error()) {
19959
+ <jv-alert tone="danger" title="Sign-in error" role="alert">{{ error() }}</jv-alert>
19960
+ }
19961
+
19962
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19963
+ <jv-form-container label="Email or username" inputId="jv-login-identifier" error="This field is required" [required]="true" [invalid]="identifierInvalid()">
19964
+ <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" placeholder="you@example.com" />
19965
+ </jv-form-container>
19966
+
19967
+ <jv-form-container label="Password" inputId="jv-login-password" error="Password is required" [required]="true" [invalid]="passwordInvalid()">
19968
+ <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" placeholder="Enter your password" />
19969
+ </jv-form-container>
19970
+
19971
+ <div class="auth-inline-row">
19972
+ <jv-checkbox formControlName="rememberMe" label="{{ rememberMeLabel() }}" />
19973
+ <button type="button" class="auth-link" (click)="forgotPasswordClick.emit()">{{ forgotPasswordLabel() }}</button>
19974
+ </div>
19975
+
19976
+ <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19977
+ </form>
19978
+ </jv-section>
19979
+ </jv-card>
19980
+ `, isInline: true, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-inline-row{display:flex;justify-content:space-between;align-items:center;gap:var(--jv-spacing-md);flex-wrap:wrap}.auth-link{border:0;padding:0;background:transparent;color:var(--jv-color-primary);text-decoration:underline;text-underline-offset:.18em}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: JvAlertComponent, selector: "jv-alert", inputs: ["tone", "title", "role"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvCardComponent, selector: "jv-card", inputs: ["elevated"] }, { kind: "component", type: JvCheckboxComponent, selector: "jv-checkbox", inputs: ["label", "describedBy", "inputId"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvSectionComponent, selector: "jv-section", inputs: ["title", "description"] }] });
19981
+ }
19982
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvLoginPageComponent, decorators: [{
19983
+ type: Component,
19984
+ args: [{ selector: 'jv-login-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvCheckboxComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
19985
+ <jv-card>
19986
+ <jv-section [title]="title()" [description]="description()">
19987
+ @if (error()) {
19988
+ <jv-alert tone="danger" title="Sign-in error" role="alert">{{ error() }}</jv-alert>
19989
+ }
19990
+
19991
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19992
+ <jv-form-container label="Email or username" inputId="jv-login-identifier" error="This field is required" [required]="true" [invalid]="identifierInvalid()">
19993
+ <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" placeholder="you@example.com" />
19994
+ </jv-form-container>
19995
+
19996
+ <jv-form-container label="Password" inputId="jv-login-password" error="Password is required" [required]="true" [invalid]="passwordInvalid()">
19997
+ <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" placeholder="Enter your password" />
19998
+ </jv-form-container>
19999
+
20000
+ <div class="auth-inline-row">
20001
+ <jv-checkbox formControlName="rememberMe" label="{{ rememberMeLabel() }}" />
20002
+ <button type="button" class="auth-link" (click)="forgotPasswordClick.emit()">{{ forgotPasswordLabel() }}</button>
20003
+ </div>
20004
+
20005
+ <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
20006
+ </form>
20007
+ </jv-section>
20008
+ </jv-card>
20009
+ `, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-inline-row{display:flex;justify-content:space-between;align-items:center;gap:var(--jv-spacing-md);flex-wrap:wrap}.auth-link{border:0;padding:0;background:transparent;color:var(--jv-color-primary);text-decoration:underline;text-underline-offset:.18em}\n"] }]
20010
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], submitLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitLabel", required: false }] }], rememberMeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rememberMeLabel", required: false }] }], forgotPasswordLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "forgotPasswordLabel", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], loginSubmit: [{ type: i0.Output, args: ["loginSubmit"] }], forgotPasswordClick: [{ type: i0.Output, args: ["forgotPasswordClick"] }] } });
20011
+
20012
+ class JvDividerComponent {
20013
+ vertical = input(false, ...(ngDevMode ? [{ debugName: "vertical" }] : /* istanbul ignore next */ []));
20014
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDividerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
20015
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvDividerComponent, isStandalone: true, selector: "jv-divider", inputs: { vertical: { classPropertyName: "vertical", publicName: "vertical", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
20016
+ <div
20017
+ class="jv-divider"
20018
+ [class.jv-divider--vertical]="vertical()"
20019
+ [attr.role]="'separator'"
20020
+ [attr.aria-orientation]="vertical() ? 'vertical' : 'horizontal'"
20021
+ ></div>
20022
+ `, isInline: true, styles: [".jv-divider{width:100%;height:1px;background:var(--jv-color-border)}.jv-divider--vertical{width:1px;height:100%;min-height:1.5rem}\n"] });
20023
+ }
20024
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDividerComponent, decorators: [{
20025
+ type: Component,
20026
+ args: [{ selector: 'jv-divider', standalone: true, template: `
20027
+ <div
20028
+ class="jv-divider"
20029
+ [class.jv-divider--vertical]="vertical()"
20030
+ [attr.role]="'separator'"
20031
+ [attr.aria-orientation]="vertical() ? 'vertical' : 'horizontal'"
20032
+ ></div>
20033
+ `, styles: [".jv-divider{width:100%;height:1px;background:var(--jv-color-border)}.jv-divider--vertical{width:1px;height:100%;min-height:1.5rem}\n"] }]
20034
+ }], propDecorators: { vertical: [{ type: i0.Input, args: [{ isSignal: true, alias: "vertical", required: false }] }] } });
19111
20035
 
19112
- class JvTranslationService {
19113
- config = inject(JvUiConfigService);
19114
- locale = signal(this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale), ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
19115
- initialize() {
19116
- const locale = this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale);
19117
- this.locale.set(locale);
19118
- }
19119
- setLocale(locale) {
19120
- this.locale.set(locale);
19121
- }
19122
- setMessagesLocale(locale) {
19123
- this.setLocale(locale);
20036
+ class JvAccordionPanelDirective {
20037
+ templateRef;
20038
+ id = input.required({ ...(ngDevMode ? { debugName: "id" } : /* istanbul ignore next */ {}), alias: 'jvAccordionPanel' });
20039
+ constructor(templateRef) {
20040
+ this.templateRef = templateRef;
19124
20041
  }
19125
- translate(key, params) {
19126
- const dict = JV_LOCALE_DICTIONARIES[this.locale()] ?? JV_LOCALE_DICTIONARIES[JV_DEFAULT_LOCALE];
19127
- let value = dict[key];
19128
- if (value === undefined) {
19129
- value = JV_LOCALE_DICTIONARIES[JV_DEFAULT_LOCALE][key] ?? key;
19130
- }
19131
- if (params) {
19132
- for (const [k, v] of Object.entries(params)) {
19133
- value = value.replace(`{${k}}`, String(v));
19134
- }
20042
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAccordionPanelDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
20043
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.17", type: JvAccordionPanelDirective, isStandalone: true, selector: "ng-template[jvAccordionPanel]", inputs: { id: { classPropertyName: "id", publicName: "jvAccordionPanel", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
20044
+ }
20045
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAccordionPanelDirective, decorators: [{
20046
+ type: Directive,
20047
+ args: [{
20048
+ selector: 'ng-template[jvAccordionPanel]',
20049
+ standalone: true,
20050
+ }]
20051
+ }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "jvAccordionPanel", required: true }] }] } });
20052
+
20053
+ class JvAnnouncementService {
20054
+ document = inject(DOCUMENT);
20055
+ region = null;
20056
+ announce(message, politeness = 'polite') {
20057
+ if (!message.trim()) {
20058
+ return;
19135
20059
  }
19136
- return value;
20060
+ const region = this.ensureRegion(politeness);
20061
+ region.textContent = '';
20062
+ // Clear and reinsert so NVDA reliably reads repeated updates.
20063
+ setTimeout(() => {
20064
+ region.textContent = message;
20065
+ }, 20);
19137
20066
  }
19138
- resolveLocale(locale) {
19139
- if (!locale)
19140
- return JV_DEFAULT_LOCALE;
19141
- if (locale === 'es' || locale === 'en')
19142
- return locale;
19143
- return locale.startsWith('es') ? 'es' : 'en';
20067
+ ensureRegion(politeness) {
20068
+ if (!this.region) {
20069
+ const region = this.document.createElement('div');
20070
+ region.className = 'sr-only';
20071
+ region.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');
20072
+ region.setAttribute('aria-live', politeness);
20073
+ region.setAttribute('aria-atomic', 'true');
20074
+ this.document.body.appendChild(region);
20075
+ this.region = region;
20076
+ return region;
20077
+ }
20078
+ this.region.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');
20079
+ this.region.setAttribute('aria-live', politeness);
20080
+ return this.region;
19144
20081
  }
19145
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
19146
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, providedIn: 'root' });
20082
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAnnouncementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
20083
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAnnouncementService, providedIn: 'root' });
19147
20084
  }
19148
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, decorators: [{
20085
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAnnouncementService, decorators: [{
19149
20086
  type: Injectable,
19150
20087
  args: [{ providedIn: 'root' }]
19151
20088
  }] });
@@ -19396,17 +20333,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
19396
20333
  `, styles: [".jv-accordion{display:grid;gap:var(--jv-spacing-sm)}\n"] }]
19397
20334
  }], ctorParameters: () => [], propDecorators: { panelTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => JvAccordionPanelDirective), { isSignal: true }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], openItemIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openItemIds", required: false }] }], defaultOpenItemIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpenItemIds", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], keepMounted: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepMounted", required: false }] }], showIndicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIndicator", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], openItemIdsChange: [{ type: i0.Output, args: ["openItemIdsChange"] }] } });
19398
20335
 
19399
- class JvBadgeComponent {
19400
- tone = input('primary', ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
19401
- badgeClass = computed(() => `jv-badge--${this.tone()}`, ...(ngDevMode ? [{ debugName: "badgeClass" }] : /* istanbul ignore next */ []));
19402
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19403
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvBadgeComponent, isStandalone: true, selector: "jv-badge", inputs: { tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `<span class="jv-badge" [class]="badgeClass()"><ng-content></ng-content></span>`, isInline: true, styles: [".jv-badge{display:inline-flex;align-items:center;justify-content:center;min-height:1.75rem;padding:0 var(--jv-spacing-sm);border-radius:999px;font-size:.8rem;font-weight:700;line-height:1;white-space:nowrap}.jv-badge--primary{background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface));color:var(--jv-color-primary)}.jv-badge--secondary,.jv-badge--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-badge--success{background:color-mix(in srgb,var(--jv-color-success) 16%,var(--jv-color-surface));color:var(--jv-color-success)}.jv-badge--warning{background:color-mix(in srgb,var(--jv-color-warning) 20%,var(--jv-color-surface));color:#8a4b00}.jv-badge--danger{background:color-mix(in srgb,var(--jv-color-danger) 16%,var(--jv-color-surface));color:var(--jv-color-danger)}.jv-badge--info{background:color-mix(in srgb,var(--jv-color-info) 16%,var(--jv-color-surface));color:var(--jv-color-info)}\n"] });
19404
- }
19405
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvBadgeComponent, decorators: [{
19406
- type: Component,
19407
- args: [{ selector: 'jv-badge', standalone: true, template: `<span class="jv-badge" [class]="badgeClass()"><ng-content></ng-content></span>`, styles: [".jv-badge{display:inline-flex;align-items:center;justify-content:center;min-height:1.75rem;padding:0 var(--jv-spacing-sm);border-radius:999px;font-size:.8rem;font-weight:700;line-height:1;white-space:nowrap}.jv-badge--primary{background:color-mix(in srgb,var(--jv-color-primary) 14%,var(--jv-color-surface));color:var(--jv-color-primary)}.jv-badge--secondary,.jv-badge--neutral{background:var(--jv-color-surface-muted);color:var(--jv-color-foreground)}.jv-badge--success{background:color-mix(in srgb,var(--jv-color-success) 16%,var(--jv-color-surface));color:var(--jv-color-success)}.jv-badge--warning{background:color-mix(in srgb,var(--jv-color-warning) 20%,var(--jv-color-surface));color:#8a4b00}.jv-badge--danger{background:color-mix(in srgb,var(--jv-color-danger) 16%,var(--jv-color-surface));color:var(--jv-color-danger)}.jv-badge--info{background:color-mix(in srgb,var(--jv-color-info) 16%,var(--jv-color-surface));color:var(--jv-color-info)}\n"] }]
19408
- }], propDecorators: { tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }] } });
19409
-
19410
20336
  class JvLoaderService {
19411
20337
  counter = signal(0, ...(ngDevMode ? [{ debugName: "counter" }] : /* istanbul ignore next */ []));
19412
20338
  visible = signal(false, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
@@ -19705,6 +20631,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
19705
20631
  class JvDialogComponent {
19706
20632
  document = inject(DOCUMENT);
19707
20633
  panelRef = viewChild('panel', ...(ngDevMode ? [{ debugName: "panelRef" }] : /* istanbul ignore next */ []));
20634
+ previouslyFocusedElement = null;
19708
20635
  open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
19709
20636
  title = input('Dialog', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
19710
20637
  closed = output();
@@ -19713,8 +20640,11 @@ class JvDialogComponent {
19713
20640
  constructor() {
19714
20641
  effect(() => {
19715
20642
  if (this.open()) {
20643
+ this.previouslyFocusedElement = this.document.activeElement instanceof HTMLElement ? this.document.activeElement : null;
19716
20644
  queueMicrotask(() => this.focusInitialElement());
20645
+ return;
19717
20646
  }
20647
+ this.restoreFocus();
19718
20648
  });
19719
20649
  }
19720
20650
  handleDocumentKeydown(event) {
@@ -19741,6 +20671,10 @@ class JvDialogComponent {
19741
20671
  backdropClose() {
19742
20672
  this.closed.emit();
19743
20673
  }
20674
+ restoreFocus() {
20675
+ this.previouslyFocusedElement?.focus();
20676
+ this.previouslyFocusedElement = null;
20677
+ }
19744
20678
  trapFocus(event) {
19745
20679
  const focusable = this.getFocusableElements();
19746
20680
  const panel = this.panelRef()?.nativeElement;
@@ -19772,7 +20706,7 @@ class JvDialogComponent {
19772
20706
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvDialogComponent, isStandalone: true, selector: "jv-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { listeners: { "document:keydown": "handleDocumentKeydown($event)" } }, viewQueries: [{ propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: `
19773
20707
  @if (open()) {
19774
20708
  <div class="jv-dialog-backdrop" (click)="backdropClose()">
19775
- <div class="jv-dialog-panel" role="dialog" aria-modal="true" tabindex="-1" [attr.aria-labelledby]="titleId" [attr.aria-describedby]="descriptionId" (click)="$event.stopPropagation()" #panel>
20709
+ <div class="jv-dialog-panel" role="dialog" aria-modal="true" tabindex="-1" [attr.aria-labelledby]="titleId" [attr.aria-describedby]="descriptionId" (click)="$event.stopPropagation()" #panel>
19776
20710
  <header class="jv-dialog-header">
19777
20711
  <h2 [id]="titleId">{{ title() }}</h2>
19778
20712
  </header>
@@ -19794,7 +20728,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
19794
20728
  args: [{ selector: 'jv-dialog', standalone: true, template: `
19795
20729
  @if (open()) {
19796
20730
  <div class="jv-dialog-backdrop" (click)="backdropClose()">
19797
- <div class="jv-dialog-panel" role="dialog" aria-modal="true" tabindex="-1" [attr.aria-labelledby]="titleId" [attr.aria-describedby]="descriptionId" (click)="$event.stopPropagation()" #panel>
20731
+ <div class="jv-dialog-panel" role="dialog" aria-modal="true" tabindex="-1" [attr.aria-labelledby]="titleId" [attr.aria-describedby]="descriptionId" (click)="$event.stopPropagation()" #panel>
19798
20732
  <header class="jv-dialog-header">
19799
20733
  <h2 [id]="titleId">{{ title() }}</h2>
19800
20734
  </header>
@@ -19815,104 +20749,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
19815
20749
  args: ['document:keydown', ['$event']]
19816
20750
  }] } });
19817
20751
 
19818
- let selectIdSequence = 0;
19819
- class JvSelectComponent {
19820
- options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
19821
- placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
19822
- required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
19823
- invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
19824
- describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
19825
- inputId = input(`jv-select-${++selectIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
19826
- modelValue = input('', ...(ngDevMode ? [{ debugName: "modelValue" }] : /* istanbul ignore next */ []));
19827
- selectionChange = output();
19828
- value = '';
19829
- disabled = false;
19830
- onChange = () => undefined;
19831
- onTouched = () => undefined;
19832
- currentValue = computed(() => this.modelValue() || this.value, ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
19833
- writeValue(value) {
19834
- this.value = value ?? '';
19835
- }
19836
- registerOnChange(fn) {
19837
- this.onChange = fn;
19838
- }
19839
- registerOnTouched(fn) {
19840
- this.onTouched = fn;
19841
- }
19842
- setDisabledState(isDisabled) {
19843
- this.disabled = isDisabled;
19844
- }
19845
- handleChange(event) {
19846
- const nextValue = event.target.value;
19847
- this.value = nextValue;
19848
- this.onChange(nextValue);
19849
- this.selectionChange.emit(nextValue);
19850
- }
19851
- handleBlur() {
19852
- this.onTouched();
19853
- }
19854
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19855
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvSelectComponent, isStandalone: true, selector: "jv-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "describedBy", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, modelValue: { classPropertyName: "modelValue", publicName: "modelValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, providers: [
19856
- {
19857
- provide: NG_VALUE_ACCESSOR,
19858
- useExisting: forwardRef(() => JvSelectComponent),
19859
- multi: true,
19860
- },
19861
- ], ngImport: i0, template: `
19862
- <select
19863
- class="jv-select"
19864
- [class.is-invalid]="invalid()"
19865
- [id]="inputId()"
19866
- [disabled]="disabled"
19867
- [required]="required()"
19868
- [attr.aria-invalid]="invalid() ? 'true' : null"
19869
- [attr.aria-describedby]="describedBy() || null"
19870
- [value]="currentValue()"
19871
- (change)="handleChange($event)"
19872
- (blur)="handleBlur()"
19873
- >
19874
- @if (placeholder()) {
19875
- <option value="" [disabled]="required()">{{ placeholder() }}</option>
19876
- }
19877
-
19878
- @for (option of options(); track option.label + ':' + option.value) {
19879
- <option [value]="option.value" [disabled]="option.disabled ?? false">{{ option.label }}</option>
19880
- }
19881
- </select>
19882
- `, isInline: true, styles: [".jv-select{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-select.is-invalid{border-color:var(--jv-color-danger)}\n"] });
19883
- }
19884
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSelectComponent, decorators: [{
19885
- type: Component,
19886
- args: [{ selector: 'jv-select', standalone: true, providers: [
19887
- {
19888
- provide: NG_VALUE_ACCESSOR,
19889
- useExisting: forwardRef(() => JvSelectComponent),
19890
- multi: true,
19891
- },
19892
- ], template: `
19893
- <select
19894
- class="jv-select"
19895
- [class.is-invalid]="invalid()"
19896
- [id]="inputId()"
19897
- [disabled]="disabled"
19898
- [required]="required()"
19899
- [attr.aria-invalid]="invalid() ? 'true' : null"
19900
- [attr.aria-describedby]="describedBy() || null"
19901
- [value]="currentValue()"
19902
- (change)="handleChange($event)"
19903
- (blur)="handleBlur()"
19904
- >
19905
- @if (placeholder()) {
19906
- <option value="" [disabled]="required()">{{ placeholder() }}</option>
19907
- }
19908
-
19909
- @for (option of options(); track option.label + ':' + option.value) {
19910
- <option [value]="option.value" [disabled]="option.disabled ?? false">{{ option.label }}</option>
19911
- }
19912
- </select>
19913
- `, styles: [".jv-select{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground)}.jv-select.is-invalid{border-color:var(--jv-color-danger)}\n"] }]
19914
- }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], modelValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelValue", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
19915
-
19916
20752
  let datePickerIdSequence = 0;
19917
20753
  class JvDatePickerComponent {
19918
20754
  translation = inject(JvTranslationService);
@@ -20202,7 +21038,7 @@ class JvDatePickerComponent {
20202
21038
  <jv-button variant="outline" (click)="closeDialog()">{{ translation.translate('datePicker.close') }}</jv-button>
20203
21039
  </div>
20204
21040
  </jv-dialog>
20205
- `, isInline: true, styles: [".jv-date-picker-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-date-picker-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-date-picker-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-date-picker-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-placeholder{color:var(--jv-color-foreground-muted)}.jv-date-picker-dialog,.jv-date-picker-actions{display:grid;gap:var(--jv-spacing-md)}.jv-date-picker-toolbar,.jv-date-picker-selects,.jv-date-picker-weekdays,.jv-date-picker-grid{display:grid;gap:var(--jv-spacing-sm)}.jv-date-picker-toolbar{grid-template-columns:auto 1fr auto;align-items:center}.jv-date-picker-selects{grid-template-columns:1fr 1fr}.jv-date-picker-weekdays,.jv-date-picker-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.jv-date-picker-weekdays span{text-align:center;font-size:.8125rem;font-weight:600;color:var(--jv-color-foreground-muted)}.jv-date-picker-day{min-height:2.5rem;border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground);font:inherit;cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease}.jv-date-picker-day:hover,.jv-date-picker-day:focus-visible{background:var(--jv-color-surface-muted)}.jv-date-picker-day:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-day--outside{color:var(--jv-color-foreground-muted)}.jv-date-picker-day--today{border-color:var(--jv-color-primary)}.jv-date-picker-day--selected{background:var(--jv-color-primary);color:#fff}\n"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title"], outputs: ["closed"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconButtonComponent, selector: "jv-icon-button", inputs: ["icon", "ariaLabel", "variant", "disabled"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
21041
+ `, isInline: true, styles: [".jv-date-picker-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-date-picker-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-date-picker-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-date-picker-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-placeholder{color:var(--jv-color-foreground-muted)}.jv-date-picker-dialog,.jv-date-picker-actions{display:grid;gap:var(--jv-spacing-md)}.jv-date-picker-toolbar,.jv-date-picker-selects,.jv-date-picker-weekdays,.jv-date-picker-grid{display:grid;gap:var(--jv-spacing-sm)}.jv-date-picker-toolbar{grid-template-columns:auto 1fr auto;align-items:center}.jv-date-picker-selects{grid-template-columns:1fr 1fr}.jv-date-picker-weekdays,.jv-date-picker-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.jv-date-picker-weekdays span{text-align:center;font-size:.8125rem;font-weight:600;color:var(--jv-color-foreground-muted)}.jv-date-picker-day{min-height:2.5rem;border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground);font:inherit;cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease}.jv-date-picker-day:hover,.jv-date-picker-day:focus-visible{background:var(--jv-color-surface-muted)}.jv-date-picker-day:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-day--outside{color:var(--jv-color-foreground-muted)}.jv-date-picker-day--today{border-color:var(--jv-color-primary)}.jv-date-picker-day--selected{background:var(--jv-color-primary);color:#fff}\n"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title"], outputs: ["closed"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconButtonComponent, selector: "jv-icon-button", inputs: ["icon", "ariaLabel", "variant", "disabled"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
20206
21042
  }
20207
21043
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDatePickerComponent, decorators: [{
20208
21044
  type: Component,
@@ -20482,7 +21318,7 @@ class JvFileInputComponent {
20482
21318
  [class.jv-file-input-dropzone--dragover]="dragActive()"
20483
21319
  [class.jv-file-input-dropzone--invalid]="invalid()"
20484
21320
  role="button"
20485
- tabindex="0"
21321
+ [attr.tabindex]="disabled() ? -1 : 0"
20486
21322
  [attr.aria-disabled]="disabled() ? 'true' : 'false'"
20487
21323
  [attr.aria-label]="dropzoneAriaLabel()"
20488
21324
  (click)="openFileDialog()"
@@ -20557,7 +21393,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
20557
21393
  [class.jv-file-input-dropzone--dragover]="dragActive()"
20558
21394
  [class.jv-file-input-dropzone--invalid]="invalid()"
20559
21395
  role="button"
20560
- tabindex="0"
21396
+ [attr.tabindex]="disabled() ? -1 : 0"
20561
21397
  [attr.aria-disabled]="disabled() ? 'true' : 'false'"
20562
21398
  [attr.aria-label]="dropzoneAriaLabel()"
20563
21399
  (click)="openFileDialog()"
@@ -20605,6 +21441,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
20605
21441
  }], propDecorators: { nativeInputRef: [{ type: i0.ViewChild, args: ['nativeInput', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], filesInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "files", required: false }] }], filesChange: [{ type: i0.Output, args: ["filesChange"] }], filesRejected: [{ type: i0.Output, args: ["filesRejected"] }] } });
20606
21442
 
20607
21443
  class JvListComponent {
21444
+ listId = input('', ...(ngDevMode ? [{ debugName: "listId" }] : /* istanbul ignore next */ []));
20608
21445
  role = input('list', ...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
20609
21446
  ariaRole = input(null, ...(ngDevMode ? [{ debugName: "ariaRole" }] : /* istanbul ignore next */ []));
20610
21447
  variant = input(null, ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
@@ -20615,13 +21452,14 @@ class JvListComponent {
20615
21452
  }, ...(ngDevMode ? [{ debugName: "variantClass" }] : /* istanbul ignore next */ []));
20616
21453
  resolvedRole = computed(() => this.ariaRole() ?? (this.role() === 'navigation' ? 'list' : null), ...(ngDevMode ? [{ debugName: "resolvedRole" }] : /* istanbul ignore next */ []));
20617
21454
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
20618
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvListComponent, isStandalone: true, selector: "jv-list", inputs: { role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, ariaRole: { classPropertyName: "ariaRole", publicName: "ariaRole", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
20619
- <ul
20620
- class="jv-list"
20621
- [class]="variantClass()"
20622
- [attr.role]="resolvedRole()"
20623
- [attr.aria-label]="ariaLabel()"
20624
- >
21455
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: JvListComponent, isStandalone: true, selector: "jv-list", inputs: { listId: { classPropertyName: "listId", publicName: "listId", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, ariaRole: { classPropertyName: "ariaRole", publicName: "ariaRole", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
21456
+ <ul
21457
+ [id]="listId() || null"
21458
+ class="jv-list"
21459
+ [class]="variantClass()"
21460
+ [attr.role]="resolvedRole()"
21461
+ [attr.aria-label]="ariaLabel()"
21462
+ >
20625
21463
  <ng-content />
20626
21464
  </ul>
20627
21465
  `, isInline: true, styles: [".jv-list{display:block;list-style:none;margin:0;padding:0}.jv-list>:not(:last-child){border-bottom:1px solid var(--jv-color-border)}.jv-list--bordered{border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md)}\n"] });
@@ -20629,16 +21467,17 @@ class JvListComponent {
20629
21467
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvListComponent, decorators: [{
20630
21468
  type: Component,
20631
21469
  args: [{ selector: 'jv-list', standalone: true, template: `
20632
- <ul
20633
- class="jv-list"
20634
- [class]="variantClass()"
20635
- [attr.role]="resolvedRole()"
20636
- [attr.aria-label]="ariaLabel()"
20637
- >
21470
+ <ul
21471
+ [id]="listId() || null"
21472
+ class="jv-list"
21473
+ [class]="variantClass()"
21474
+ [attr.role]="resolvedRole()"
21475
+ [attr.aria-label]="ariaLabel()"
21476
+ >
20638
21477
  <ng-content />
20639
21478
  </ul>
20640
21479
  `, styles: [".jv-list{display:block;list-style:none;margin:0;padding:0}.jv-list>:not(:last-child){border-bottom:1px solid var(--jv-color-border)}.jv-list--bordered{border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md)}\n"] }]
20641
- }], propDecorators: { role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], ariaRole: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaRole", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
21480
+ }], propDecorators: { listId: [{ type: i0.Input, args: [{ isSignal: true, alias: "listId", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], ariaRole: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaRole", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
20642
21481
 
20643
21482
  let modalSelectorIdSequence = 0;
20644
21483
  class JvModalSelectorComponent {
@@ -20668,6 +21507,8 @@ class JvModalSelectorComponent {
20668
21507
  dialogOpen = signal(false, ...(ngDevMode ? [{ debugName: "dialogOpen" }] : /* istanbul ignore next */ []));
20669
21508
  searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
20670
21509
  dialogId = `jv-modal-selector-dialog-${this.instanceId}`;
21510
+ listboxId = `jv-modal-selector-listbox-${this.instanceId}`;
21511
+ resultsId = `jv-modal-selector-results-${this.instanceId}`;
20671
21512
  searchInputId = `jv-modal-selector-search-${this.instanceId}`;
20672
21513
  value = null;
20673
21514
  disabled = false;
@@ -20801,100 +21642,102 @@ class JvModalSelectorComponent {
20801
21642
  useExisting: forwardRef(() => JvModalSelectorComponent),
20802
21643
  multi: true,
20803
21644
  },
20804
- ], viewQueries: [{ propertyName: "triggerButtonRef", first: true, predicate: ["triggerButton"], descendants: true, isSignal: true }, { propertyName: "optionElements", predicate: ["optionElement"], descendants: true, isSignal: true }], ngImport: i0, template: `
20805
- <jv-form-container
20806
- [label]="label()"
20807
- [inputId]="inputId()"
20808
- [required]="required()"
20809
- [invalid]="invalid()"
20810
- [hint]="hint()"
20811
- [error]="error()"
20812
- >
20813
- <button
20814
- #triggerButton
20815
- type="button"
20816
- class="jv-modal-selector-trigger"
20817
- [class.is-invalid]="invalid()"
20818
- [id]="inputId()"
20819
- [disabled]="disabled"
20820
- [attr.aria-haspopup]="'dialog'"
20821
- [attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
20822
- [attr.aria-controls]="dialogId"
20823
- [attr.aria-invalid]="invalid() ? 'true' : null"
20824
- [attr.aria-describedby]="describedBy() || null"
20825
- [attr.aria-label]="triggerAriaLabel()"
20826
- (click)="openDialog()"
20827
- (blur)="handleBlur()"
20828
- >
20829
- <span class="jv-modal-selector-trigger-copy">
20830
- <span [class.jv-modal-selector-trigger-placeholder]="!selectedOption()">
20831
- {{ selectedOption()?.label ?? resolvedPlaceholder() }}
20832
- </span>
20833
- </span>
20834
- <jv-icon name="chevrons-up-down" [size]="18" />
20835
- </button>
20836
- </jv-form-container>
20837
-
20838
- <jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
20839
- <div [id]="dialogId" class="jv-modal-selector-dialog">
20840
- @if (dialogSubtitle()) {
20841
- <p class="jv-modal-selector-subtitle">{{ dialogSubtitle() }}</p>
20842
- }
20843
-
20844
- @if (showSearch()) {
20845
- <jv-input
20846
- type="search"
20847
- [inputId]="searchInputId"
20848
- [placeholder]="searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')"
20849
- [ngModel]="searchQuery()"
20850
- (ngModelChange)="searchQuery.set($event)"
20851
- />
20852
- }
20853
-
20854
- <p class="jv-modal-selector-results" aria-live="polite">{{ resultsLabel() }}</p>
20855
-
20856
- @if (filteredOptions().length > 0) {
20857
- <jv-list variant="bordered" [ariaRole]="'listbox'" [ariaLabel]="resolvedDialogTitle()">
20858
- @for (option of filteredOptions(); track option.value; let index = $index) {
20859
- <li role="presentation">
20860
- <div
20861
- #optionElement
20862
- class="jv-modal-selector-option"
20863
- [class.jv-modal-selector-option--selected]="isSelected(option)"
20864
- [class.jv-modal-selector-option--disabled]="option.disabled ?? false"
20865
- [id]="optionId(index)"
20866
- role="option"
20867
- [attr.aria-selected]="isSelected(option) ? 'true' : 'false'"
20868
- [attr.tabindex]="getOptionTabIndex(option, index)"
20869
- (click)="selectOption(option)"
20870
- (keydown)="handleOptionKeydown($event, index, option)"
20871
- >
20872
- <div class="jv-modal-selector-option-copy">
20873
- <span class="jv-modal-selector-option-label">{{ option.label }}</span>
20874
- @if (option.description) {
20875
- <span class="jv-modal-selector-option-description">{{ option.description }}</span>
20876
- }
20877
- </div>
20878
- @if (isSelected(option)) {
20879
- <jv-icon name="check" [size]="16" />
20880
- }
20881
- </div>
20882
- </li>
20883
- }
20884
- </jv-list>
20885
- } @else {
20886
- <div class="jv-modal-selector-empty" aria-live="polite">{{ emptyMessage() || translation.translate('modalSelector.emptyMessage') }}</div>
20887
- }
20888
- </div>
20889
-
20890
- <div dialog-actions class="jv-modal-selector-actions">
20891
- @if (selectedOption()) {
20892
- <jv-button variant="ghost" (click)="clearSelection()">{{ clearLabel() || translation.translate('modalSelector.clear') }}</jv-button>
20893
- }
20894
- <jv-button variant="outline" (click)="closeDialog()">{{ closeLabel() || translation.translate('modalSelector.close') }}</jv-button>
20895
- </div>
20896
- </jv-dialog>
20897
- `, isInline: true, styles: [".jv-modal-selector-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-modal-selector-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-modal-selector-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-modal-selector-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-modal-selector-trigger-copy{min-width:0;flex:1}.jv-modal-selector-trigger-placeholder{color:var(--jv-color-foreground-muted)}.jv-modal-selector-dialog,.jv-modal-selector-actions{display:grid;gap:var(--jv-spacing-md)}.jv-modal-selector-subtitle,.jv-modal-selector-results,.jv-modal-selector-option-description,.jv-modal-selector-empty{margin:0;color:var(--jv-color-foreground-muted)}.jv-modal-selector-empty{padding:var(--jv-spacing-md);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-md);text-align:center}.jv-modal-selector-option{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md);background:var(--jv-color-surface);cursor:pointer;outline:none;transition:background-color .16s ease}.jv-modal-selector-option:hover,.jv-modal-selector-option:focus-visible{background:var(--jv-color-surface-muted)}.jv-modal-selector-option:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-modal-selector-option--selected{background:color-mix(in srgb,var(--jv-color-primary) 8%,var(--jv-color-surface))}.jv-modal-selector-option--disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.jv-modal-selector-option-copy{min-width:0;display:grid;gap:.25rem}.jv-modal-selector-option-label{font-weight:600;color:var(--jv-color-foreground)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title"], outputs: ["closed"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvListComponent, selector: "jv-list", inputs: ["role", "ariaRole", "variant", "ariaLabel"] }] });
21645
+ ], viewQueries: [{ propertyName: "triggerButtonRef", first: true, predicate: ["triggerButton"], descendants: true, isSignal: true }, { propertyName: "optionElements", predicate: ["optionElement"], descendants: true, isSignal: true }], ngImport: i0, template: `
21646
+ <jv-form-container
21647
+ [label]="label()"
21648
+ [inputId]="inputId()"
21649
+ [required]="required()"
21650
+ [invalid]="invalid()"
21651
+ [hint]="hint()"
21652
+ [error]="error()"
21653
+ >
21654
+ <button
21655
+ #triggerButton
21656
+ type="button"
21657
+ class="jv-modal-selector-trigger"
21658
+ [class.is-invalid]="invalid()"
21659
+ [id]="inputId()"
21660
+ [disabled]="disabled"
21661
+ [attr.aria-haspopup]="'dialog'"
21662
+ [attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
21663
+ [attr.aria-controls]="dialogId"
21664
+ [attr.aria-invalid]="invalid() ? 'true' : null"
21665
+ [attr.aria-describedby]="describedBy() || null"
21666
+ [attr.aria-label]="triggerAriaLabel()"
21667
+ (click)="openDialog()"
21668
+ (blur)="handleBlur()"
21669
+ >
21670
+ <span class="jv-modal-selector-trigger-copy">
21671
+ <span [class.jv-modal-selector-trigger-placeholder]="!selectedOption()">
21672
+ {{ selectedOption()?.label ?? resolvedPlaceholder() }}
21673
+ </span>
21674
+ </span>
21675
+ <jv-icon name="chevrons-up-down" [size]="18" />
21676
+ </button>
21677
+ </jv-form-container>
21678
+
21679
+ <jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
21680
+ <div [id]="dialogId" class="jv-modal-selector-dialog">
21681
+ @if (dialogSubtitle()) {
21682
+ <p class="jv-modal-selector-subtitle">{{ dialogSubtitle() }}</p>
21683
+ }
21684
+
21685
+ @if (showSearch()) {
21686
+ <jv-input
21687
+ type="search"
21688
+ [inputId]="searchInputId"
21689
+ [placeholder]="searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')"
21690
+ [describedBy]="resultsId"
21691
+ [ngModel]="searchQuery()"
21692
+ (ngModelChange)="searchQuery.set($event)"
21693
+ />
21694
+ }
21695
+
21696
+ <p class="jv-modal-selector-results" [id]="resultsId" aria-live="polite">{{ resultsLabel() }}</p>
21697
+
21698
+ @if (filteredOptions().length > 0) {
21699
+ <jv-list [listId]="listboxId" variant="bordered" [ariaRole]="'listbox'" [ariaLabel]="resolvedDialogTitle()">
21700
+ @for (option of filteredOptions(); track option.value; let index = $index) {
21701
+ <li role="presentation">
21702
+ <div
21703
+ #optionElement
21704
+ class="jv-modal-selector-option"
21705
+ [class.jv-modal-selector-option--selected]="isSelected(option)"
21706
+ [class.jv-modal-selector-option--disabled]="option.disabled ?? false"
21707
+ [id]="optionId(index)"
21708
+ role="option"
21709
+ [attr.aria-selected]="isSelected(option) ? 'true' : 'false'"
21710
+ [attr.aria-disabled]="option.disabled ? 'true' : null"
21711
+ [attr.tabindex]="getOptionTabIndex(option, index)"
21712
+ (click)="selectOption(option)"
21713
+ (keydown)="handleOptionKeydown($event, index, option)"
21714
+ >
21715
+ <div class="jv-modal-selector-option-copy">
21716
+ <span class="jv-modal-selector-option-label">{{ option.label }}</span>
21717
+ @if (option.description) {
21718
+ <span class="jv-modal-selector-option-description">{{ option.description }}</span>
21719
+ }
21720
+ </div>
21721
+ @if (isSelected(option)) {
21722
+ <jv-icon name="check" [size]="16" />
21723
+ }
21724
+ </div>
21725
+ </li>
21726
+ }
21727
+ </jv-list>
21728
+ } @else {
21729
+ <div class="jv-modal-selector-empty" aria-live="polite">{{ emptyMessage() || translation.translate('modalSelector.emptyMessage') }}</div>
21730
+ }
21731
+ </div>
21732
+
21733
+ <div dialog-actions class="jv-modal-selector-actions">
21734
+ @if (selectedOption()) {
21735
+ <jv-button variant="ghost" (click)="clearSelection()">{{ clearLabel() || translation.translate('modalSelector.clear') }}</jv-button>
21736
+ }
21737
+ <jv-button variant="outline" (click)="closeDialog()">{{ closeLabel() || translation.translate('modalSelector.close') }}</jv-button>
21738
+ </div>
21739
+ </jv-dialog>
21740
+ `, isInline: true, styles: [".jv-modal-selector-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-modal-selector-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-modal-selector-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-modal-selector-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-modal-selector-trigger-copy{min-width:0;flex:1}.jv-modal-selector-trigger-placeholder{color:var(--jv-color-foreground-muted)}.jv-modal-selector-dialog,.jv-modal-selector-actions{display:grid;gap:var(--jv-spacing-md)}.jv-modal-selector-subtitle,.jv-modal-selector-results,.jv-modal-selector-option-description,.jv-modal-selector-empty{margin:0;color:var(--jv-color-foreground-muted)}.jv-modal-selector-empty{padding:var(--jv-spacing-md);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-md);text-align:center}.jv-modal-selector-option{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md);background:var(--jv-color-surface);cursor:pointer;outline:none;transition:background-color .16s ease}.jv-modal-selector-option:hover,.jv-modal-selector-option:focus-visible{background:var(--jv-color-surface-muted)}.jv-modal-selector-option:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-modal-selector-option--selected{background:color-mix(in srgb,var(--jv-color-primary) 8%,var(--jv-color-surface))}.jv-modal-selector-option--disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.jv-modal-selector-option-copy{min-width:0;display:grid;gap:.25rem}.jv-modal-selector-option-label{font-weight:600;color:var(--jv-color-foreground)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title"], outputs: ["closed"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvListComponent, selector: "jv-list", inputs: ["listId", "role", "ariaRole", "variant", "ariaLabel"] }] });
20898
21741
  }
20899
21742
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvModalSelectorComponent, decorators: [{
20900
21743
  type: Component,
@@ -20904,99 +21747,101 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
20904
21747
  useExisting: forwardRef(() => JvModalSelectorComponent),
20905
21748
  multi: true,
20906
21749
  },
20907
- ], template: `
20908
- <jv-form-container
20909
- [label]="label()"
20910
- [inputId]="inputId()"
20911
- [required]="required()"
20912
- [invalid]="invalid()"
20913
- [hint]="hint()"
20914
- [error]="error()"
20915
- >
20916
- <button
20917
- #triggerButton
20918
- type="button"
20919
- class="jv-modal-selector-trigger"
20920
- [class.is-invalid]="invalid()"
20921
- [id]="inputId()"
20922
- [disabled]="disabled"
20923
- [attr.aria-haspopup]="'dialog'"
20924
- [attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
20925
- [attr.aria-controls]="dialogId"
20926
- [attr.aria-invalid]="invalid() ? 'true' : null"
20927
- [attr.aria-describedby]="describedBy() || null"
20928
- [attr.aria-label]="triggerAriaLabel()"
20929
- (click)="openDialog()"
20930
- (blur)="handleBlur()"
20931
- >
20932
- <span class="jv-modal-selector-trigger-copy">
20933
- <span [class.jv-modal-selector-trigger-placeholder]="!selectedOption()">
20934
- {{ selectedOption()?.label ?? resolvedPlaceholder() }}
20935
- </span>
20936
- </span>
20937
- <jv-icon name="chevrons-up-down" [size]="18" />
20938
- </button>
20939
- </jv-form-container>
20940
-
20941
- <jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
20942
- <div [id]="dialogId" class="jv-modal-selector-dialog">
20943
- @if (dialogSubtitle()) {
20944
- <p class="jv-modal-selector-subtitle">{{ dialogSubtitle() }}</p>
20945
- }
20946
-
20947
- @if (showSearch()) {
20948
- <jv-input
20949
- type="search"
20950
- [inputId]="searchInputId"
20951
- [placeholder]="searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')"
20952
- [ngModel]="searchQuery()"
20953
- (ngModelChange)="searchQuery.set($event)"
20954
- />
20955
- }
20956
-
20957
- <p class="jv-modal-selector-results" aria-live="polite">{{ resultsLabel() }}</p>
20958
-
20959
- @if (filteredOptions().length > 0) {
20960
- <jv-list variant="bordered" [ariaRole]="'listbox'" [ariaLabel]="resolvedDialogTitle()">
20961
- @for (option of filteredOptions(); track option.value; let index = $index) {
20962
- <li role="presentation">
20963
- <div
20964
- #optionElement
20965
- class="jv-modal-selector-option"
20966
- [class.jv-modal-selector-option--selected]="isSelected(option)"
20967
- [class.jv-modal-selector-option--disabled]="option.disabled ?? false"
20968
- [id]="optionId(index)"
20969
- role="option"
20970
- [attr.aria-selected]="isSelected(option) ? 'true' : 'false'"
20971
- [attr.tabindex]="getOptionTabIndex(option, index)"
20972
- (click)="selectOption(option)"
20973
- (keydown)="handleOptionKeydown($event, index, option)"
20974
- >
20975
- <div class="jv-modal-selector-option-copy">
20976
- <span class="jv-modal-selector-option-label">{{ option.label }}</span>
20977
- @if (option.description) {
20978
- <span class="jv-modal-selector-option-description">{{ option.description }}</span>
20979
- }
20980
- </div>
20981
- @if (isSelected(option)) {
20982
- <jv-icon name="check" [size]="16" />
20983
- }
20984
- </div>
20985
- </li>
20986
- }
20987
- </jv-list>
20988
- } @else {
20989
- <div class="jv-modal-selector-empty" aria-live="polite">{{ emptyMessage() || translation.translate('modalSelector.emptyMessage') }}</div>
20990
- }
20991
- </div>
20992
-
20993
- <div dialog-actions class="jv-modal-selector-actions">
20994
- @if (selectedOption()) {
20995
- <jv-button variant="ghost" (click)="clearSelection()">{{ clearLabel() || translation.translate('modalSelector.clear') }}</jv-button>
20996
- }
20997
- <jv-button variant="outline" (click)="closeDialog()">{{ closeLabel() || translation.translate('modalSelector.close') }}</jv-button>
20998
- </div>
20999
- </jv-dialog>
21750
+ ], template: `
21751
+ <jv-form-container
21752
+ [label]="label()"
21753
+ [inputId]="inputId()"
21754
+ [required]="required()"
21755
+ [invalid]="invalid()"
21756
+ [hint]="hint()"
21757
+ [error]="error()"
21758
+ >
21759
+ <button
21760
+ #triggerButton
21761
+ type="button"
21762
+ class="jv-modal-selector-trigger"
21763
+ [class.is-invalid]="invalid()"
21764
+ [id]="inputId()"
21765
+ [disabled]="disabled"
21766
+ [attr.aria-haspopup]="'dialog'"
21767
+ [attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
21768
+ [attr.aria-controls]="dialogId"
21769
+ [attr.aria-invalid]="invalid() ? 'true' : null"
21770
+ [attr.aria-describedby]="describedBy() || null"
21771
+ [attr.aria-label]="triggerAriaLabel()"
21772
+ (click)="openDialog()"
21773
+ (blur)="handleBlur()"
21774
+ >
21775
+ <span class="jv-modal-selector-trigger-copy">
21776
+ <span [class.jv-modal-selector-trigger-placeholder]="!selectedOption()">
21777
+ {{ selectedOption()?.label ?? resolvedPlaceholder() }}
21778
+ </span>
21779
+ </span>
21780
+ <jv-icon name="chevrons-up-down" [size]="18" />
21781
+ </button>
21782
+ </jv-form-container>
21783
+
21784
+ <jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
21785
+ <div [id]="dialogId" class="jv-modal-selector-dialog">
21786
+ @if (dialogSubtitle()) {
21787
+ <p class="jv-modal-selector-subtitle">{{ dialogSubtitle() }}</p>
21788
+ }
21789
+
21790
+ @if (showSearch()) {
21791
+ <jv-input
21792
+ type="search"
21793
+ [inputId]="searchInputId"
21794
+ [placeholder]="searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')"
21795
+ [describedBy]="resultsId"
21796
+ [ngModel]="searchQuery()"
21797
+ (ngModelChange)="searchQuery.set($event)"
21798
+ />
21799
+ }
21800
+
21801
+ <p class="jv-modal-selector-results" [id]="resultsId" aria-live="polite">{{ resultsLabel() }}</p>
21802
+
21803
+ @if (filteredOptions().length > 0) {
21804
+ <jv-list [listId]="listboxId" variant="bordered" [ariaRole]="'listbox'" [ariaLabel]="resolvedDialogTitle()">
21805
+ @for (option of filteredOptions(); track option.value; let index = $index) {
21806
+ <li role="presentation">
21807
+ <div
21808
+ #optionElement
21809
+ class="jv-modal-selector-option"
21810
+ [class.jv-modal-selector-option--selected]="isSelected(option)"
21811
+ [class.jv-modal-selector-option--disabled]="option.disabled ?? false"
21812
+ [id]="optionId(index)"
21813
+ role="option"
21814
+ [attr.aria-selected]="isSelected(option) ? 'true' : 'false'"
21815
+ [attr.aria-disabled]="option.disabled ? 'true' : null"
21816
+ [attr.tabindex]="getOptionTabIndex(option, index)"
21817
+ (click)="selectOption(option)"
21818
+ (keydown)="handleOptionKeydown($event, index, option)"
21819
+ >
21820
+ <div class="jv-modal-selector-option-copy">
21821
+ <span class="jv-modal-selector-option-label">{{ option.label }}</span>
21822
+ @if (option.description) {
21823
+ <span class="jv-modal-selector-option-description">{{ option.description }}</span>
21824
+ }
21825
+ </div>
21826
+ @if (isSelected(option)) {
21827
+ <jv-icon name="check" [size]="16" />
21828
+ }
21829
+ </div>
21830
+ </li>
21831
+ }
21832
+ </jv-list>
21833
+ } @else {
21834
+ <div class="jv-modal-selector-empty" aria-live="polite">{{ emptyMessage() || translation.translate('modalSelector.emptyMessage') }}</div>
21835
+ }
21836
+ </div>
21837
+
21838
+ <div dialog-actions class="jv-modal-selector-actions">
21839
+ @if (selectedOption()) {
21840
+ <jv-button variant="ghost" (click)="clearSelection()">{{ clearLabel() || translation.translate('modalSelector.clear') }}</jv-button>
21841
+ }
21842
+ <jv-button variant="outline" (click)="closeDialog()">{{ closeLabel() || translation.translate('modalSelector.close') }}</jv-button>
21843
+ </div>
21844
+ </jv-dialog>
21000
21845
  `, styles: [".jv-modal-selector-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-modal-selector-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-modal-selector-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-modal-selector-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-modal-selector-trigger-copy{min-width:0;flex:1}.jv-modal-selector-trigger-placeholder{color:var(--jv-color-foreground-muted)}.jv-modal-selector-dialog,.jv-modal-selector-actions{display:grid;gap:var(--jv-spacing-md)}.jv-modal-selector-subtitle,.jv-modal-selector-results,.jv-modal-selector-option-description,.jv-modal-selector-empty{margin:0;color:var(--jv-color-foreground-muted)}.jv-modal-selector-empty{padding:var(--jv-spacing-md);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-md);text-align:center}.jv-modal-selector-option{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md);background:var(--jv-color-surface);cursor:pointer;outline:none;transition:background-color .16s ease}.jv-modal-selector-option:hover,.jv-modal-selector-option:focus-visible{background:var(--jv-color-surface-muted)}.jv-modal-selector-option:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-modal-selector-option--selected{background:color-mix(in srgb,var(--jv-color-primary) 8%,var(--jv-color-surface))}.jv-modal-selector-option--disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.jv-modal-selector-option-copy{min-width:0;display:grid;gap:.25rem}.jv-modal-selector-option-label{font-weight:600;color:var(--jv-color-foreground)}\n"] }]
21001
21846
  }], propDecorators: { triggerButtonRef: [{ type: i0.ViewChild, args: ['triggerButton', { isSignal: true }] }], optionElements: [{ type: i0.ViewChildren, args: ['optionElement', { isSignal: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], dialogTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "dialogTitle", required: false }] }], dialogSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "dialogSubtitle", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
21002
21847
 
@@ -21872,6 +22717,213 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
21872
22717
  `, styles: [".actions{display:flex;justify-content:flex-end;gap:var(--jv-spacing-sm);flex-wrap:wrap}p{margin:0;color:var(--jv-color-foreground-muted)}\n"] }]
21873
22718
  }] });
21874
22719
 
22720
+ class JvWindowModalComponent {
22721
+ document = inject(DOCUMENT);
22722
+ panelRef = viewChild('panel', ...(ngDevMode ? [{ debugName: "panelRef" }] : /* istanbul ignore next */ []));
22723
+ open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
22724
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
22725
+ subtitle = input('', ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
22726
+ mode = input('floating', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
22727
+ size = input('xl', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
22728
+ showCloseButton = input(true, ...(ngDevMode ? [{ debugName: "showCloseButton" }] : /* istanbul ignore next */ []));
22729
+ closeOnBackdrop = input(true, ...(ngDevMode ? [{ debugName: "closeOnBackdrop" }] : /* istanbul ignore next */ []));
22730
+ closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : /* istanbul ignore next */ []));
22731
+ closeLabel = input('Close workspace', ...(ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []));
22732
+ closed = output();
22733
+ close = output();
22734
+ resolvedMode = computed(() => (this.size() === 'fullscreen' ? 'fullscreen' : this.mode()), ...(ngDevMode ? [{ debugName: "resolvedMode" }] : /* istanbul ignore next */ []));
22735
+ titleId = `jv-window-modal-title-${Math.random().toString(36).slice(2, 8)}`;
22736
+ descriptionId = `jv-window-modal-description-${Math.random().toString(36).slice(2, 8)}`;
22737
+ previousFocusedElement = null;
22738
+ previousBodyOverflow = '';
22739
+ wasOpen = false;
22740
+ constructor() {
22741
+ effect(() => {
22742
+ const isOpen = this.open();
22743
+ if (isOpen) {
22744
+ if (!this.wasOpen) {
22745
+ this.previousFocusedElement = this.document.activeElement instanceof HTMLElement ? this.document.activeElement : null;
22746
+ this.previousBodyOverflow = this.document.body.style.overflow;
22747
+ this.document.body.style.overflow = 'hidden';
22748
+ }
22749
+ queueMicrotask(() => this.focusInitialElement());
22750
+ }
22751
+ else if (this.wasOpen) {
22752
+ this.document.body.style.overflow = this.previousBodyOverflow;
22753
+ const previousFocusedElement = this.previousFocusedElement;
22754
+ queueMicrotask(() => previousFocusedElement?.focus());
22755
+ }
22756
+ this.wasOpen = isOpen;
22757
+ });
22758
+ }
22759
+ ngOnDestroy() {
22760
+ if (this.wasOpen) {
22761
+ this.document.body.style.overflow = this.previousBodyOverflow;
22762
+ }
22763
+ }
22764
+ handleDocumentKeydown(event) {
22765
+ if (!this.open()) {
22766
+ return;
22767
+ }
22768
+ if (event.key === 'Escape' && this.closeOnEscape()) {
22769
+ event.preventDefault();
22770
+ this.requestClose();
22771
+ return;
22772
+ }
22773
+ if (event.key === 'Tab') {
22774
+ this.trapFocus(event);
22775
+ }
22776
+ }
22777
+ backdropClose() {
22778
+ if (!this.closeOnBackdrop()) {
22779
+ return;
22780
+ }
22781
+ this.requestClose();
22782
+ }
22783
+ requestClose() {
22784
+ this.closed.emit();
22785
+ this.close.emit();
22786
+ }
22787
+ focusInitialElement() {
22788
+ const panel = this.panelRef()?.nativeElement;
22789
+ if (!panel) {
22790
+ return;
22791
+ }
22792
+ const firstFocusable = this.getFocusableElements()[0];
22793
+ (firstFocusable ?? panel).focus();
22794
+ }
22795
+ trapFocus(event) {
22796
+ const focusable = this.getFocusableElements();
22797
+ const panel = this.panelRef()?.nativeElement;
22798
+ if (!panel || focusable.length === 0) {
22799
+ panel?.focus();
22800
+ event.preventDefault();
22801
+ return;
22802
+ }
22803
+ const first = focusable[0];
22804
+ const last = focusable[focusable.length - 1];
22805
+ const active = this.document.activeElement;
22806
+ if (event.shiftKey && active === first) {
22807
+ last.focus();
22808
+ event.preventDefault();
22809
+ }
22810
+ else if (!event.shiftKey && active === last) {
22811
+ first.focus();
22812
+ event.preventDefault();
22813
+ }
22814
+ }
22815
+ getFocusableElements() {
22816
+ const panel = this.panelRef()?.nativeElement;
22817
+ if (!panel) {
22818
+ return [];
22819
+ }
22820
+ return Array.from(panel.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'));
22821
+ }
22822
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvWindowModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
22823
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvWindowModalComponent, isStandalone: true, selector: "jv-window-modal", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdrop: { classPropertyName: "closeOnBackdrop", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", close: "close" }, host: { listeners: { "document:keydown": "handleDocumentKeydown($event)" } }, viewQueries: [{ propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: `
22824
+ @if (open()) {
22825
+ <div class="jv-window-modal-backdrop" (click)="backdropClose()">
22826
+ <section
22827
+ class="jv-window-modal-panel"
22828
+ [class.jv-window-modal-panel--floating]="resolvedMode() === 'floating'"
22829
+ [class.jv-window-modal-panel--fullscreen]="resolvedMode() === 'fullscreen'"
22830
+ [class.jv-window-modal-panel--lg]="resolvedMode() === 'floating' && size() === 'lg'"
22831
+ [class.jv-window-modal-panel--xl]="resolvedMode() === 'floating' && size() === 'xl'"
22832
+ role="dialog"
22833
+ aria-modal="true"
22834
+ tabindex="-1"
22835
+ [attr.aria-labelledby]="title() ? titleId : null"
22836
+ [attr.aria-describedby]="descriptionId"
22837
+ (click)="$event.stopPropagation()"
22838
+ #panel
22839
+ >
22840
+ <header class="jv-window-modal-header">
22841
+ <div class="jv-window-modal-heading">
22842
+ @if (title()) {
22843
+ <h2 [id]="titleId">{{ title() }}</h2>
22844
+ }
22845
+
22846
+ @if (subtitle()) {
22847
+ <p class="jv-window-modal-subtitle">{{ subtitle() }}</p>
22848
+ }
22849
+ </div>
22850
+
22851
+ <div class="jv-window-modal-header-actions">
22852
+ <ng-content select="[window-modal-header-actions]"></ng-content>
22853
+
22854
+ @if (showCloseButton()) {
22855
+ <jv-icon-button icon="x" variant="ghost" [ariaLabel]="closeLabel()" (click)="requestClose()" />
22856
+ }
22857
+ </div>
22858
+ </header>
22859
+
22860
+ <div class="jv-window-modal-body" [id]="descriptionId">
22861
+ <ng-content></ng-content>
22862
+ </div>
22863
+
22864
+ <footer class="jv-window-modal-footer">
22865
+ <ng-content select="[window-modal-footer]"></ng-content>
22866
+ </footer>
22867
+ </section>
22868
+ </div>
22869
+ }
22870
+ `, isInline: true, styles: [".jv-window-modal-backdrop{position:fixed;inset:0;z-index:1250;display:flex;align-items:center;justify-content:center;padding:1rem;background:#0f172a94}.jv-window-modal-panel{width:min(100%,72rem);max-width:100%;max-height:calc(100dvh - 2rem);display:grid;grid-template-rows:auto minmax(0,1fr) auto;overflow:hidden;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-xl, 1.25rem);background:var(--jv-color-surface);color:var(--jv-color-foreground);box-shadow:var(--jv-shadow-lg)}.jv-window-modal-panel--lg{width:min(100%,56rem)}.jv-window-modal-panel--xl{width:min(100%,72rem)}.jv-window-modal-panel--fullscreen{width:min(100%,calc(100vw - 1rem));height:calc(100dvh - 1rem);max-height:calc(100dvh - 1rem)}.jv-window-modal-header,.jv-window-modal-footer{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-lg);background:var(--jv-color-surface)}.jv-window-modal-header{border-bottom:1px solid var(--jv-color-border)}.jv-window-modal-footer{border-top:1px solid var(--jv-color-border);justify-content:flex-end}.jv-window-modal-footer:empty{display:none}.jv-window-modal-heading{display:grid;gap:.35rem;min-width:0}.jv-window-modal-heading h2,.jv-window-modal-subtitle{margin:0}.jv-window-modal-subtitle{color:var(--jv-color-foreground-muted)}.jv-window-modal-header-actions{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);flex-shrink:0}.jv-window-modal-body{min-height:0;overflow:auto;padding:var(--jv-spacing-lg);display:grid;gap:var(--jv-spacing-lg);overscroll-behavior:contain}@media(max-width:720px){.jv-window-modal-backdrop{padding:0}.jv-window-modal-panel,.jv-window-modal-panel--fullscreen{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border-left:none;border-right:none}.jv-window-modal-header,.jv-window-modal-body,.jv-window-modal-footer{padding:var(--jv-spacing-md)}}\n"], dependencies: [{ kind: "component", type: JvIconButtonComponent, selector: "jv-icon-button", inputs: ["icon", "ariaLabel", "variant", "disabled"] }] });
22871
+ }
22872
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvWindowModalComponent, decorators: [{
22873
+ type: Component,
22874
+ args: [{ selector: 'jv-window-modal', standalone: true, imports: [JvIconButtonComponent], template: `
22875
+ @if (open()) {
22876
+ <div class="jv-window-modal-backdrop" (click)="backdropClose()">
22877
+ <section
22878
+ class="jv-window-modal-panel"
22879
+ [class.jv-window-modal-panel--floating]="resolvedMode() === 'floating'"
22880
+ [class.jv-window-modal-panel--fullscreen]="resolvedMode() === 'fullscreen'"
22881
+ [class.jv-window-modal-panel--lg]="resolvedMode() === 'floating' && size() === 'lg'"
22882
+ [class.jv-window-modal-panel--xl]="resolvedMode() === 'floating' && size() === 'xl'"
22883
+ role="dialog"
22884
+ aria-modal="true"
22885
+ tabindex="-1"
22886
+ [attr.aria-labelledby]="title() ? titleId : null"
22887
+ [attr.aria-describedby]="descriptionId"
22888
+ (click)="$event.stopPropagation()"
22889
+ #panel
22890
+ >
22891
+ <header class="jv-window-modal-header">
22892
+ <div class="jv-window-modal-heading">
22893
+ @if (title()) {
22894
+ <h2 [id]="titleId">{{ title() }}</h2>
22895
+ }
22896
+
22897
+ @if (subtitle()) {
22898
+ <p class="jv-window-modal-subtitle">{{ subtitle() }}</p>
22899
+ }
22900
+ </div>
22901
+
22902
+ <div class="jv-window-modal-header-actions">
22903
+ <ng-content select="[window-modal-header-actions]"></ng-content>
22904
+
22905
+ @if (showCloseButton()) {
22906
+ <jv-icon-button icon="x" variant="ghost" [ariaLabel]="closeLabel()" (click)="requestClose()" />
22907
+ }
22908
+ </div>
22909
+ </header>
22910
+
22911
+ <div class="jv-window-modal-body" [id]="descriptionId">
22912
+ <ng-content></ng-content>
22913
+ </div>
22914
+
22915
+ <footer class="jv-window-modal-footer">
22916
+ <ng-content select="[window-modal-footer]"></ng-content>
22917
+ </footer>
22918
+ </section>
22919
+ </div>
22920
+ }
22921
+ `, styles: [".jv-window-modal-backdrop{position:fixed;inset:0;z-index:1250;display:flex;align-items:center;justify-content:center;padding:1rem;background:#0f172a94}.jv-window-modal-panel{width:min(100%,72rem);max-width:100%;max-height:calc(100dvh - 2rem);display:grid;grid-template-rows:auto minmax(0,1fr) auto;overflow:hidden;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-xl, 1.25rem);background:var(--jv-color-surface);color:var(--jv-color-foreground);box-shadow:var(--jv-shadow-lg)}.jv-window-modal-panel--lg{width:min(100%,56rem)}.jv-window-modal-panel--xl{width:min(100%,72rem)}.jv-window-modal-panel--fullscreen{width:min(100%,calc(100vw - 1rem));height:calc(100dvh - 1rem);max-height:calc(100dvh - 1rem)}.jv-window-modal-header,.jv-window-modal-footer{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-lg);background:var(--jv-color-surface)}.jv-window-modal-header{border-bottom:1px solid var(--jv-color-border)}.jv-window-modal-footer{border-top:1px solid var(--jv-color-border);justify-content:flex-end}.jv-window-modal-footer:empty{display:none}.jv-window-modal-heading{display:grid;gap:.35rem;min-width:0}.jv-window-modal-heading h2,.jv-window-modal-subtitle{margin:0}.jv-window-modal-subtitle{color:var(--jv-color-foreground-muted)}.jv-window-modal-header-actions{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);flex-shrink:0}.jv-window-modal-body{min-height:0;overflow:auto;padding:var(--jv-spacing-lg);display:grid;gap:var(--jv-spacing-lg);overscroll-behavior:contain}@media(max-width:720px){.jv-window-modal-backdrop{padding:0}.jv-window-modal-panel,.jv-window-modal-panel--fullscreen{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border-left:none;border-right:none}.jv-window-modal-header,.jv-window-modal-body,.jv-window-modal-footer{padding:var(--jv-spacing-md)}}\n"] }]
22922
+ }], ctorParameters: () => [], propDecorators: { panelRef: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], closeOnBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdrop", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], close: [{ type: i0.Output, args: ["close"] }], handleDocumentKeydown: [{
22923
+ type: HostListener,
22924
+ args: ['document:keydown', ['$event']]
22925
+ }] } });
22926
+
21875
22927
  class JvBreadcrumbComponent {
21876
22928
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
21877
22929
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
@@ -22595,8 +23647,9 @@ class JvListItemComponent {
22595
23647
  class="jv-list-item"
22596
23648
  [class.jv-list-item--disabled]="disabled()"
22597
23649
  [class.jv-list-item--active]="active()"
22598
- tabindex="0"
23650
+ [attr.tabindex]="disabled() ? -1 : 0"
22599
23651
  role="listitem"
23652
+ [attr.aria-disabled]="disabled() ? 'true' : null"
22600
23653
  (click)="onActivate()"
22601
23654
  (keydown.enter)="onActivate()"
22602
23655
  (keydown.space)="onActivate(); $event.preventDefault()"
@@ -22623,8 +23676,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22623
23676
  class="jv-list-item"
22624
23677
  [class.jv-list-item--disabled]="disabled()"
22625
23678
  [class.jv-list-item--active]="active()"
22626
- tabindex="0"
23679
+ [attr.tabindex]="disabled() ? -1 : 0"
22627
23680
  role="listitem"
23681
+ [attr.aria-disabled]="disabled() ? 'true' : null"
22628
23682
  (click)="onActivate()"
22629
23683
  (keydown.enter)="onActivate()"
22630
23684
  (keydown.space)="onActivate(); $event.preventDefault()"
@@ -22860,11 +23914,23 @@ class JvTabsComponent {
22860
23914
  </div>
22861
23915
 
22862
23916
  @if (showScrollLeft() || showScrollRight()) {
22863
- <div class="jv-tabs-controls" aria-hidden="true">
22864
- <button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollLeft()" (click)="scrollTabs(-1)">
23917
+ <div class="jv-tabs-controls">
23918
+ <button
23919
+ type="button"
23920
+ class="jv-tabs-scroll-button"
23921
+ aria-label="Scroll tabs backward"
23922
+ [disabled]="!showScrollLeft()"
23923
+ (click)="scrollTabs(-1)"
23924
+ >
22865
23925
  <jv-icon name="chevron-left" [size]="16" />
22866
23926
  </button>
22867
- <button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollRight()" (click)="scrollTabs(1)">
23927
+ <button
23928
+ type="button"
23929
+ class="jv-tabs-scroll-button"
23930
+ aria-label="Scroll tabs forward"
23931
+ [disabled]="!showScrollRight()"
23932
+ (click)="scrollTabs(1)"
23933
+ >
22868
23934
  <jv-icon name="chevron-right" [size]="16" />
22869
23935
  </button>
22870
23936
  </div>
@@ -22955,11 +24021,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22955
24021
  </div>
22956
24022
 
22957
24023
  @if (showScrollLeft() || showScrollRight()) {
22958
- <div class="jv-tabs-controls" aria-hidden="true">
22959
- <button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollLeft()" (click)="scrollTabs(-1)">
24024
+ <div class="jv-tabs-controls">
24025
+ <button
24026
+ type="button"
24027
+ class="jv-tabs-scroll-button"
24028
+ aria-label="Scroll tabs backward"
24029
+ [disabled]="!showScrollLeft()"
24030
+ (click)="scrollTabs(-1)"
24031
+ >
22960
24032
  <jv-icon name="chevron-left" [size]="16" />
22961
24033
  </button>
22962
- <button type="button" class="jv-tabs-scroll-button" [disabled]="!showScrollRight()" (click)="scrollTabs(1)">
24034
+ <button
24035
+ type="button"
24036
+ class="jv-tabs-scroll-button"
24037
+ aria-label="Scroll tabs forward"
24038
+ [disabled]="!showScrollRight()"
24039
+ (click)="scrollTabs(1)"
24040
+ >
22963
24041
  <jv-icon name="chevron-right" [size]="16" />
22964
24042
  </button>
22965
24043
  </div>
@@ -23032,6 +24110,7 @@ class JvTooltipDirective {
23032
24110
  showTimeout = null;
23033
24111
  hideTimeout = null;
23034
24112
  tooltipId = `jv-tooltip-${++tooltipSequence}`;
24113
+ originalDescribedBy = null;
23035
24114
  text = input.required({ ...(ngDevMode ? { debugName: "text" } : /* istanbul ignore next */ {}), alias: 'jvTooltip' });
23036
24115
  position = input('top', { ...(ngDevMode ? { debugName: "position" } : /* istanbul ignore next */ {}), alias: 'jvTooltipPosition' });
23037
24116
  show() {
@@ -23045,7 +24124,7 @@ class JvTooltipDirective {
23045
24124
  this.showTimeout = setTimeout(() => {
23046
24125
  this.renderTooltip();
23047
24126
  this.positionTooltip();
23048
- this.renderer.setAttribute(this.anchorElement(), 'aria-describedby', this.tooltipId);
24127
+ this.attachTooltipDescription();
23049
24128
  }, 120);
23050
24129
  }
23051
24130
  hide() {
@@ -23132,10 +24211,29 @@ class JvTooltipDirective {
23132
24211
  if (!this.tooltipElement) {
23133
24212
  return;
23134
24213
  }
23135
- this.renderer.removeAttribute(this.anchorElement(), 'aria-describedby');
24214
+ this.restoreTooltipDescription();
23136
24215
  this.renderer.removeChild(this.document.body, this.tooltipElement);
23137
24216
  this.tooltipElement = null;
23138
24217
  }
24218
+ attachTooltipDescription() {
24219
+ const anchor = this.anchorElement();
24220
+ this.originalDescribedBy ??= anchor.getAttribute('aria-describedby');
24221
+ const describedBy = [this.originalDescribedBy, this.tooltipId]
24222
+ .filter((value) => !!value)
24223
+ .join(' ')
24224
+ .trim();
24225
+ this.renderer.setAttribute(anchor, 'aria-describedby', describedBy);
24226
+ }
24227
+ restoreTooltipDescription() {
24228
+ const anchor = this.anchorElement();
24229
+ if (this.originalDescribedBy) {
24230
+ this.renderer.setAttribute(anchor, 'aria-describedby', this.originalDescribedBy);
24231
+ }
24232
+ else {
24233
+ this.renderer.removeAttribute(anchor, 'aria-describedby');
24234
+ }
24235
+ this.originalDescribedBy = null;
24236
+ }
23139
24237
  anchorElement() {
23140
24238
  const host = this.hostRef.nativeElement;
23141
24239
  if (isInteractiveElement(host)) {
@@ -23495,6 +24593,7 @@ function exportGridToExcel(header, rows, filename = 'export.xlsx') {
23495
24593
  let gridIdSequence = 0;
23496
24594
  class JvGridComponent {
23497
24595
  gridId = `jv-grid-${++gridIdSequence}`;
24596
+ gridSearchInputId = `${this.gridId}-search`;
23498
24597
  formatService = inject(JvFormatService);
23499
24598
  translationService = inject(JvTranslationService);
23500
24599
  data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
@@ -24038,7 +25137,7 @@ class JvGridComponent {
24038
25137
  <div class="jv-grid-search">
24039
25138
  <jv-icon name="search" [size]="16" />
24040
25139
  <jv-input
24041
- inputId="grid-search"
25140
+ [inputId]="gridSearchInputId"
24042
25141
  [placeholder]="t('grid.searchPlaceholder')"
24043
25142
  [ngModel]="searchTerm()"
24044
25143
  (ngModelChange)="onSearchInput($event)"
@@ -24377,7 +25476,7 @@ class JvGridComponent {
24377
25476
  </nav>
24378
25477
  }
24379
25478
  </div>
24380
- `, isInline: true, styles: [".jv-grid{display:flex;flex-direction:column;gap:var(--jv-spacing-md)}.jv-grid-toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-grid-search{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-grid-export-actions{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-table-wrap{overflow-x:auto;overflow-y:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);position:relative}.jv-grid-virtual{max-height:600px}.jv-grid-virtual-spacer{pointer-events:none}.jv-grid-table{width:100%;border-collapse:collapse;background:var(--jv-color-surface)}.jv-grid-thead{background:var(--jv-color-surface-muted)}.jv-grid-th{padding:var(--jv-spacing-sm) var(--jv-spacing-md);font-weight:600;font-size:.875rem;color:var(--jv-color-foreground-muted);text-align:start;white-space:nowrap;border-bottom:1px solid var(--jv-color-border);-webkit-user-select:none;user-select:none;position:relative}.jv-grid-th-sortable{cursor:pointer}.jv-grid-th-sortable:hover{background:var(--jv-color-surface)}.jv-grid-th-reorderable{cursor:grab}.jv-grid-th-reorderable:active{cursor:grabbing}.jv-grid-th-sticky-left{position:sticky;left:0;z-index:2;background:var(--jv-color-surface-muted);border-right:1px solid var(--jv-color-border)}.jv-grid-th-sticky-right{position:sticky;right:0;z-index:2;background:var(--jv-color-surface-muted);border-left:1px solid var(--jv-color-border)}.jv-grid-th-content{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-sort-icon{font-size:.75rem;line-height:1}.jv-grid-th-select,.jv-grid-td-select{width:3rem;text-align:center}.jv-grid-th-actions,.jv-grid-td-actions{width:1%;white-space:nowrap}.jv-grid-td{padding:var(--jv-spacing-sm) var(--jv-spacing-md);color:var(--jv-color-foreground);font-size:var(--jv-density-font-size);border-bottom:1px solid var(--jv-color-border)}.jv-grid-td-sticky-left{position:sticky;left:0;z-index:1;background:var(--jv-color-surface);border-right:1px solid var(--jv-color-border)}.jv-grid-td-sticky-right{position:sticky;right:0;z-index:1;background:var(--jv-color-surface);border-left:1px solid var(--jv-color-border)}.jv-grid-t:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-tr{transition:background-color .12s ease}.jv-grid-tr:hover{background:var(--jv-color-surface-muted)}.jv-grid-tr:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-tr-editing{background:var(--jv-color-surface-highlight, rgba(59, 130, 246, .05))}.jv-grid-tr-selected{background:var(--jv-color-primary-light, rgba(59, 130, 246, .08))}.jv-grid-checkbox{width:1rem;height:1rem;accent-color:var(--jv-color-primary);cursor:pointer}.jv-grid-boolean{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:999px;font-size:.75rem;font-weight:700}.jv-grid-boolean-true{background:var(--jv-color-success);color:#fff}.jv-grid-boolean-false{background:var(--jv-color-danger);color:#fff}.jv-grid-empty{padding:var(--jv-spacing-xl) var(--jv-spacing-md);text-align:center;color:var(--jv-color-foreground-muted);font-style:italic}.jv-grid-actions-group{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-loading{display:flex;align-items:center;justify-content:center;gap:var(--jv-spacing-md);padding:var(--jv-spacing-xl);color:var(--jv-color-foreground-muted)}.jv-grid-spinner{width:1.25rem;height:1.25rem;border:2px solid var(--jv-color-border);border-right-color:var(--jv-color-primary);border-radius:999px;animation:jv-grid-spin .8s linear infinite}@keyframes jv-grid-spin{to{transform:rotate(360deg)}}.jv-grid-pagination{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-grid-pagination-info{font-size:.875rem;color:var(--jv-color-foreground-muted)}.jv-grid-pagination-controls{display:flex;align-items:center;gap:var(--jv-spacing-xs);flex-wrap:wrap}@media(max-width:640px){.jv-grid-pagination{flex-direction:column;align-items:stretch;gap:var(--jv-spacing-sm)}.jv-grid-pagination-info{text-align:center}.jv-grid-pagination-controls{justify-content:center}.jv-grid-toolbar{flex-direction:column;align-items:stretch}.jv-grid-search{width:100%}.jv-grid-export-actions{justify-content:stretch}.jv-grid-export-actions jv-button{flex:1}}.jv-grid-resize-handle{position:absolute;top:0;right:0;width:4px;height:100%;cursor:col-resize;background:transparent;z-index:3}.jv-grid-resize-handle:hover,.jv-grid-resize-handle:active{background:var(--jv-color-primary)}.jv-grid-filter-row .jv-grid-th{padding:var(--jv-spacing-xs) var(--jv-spacing-sm)}.jv-grid-filter-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-sm);background:var(--jv-color-surface);color:var(--jv-color-foreground);font-size:.8rem;box-sizing:border-box}.jv-grid-td-editable{cursor:pointer}.jv-grid-td-editable:hover{box-shadow:inset 0 0 0 1px var(--jv-color-primary)}.jv-grid-edit-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-primary);border-radius:var(--jv-radius-sm);background:var(--jv-color-surface);color:var(--jv-color-foreground);font-size:var(--jv-density-font-size);box-sizing:border-box}.jv-grid-edit-input:focus{outline:2px solid var(--jv-color-primary);outline-offset:-1px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
25479
+ `, isInline: true, styles: [".jv-grid{display:flex;flex-direction:column;gap:var(--jv-spacing-md)}.jv-grid-toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-grid-search{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-grid-export-actions{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-table-wrap{overflow-x:auto;overflow-y:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);position:relative}.jv-grid-virtual{max-height:600px}.jv-grid-virtual-spacer{pointer-events:none}.jv-grid-table{width:100%;border-collapse:collapse;background:var(--jv-color-surface)}.jv-grid-thead{background:var(--jv-color-surface-muted)}.jv-grid-th{padding:var(--jv-spacing-sm) var(--jv-spacing-md);font-weight:600;font-size:.875rem;color:var(--jv-color-foreground-muted);text-align:start;white-space:nowrap;border-bottom:1px solid var(--jv-color-border);-webkit-user-select:none;user-select:none;position:relative}.jv-grid-th-sortable{cursor:pointer}.jv-grid-th-sortable:hover{background:var(--jv-color-surface)}.jv-grid-th-reorderable{cursor:grab}.jv-grid-th-reorderable:active{cursor:grabbing}.jv-grid-th-sticky-left{position:sticky;left:0;z-index:2;background:var(--jv-color-surface-muted);border-right:1px solid var(--jv-color-border)}.jv-grid-th-sticky-right{position:sticky;right:0;z-index:2;background:var(--jv-color-surface-muted);border-left:1px solid var(--jv-color-border)}.jv-grid-th-content{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-sort-icon{font-size:.75rem;line-height:1}.jv-grid-th-select,.jv-grid-td-select{width:3rem;text-align:center}.jv-grid-th-actions,.jv-grid-td-actions{width:1%;white-space:nowrap}.jv-grid-td{padding:var(--jv-spacing-sm) var(--jv-spacing-md);color:var(--jv-color-foreground);font-size:var(--jv-density-font-size);border-bottom:1px solid var(--jv-color-border)}.jv-grid-td-sticky-left{position:sticky;left:0;z-index:1;background:var(--jv-color-surface);border-right:1px solid var(--jv-color-border)}.jv-grid-td-sticky-right{position:sticky;right:0;z-index:1;background:var(--jv-color-surface);border-left:1px solid var(--jv-color-border)}.jv-grid-t:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-tr{transition:background-color .12s ease}.jv-grid-tr:hover{background:var(--jv-color-surface-muted)}.jv-grid-tr:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-tr-editing{background:var(--jv-color-surface-highlight, rgba(59, 130, 246, .05))}.jv-grid-tr-selected{background:var(--jv-color-primary-light, rgba(59, 130, 246, .08))}.jv-grid-checkbox{width:1rem;height:1rem;accent-color:var(--jv-color-primary);cursor:pointer}.jv-grid-boolean{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:999px;font-size:.75rem;font-weight:700}.jv-grid-boolean-true{background:var(--jv-color-success);color:#fff}.jv-grid-boolean-false{background:var(--jv-color-danger);color:#fff}.jv-grid-empty{padding:var(--jv-spacing-xl) var(--jv-spacing-md);text-align:center;color:var(--jv-color-foreground-muted);font-style:italic}.jv-grid-actions-group{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-loading{display:flex;align-items:center;justify-content:center;gap:var(--jv-spacing-md);padding:var(--jv-spacing-xl);color:var(--jv-color-foreground-muted)}.jv-grid-spinner{width:1.25rem;height:1.25rem;border:2px solid var(--jv-color-border);border-right-color:var(--jv-color-primary);border-radius:999px;animation:jv-grid-spin .8s linear infinite}@keyframes jv-grid-spin{to{transform:rotate(360deg)}}.jv-grid-pagination{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-grid-pagination-info{font-size:.875rem;color:var(--jv-color-foreground-muted)}.jv-grid-pagination-controls{display:flex;align-items:center;gap:var(--jv-spacing-xs);flex-wrap:wrap}@media(max-width:640px){.jv-grid-pagination{flex-direction:column;align-items:stretch;gap:var(--jv-spacing-sm)}.jv-grid-pagination-info{text-align:center}.jv-grid-pagination-controls{justify-content:center}.jv-grid-toolbar{flex-direction:column;align-items:stretch}.jv-grid-search{width:100%}.jv-grid-export-actions{justify-content:stretch}.jv-grid-export-actions jv-button{flex:1}}.jv-grid-resize-handle{position:absolute;top:0;right:0;width:4px;height:100%;cursor:col-resize;background:transparent;z-index:3}.jv-grid-resize-handle:hover,.jv-grid-resize-handle:active{background:var(--jv-color-primary)}.jv-grid-filter-row .jv-grid-th{padding:var(--jv-spacing-xs) var(--jv-spacing-sm)}.jv-grid-filter-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-sm);background:var(--jv-color-surface);color:var(--jv-color-foreground);font-size:.8rem;box-sizing:border-box}.jv-grid-td-editable{cursor:pointer}.jv-grid-td-editable:hover{box-shadow:inset 0 0 0 1px var(--jv-color-primary)}.jv-grid-edit-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-primary);border-radius:var(--jv-radius-sm);background:var(--jv-color-surface);color:var(--jv-color-foreground);font-size:var(--jv-density-font-size);box-sizing:border-box}.jv-grid-edit-input:focus{outline:2px solid var(--jv-color-primary);outline-offset:-1px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
24381
25480
  }
24382
25481
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvGridComponent, decorators: [{
24383
25482
  type: Component,
@@ -24389,7 +25488,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24389
25488
  <div class="jv-grid-search">
24390
25489
  <jv-icon name="search" [size]="16" />
24391
25490
  <jv-input
24392
- inputId="grid-search"
25491
+ [inputId]="gridSearchInputId"
24393
25492
  [placeholder]="t('grid.searchPlaceholder')"
24394
25493
  [ngModel]="searchTerm()"
24395
25494
  (ngModelChange)="onSearchInput($event)"
@@ -24828,7 +25927,7 @@ class JvPaginationComponent {
24828
25927
  </div>
24829
25928
  </div>
24830
25929
  </nav>
24831
- `, isInline: true, styles: [".jv-pagination{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-pagination-info{font-size:.875rem;color:var(--jv-color-foreground-muted)}.jv-pagination-controls{display:flex;align-items:center;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-pagination-size{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-pagination-size-label{font-size:.875rem;color:var(--jv-color-foreground-muted);white-space:nowrap}.jv-pagination-size jv-select{width:auto;min-width:4.5rem}.jv-pagination-buttons{display:flex;align-items:center;gap:var(--jv-spacing-xs)}\n"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
25930
+ `, isInline: true, styles: [".jv-pagination{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-pagination-info{font-size:.875rem;color:var(--jv-color-foreground-muted)}.jv-pagination-controls{display:flex;align-items:center;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-pagination-size{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-pagination-size-label{font-size:.875rem;color:var(--jv-color-foreground-muted);white-space:nowrap}.jv-pagination-size jv-select{width:auto;min-width:4.5rem}.jv-pagination-buttons{display:flex;align-items:center;gap:var(--jv-spacing-xs)}\n"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
24832
25931
  }
24833
25932
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvPaginationComponent, decorators: [{
24834
25933
  type: Component,
@@ -24899,5 +25998,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24899
25998
  * Generated bundle index. Do not edit.
24900
25999
  */
24901
26000
 
24902
- 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, JvDialogComponent, JvDialogService, JvDividerComponent, JvFileInputComponent, JvForgotPasswordPageComponent, JvFormContainerComponent, JvFormatService, JvGridComponent, JvIconButtonComponent, JvIconComponent, JvImageGalleryComponent, JvImageSliderComponent, JvInputComponent, JvListComponent, JvListItemComponent, JvLoaderComponent, JvLoaderService, JvLoginPageComponent, JvModalSelectorComponent, JvPageComponent, JvPaginationComponent, JvRadioComponent, JvSectionComponent, JvSelectComponent, JvSidebarComponent, JvSwitchComponent, JvTabPanelDirective, JvTabsComponent, JvTextareaComponent, JvThemeService, JvToastComponent, JvToastService, JvTooltipDirective, JvTopbarComponent, JvTranslationService, provideJvUi };
26001
+ 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 };
24903
26002
  //# sourceMappingURL=devjuliovilla-jv-ui.mjs.map