@devjuliovilla/jv-ui 1.11.2 → 1.12.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, 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,218 +18042,1495 @@ 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
- />
18103
+ resolveInitialTheme(fallbackTheme) {
18104
+ const savedTheme = this.readSavedTheme();
18105
+ if (savedTheme) {
18106
+ return savedTheme;
18107
+ }
18108
+ if (fallbackTheme === 'high-contrast') {
18109
+ return fallbackTheme;
18110
+ }
18111
+ return this.prefersDarkMode() ? 'dark' : fallbackTheme;
18112
+ }
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
+ }
18121
+ }
18122
+ prefersDarkMode() {
18123
+ return this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
18124
+ }
18125
+ isTheme(value) {
18126
+ return value === 'light' || value === 'dark' || value === 'high-contrast';
18127
+ }
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' });
18130
+ }
18131
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvThemeService, decorators: [{
18132
+ type: Injectable,
18133
+ args: [{ providedIn: 'root' }]
18134
+ }] });
18135
+
18136
+ const ES = {
18137
+ 'list.emptyMessage': 'No hay elementos',
18138
+ 'grid.emptyMessage': 'No hay registros',
18139
+ 'grid.noResults': 'No se encontraron resultados',
18140
+ 'grid.searchPlaceholder': 'Buscar...',
18141
+ 'grid.loading': 'Cargando datos...',
18142
+ 'grid.pageOf': 'de',
18143
+ 'grid.itemsPerPage': 'Registros por página',
18144
+ 'grid.selected': 'seleccionados',
18145
+ 'grid.selectAll': 'Seleccionar todo',
18146
+ 'grid.deselectAll': 'Deseleccionar todo',
18147
+ 'grid.sortAsc': 'Orden ascendente',
18148
+ 'grid.sortDesc': 'Orden descendente',
18149
+ 'grid.sortNone': 'Sin orden',
18150
+ 'grid.pageFirst': 'Primera página',
18151
+ 'grid.pagePrev': 'Página anterior',
18152
+ 'grid.pageNext': 'Página siguiente',
18153
+ 'grid.pageLast': 'Última página',
18154
+ 'grid.pageOfTotal': 'Página {page} de {total}',
18155
+ 'grid.itemsTotal': '{total} registros',
18156
+ 'grid.itemsShowing': 'Mostrando {start}-{end} de {total}',
18157
+ 'grid.exportCsv': 'CSV',
18158
+ 'grid.exportExcel': 'Excel',
18159
+ 'grid.filterPlaceholder': 'Filtrar...',
18160
+ 'grid.filterForColumn': 'Filtrar por ${column}',
18161
+ 'grid.actionsLabel': 'Acciones',
18162
+ 'pagination.pageLabel': 'Página {page}',
18163
+ 'pagination.itemsShowing': '{start}-{end} de {total}',
18164
+ 'pagination.of': 'de',
18165
+ 'pagination.firstPage': 'Primera página',
18166
+ 'pagination.prevPage': 'Página anterior',
18167
+ 'pagination.nextPage': 'Página siguiente',
18168
+ 'pagination.lastPage': 'Última página',
18169
+ 'pagination.itemsPerPage': 'Registros por página',
18170
+ 'datePicker.placeholder': 'Seleccione una fecha',
18171
+ 'datePicker.dialogTitle': 'Seleccionar fecha',
18172
+ 'datePicker.clear': 'Limpiar fecha',
18173
+ 'datePicker.close': 'Cerrar',
18174
+ 'datePicker.prevMonth': 'Mes anterior',
18175
+ 'datePicker.nextMonth': 'Mes siguiente',
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
+ 'modalSelector.placeholder': 'Seleccione una opcion',
18182
+ 'modalSelector.searchPlaceholder': 'Buscar',
18183
+ 'modalSelector.emptyMessage': 'No se encontraron resultados',
18184
+ 'modalSelector.clear': 'Limpiar seleccion',
18185
+ 'modalSelector.close': 'Cerrar',
18186
+ 'modalSelector.results': '{count} resultados',
18187
+ 'modalSelector.selected': '{label} seleccionado',
18188
+ 'modalSelector.selectionCleared': 'Seleccion limpiada',
18189
+ 'fileInput.dropLabel': 'Arrastre archivos aqui o haga clic para seleccionarlos',
18190
+ 'fileInput.helperText': 'Compatible con seleccion multiple y arrastrar y soltar',
18191
+ 'fileInput.selectionSummary': '{count} de {max} archivos seleccionados',
18192
+ 'fileInput.invalidFiles': '{count} archivos no coinciden con el tipo permitido',
18193
+ 'fileInput.tooManyFiles': 'Solo se permiten hasta {max} archivos',
18194
+ 'fileInput.removeFile': 'Quitar archivo {name}',
18195
+ 'dialog.confirmTitle': 'Confirmar',
18196
+ 'dialog.confirm': 'Aceptar',
18197
+ 'dialog.cancel': 'Cancelar',
18198
+ 'common.expanded': 'Expandido',
18199
+ 'common.collapsed': 'Colapsado',
18200
+ 'planner.title': 'Planificador',
18201
+ 'planner.emptyMessage': 'No hay elementos programados',
18202
+ 'planner.expand': 'Expandir detalles',
18203
+ 'planner.collapse': 'Colapsar detalles',
18204
+ 'planner.unscheduled': 'Sin programar',
18205
+ 'slider.prevImage': 'Imagen anterior',
18206
+ 'slider.nextImage': 'Imagen siguiente',
18207
+ 'slider.thumbnailList': 'Miniaturas de imagenes',
18208
+ 'gallery.close': 'Cerrar',
18209
+ 'gallery.prevImage': 'Imagen anterior',
18210
+ 'gallery.nextImage': 'Imagen siguiente',
18211
+ };
18212
+
18213
+ const EN = {
18214
+ 'list.emptyMessage': 'No items',
18215
+ 'grid.emptyMessage': 'No records found',
18216
+ 'grid.noResults': 'No results found',
18217
+ 'grid.searchPlaceholder': 'Search...',
18218
+ 'grid.loading': 'Loading data...',
18219
+ 'grid.pageOf': 'of',
18220
+ 'grid.itemsPerPage': 'Items per page',
18221
+ 'grid.selected': 'selected',
18222
+ 'grid.selectAll': 'Select all',
18223
+ 'grid.deselectAll': 'Deselect all',
18224
+ 'grid.sortAsc': 'Sort ascending',
18225
+ 'grid.sortDesc': 'Sort descending',
18226
+ 'grid.sortNone': 'No sort',
18227
+ 'grid.pageFirst': 'First page',
18228
+ 'grid.pagePrev': 'Previous page',
18229
+ 'grid.pageNext': 'Next page',
18230
+ 'grid.pageLast': 'Last page',
18231
+ 'grid.pageOfTotal': 'Page {page} of {total}',
18232
+ 'grid.itemsTotal': '{total} items',
18233
+ 'grid.itemsShowing': 'Showing {start}-{end} of {total}',
18234
+ 'grid.exportCsv': 'CSV',
18235
+ 'grid.exportExcel': 'Excel',
18236
+ 'grid.filterPlaceholder': 'Filter...',
18237
+ 'grid.filterForColumn': 'Filter by ${column}',
18238
+ 'grid.actionsLabel': 'Actions',
18239
+ 'pagination.pageLabel': 'Page {page}',
18240
+ 'pagination.itemsShowing': '{start}-{end} of {total}',
18241
+ 'pagination.of': 'of',
18242
+ 'pagination.firstPage': 'First page',
18243
+ 'pagination.prevPage': 'Previous page',
18244
+ 'pagination.nextPage': 'Next page',
18245
+ 'pagination.lastPage': 'Last page',
18246
+ 'pagination.itemsPerPage': 'Items per page',
18247
+ 'datePicker.placeholder': 'Select a date',
18248
+ 'datePicker.dialogTitle': 'Select date',
18249
+ 'datePicker.clear': 'Clear date',
18250
+ 'datePicker.close': 'Close',
18251
+ 'datePicker.prevMonth': 'Previous month',
18252
+ 'datePicker.nextMonth': 'Next month',
18253
+ 'datePicker.selectionCleared': 'Date selection cleared',
18254
+ 'monthCalendar.title': 'Month calendar',
18255
+ 'monthCalendar.today': 'Today',
18256
+ 'monthCalendar.prevMonth': 'Previous month',
18257
+ 'monthCalendar.nextMonth': 'Next month',
18258
+ 'modalSelector.placeholder': 'Select an option',
18259
+ 'modalSelector.searchPlaceholder': 'Search',
18260
+ 'modalSelector.emptyMessage': 'No results found',
18261
+ 'modalSelector.clear': 'Clear selection',
18262
+ 'modalSelector.close': 'Close',
18263
+ 'modalSelector.results': '{count} results',
18264
+ 'modalSelector.selected': '{label} selected',
18265
+ 'modalSelector.selectionCleared': 'Selection cleared',
18266
+ 'fileInput.dropLabel': 'Drag files here or click to choose them',
18267
+ 'fileInput.helperText': 'Supports multiple selection and drag and drop',
18268
+ 'fileInput.selectionSummary': '{count} of {max} files selected',
18269
+ 'fileInput.invalidFiles': '{count} files do not match the allowed type',
18270
+ 'fileInput.tooManyFiles': 'Only up to {max} files are allowed',
18271
+ 'fileInput.removeFile': 'Remove file {name}',
18272
+ 'dialog.confirmTitle': 'Confirm',
18273
+ 'dialog.confirm': 'Confirm',
18274
+ 'dialog.cancel': 'Cancel',
18275
+ 'common.expanded': 'Expanded',
18276
+ 'common.collapsed': 'Collapsed',
18277
+ 'planner.title': 'Schedule planner',
18278
+ 'planner.emptyMessage': 'No scheduled items',
18279
+ 'planner.expand': 'Expand details',
18280
+ 'planner.collapse': 'Collapse details',
18281
+ 'planner.unscheduled': 'Unscheduled',
18282
+ 'slider.prevImage': 'Previous image',
18283
+ 'slider.nextImage': 'Next image',
18284
+ 'slider.thumbnailList': 'Image thumbnails',
18285
+ 'gallery.close': 'Close',
18286
+ 'gallery.prevImage': 'Previous image',
18287
+ 'gallery.nextImage': 'Next image',
18288
+ };
18289
+
18290
+ const JV_LOCALE_DICTIONARIES = {
18291
+ es: ES,
18292
+ en: EN,
18293
+ };
18294
+ const JV_DEFAULT_LOCALE = 'es';
18295
+
18296
+ class JvTranslationService {
18297
+ config = inject(JvUiConfigService);
18298
+ locale = signal(this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale), ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
18299
+ initialize() {
18300
+ const locale = this.resolveLocale(this.config.snapshot.messagesLocale ?? this.config.snapshot.locale);
18301
+ this.locale.set(locale);
18302
+ }
18303
+ setLocale(locale) {
18304
+ this.locale.set(locale);
18305
+ }
18306
+ setMessagesLocale(locale) {
18307
+ this.setLocale(locale);
18308
+ }
18309
+ translate(key, params) {
18310
+ const dict = JV_LOCALE_DICTIONARIES[this.locale()] ?? JV_LOCALE_DICTIONARIES[JV_DEFAULT_LOCALE];
18311
+ let value = dict[key];
18312
+ if (value === undefined) {
18313
+ value = JV_LOCALE_DICTIONARIES[JV_DEFAULT_LOCALE][key] ?? key;
18314
+ }
18315
+ if (params) {
18316
+ for (const [k, v] of Object.entries(params)) {
18317
+ value = value.replace(`{${k}}`, String(v));
18318
+ }
18319
+ }
18320
+ return value;
18321
+ }
18322
+ resolveLocale(locale) {
18323
+ if (!locale)
18324
+ return JV_DEFAULT_LOCALE;
18325
+ if (locale === 'es' || locale === 'en')
18326
+ return locale;
18327
+ return locale.startsWith('es') ? 'es' : 'en';
18328
+ }
18329
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18330
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, providedIn: 'root' });
18331
+ }
18332
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, decorators: [{
18333
+ type: Injectable,
18334
+ args: [{ providedIn: 'root' }]
18335
+ }] });
18336
+
18337
+ const JV_UI_CONFIG = new InjectionToken('JV_UI_CONFIG');
18338
+ const JV_UI_CONFIG_DEFAULTS = new InjectionToken('JV_UI_CONFIG_DEFAULTS', {
18339
+ providedIn: 'root',
18340
+ factory: () => JV_UI_DEFAULT_CONFIG,
18341
+ });
18342
+ function provideJvUi(config = {}) {
18343
+ const configProvider = {
18344
+ provide: JV_UI_CONFIG,
18345
+ useValue: config,
18346
+ multi: true,
18347
+ };
18348
+ return makeEnvironmentProviders([
18349
+ configProvider,
18350
+ {
18351
+ provide: ENVIRONMENT_INITIALIZER,
18352
+ multi: true,
18353
+ useValue: () => {
18354
+ inject(JvThemeService).initialize();
18355
+ inject(JvTranslationService).initialize();
18356
+ inject(JvFormatService).initialize();
18357
+ },
18358
+ },
18359
+ ]);
18360
+ }
18361
+
18362
+ class JvUiConfigService {
18363
+ defaults = inject(JV_UI_CONFIG_DEFAULTS);
18364
+ configLayers = (inject(JV_UI_CONFIG, { optional: true }) ?? []);
18365
+ get snapshot() {
18366
+ return this.configLayers.reduce((merged, layer) => ({
18367
+ ...merged,
18368
+ ...layer,
18369
+ formats: {
18370
+ ...merged.formats,
18371
+ ...(layer.formats ?? {}),
18372
+ },
18373
+ }), {
18374
+ ...this.defaults,
18375
+ formats: { ...this.defaults.formats },
18376
+ });
18377
+ }
18378
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18379
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, providedIn: 'root' });
18380
+ }
18381
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, decorators: [{
18382
+ type: Injectable,
18383
+ args: [{ providedIn: 'root' }]
18384
+ }] });
18385
+
18386
+ class JvFormatService {
18387
+ config = inject(JvUiConfigService);
18388
+ formatLocale = signal(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX', ...(ngDevMode ? [{ debugName: "formatLocale" }] : /* istanbul ignore next */ []));
18389
+ formats = signal(this.resolveFormats(this.config.snapshot.formats), ...(ngDevMode ? [{ debugName: "formats" }] : /* istanbul ignore next */ []));
18390
+ firstDayOfWeek = computed(() => this.resolveFirstDayOfWeek(this.formatLocale()), ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
18391
+ initialize() {
18392
+ this.formatLocale.set(this.config.snapshot.formatLocale || this.config.snapshot.language || 'es-MX');
18393
+ this.formats.set(this.resolveFormats(this.config.snapshot.formats));
18394
+ }
18395
+ setFormatLocale(locale) {
18396
+ this.formatLocale.set(locale);
18397
+ }
18398
+ setFormats(formats) {
18399
+ this.formats.update((current) => this.resolveFormats({ ...current, ...formats }));
18400
+ }
18401
+ format(kind, value, overrides) {
18402
+ if (value == null || value === '')
18403
+ return '';
18404
+ if (kind === 'date' || kind === 'time' || kind === 'datetime') {
18405
+ const date = this.toDate(value);
18406
+ if (!date)
18407
+ return String(value);
18408
+ return new Intl.DateTimeFormat(this.formatLocale(), this.resolveDateOptions(kind, overrides)).format(date);
18409
+ }
18410
+ const number = this.toNumber(value);
18411
+ if (number === null)
18412
+ return String(value);
18413
+ return new Intl.NumberFormat(this.formatLocale(), this.resolveNumberOptions(kind, overrides)).format(number);
18414
+ }
18415
+ toComparable(kind, value) {
18416
+ if (value == null || value === '')
18417
+ return null;
18418
+ if (kind === 'date' || kind === 'time' || kind === 'datetime') {
18419
+ const date = this.toDate(value);
18420
+ return date ? date.getTime() : String(value);
18421
+ }
18422
+ if (kind === 'integer' || kind === 'number' || kind === 'currency' || kind === 'percent') {
18423
+ const number = this.toNumber(value);
18424
+ return number ?? String(value);
18425
+ }
18426
+ return String(value);
18427
+ }
18428
+ toDate(value) {
18429
+ if (value instanceof Date) {
18430
+ return Number.isNaN(value.getTime()) ? null : value;
18431
+ }
18432
+ if (typeof value === 'number' || typeof value === 'string') {
18433
+ const date = new Date(value);
18434
+ return Number.isNaN(date.getTime()) ? null : date;
18435
+ }
18436
+ return null;
18437
+ }
18438
+ toNumber(value) {
18439
+ if (typeof value === 'number') {
18440
+ return Number.isFinite(value) ? value : null;
18441
+ }
18442
+ if (typeof value === 'string') {
18443
+ const normalized = value.trim().replace(/[%,$\s]/g, '').replace(/,/g, '');
18444
+ if (!normalized)
18445
+ return null;
18446
+ const parsed = Number(normalized);
18447
+ return Number.isFinite(parsed) ? parsed : null;
18448
+ }
18449
+ return null;
18450
+ }
18451
+ toSearchValue(kind, value) {
18452
+ if (value == null)
18453
+ return '';
18454
+ if (kind === 'date' || kind === 'time' || kind === 'datetime') {
18455
+ const date = this.toDate(value);
18456
+ if (!date)
18457
+ return String(value).toLowerCase();
18458
+ return date.toISOString().toLowerCase();
18459
+ }
18460
+ return String(value).toLowerCase();
18461
+ }
18462
+ resolveFormats(formats) {
18463
+ const defaults = this.config.snapshot.formats;
18464
+ return {
18465
+ date: { ...defaults.date, ...formats?.date },
18466
+ time: { ...defaults.time, ...formats?.time },
18467
+ datetime: { ...defaults.datetime, ...formats?.datetime },
18468
+ integer: { ...defaults.integer, ...formats?.integer },
18469
+ number: { ...defaults.number, ...formats?.number },
18470
+ currency: { ...defaults.currency, ...formats?.currency },
18471
+ percent: { ...defaults.percent, ...formats?.percent },
18472
+ };
18473
+ }
18474
+ resolveDateOptions(kind, overrides) {
18475
+ return { ...this.formats()[kind], ...overrides };
18476
+ }
18477
+ resolveNumberOptions(kind, overrides) {
18478
+ return { ...this.formats()[kind], ...overrides };
18479
+ }
18480
+ resolveFirstDayOfWeek(locale) {
18481
+ try {
18482
+ const intlLocale = new Intl.Locale(locale);
18483
+ const firstDay = intlLocale.weekInfo?.firstDay;
18484
+ if (typeof firstDay === 'number') {
18485
+ return firstDay % 7;
18486
+ }
18487
+ }
18488
+ catch {
18489
+ // Ignore unsupported Intl.Locale implementations.
18490
+ }
18491
+ return 0;
18492
+ }
18493
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18494
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, providedIn: 'root' });
18495
+ }
18496
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, decorators: [{
18497
+ type: Injectable,
18498
+ args: [{ providedIn: 'root' }]
18499
+ }] });
18500
+
18501
+ class JvBadgeComponent {
18502
+ tone = input('primary', ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
18503
+ badgeClass = computed(() => `jv-badge--${this.tone()}`, ...(ngDevMode ? [{ debugName: "badgeClass" }] : /* istanbul ignore next */ []));
18504
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18505
+ 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"] });
18506
+ }
18507
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvBadgeComponent, decorators: [{
18508
+ type: Component,
18509
+ 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"] }]
18510
+ }], propDecorators: { tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }] } });
18511
+
18512
+ class JvDayPlannerDetailDirective {
18513
+ templateRef;
18514
+ constructor(templateRef) {
18515
+ this.templateRef = templateRef;
18516
+ }
18517
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerDetailDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
18518
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: JvDayPlannerDetailDirective, isStandalone: true, selector: "ng-template[jvDayPlannerDetail]", ngImport: i0 });
18519
+ }
18520
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerDetailDirective, decorators: [{
18521
+ type: Directive,
18522
+ args: [{
18523
+ selector: 'ng-template[jvDayPlannerDetail]',
18524
+ standalone: true,
18525
+ }]
18526
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
18527
+
18528
+ class JvDayPlannerItemDirective {
18529
+ templateRef;
18530
+ constructor(templateRef) {
18531
+ this.templateRef = templateRef;
18532
+ }
18533
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerItemDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
18534
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: JvDayPlannerItemDirective, isStandalone: true, selector: "ng-template[jvDayPlannerItem]", ngImport: i0 });
18535
+ }
18536
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerItemDirective, decorators: [{
18537
+ type: Directive,
18538
+ args: [{
18539
+ selector: 'ng-template[jvDayPlannerItem]',
18540
+ standalone: true,
18541
+ }]
18542
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
18543
+
18544
+ class JvDayPlannerComponent {
18545
+ translation = inject(JvTranslationService);
18546
+ formatService = inject(JvFormatService);
18547
+ customItemTemplate = contentChild(JvDayPlannerItemDirective, ...(ngDevMode ? [{ debugName: "customItemTemplate" }] : /* istanbul ignore next */ []));
18548
+ customDetailTemplate = contentChild(JvDayPlannerDetailDirective, ...(ngDevMode ? [{ debugName: "customDetailTemplate" }] : /* istanbul ignore next */ []));
18549
+ expandedIds = signal([], ...(ngDevMode ? [{ debugName: "expandedIds" }] : /* istanbul ignore next */ []));
18550
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
18551
+ groupByDate = input(false, ...(ngDevMode ? [{ debugName: "groupByDate" }] : /* istanbul ignore next */ []));
18552
+ emptyMessage = input('', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
18553
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
18554
+ defaultExpandedItemIds = input([], ...(ngDevMode ? [{ debugName: "defaultExpandedItemIds" }] : /* istanbul ignore next */ []));
18555
+ itemSelect = output();
18556
+ resolvedAriaLabel = computed(() => this.ariaLabel() || this.translation.translate('planner.title'), ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
18557
+ resolvedItems = computed(() => {
18558
+ return this.items()
18559
+ .map((item) => {
18560
+ const date = normalizeDate$1(item.date ?? item.start ?? null);
18561
+ const start = normalizeDateTime(item.start ?? item.date ?? null);
18562
+ const end = normalizeDateTime(item.end ?? null);
18563
+ return {
18564
+ id: String(item.id),
18565
+ raw: item,
18566
+ date,
18567
+ start,
18568
+ end,
18569
+ sortValue: start?.getTime() ?? date?.getTime() ?? Number.MAX_SAFE_INTEGER,
18570
+ hasDetails: Boolean(item.details) || Boolean(this.customDetailTemplate()),
18571
+ };
18572
+ })
18573
+ .sort((left, right) => left.sortValue - right.sortValue);
18574
+ }, ...(ngDevMode ? [{ debugName: "resolvedItems" }] : /* istanbul ignore next */ []));
18575
+ groupedItems = computed(() => {
18576
+ const items = this.resolvedItems();
18577
+ if (!this.groupByDate()) {
18578
+ return [{ key: 'all', label: '', items }];
18579
+ }
18580
+ const groups = new Map();
18581
+ for (const item of items) {
18582
+ const key = item.date ? toDateKey$1(item.date) : 'unscheduled';
18583
+ const bucket = groups.get(key) ?? [];
18584
+ bucket.push(item);
18585
+ groups.set(key, bucket);
18586
+ }
18587
+ return Array.from(groups.entries()).map(([key, groupItems]) => ({
18588
+ key,
18589
+ label: key === 'unscheduled' ? this.translation.translate('planner.unscheduled') : this.formatDateLabel(groupItems[0]?.date),
18590
+ items: groupItems,
18591
+ }));
18592
+ }, ...(ngDevMode ? [{ debugName: "groupedItems" }] : /* istanbul ignore next */ []));
18593
+ constructor() {
18594
+ effect(() => {
18595
+ this.expandedIds.set(this.defaultExpandedItemIds().map((id) => String(id)));
18596
+ });
18597
+ }
18598
+ itemTemplate() {
18599
+ return this.customItemTemplate();
18600
+ }
18601
+ detailTemplate() {
18602
+ return this.customDetailTemplate();
18603
+ }
18604
+ itemContext(item) {
18605
+ return { $implicit: item.raw, item: item.raw, expanded: this.isExpanded(item.id) };
18606
+ }
18607
+ detailContext(item) {
18608
+ return { $implicit: item.raw, item: item.raw };
18609
+ }
18610
+ selectItem(item) {
18611
+ this.itemSelect.emit(item);
18612
+ }
18613
+ toggleExpanded(itemId) {
18614
+ this.expandedIds.update((current) => current.includes(itemId)
18615
+ ? current.filter((id) => id !== itemId)
18616
+ : [...current, itemId]);
18617
+ }
18618
+ isExpanded(itemId) {
18619
+ return this.expandedIds().includes(itemId);
18620
+ }
18621
+ timeLabel(item) {
18622
+ if (!item.start && !item.end) {
18623
+ return '';
18624
+ }
18625
+ const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), {
18626
+ hour: 'numeric',
18627
+ minute: '2-digit',
18628
+ });
18629
+ if (item.start && item.end) {
18630
+ return `${formatter.format(item.start)} - ${formatter.format(item.end)}`;
18631
+ }
18632
+ return formatter.format(item.start ?? item.end);
18633
+ }
18634
+ formatDateLabel(date) {
18635
+ if (!date) {
18636
+ return this.translation.translate('planner.unscheduled');
18637
+ }
18638
+ return new Intl.DateTimeFormat(this.formatService.formatLocale(), {
18639
+ weekday: 'long',
18640
+ day: 'numeric',
18641
+ month: 'long',
18642
+ year: 'numeric',
18643
+ }).format(date);
18644
+ }
18645
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18646
+ 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: `
18647
+ <section class="jv-day-planner" [attr.aria-label]="resolvedAriaLabel()">
18648
+ @if (groupedItems().length === 0) {
18649
+ <div class="jv-day-planner-empty">{{ emptyMessage() || translation.translate('planner.emptyMessage') }}</div>
18650
+ } @else {
18651
+ <div class="jv-day-planner-groups">
18652
+ @for (group of groupedItems(); track group.key) {
18653
+ <section class="jv-day-planner-group">
18654
+ @if (groupByDate()) {
18655
+ <header class="jv-day-planner-group-header">{{ group.label }}</header>
18656
+ }
18657
+
18658
+ <div class="jv-day-planner-items">
18659
+ @for (item of group.items; track item.id) {
18660
+ <article class="jv-day-planner-item" [class.jv-day-planner-item--completed]="item.raw.completed">
18661
+ <div class="jv-day-planner-item-header">
18662
+ <button type="button" class="jv-day-planner-item-button" (click)="selectItem(item.raw)">
18663
+ @if (itemTemplate()) {
18664
+ <ng-container
18665
+ [ngTemplateOutlet]="itemTemplate()!.templateRef"
18666
+ [ngTemplateOutletContext]="itemContext(item)"
18667
+ />
18668
+ } @else {
18669
+ <div class="jv-day-planner-item-content">
18670
+ <div class="jv-day-planner-item-topline">
18671
+ <strong>{{ item.raw.title }}</strong>
18672
+ <span class="jv-day-planner-item-time">{{ timeLabel(item) }}</span>
18673
+ </div>
18674
+
18675
+ <div class="jv-day-planner-item-badges">
18676
+ @if (item.raw.status) {
18677
+ <jv-badge [tone]="item.raw.statusTone ?? 'secondary'">{{ item.raw.status }}</jv-badge>
18678
+ }
18679
+ @if (item.raw.type) {
18680
+ <jv-badge [tone]="item.raw.typeTone ?? 'primary'">{{ item.raw.type }}</jv-badge>
18681
+ }
18682
+ </div>
18683
+
18684
+ <div class="jv-day-planner-item-meta">
18685
+ @if (item.raw.responsible) {
18686
+ <span>{{ item.raw.responsible }}</span>
18687
+ }
18688
+ @if (item.raw.location) {
18689
+ <span>{{ item.raw.location }}</span>
18690
+ }
18691
+ </div>
18692
+ </div>
18693
+ }
18694
+ </button>
18695
+
18696
+ @if (item.hasDetails) {
18697
+ <button
18698
+ type="button"
18699
+ class="jv-day-planner-toggle"
18700
+ [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
18701
+ [attr.aria-label]="isExpanded(item.id) ? translation.translate('planner.collapse') : translation.translate('planner.expand')"
18702
+ (click)="toggleExpanded(item.id)"
18703
+ >
18704
+ {{ isExpanded(item.id) ? '−' : '+' }}
18705
+ </button>
18706
+ }
18707
+ </div>
18708
+
18709
+ @if (item.hasDetails && isExpanded(item.id)) {
18710
+ <div class="jv-day-planner-detail">
18711
+ @if (detailTemplate()) {
18712
+ <ng-container
18713
+ [ngTemplateOutlet]="detailTemplate()!.templateRef"
18714
+ [ngTemplateOutletContext]="detailContext(item)"
18715
+ />
18716
+ } @else {
18717
+ <p>{{ item.raw.details }}</p>
18718
+ }
18719
+ </div>
18720
+ }
18721
+ </article>
18722
+ }
18723
+ </div>
18724
+ </section>
18725
+ }
18726
+ </div>
18727
+ }
18728
+ </section>
18729
+ `, 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"] }] });
18730
+ }
18731
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDayPlannerComponent, decorators: [{
18732
+ type: Component,
18733
+ args: [{ selector: 'jv-day-planner', standalone: true, imports: [NgTemplateOutlet, JvBadgeComponent], template: `
18734
+ <section class="jv-day-planner" [attr.aria-label]="resolvedAriaLabel()">
18735
+ @if (groupedItems().length === 0) {
18736
+ <div class="jv-day-planner-empty">{{ emptyMessage() || translation.translate('planner.emptyMessage') }}</div>
18737
+ } @else {
18738
+ <div class="jv-day-planner-groups">
18739
+ @for (group of groupedItems(); track group.key) {
18740
+ <section class="jv-day-planner-group">
18741
+ @if (groupByDate()) {
18742
+ <header class="jv-day-planner-group-header">{{ group.label }}</header>
18743
+ }
18744
+
18745
+ <div class="jv-day-planner-items">
18746
+ @for (item of group.items; track item.id) {
18747
+ <article class="jv-day-planner-item" [class.jv-day-planner-item--completed]="item.raw.completed">
18748
+ <div class="jv-day-planner-item-header">
18749
+ <button type="button" class="jv-day-planner-item-button" (click)="selectItem(item.raw)">
18750
+ @if (itemTemplate()) {
18751
+ <ng-container
18752
+ [ngTemplateOutlet]="itemTemplate()!.templateRef"
18753
+ [ngTemplateOutletContext]="itemContext(item)"
18754
+ />
18755
+ } @else {
18756
+ <div class="jv-day-planner-item-content">
18757
+ <div class="jv-day-planner-item-topline">
18758
+ <strong>{{ item.raw.title }}</strong>
18759
+ <span class="jv-day-planner-item-time">{{ timeLabel(item) }}</span>
18760
+ </div>
18761
+
18762
+ <div class="jv-day-planner-item-badges">
18763
+ @if (item.raw.status) {
18764
+ <jv-badge [tone]="item.raw.statusTone ?? 'secondary'">{{ item.raw.status }}</jv-badge>
18765
+ }
18766
+ @if (item.raw.type) {
18767
+ <jv-badge [tone]="item.raw.typeTone ?? 'primary'">{{ item.raw.type }}</jv-badge>
18768
+ }
18769
+ </div>
18770
+
18771
+ <div class="jv-day-planner-item-meta">
18772
+ @if (item.raw.responsible) {
18773
+ <span>{{ item.raw.responsible }}</span>
18774
+ }
18775
+ @if (item.raw.location) {
18776
+ <span>{{ item.raw.location }}</span>
18777
+ }
18778
+ </div>
18779
+ </div>
18780
+ }
18781
+ </button>
18782
+
18783
+ @if (item.hasDetails) {
18784
+ <button
18785
+ type="button"
18786
+ class="jv-day-planner-toggle"
18787
+ [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
18788
+ [attr.aria-label]="isExpanded(item.id) ? translation.translate('planner.collapse') : translation.translate('planner.expand')"
18789
+ (click)="toggleExpanded(item.id)"
18790
+ >
18791
+ {{ isExpanded(item.id) ? '−' : '+' }}
18792
+ </button>
18793
+ }
18794
+ </div>
18795
+
18796
+ @if (item.hasDetails && isExpanded(item.id)) {
18797
+ <div class="jv-day-planner-detail">
18798
+ @if (detailTemplate()) {
18799
+ <ng-container
18800
+ [ngTemplateOutlet]="detailTemplate()!.templateRef"
18801
+ [ngTemplateOutletContext]="detailContext(item)"
18802
+ />
18803
+ } @else {
18804
+ <p>{{ item.raw.details }}</p>
18805
+ }
18806
+ </div>
18807
+ }
18808
+ </article>
18809
+ }
18810
+ </div>
18811
+ </section>
18812
+ }
18813
+ </div>
18814
+ }
18815
+ </section>
18816
+ `, 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"] }]
18817
+ }], 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"] }] } });
18818
+ function normalizeDate$1(value) {
18819
+ if (!value) {
18820
+ return null;
18821
+ }
18822
+ const date = value instanceof Date ? value : new Date(value);
18823
+ return Number.isNaN(date.getTime()) ? null : new Date(date.getFullYear(), date.getMonth(), date.getDate());
18824
+ }
18825
+ function normalizeDateTime(value) {
18826
+ if (!value) {
18827
+ return null;
18828
+ }
18829
+ const date = value instanceof Date ? value : new Date(value);
18830
+ return Number.isNaN(date.getTime()) ? null : date;
18831
+ }
18832
+ function toDateKey$1(date) {
18833
+ const year = date.getFullYear();
18834
+ const month = String(date.getMonth() + 1).padStart(2, '0');
18835
+ const day = String(date.getDate()).padStart(2, '0');
18836
+ return `${year}-${month}-${day}`;
18837
+ }
18838
+
18839
+ let selectIdSequence = 0;
18840
+ class JvSelectComponent {
18841
+ options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
18842
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
18843
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
18844
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
18845
+ describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
18846
+ inputId = input(`jv-select-${++selectIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
18847
+ modelValue = input('', ...(ngDevMode ? [{ debugName: "modelValue" }] : /* istanbul ignore next */ []));
18848
+ selectionChange = output();
18849
+ value = '';
18850
+ disabled = false;
18851
+ onChange = () => undefined;
18852
+ onTouched = () => undefined;
18853
+ currentValue = computed(() => this.modelValue() || this.value, ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
18854
+ writeValue(value) {
18855
+ this.value = value ?? '';
18856
+ }
18857
+ registerOnChange(fn) {
18858
+ this.onChange = fn;
18859
+ }
18860
+ registerOnTouched(fn) {
18861
+ this.onTouched = fn;
18862
+ }
18863
+ setDisabledState(isDisabled) {
18864
+ this.disabled = isDisabled;
18865
+ }
18866
+ handleChange(event) {
18867
+ const nextValue = event.target.value;
18868
+ this.value = nextValue;
18869
+ this.onChange(nextValue);
18870
+ this.selectionChange.emit(nextValue);
18871
+ }
18872
+ handleBlur() {
18873
+ this.onTouched();
18874
+ }
18875
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18876
+ 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: [
18877
+ {
18878
+ provide: NG_VALUE_ACCESSOR,
18879
+ useExisting: forwardRef(() => JvSelectComponent),
18880
+ multi: true,
18881
+ },
18882
+ ], ngImport: i0, template: `
18883
+ <select
18884
+ class="jv-select"
18885
+ [class.is-invalid]="invalid()"
18886
+ [id]="inputId()"
18887
+ [disabled]="disabled"
18888
+ [required]="required()"
18889
+ [attr.aria-invalid]="invalid() ? 'true' : null"
18890
+ [attr.aria-describedby]="describedBy() || null"
18891
+ [value]="currentValue()"
18892
+ (change)="handleChange($event)"
18893
+ (blur)="handleBlur()"
18894
+ >
18895
+ @if (placeholder()) {
18896
+ <option value="" [disabled]="required()">{{ placeholder() }}</option>
18897
+ }
18898
+
18899
+ @for (option of options(); track option.label + ':' + option.value) {
18900
+ <option [value]="option.value" [disabled]="option.disabled ?? false">{{ option.label }}</option>
18901
+ }
18902
+ </select>
18903
+ `, 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"] });
18904
+ }
18905
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSelectComponent, decorators: [{
18906
+ type: Component,
18907
+ args: [{ selector: 'jv-select', standalone: true, providers: [
18908
+ {
18909
+ provide: NG_VALUE_ACCESSOR,
18910
+ useExisting: forwardRef(() => JvSelectComponent),
18911
+ multi: true,
18912
+ },
18913
+ ], template: `
18914
+ <select
18915
+ class="jv-select"
18916
+ [class.is-invalid]="invalid()"
18917
+ [id]="inputId()"
18918
+ [disabled]="disabled"
18919
+ [required]="required()"
18920
+ [attr.aria-invalid]="invalid() ? 'true' : null"
18921
+ [attr.aria-describedby]="describedBy() || null"
18922
+ [value]="currentValue()"
18923
+ (change)="handleChange($event)"
18924
+ (blur)="handleBlur()"
18925
+ >
18926
+ @if (placeholder()) {
18927
+ <option value="" [disabled]="required()">{{ placeholder() }}</option>
18928
+ }
18929
+
18930
+ @for (option of options(); track option.label + ':' + option.value) {
18931
+ <option [value]="option.value" [disabled]="option.disabled ?? false">{{ option.label }}</option>
18932
+ }
18933
+ </select>
18934
+ `, 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"] }]
18935
+ }], 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"] }] } });
18936
+
18937
+ class JvMonthCalendarDayDirective {
18938
+ templateRef;
18939
+ constructor(templateRef) {
18940
+ this.templateRef = templateRef;
18941
+ }
18942
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvMonthCalendarDayDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
18943
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: JvMonthCalendarDayDirective, isStandalone: true, selector: "ng-template[jvMonthCalendarDay]", ngImport: i0 });
18944
+ }
18945
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvMonthCalendarDayDirective, decorators: [{
18946
+ type: Directive,
18947
+ args: [{
18948
+ selector: 'ng-template[jvMonthCalendarDay]',
18949
+ standalone: true,
18950
+ }]
18951
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
18952
+
18953
+ class JvMonthCalendarComponent {
18954
+ translation = inject(JvTranslationService);
18955
+ formatService = inject(JvFormatService);
18956
+ gridRootRef = viewChild('gridRoot', ...(ngDevMode ? [{ debugName: "gridRootRef" }] : /* istanbul ignore next */ []));
18957
+ customDayTemplate = contentChild(JvMonthCalendarDayDirective, ...(ngDevMode ? [{ debugName: "customDayTemplate" }] : /* istanbul ignore next */ []));
18958
+ valueInput = input(undefined, { ...(ngDevMode ? { debugName: "valueInput" } : /* istanbul ignore next */ {}), alias: 'value' });
18959
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
18960
+ dayMeta = input([], ...(ngDevMode ? [{ debugName: "dayMeta" }] : /* istanbul ignore next */ []));
18961
+ selectionChange = output();
18962
+ visibleMonthChange = output();
18963
+ visibleMonth = signal(firstOfMonth$1(new Date()), ...(ngDevMode ? [{ debugName: "visibleMonth" }] : /* istanbul ignore next */ []));
18964
+ focusedDate = signal(startOfDay$1(new Date()), ...(ngDevMode ? [{ debugName: "focusedDate" }] : /* istanbul ignore next */ []));
18965
+ resolvedAriaLabel = computed(() => this.ariaLabel() || this.translation.translate('monthCalendar.title'), ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
18966
+ monthOptions = computed(() => {
18967
+ const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), { month: 'long' });
18968
+ return Array.from({ length: 12 }, (_, month) => ({
18969
+ label: capitalize$1(formatter.format(new Date(2026, month, 1))),
18970
+ value: String(month),
18971
+ }));
18972
+ }, ...(ngDevMode ? [{ debugName: "monthOptions" }] : /* istanbul ignore next */ []));
18973
+ yearOptions = computed(() => {
18974
+ const currentYear = new Date().getFullYear();
18975
+ return Array.from({ length: 21 }, (_, index) => {
18976
+ const year = currentYear - 10 + index;
18977
+ return { label: String(year), value: String(year) };
18978
+ });
18979
+ }, ...(ngDevMode ? [{ debugName: "yearOptions" }] : /* istanbul ignore next */ []));
18980
+ weekdayLabels = computed(() => {
18981
+ const startDay = this.formatService.firstDayOfWeek();
18982
+ const formatter = new Intl.DateTimeFormat(this.formatService.formatLocale(), { weekday: 'short' });
18983
+ return Array.from({ length: 7 }, (_, index) => capitalize$1(formatter.format(addDays$1(new Date(2026, 5, 7), startDay + index))));
18984
+ }, ...(ngDevMode ? [{ debugName: "weekdayLabels" }] : /* istanbul ignore next */ []));
18985
+ metaMap = computed(() => {
18986
+ const entries = this.dayMeta()
18987
+ .map((meta) => {
18988
+ const date = normalizeDate(meta.date);
18989
+ return date ? [toDateKey(date), {
18990
+ count: Math.max(0, meta.count ?? 0),
18991
+ tone: meta.tone ?? 'primary',
18992
+ label: meta.label ?? '',
18993
+ }] : null;
18994
+ })
18995
+ .filter((entry) => entry !== null);
18996
+ return new Map(entries);
18997
+ }, ...(ngDevMode ? [{ debugName: "metaMap" }] : /* istanbul ignore next */ []));
18998
+ calendarCells = computed(() => {
18999
+ const month = this.visibleMonth();
19000
+ const firstDay = firstOfMonth$1(month);
19001
+ const startOffset = (firstDay.getDay() - this.formatService.firstDayOfWeek() + 7) % 7;
19002
+ const daysInCurrentMonth = daysInMonth$1(month.getFullYear(), month.getMonth());
19003
+ const gridStart = addDays$1(firstDay, -startOffset);
19004
+ const selectedDate = this.selectedDate();
19005
+ const today = startOfDay$1(new Date());
19006
+ return Array.from({ length: Math.ceil((startOffset + daysInCurrentMonth) / 7) * 7 }, (_, index) => {
19007
+ const date = addDays$1(gridStart, index);
19008
+ return {
19009
+ date,
19010
+ currentMonth: date.getMonth() === month.getMonth(),
19011
+ isToday: sameDate$1(date, today),
19012
+ isSelected: sameDate$1(date, selectedDate),
19013
+ meta: this.metaMap().get(toDateKey(date)) ?? null,
19014
+ };
19015
+ });
19016
+ }, ...(ngDevMode ? [{ debugName: "calendarCells" }] : /* istanbul ignore next */ []));
19017
+ selectedDate = computed(() => normalizeDate(this.valueInput()), ...(ngDevMode ? [{ debugName: "selectedDate" }] : /* istanbul ignore next */ []));
19018
+ constructor() {
19019
+ effect(() => {
19020
+ const selectedDate = this.selectedDate();
19021
+ if (!selectedDate) {
19022
+ return;
19023
+ }
19024
+ this.focusedDate.set(selectedDate);
19025
+ this.visibleMonth.set(firstOfMonth$1(selectedDate));
19026
+ });
19027
+ }
19028
+ dayTemplate() {
19029
+ return this.customDayTemplate();
19030
+ }
19031
+ dayContext(cell) {
19032
+ return { $implicit: cell, cell };
19033
+ }
19034
+ shiftMonth(offset) {
19035
+ this.setVisibleMonth(new Date(this.visibleMonth().getFullYear(), this.visibleMonth().getMonth() + offset, 1));
19036
+ this.focusDateWithinVisibleMonth(this.focusedDate());
19037
+ }
19038
+ handleMonthChange(value) {
19039
+ const current = this.visibleMonth();
19040
+ this.setVisibleMonth(new Date(current.getFullYear(), Number(value), 1));
19041
+ this.focusDateWithinVisibleMonth(this.focusedDate());
19042
+ }
19043
+ handleYearChange(value) {
19044
+ const current = this.visibleMonth();
19045
+ this.setVisibleMonth(new Date(Number(value), current.getMonth(), 1));
19046
+ this.focusDateWithinVisibleMonth(this.focusedDate());
19047
+ }
19048
+ selectToday() {
19049
+ const today = startOfDay$1(new Date());
19050
+ this.setVisibleMonth(today);
19051
+ this.selectDate(today);
19052
+ }
19053
+ selectDate(date) {
19054
+ const nextValue = startOfDay$1(date);
19055
+ this.focusedDate.set(nextValue);
19056
+ this.setVisibleMonth(nextValue);
19057
+ this.selectionChange.emit(nextValue);
19058
+ }
19059
+ handleDayKeydown(event, date) {
19060
+ let nextDate = null;
19061
+ switch (event.key) {
19062
+ case 'ArrowRight':
19063
+ nextDate = addDays$1(date, 1);
19064
+ break;
19065
+ case 'ArrowLeft':
19066
+ nextDate = addDays$1(date, -1);
19067
+ break;
19068
+ case 'ArrowDown':
19069
+ nextDate = addDays$1(date, 7);
19070
+ break;
19071
+ case 'ArrowUp':
19072
+ nextDate = addDays$1(date, -7);
19073
+ break;
19074
+ case 'Home':
19075
+ nextDate = addDays$1(date, -((date.getDay() - this.formatService.firstDayOfWeek() + 7) % 7));
19076
+ break;
19077
+ case 'End':
19078
+ nextDate = addDays$1(date, 6 - ((date.getDay() - this.formatService.firstDayOfWeek() + 7) % 7));
19079
+ break;
19080
+ case 'Enter':
19081
+ case ' ':
19082
+ event.preventDefault();
19083
+ this.selectDate(date);
19084
+ return;
19085
+ }
19086
+ if (!nextDate) {
19087
+ return;
19088
+ }
19089
+ event.preventDefault();
19090
+ this.focusedDate.set(nextDate);
19091
+ this.setVisibleMonth(nextDate);
19092
+ queueMicrotask(() => this.focusDateButton(nextDate));
19093
+ }
19094
+ isFocusedDate(date) {
19095
+ return sameDate$1(date, this.focusedDate());
19096
+ }
19097
+ dayAriaLabel(cell) {
19098
+ const parts = [new Intl.DateTimeFormat(this.formatService.formatLocale(), {
19099
+ weekday: 'long',
19100
+ day: 'numeric',
19101
+ month: 'long',
19102
+ year: 'numeric',
19103
+ }).format(cell.date)];
19104
+ if (cell.meta?.count) {
19105
+ parts.push(`${cell.meta.count}`);
19106
+ }
19107
+ if (cell.meta?.label) {
19108
+ parts.push(cell.meta.label);
19109
+ }
19110
+ return parts.join('. ');
19111
+ }
19112
+ markerClass(tone) {
19113
+ return `jv-month-calendar-marker--${tone}`;
19114
+ }
19115
+ isoDate(date) {
19116
+ return toDateKey(date);
19117
+ }
19118
+ setVisibleMonth(date) {
19119
+ const month = firstOfMonth$1(date);
19120
+ this.visibleMonth.set(month);
19121
+ this.visibleMonthChange.emit(month);
19122
+ }
19123
+ focusDateWithinVisibleMonth(date) {
19124
+ const month = this.visibleMonth();
19125
+ const nextDate = startOfDay$1(new Date(month.getFullYear(), month.getMonth(), Math.min(date.getDate(), daysInMonth$1(month.getFullYear(), month.getMonth()))));
19126
+ this.focusedDate.set(nextDate);
19127
+ queueMicrotask(() => this.focusDateButton(nextDate));
19128
+ }
19129
+ focusDateButton(date) {
19130
+ const button = this.gridRootRef()?.nativeElement
19131
+ .querySelector(`[data-jv-date="${toDateKey(date)}"]`);
19132
+ button?.focus();
19133
+ }
19134
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvMonthCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19135
+ 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", 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: `
19136
+ <section class="jv-month-calendar" [attr.aria-label]="resolvedAriaLabel()">
19137
+ <div class="jv-month-calendar-toolbar">
19138
+ <jv-icon-button
19139
+ icon="chevron-left"
19140
+ variant="ghost"
19141
+ [ariaLabel]="translation.translate('monthCalendar.prevMonth')"
19142
+ (click)="shiftMonth(-1)"
19143
+ />
19144
+
19145
+ <div class="jv-month-calendar-selects">
19146
+ <jv-select
19147
+ [options]="monthOptions()"
19148
+ [modelValue]="visibleMonth().getMonth().toString()"
19149
+ (selectionChange)="handleMonthChange($event)"
19150
+ />
19151
+ <jv-select
19152
+ [options]="yearOptions()"
19153
+ [modelValue]="visibleMonth().getFullYear().toString()"
19154
+ (selectionChange)="handleYearChange($event)"
19155
+ />
19156
+ </div>
19157
+
19158
+ <jv-icon-button
19159
+ icon="chevron-right"
19160
+ variant="ghost"
19161
+ [ariaLabel]="translation.translate('monthCalendar.nextMonth')"
19162
+ (click)="shiftMonth(1)"
19163
+ />
19164
+ </div>
19165
+
19166
+ <div class="jv-month-calendar-actions">
19167
+ <button type="button" class="jv-month-calendar-today" (click)="selectToday()">
19168
+ {{ translation.translate('monthCalendar.today') }}
19169
+ </button>
19170
+ </div>
19171
+
19172
+ <div class="jv-month-calendar-weekdays" aria-hidden="true">
19173
+ @for (weekday of weekdayLabels(); track weekday) {
19174
+ <span>{{ weekday }}</span>
19175
+ }
19176
+ </div>
19177
+
19178
+ <div #gridRoot class="jv-month-calendar-grid" role="grid" [attr.aria-label]="resolvedAriaLabel()">
19179
+ @for (cell of calendarCells(); track isoDate(cell.date)) {
19180
+ <button
19181
+ type="button"
19182
+ class="jv-month-calendar-day"
19183
+ [class.jv-month-calendar-day--outside]="!cell.currentMonth"
19184
+ [class.jv-month-calendar-day--today]="cell.isToday"
19185
+ [class.jv-month-calendar-day--selected]="cell.isSelected"
19186
+ [attr.aria-selected]="cell.isSelected ? 'true' : 'false'"
19187
+ [attr.aria-label]="dayAriaLabel(cell)"
19188
+ [attr.data-jv-date]="isoDate(cell.date)"
19189
+ [attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
19190
+ (click)="selectDate(cell.date)"
19191
+ (keydown)="handleDayKeydown($event, cell.date)"
19192
+ >
19193
+ @if (dayTemplate()) {
19194
+ <ng-container [ngTemplateOutlet]="dayTemplate()!.templateRef" [ngTemplateOutletContext]="dayContext(cell)" />
19195
+ } @else {
19196
+ <span class="jv-month-calendar-day-number">{{ cell.date.getDate() }}</span>
19197
+ @if (cell.meta?.count) {
19198
+ <span class="jv-month-calendar-day-count" [class]="markerClass(cell.meta!.tone)">{{ cell.meta?.count }}</span>
19199
+ } @else if (cell.meta) {
19200
+ <span class="jv-month-calendar-day-dot" [class]="markerClass(cell.meta.tone)"></span>
19201
+ }
19202
+ }
19203
+ </button>
19204
+ }
19205
+ </div>
19206
+ </section>
19207
+ `, 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-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-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", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
19208
+ }
19209
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvMonthCalendarComponent, decorators: [{
19210
+ type: Component,
19211
+ args: [{ selector: 'jv-month-calendar', standalone: true, imports: [NgTemplateOutlet, JvIconButtonComponent, JvSelectComponent], template: `
19212
+ <section class="jv-month-calendar" [attr.aria-label]="resolvedAriaLabel()">
19213
+ <div class="jv-month-calendar-toolbar">
19214
+ <jv-icon-button
19215
+ icon="chevron-left"
19216
+ variant="ghost"
19217
+ [ariaLabel]="translation.translate('monthCalendar.prevMonth')"
19218
+ (click)="shiftMonth(-1)"
19219
+ />
19220
+
19221
+ <div class="jv-month-calendar-selects">
19222
+ <jv-select
19223
+ [options]="monthOptions()"
19224
+ [modelValue]="visibleMonth().getMonth().toString()"
19225
+ (selectionChange)="handleMonthChange($event)"
19226
+ />
19227
+ <jv-select
19228
+ [options]="yearOptions()"
19229
+ [modelValue]="visibleMonth().getFullYear().toString()"
19230
+ (selectionChange)="handleYearChange($event)"
19231
+ />
19232
+ </div>
19233
+
19234
+ <jv-icon-button
19235
+ icon="chevron-right"
19236
+ variant="ghost"
19237
+ [ariaLabel]="translation.translate('monthCalendar.nextMonth')"
19238
+ (click)="shiftMonth(1)"
19239
+ />
19240
+ </div>
19241
+
19242
+ <div class="jv-month-calendar-actions">
19243
+ <button type="button" class="jv-month-calendar-today" (click)="selectToday()">
19244
+ {{ translation.translate('monthCalendar.today') }}
19245
+ </button>
19246
+ </div>
19247
+
19248
+ <div class="jv-month-calendar-weekdays" aria-hidden="true">
19249
+ @for (weekday of weekdayLabels(); track weekday) {
19250
+ <span>{{ weekday }}</span>
19251
+ }
19252
+ </div>
19253
+
19254
+ <div #gridRoot class="jv-month-calendar-grid" role="grid" [attr.aria-label]="resolvedAriaLabel()">
19255
+ @for (cell of calendarCells(); track isoDate(cell.date)) {
19256
+ <button
19257
+ type="button"
19258
+ class="jv-month-calendar-day"
19259
+ [class.jv-month-calendar-day--outside]="!cell.currentMonth"
19260
+ [class.jv-month-calendar-day--today]="cell.isToday"
19261
+ [class.jv-month-calendar-day--selected]="cell.isSelected"
19262
+ [attr.aria-selected]="cell.isSelected ? 'true' : 'false'"
19263
+ [attr.aria-label]="dayAriaLabel(cell)"
19264
+ [attr.data-jv-date]="isoDate(cell.date)"
19265
+ [attr.tabindex]="isFocusedDate(cell.date) ? 0 : -1"
19266
+ (click)="selectDate(cell.date)"
19267
+ (keydown)="handleDayKeydown($event, cell.date)"
19268
+ >
19269
+ @if (dayTemplate()) {
19270
+ <ng-container [ngTemplateOutlet]="dayTemplate()!.templateRef" [ngTemplateOutletContext]="dayContext(cell)" />
19271
+ } @else {
19272
+ <span class="jv-month-calendar-day-number">{{ cell.date.getDate() }}</span>
19273
+ @if (cell.meta?.count) {
19274
+ <span class="jv-month-calendar-day-count" [class]="markerClass(cell.meta!.tone)">{{ cell.meta?.count }}</span>
19275
+ } @else if (cell.meta) {
19276
+ <span class="jv-month-calendar-day-dot" [class]="markerClass(cell.meta.tone)"></span>
19277
+ }
19278
+ }
19279
+ </button>
19280
+ }
19281
+ </div>
19282
+ </section>
19283
+ `, 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-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-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"] }]
19284
+ }], 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 }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", 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"] }] } });
19285
+ function normalizeDate(value) {
19286
+ if (!value) {
19287
+ return null;
19288
+ }
19289
+ const date = value instanceof Date ? value : new Date(value);
19290
+ return Number.isNaN(date.getTime()) ? null : startOfDay$1(date);
19291
+ }
19292
+ function daysInMonth$1(year, month) {
19293
+ return new Date(year, month + 1, 0).getDate();
19294
+ }
19295
+ function firstOfMonth$1(date) {
19296
+ return new Date(date.getFullYear(), date.getMonth(), 1);
19297
+ }
19298
+ function startOfDay$1(date) {
19299
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
19300
+ }
19301
+ function addDays$1(date, amount) {
19302
+ return startOfDay$1(new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount));
19303
+ }
19304
+ function sameDate$1(left, right) {
19305
+ if (!left || !right) {
19306
+ return false;
19307
+ }
19308
+ return left.getFullYear() === right.getFullYear()
19309
+ && left.getMonth() === right.getMonth()
19310
+ && left.getDate() === right.getDate();
19311
+ }
19312
+ function toDateKey(date) {
19313
+ const year = date.getFullYear();
19314
+ const month = String(date.getMonth() + 1).padStart(2, '0');
19315
+ const day = String(date.getDate()).padStart(2, '0');
19316
+ return `${year}-${month}-${day}`;
19317
+ }
19318
+ function capitalize$1(value) {
19319
+ return value.charAt(0).toUpperCase() + value.slice(1);
19320
+ }
19321
+
19322
+ class JvAlertComponent {
19323
+ tone = input('info', ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
19324
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
19325
+ role = input('status', ...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
19326
+ alertClass = computed(() => `jv-alert--${this.tone()}`, ...(ngDevMode ? [{ debugName: "alertClass" }] : /* istanbul ignore next */ []));
19327
+ iconName = computed(() => {
19328
+ switch (this.tone()) {
19329
+ case 'success':
19330
+ return 'check';
19331
+ case 'warning':
19332
+ return 'triangle-alert';
19333
+ case 'danger':
19334
+ return 'circle-alert';
19335
+ case 'primary':
19336
+ return 'sparkles';
19337
+ case 'secondary':
19338
+ case 'neutral':
19339
+ return 'info';
19340
+ default:
19341
+ return 'info';
19342
+ }
19343
+ }, ...(ngDevMode ? [{ debugName: "iconName" }] : /* istanbul ignore next */ []));
19344
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19345
+ 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: `
19346
+ <div class="jv-alert" [class]="alertClass()" [attr.role]="role()">
19347
+ <div class="jv-alert-icon">
19348
+ <jv-icon [name]="iconName()" [size]="18" />
19349
+ </div>
19350
+ <div class="jv-alert-content">
19351
+ @if (title()) {
19352
+ <strong>{{ title() }}</strong>
19353
+ }
19354
+ <div><ng-content></ng-content></div>
19355
+ </div>
19356
+ </div>
19357
+ `, 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"] }] });
19358
+ }
19359
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAlertComponent, decorators: [{
19360
+ type: Component,
19361
+ args: [{ selector: 'jv-alert', standalone: true, imports: [JvIconComponent], template: `
19362
+ <div class="jv-alert" [class]="alertClass()" [attr.role]="role()">
19363
+ <div class="jv-alert-icon">
19364
+ <jv-icon [name]="iconName()" [size]="18" />
19365
+ </div>
19366
+ <div class="jv-alert-content">
19367
+ @if (title()) {
19368
+ <strong>{{ title() }}</strong>
19369
+ }
19370
+ <div><ng-content></ng-content></div>
19371
+ </div>
19372
+ </div>
19373
+ `, 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"] }]
19374
+ }], 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 }] }] } });
19375
+
19376
+ class JvCardComponent {
19377
+ elevated = input(true, ...(ngDevMode ? [{ debugName: "elevated" }] : /* istanbul ignore next */ []));
19378
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19379
+ 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: `
19380
+ <article class="jv-card" [class]="elevated() ? 'jv-card--elevated' : 'jv-card--flat'">
19381
+ <ng-content></ng-content>
19382
+ </article>
19383
+ `, 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"] });
19384
+ }
19385
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCardComponent, decorators: [{
19386
+ type: Component,
19387
+ args: [{ selector: 'jv-card', standalone: true, template: `
19388
+ <article class="jv-card" [class]="elevated() ? 'jv-card--elevated' : 'jv-card--flat'">
19389
+ <ng-content></ng-content>
19390
+ </article>
19391
+ `, 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"] }]
19392
+ }], propDecorators: { elevated: [{ type: i0.Input, args: [{ isSignal: true, alias: "elevated", required: false }] }] } });
19393
+
19394
+ class JvFormContainerComponent {
19395
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
19396
+ hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
19397
+ error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
19398
+ inputId = input('', ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
19399
+ hintId = input('', ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
19400
+ errorId = input('', ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
19401
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
19402
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
19403
+ resolvedHintId = computed(() => this.hintId() || (this.inputId() ? `${this.inputId()}-hint` : ''), ...(ngDevMode ? [{ debugName: "resolvedHintId" }] : /* istanbul ignore next */ []));
19404
+ resolvedErrorId = computed(() => this.errorId() || (this.inputId() ? `${this.inputId()}-error` : ''), ...(ngDevMode ? [{ debugName: "resolvedErrorId" }] : /* istanbul ignore next */ []));
19405
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19406
+ 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: `
19407
+ <div class="jv-form-container" [class.is-invalid]="invalid()">
19408
+ @if (label()) {
19409
+ <label class="jv-form-label" [attr.for]="inputId() || null">
19410
+ <span>{{ label() }}</span>
19411
+ @if (required()) {
19412
+ <span class="required-indicator" aria-hidden="true">*</span>
19413
+ }
19414
+ </label>
19415
+ }
19416
+
19417
+ <ng-content></ng-content>
19418
+
19419
+ @if (hint() && !invalid()) {
19420
+ <p class="jv-form-hint" [id]="resolvedHintId() || null">{{ hint() }}</p>
19421
+ }
19422
+
19423
+ @if (error() && invalid()) {
19424
+ <p class="jv-form-error" [id]="resolvedErrorId() || null" role="alert" aria-live="assertive">{{ error() }}</p>
19425
+ }
19426
+ </div>
19427
+ `, 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"] });
19428
+ }
19429
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormContainerComponent, decorators: [{
19430
+ type: Component,
19431
+ args: [{ selector: 'jv-form-container', standalone: true, template: `
19432
+ <div class="jv-form-container" [class.is-invalid]="invalid()">
19433
+ @if (label()) {
19434
+ <label class="jv-form-label" [attr.for]="inputId() || null">
19435
+ <span>{{ label() }}</span>
19436
+ @if (required()) {
19437
+ <span class="required-indicator" aria-hidden="true">*</span>
19438
+ }
19439
+ </label>
19440
+ }
19441
+
19442
+ <ng-content></ng-content>
19443
+
19444
+ @if (hint() && !invalid()) {
19445
+ <p class="jv-form-hint" [id]="resolvedHintId() || null">{{ hint() }}</p>
19446
+ }
19447
+
19448
+ @if (error() && invalid()) {
19449
+ <p class="jv-form-error" [id]="resolvedErrorId() || null" role="alert" aria-live="assertive">{{ error() }}</p>
19450
+ }
19451
+ </div>
19452
+ `, 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"] }]
19453
+ }], 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 }] }] } });
19454
+
19455
+ let inputIdSequence = 0;
19456
+ class JvInputComponent {
19457
+ type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
19458
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
19459
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
19460
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
19461
+ describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
19462
+ inputId = input(`jv-input-${++inputIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
19463
+ value = '';
19464
+ disabled = false;
19465
+ onChange = () => undefined;
19466
+ onTouched = () => undefined;
19467
+ writeValue(value) {
19468
+ this.value = value ?? '';
19469
+ }
19470
+ registerOnChange(fn) {
19471
+ this.onChange = fn;
19472
+ }
19473
+ registerOnTouched(fn) {
19474
+ this.onTouched = fn;
19475
+ }
19476
+ setDisabledState(isDisabled) {
19477
+ this.disabled = isDisabled;
19478
+ }
19479
+ handleInput(event) {
19480
+ const nextValue = event.target.value;
19481
+ this.value = nextValue;
19482
+ this.onChange(nextValue);
19483
+ }
19484
+ handleBlur() {
19485
+ this.onTouched();
19486
+ }
19487
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19488
+ 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: [
19489
+ {
19490
+ provide: NG_VALUE_ACCESSOR,
19491
+ useExisting: forwardRef(() => JvInputComponent),
19492
+ multi: true,
19493
+ },
19494
+ ], ngImport: i0, template: `
19495
+ <input
19496
+ class="jv-input"
19497
+ [class.is-invalid]="invalid()"
19498
+ [id]="inputId()"
19499
+ [type]="type()"
19500
+ [value]="value"
19501
+ [placeholder]="placeholder()"
19502
+ [required]="required()"
19503
+ [disabled]="disabled"
19504
+ [attr.aria-invalid]="invalid() ? 'true' : null"
19505
+ [attr.aria-describedby]="describedBy() || null"
19506
+ (input)="handleInput($event)"
19507
+ (blur)="handleBlur()"
19508
+ />
19509
+ `, 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 }] });
19510
+ }
19511
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvInputComponent, decorators: [{
19512
+ type: Component,
19513
+ args: [{ selector: 'jv-input', standalone: true, imports: [CommonModule], providers: [
19514
+ {
19515
+ provide: NG_VALUE_ACCESSOR,
19516
+ useExisting: forwardRef(() => JvInputComponent),
19517
+ multi: true,
19518
+ },
19519
+ ], template: `
19520
+ <input
19521
+ class="jv-input"
19522
+ [class.is-invalid]="invalid()"
19523
+ [id]="inputId()"
19524
+ [type]="type()"
19525
+ [value]="value"
19526
+ [placeholder]="placeholder()"
19527
+ [required]="required()"
19528
+ [disabled]="disabled"
19529
+ [attr.aria-invalid]="invalid() ? 'true' : null"
19530
+ [attr.aria-describedby]="describedBy() || null"
19531
+ (input)="handleInput($event)"
19532
+ (blur)="handleBlur()"
19533
+ />
18257
19534
  `, 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
19535
  }], 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
19536
 
@@ -18368,784 +19645,346 @@ class JvChangePasswordPageComponent {
18368
19645
  </jv-card>
18369
19646
  `, 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
19647
  }
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;
18424
- }
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;
18487
- }
18488
- registerOnTouched(fn) {
18489
- this.onTouched = fn;
18490
- }
18491
- setDisabledState(isDisabled) {
18492
- this.disabled = isDisabled;
18493
- }
18494
- handleChange(event) {
18495
- const nextValue = event.target.checked;
18496
- this.value = nextValue;
18497
- this.onChange(nextValue);
18498
- }
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: [{
19648
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvChangePasswordPageComponent, decorators: [{
18608
19649
  type: Component,
18609
- args: [{ selector: 'jv-login-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvCheckboxComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
19650
+ args: [{ selector: 'jv-change-password-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
18610
19651
  <jv-card>
18611
19652
  <jv-section [title]="title()" [description]="description()">
18612
19653
  @if (error()) {
18613
- <jv-alert tone="danger" title="Sign-in error" role="alert">{{ error() }}</jv-alert>
19654
+ <jv-alert tone="danger" title="Password change error" role="alert">{{ error() }}</jv-alert>
18614
19655
  }
18615
19656
 
18616
19657
  <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" />
19658
+ <jv-form-container label="Current password" inputId="jv-current-password" error="Current password is required" [required]="true" [invalid]="currentInvalid()">
19659
+ <jv-input inputId="jv-current-password" type="password" formControlName="currentPassword" [invalid]="currentInvalid()" />
18619
19660
  </jv-form-container>
18620
19661
 
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" />
19662
+ <jv-form-container label="New password" inputId="jv-new-password" error="New password is required" [required]="true" [invalid]="newInvalid()">
19663
+ <jv-input inputId="jv-new-password" type="password" formControlName="newPassword" [invalid]="newInvalid()" />
18623
19664
  </jv-form-container>
18624
19665
 
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>
19666
+ <jv-form-container label="Confirm new password" inputId="jv-confirm-password" error="Passwords must match" [required]="true" [invalid]="confirmInvalid()">
19667
+ <jv-input inputId="jv-confirm-password" type="password" formControlName="confirmPassword" [invalid]="confirmInvalid()" />
19668
+ </jv-form-container>
18629
19669
 
18630
- <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19670
+ <div class="auth-actions">
19671
+ <jv-button variant="outline" (click)="cancel.emit()">{{ cancelLabel() }}</jv-button>
19672
+ <jv-button variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19673
+ </div>
18631
19674
  </form>
18632
19675
  </jv-section>
18633
19676
  </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 }] }] } });
19677
+ `, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"] }]
19678
+ }], 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"] }] } });
18677
19679
 
18678
- class JvAnnouncementService {
18679
- document = inject(DOCUMENT);
18680
- region = null;
18681
- announce(message, politeness = 'polite') {
18682
- if (!message.trim()) {
19680
+ class JvForgotPasswordPageComponent {
19681
+ formBuilder = inject(FormBuilder);
19682
+ title = input('Reset your password', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
19683
+ description = input('We will send reset instructions to your email address.', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
19684
+ submitLabel = input('Send reset link', ...(ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []));
19685
+ backLabel = input('Back to login', ...(ngDevMode ? [{ debugName: "backLabel" }] : /* istanbul ignore next */ []));
19686
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
19687
+ error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
19688
+ forgotPasswordSubmit = output();
19689
+ backToLogin = output();
19690
+ form = this.formBuilder.group({
19691
+ email: ['', [Validators.required, Validators.email]],
19692
+ });
19693
+ emailInvalid = computed(() => {
19694
+ const control = this.form.controls.email;
19695
+ return control.invalid && (control.touched || control.dirty);
19696
+ }, ...(ngDevMode ? [{ debugName: "emailInvalid" }] : /* istanbul ignore next */ []));
19697
+ submit() {
19698
+ if (this.form.invalid) {
19699
+ this.form.markAllAsTouched();
18683
19700
  return;
18684
19701
  }
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' });
18709
- }
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' });
19702
+ this.forgotPasswordSubmit.emit(this.form.getRawValue());
19703
+ }
19704
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvForgotPasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19705
+ 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: `
19706
+ <jv-card>
19707
+ <jv-section [title]="title()" [description]="description()">
19708
+ @if (error()) {
19709
+ <jv-alert tone="danger" title="Reset error" role="alert">{{ error() }}</jv-alert>
19710
+ }
19711
+
19712
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19713
+ <jv-form-container label="Email" inputId="jv-forgot-email" error="Enter a valid email" [required]="true" [invalid]="emailInvalid()">
19714
+ <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" placeholder="you@example.com" />
19715
+ </jv-form-container>
19716
+
19717
+ <div class="auth-actions">
19718
+ <jv-button variant="outline" (click)="backToLogin.emit()">{{ backLabel() }}</jv-button>
19719
+ <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19720
+ </div>
19721
+ </form>
19722
+ </jv-section>
19723
+ </jv-card>
19724
+ `, 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"] }] });
18844
19725
  }
18845
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvFormatService, decorators: [{
18846
- type: Injectable,
18847
- args: [{ providedIn: 'root' }]
18848
- }] });
19726
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvForgotPasswordPageComponent, decorators: [{
19727
+ type: Component,
19728
+ args: [{ selector: 'jv-forgot-password-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
19729
+ <jv-card>
19730
+ <jv-section [title]="title()" [description]="description()">
19731
+ @if (error()) {
19732
+ <jv-alert tone="danger" title="Reset error" role="alert">{{ error() }}</jv-alert>
19733
+ }
19734
+
19735
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19736
+ <jv-form-container label="Email" inputId="jv-forgot-email" error="Enter a valid email" [required]="true" [invalid]="emailInvalid()">
19737
+ <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" placeholder="you@example.com" />
19738
+ </jv-form-container>
19739
+
19740
+ <div class="auth-actions">
19741
+ <jv-button variant="outline" (click)="backToLogin.emit()">{{ backLabel() }}</jv-button>
19742
+ <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19743
+ </div>
19744
+ </form>
19745
+ </jv-section>
19746
+ </jv-card>
19747
+ `, styles: [".auth-form{display:grid;gap:var(--jv-spacing-md)}.auth-actions{display:flex;gap:var(--jv-spacing-sm);flex-wrap:wrap}\n"] }]
19748
+ }], 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"] }] } });
18849
19749
 
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
- }
19750
+ let checkboxIdSequence = 0;
19751
+ class JvCheckboxComponent {
19752
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
19753
+ describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
19754
+ inputId = input(`jv-checkbox-${++checkboxIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
19755
+ value = false;
19756
+ disabled = false;
19757
+ onChange = () => undefined;
19758
+ onTouched = () => undefined;
19759
+ writeValue(value) {
19760
+ this.value = value ?? false;
18871
19761
  }
18872
- setDensity(density) {
18873
- this.applyDensity(density);
19762
+ registerOnChange(fn) {
19763
+ this.onChange = fn;
18874
19764
  }
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';
19765
+ registerOnTouched(fn) {
19766
+ this.onTouched = fn;
18880
19767
  }
18881
- applyDensity(density) {
18882
- this.density.set(density);
18883
- this.document.documentElement.dataset['density'] = density;
19768
+ setDisabledState(isDisabled) {
19769
+ this.disabled = isDisabled;
18884
19770
  }
18885
- applyLanguage(language) {
18886
- this.document.documentElement.lang = language;
19771
+ handleChange(event) {
19772
+ const nextValue = event.target.checked;
19773
+ this.value = nextValue;
19774
+ this.onChange(nextValue);
18887
19775
  }
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;
19776
+ handleBlur() {
19777
+ this.onTouched();
18897
19778
  }
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;
19779
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19780
+ 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: [
19781
+ {
19782
+ provide: NG_VALUE_ACCESSOR,
19783
+ useExisting: forwardRef(() => JvCheckboxComponent),
19784
+ multi: true,
19785
+ },
19786
+ ], ngImport: i0, template: `
19787
+ <label class="jv-checkbox" [class.is-disabled]="disabled">
19788
+ <input
19789
+ type="checkbox"
19790
+ [id]="inputId()"
19791
+ [checked]="value"
19792
+ [disabled]="disabled"
19793
+ [attr.aria-describedby]="describedBy() || null"
19794
+ (change)="handleChange($event)"
19795
+ (blur)="handleBlur()"
19796
+ />
19797
+ <span>{{ label() }}</span>
19798
+ </label>
19799
+ `, 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"] });
19800
+ }
19801
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvCheckboxComponent, decorators: [{
19802
+ type: Component,
19803
+ args: [{ selector: 'jv-checkbox', standalone: true, providers: [
19804
+ {
19805
+ provide: NG_VALUE_ACCESSOR,
19806
+ useExisting: forwardRef(() => JvCheckboxComponent),
19807
+ multi: true,
19808
+ },
19809
+ ], template: `
19810
+ <label class="jv-checkbox" [class.is-disabled]="disabled">
19811
+ <input
19812
+ type="checkbox"
19813
+ [id]="inputId()"
19814
+ [checked]="value"
19815
+ [disabled]="disabled"
19816
+ [attr.aria-describedby]="describedBy() || null"
19817
+ (change)="handleChange($event)"
19818
+ (blur)="handleBlur()"
19819
+ />
19820
+ <span>{{ label() }}</span>
19821
+ </label>
19822
+ `, 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"] }]
19823
+ }], 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 }] }] } });
19824
+
19825
+ class JvLoginPageComponent {
19826
+ formBuilder = inject(FormBuilder);
19827
+ title = input('Welcome back', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
19828
+ description = input('Use your account credentials to continue.', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
19829
+ submitLabel = input('Sign in', ...(ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []));
19830
+ rememberMeLabel = input('Remember me', ...(ngDevMode ? [{ debugName: "rememberMeLabel" }] : /* istanbul ignore next */ []));
19831
+ forgotPasswordLabel = input('Forgot password?', ...(ngDevMode ? [{ debugName: "forgotPasswordLabel" }] : /* istanbul ignore next */ []));
19832
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
19833
+ error = input('', ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
19834
+ loginSubmit = output();
19835
+ forgotPasswordClick = output();
19836
+ form = this.formBuilder.group({
19837
+ identifier: ['', Validators.required],
19838
+ password: ['', Validators.required],
19839
+ rememberMe: [false],
19840
+ });
19841
+ identifierInvalid = computed(() => {
19842
+ const control = this.form.controls.identifier;
19843
+ return control.invalid && (control.touched || control.dirty);
19844
+ }, ...(ngDevMode ? [{ debugName: "identifierInvalid" }] : /* istanbul ignore next */ []));
19845
+ passwordInvalid = computed(() => {
19846
+ const control = this.form.controls.password;
19847
+ return control.invalid && (control.touched || control.dirty);
19848
+ }, ...(ngDevMode ? [{ debugName: "passwordInvalid" }] : /* istanbul ignore next */ []));
19849
+ submit() {
19850
+ if (this.form.invalid) {
19851
+ this.form.markAllAsTouched();
19852
+ return;
18905
19853
  }
19854
+ this.loginSubmit.emit(this.form.getRawValue());
18906
19855
  }
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' });
19856
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvLoginPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19857
+ 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: `
19858
+ <jv-card>
19859
+ <jv-section [title]="title()" [description]="description()">
19860
+ @if (error()) {
19861
+ <jv-alert tone="danger" title="Sign-in error" role="alert">{{ error() }}</jv-alert>
19862
+ }
19863
+
19864
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19865
+ <jv-form-container label="Email or username" inputId="jv-login-identifier" error="This field is required" [required]="true" [invalid]="identifierInvalid()">
19866
+ <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" placeholder="you@example.com" />
19867
+ </jv-form-container>
19868
+
19869
+ <jv-form-container label="Password" inputId="jv-login-password" error="Password is required" [required]="true" [invalid]="passwordInvalid()">
19870
+ <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" placeholder="Enter your password" />
19871
+ </jv-form-container>
19872
+
19873
+ <div class="auth-inline-row">
19874
+ <jv-checkbox formControlName="rememberMe" label="{{ rememberMeLabel() }}" />
19875
+ <button type="button" class="auth-link" (click)="forgotPasswordClick.emit()">{{ forgotPasswordLabel() }}</button>
19876
+ </div>
19877
+
19878
+ <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19879
+ </form>
19880
+ </jv-section>
19881
+ </jv-card>
19882
+ `, 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"] }] });
18915
19883
  }
18916
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvThemeService, decorators: [{
18917
- type: Injectable,
18918
- args: [{ providedIn: 'root' }]
18919
- }] });
19884
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvLoginPageComponent, decorators: [{
19885
+ type: Component,
19886
+ args: [{ selector: 'jv-login-page', standalone: true, imports: [ReactiveFormsModule, JvAlertComponent, JvButtonComponent, JvCardComponent, JvCheckboxComponent, JvFormContainerComponent, JvInputComponent, JvSectionComponent], template: `
19887
+ <jv-card>
19888
+ <jv-section [title]="title()" [description]="description()">
19889
+ @if (error()) {
19890
+ <jv-alert tone="danger" title="Sign-in error" role="alert">{{ error() }}</jv-alert>
19891
+ }
19892
+
19893
+ <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19894
+ <jv-form-container label="Email or username" inputId="jv-login-identifier" error="This field is required" [required]="true" [invalid]="identifierInvalid()">
19895
+ <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" placeholder="you@example.com" />
19896
+ </jv-form-container>
19897
+
19898
+ <jv-form-container label="Password" inputId="jv-login-password" error="Password is required" [required]="true" [invalid]="passwordInvalid()">
19899
+ <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" placeholder="Enter your password" />
19900
+ </jv-form-container>
19901
+
19902
+ <div class="auth-inline-row">
19903
+ <jv-checkbox formControlName="rememberMe" label="{{ rememberMeLabel() }}" />
19904
+ <button type="button" class="auth-link" (click)="forgotPasswordClick.emit()">{{ forgotPasswordLabel() }}</button>
19905
+ </div>
19906
+
19907
+ <jv-button type="submit" variant="primary" icon="check" [loading]="loading()">{{ submitLabel() }}</jv-button>
19908
+ </form>
19909
+ </jv-section>
19910
+ </jv-card>
19911
+ `, 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"] }]
19912
+ }], 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"] }] } });
18920
19913
 
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
- ]);
19914
+ class JvDividerComponent {
19915
+ vertical = input(false, ...(ngDevMode ? [{ debugName: "vertical" }] : /* istanbul ignore next */ []));
19916
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDividerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19917
+ 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: `
19918
+ <div
19919
+ class="jv-divider"
19920
+ [class.jv-divider--vertical]="vertical()"
19921
+ [attr.role]="'separator'"
19922
+ [attr.aria-orientation]="vertical() ? 'vertical' : 'horizontal'"
19923
+ ></div>
19924
+ `, 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"] });
18944
19925
  }
19926
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDividerComponent, decorators: [{
19927
+ type: Component,
19928
+ args: [{ selector: 'jv-divider', standalone: true, template: `
19929
+ <div
19930
+ class="jv-divider"
19931
+ [class.jv-divider--vertical]="vertical()"
19932
+ [attr.role]="'separator'"
19933
+ [attr.aria-orientation]="vertical() ? 'vertical' : 'horizontal'"
19934
+ ></div>
19935
+ `, styles: [".jv-divider{width:100%;height:1px;background:var(--jv-color-border)}.jv-divider--vertical{width:1px;height:100%;min-height:1.5rem}\n"] }]
19936
+ }], propDecorators: { vertical: [{ type: i0.Input, args: [{ isSignal: true, alias: "vertical", required: false }] }] } });
18945
19937
 
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
- });
19938
+ class JvAccordionPanelDirective {
19939
+ templateRef;
19940
+ id = input.required({ ...(ngDevMode ? { debugName: "id" } : /* istanbul ignore next */ {}), alias: 'jvAccordionPanel' });
19941
+ constructor(templateRef) {
19942
+ this.templateRef = templateRef;
18961
19943
  }
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' });
19944
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAccordionPanelDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
19945
+ 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 });
18964
19946
  }
18965
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvUiConfigService, decorators: [{
18966
- type: Injectable,
18967
- args: [{ providedIn: 'root' }]
18968
- }] });
18969
-
18970
- const ES = {
18971
- 'list.emptyMessage': 'No hay elementos',
18972
- 'grid.emptyMessage': 'No hay registros',
18973
- 'grid.noResults': 'No se encontraron resultados',
18974
- 'grid.searchPlaceholder': 'Buscar...',
18975
- 'grid.loading': 'Cargando datos...',
18976
- 'grid.pageOf': 'de',
18977
- 'grid.itemsPerPage': 'Registros por página',
18978
- 'grid.selected': 'seleccionados',
18979
- 'grid.selectAll': 'Seleccionar todo',
18980
- 'grid.deselectAll': 'Deseleccionar todo',
18981
- 'grid.sortAsc': 'Orden ascendente',
18982
- 'grid.sortDesc': 'Orden descendente',
18983
- 'grid.sortNone': 'Sin orden',
18984
- 'grid.pageFirst': 'Primera página',
18985
- 'grid.pagePrev': 'Página anterior',
18986
- 'grid.pageNext': 'Página siguiente',
18987
- 'grid.pageLast': 'Última página',
18988
- 'grid.pageOfTotal': 'Página {page} de {total}',
18989
- 'grid.itemsTotal': '{total} registros',
18990
- 'grid.itemsShowing': 'Mostrando {start}-{end} de {total}',
18991
- 'grid.exportCsv': 'CSV',
18992
- 'grid.exportExcel': 'Excel',
18993
- 'grid.filterPlaceholder': 'Filtrar...',
18994
- 'grid.filterForColumn': 'Filtrar por ${column}',
18995
- 'grid.actionsLabel': 'Acciones',
18996
- 'pagination.pageLabel': 'Página {page}',
18997
- 'pagination.itemsShowing': '{start}-{end} de {total}',
18998
- 'pagination.of': 'de',
18999
- 'pagination.firstPage': 'Primera página',
19000
- 'pagination.prevPage': 'Página anterior',
19001
- 'pagination.nextPage': 'Página siguiente',
19002
- 'pagination.lastPage': 'Última página',
19003
- 'pagination.itemsPerPage': 'Registros por página',
19004
- 'datePicker.placeholder': 'Seleccione una fecha',
19005
- 'datePicker.dialogTitle': 'Seleccionar fecha',
19006
- 'datePicker.clear': 'Limpiar fecha',
19007
- 'datePicker.close': 'Cerrar',
19008
- 'datePicker.prevMonth': 'Mes anterior',
19009
- 'datePicker.nextMonth': 'Mes siguiente',
19010
- 'datePicker.selectionCleared': 'Seleccion de fecha limpiada',
19011
- 'modalSelector.placeholder': 'Seleccione una opcion',
19012
- 'modalSelector.searchPlaceholder': 'Buscar',
19013
- 'modalSelector.emptyMessage': 'No se encontraron resultados',
19014
- 'modalSelector.clear': 'Limpiar seleccion',
19015
- 'modalSelector.close': 'Cerrar',
19016
- 'modalSelector.results': '{count} resultados',
19017
- 'modalSelector.selected': '{label} seleccionado',
19018
- 'modalSelector.selectionCleared': 'Seleccion limpiada',
19019
- 'fileInput.dropLabel': 'Arrastre archivos aqui o haga clic para seleccionarlos',
19020
- 'fileInput.helperText': 'Compatible con seleccion multiple y arrastrar y soltar',
19021
- 'fileInput.selectionSummary': '{count} de {max} archivos seleccionados',
19022
- 'fileInput.invalidFiles': '{count} archivos no coinciden con el tipo permitido',
19023
- 'fileInput.tooManyFiles': 'Solo se permiten hasta {max} archivos',
19024
- 'fileInput.removeFile': 'Quitar archivo {name}',
19025
- 'dialog.confirmTitle': 'Confirmar',
19026
- 'dialog.confirm': 'Aceptar',
19027
- 'dialog.cancel': 'Cancelar',
19028
- 'common.expanded': 'Expandido',
19029
- 'common.collapsed': 'Colapsado',
19030
- 'slider.prevImage': 'Imagen anterior',
19031
- 'slider.nextImage': 'Imagen siguiente',
19032
- 'slider.thumbnailList': 'Miniaturas de imagenes',
19033
- 'gallery.close': 'Cerrar',
19034
- 'gallery.prevImage': 'Imagen anterior',
19035
- 'gallery.nextImage': 'Imagen siguiente',
19036
- };
19037
-
19038
- const EN = {
19039
- 'list.emptyMessage': 'No items',
19040
- 'grid.emptyMessage': 'No records found',
19041
- 'grid.noResults': 'No results found',
19042
- 'grid.searchPlaceholder': 'Search...',
19043
- 'grid.loading': 'Loading data...',
19044
- 'grid.pageOf': 'of',
19045
- 'grid.itemsPerPage': 'Items per page',
19046
- 'grid.selected': 'selected',
19047
- 'grid.selectAll': 'Select all',
19048
- 'grid.deselectAll': 'Deselect all',
19049
- 'grid.sortAsc': 'Sort ascending',
19050
- 'grid.sortDesc': 'Sort descending',
19051
- 'grid.sortNone': 'No sort',
19052
- 'grid.pageFirst': 'First page',
19053
- 'grid.pagePrev': 'Previous page',
19054
- 'grid.pageNext': 'Next page',
19055
- 'grid.pageLast': 'Last page',
19056
- 'grid.pageOfTotal': 'Page {page} of {total}',
19057
- 'grid.itemsTotal': '{total} items',
19058
- 'grid.itemsShowing': 'Showing {start}-{end} of {total}',
19059
- 'grid.exportCsv': 'CSV',
19060
- 'grid.exportExcel': 'Excel',
19061
- 'grid.filterPlaceholder': 'Filter...',
19062
- 'grid.filterForColumn': 'Filter by ${column}',
19063
- 'grid.actionsLabel': 'Actions',
19064
- 'pagination.pageLabel': 'Page {page}',
19065
- 'pagination.itemsShowing': '{start}-{end} of {total}',
19066
- 'pagination.of': 'of',
19067
- 'pagination.firstPage': 'First page',
19068
- 'pagination.prevPage': 'Previous page',
19069
- 'pagination.nextPage': 'Next page',
19070
- 'pagination.lastPage': 'Last page',
19071
- 'pagination.itemsPerPage': 'Items per page',
19072
- 'datePicker.placeholder': 'Select a date',
19073
- 'datePicker.dialogTitle': 'Select date',
19074
- 'datePicker.clear': 'Clear date',
19075
- 'datePicker.close': 'Close',
19076
- 'datePicker.prevMonth': 'Previous month',
19077
- 'datePicker.nextMonth': 'Next month',
19078
- 'datePicker.selectionCleared': 'Date selection cleared',
19079
- 'modalSelector.placeholder': 'Select an option',
19080
- 'modalSelector.searchPlaceholder': 'Search',
19081
- 'modalSelector.emptyMessage': 'No results found',
19082
- 'modalSelector.clear': 'Clear selection',
19083
- 'modalSelector.close': 'Close',
19084
- 'modalSelector.results': '{count} results',
19085
- 'modalSelector.selected': '{label} selected',
19086
- 'modalSelector.selectionCleared': 'Selection cleared',
19087
- 'fileInput.dropLabel': 'Drag files here or click to choose them',
19088
- 'fileInput.helperText': 'Supports multiple selection and drag and drop',
19089
- 'fileInput.selectionSummary': '{count} of {max} files selected',
19090
- 'fileInput.invalidFiles': '{count} files do not match the allowed type',
19091
- 'fileInput.tooManyFiles': 'Only up to {max} files are allowed',
19092
- 'fileInput.removeFile': 'Remove file {name}',
19093
- 'dialog.confirmTitle': 'Confirm',
19094
- 'dialog.confirm': 'Confirm',
19095
- 'dialog.cancel': 'Cancel',
19096
- 'common.expanded': 'Expanded',
19097
- 'common.collapsed': 'Collapsed',
19098
- 'slider.prevImage': 'Previous image',
19099
- 'slider.nextImage': 'Next image',
19100
- 'slider.thumbnailList': 'Image thumbnails',
19101
- 'gallery.close': 'Close',
19102
- 'gallery.prevImage': 'Previous image',
19103
- 'gallery.nextImage': 'Next image',
19104
- };
19105
-
19106
- const JV_LOCALE_DICTIONARIES = {
19107
- es: ES,
19108
- en: EN,
19109
- };
19110
- const JV_DEFAULT_LOCALE = 'es';
19947
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAccordionPanelDirective, decorators: [{
19948
+ type: Directive,
19949
+ args: [{
19950
+ selector: 'ng-template[jvAccordionPanel]',
19951
+ standalone: true,
19952
+ }]
19953
+ }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "jvAccordionPanel", required: true }] }] } });
19111
19954
 
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);
19124
- }
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
- }
19955
+ class JvAnnouncementService {
19956
+ document = inject(DOCUMENT);
19957
+ region = null;
19958
+ announce(message, politeness = 'polite') {
19959
+ if (!message.trim()) {
19960
+ return;
19135
19961
  }
19136
- return value;
19962
+ const region = this.ensureRegion(politeness);
19963
+ region.textContent = '';
19964
+ // Clear and reinsert so NVDA reliably reads repeated updates.
19965
+ setTimeout(() => {
19966
+ region.textContent = message;
19967
+ }, 20);
19137
19968
  }
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';
19969
+ ensureRegion(politeness) {
19970
+ if (!this.region) {
19971
+ const region = this.document.createElement('div');
19972
+ region.className = 'sr-only';
19973
+ region.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');
19974
+ region.setAttribute('aria-live', politeness);
19975
+ region.setAttribute('aria-atomic', 'true');
19976
+ this.document.body.appendChild(region);
19977
+ this.region = region;
19978
+ return region;
19979
+ }
19980
+ this.region.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');
19981
+ this.region.setAttribute('aria-live', politeness);
19982
+ return this.region;
19144
19983
  }
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' });
19984
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAnnouncementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
19985
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAnnouncementService, providedIn: 'root' });
19147
19986
  }
19148
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTranslationService, decorators: [{
19987
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvAnnouncementService, decorators: [{
19149
19988
  type: Injectable,
19150
19989
  args: [{ providedIn: 'root' }]
19151
19990
  }] });
@@ -19396,17 +20235,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
19396
20235
  `, styles: [".jv-accordion{display:grid;gap:var(--jv-spacing-sm)}\n"] }]
19397
20236
  }], 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
20237
 
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
20238
  class JvLoaderService {
19411
20239
  counter = signal(0, ...(ngDevMode ? [{ debugName: "counter" }] : /* istanbul ignore next */ []));
19412
20240
  visible = signal(false, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
@@ -19815,104 +20643,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
19815
20643
  args: ['document:keydown', ['$event']]
19816
20644
  }] } });
19817
20645
 
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
20646
  let datePickerIdSequence = 0;
19917
20647
  class JvDatePickerComponent {
19918
20648
  translation = inject(JvTranslationService);
@@ -21872,6 +22602,213 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
21872
22602
  `, 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
22603
  }] });
21874
22604
 
22605
+ class JvWindowModalComponent {
22606
+ document = inject(DOCUMENT);
22607
+ panelRef = viewChild('panel', ...(ngDevMode ? [{ debugName: "panelRef" }] : /* istanbul ignore next */ []));
22608
+ open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
22609
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
22610
+ subtitle = input('', ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
22611
+ mode = input('floating', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
22612
+ size = input('xl', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
22613
+ showCloseButton = input(true, ...(ngDevMode ? [{ debugName: "showCloseButton" }] : /* istanbul ignore next */ []));
22614
+ closeOnBackdrop = input(true, ...(ngDevMode ? [{ debugName: "closeOnBackdrop" }] : /* istanbul ignore next */ []));
22615
+ closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : /* istanbul ignore next */ []));
22616
+ closeLabel = input('Close workspace', ...(ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []));
22617
+ closed = output();
22618
+ close = output();
22619
+ resolvedMode = computed(() => (this.size() === 'fullscreen' ? 'fullscreen' : this.mode()), ...(ngDevMode ? [{ debugName: "resolvedMode" }] : /* istanbul ignore next */ []));
22620
+ titleId = `jv-window-modal-title-${Math.random().toString(36).slice(2, 8)}`;
22621
+ descriptionId = `jv-window-modal-description-${Math.random().toString(36).slice(2, 8)}`;
22622
+ previousFocusedElement = null;
22623
+ previousBodyOverflow = '';
22624
+ wasOpen = false;
22625
+ constructor() {
22626
+ effect(() => {
22627
+ const isOpen = this.open();
22628
+ if (isOpen) {
22629
+ if (!this.wasOpen) {
22630
+ this.previousFocusedElement = this.document.activeElement instanceof HTMLElement ? this.document.activeElement : null;
22631
+ this.previousBodyOverflow = this.document.body.style.overflow;
22632
+ this.document.body.style.overflow = 'hidden';
22633
+ }
22634
+ queueMicrotask(() => this.focusInitialElement());
22635
+ }
22636
+ else if (this.wasOpen) {
22637
+ this.document.body.style.overflow = this.previousBodyOverflow;
22638
+ const previousFocusedElement = this.previousFocusedElement;
22639
+ queueMicrotask(() => previousFocusedElement?.focus());
22640
+ }
22641
+ this.wasOpen = isOpen;
22642
+ });
22643
+ }
22644
+ ngOnDestroy() {
22645
+ if (this.wasOpen) {
22646
+ this.document.body.style.overflow = this.previousBodyOverflow;
22647
+ }
22648
+ }
22649
+ handleDocumentKeydown(event) {
22650
+ if (!this.open()) {
22651
+ return;
22652
+ }
22653
+ if (event.key === 'Escape' && this.closeOnEscape()) {
22654
+ event.preventDefault();
22655
+ this.requestClose();
22656
+ return;
22657
+ }
22658
+ if (event.key === 'Tab') {
22659
+ this.trapFocus(event);
22660
+ }
22661
+ }
22662
+ backdropClose() {
22663
+ if (!this.closeOnBackdrop()) {
22664
+ return;
22665
+ }
22666
+ this.requestClose();
22667
+ }
22668
+ requestClose() {
22669
+ this.closed.emit();
22670
+ this.close.emit();
22671
+ }
22672
+ focusInitialElement() {
22673
+ const panel = this.panelRef()?.nativeElement;
22674
+ if (!panel) {
22675
+ return;
22676
+ }
22677
+ const firstFocusable = this.getFocusableElements()[0];
22678
+ (firstFocusable ?? panel).focus();
22679
+ }
22680
+ trapFocus(event) {
22681
+ const focusable = this.getFocusableElements();
22682
+ const panel = this.panelRef()?.nativeElement;
22683
+ if (!panel || focusable.length === 0) {
22684
+ panel?.focus();
22685
+ event.preventDefault();
22686
+ return;
22687
+ }
22688
+ const first = focusable[0];
22689
+ const last = focusable[focusable.length - 1];
22690
+ const active = this.document.activeElement;
22691
+ if (event.shiftKey && active === first) {
22692
+ last.focus();
22693
+ event.preventDefault();
22694
+ }
22695
+ else if (!event.shiftKey && active === last) {
22696
+ first.focus();
22697
+ event.preventDefault();
22698
+ }
22699
+ }
22700
+ getFocusableElements() {
22701
+ const panel = this.panelRef()?.nativeElement;
22702
+ if (!panel) {
22703
+ return [];
22704
+ }
22705
+ return Array.from(panel.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'));
22706
+ }
22707
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvWindowModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
22708
+ 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: `
22709
+ @if (open()) {
22710
+ <div class="jv-window-modal-backdrop" (click)="backdropClose()">
22711
+ <section
22712
+ class="jv-window-modal-panel"
22713
+ [class.jv-window-modal-panel--floating]="resolvedMode() === 'floating'"
22714
+ [class.jv-window-modal-panel--fullscreen]="resolvedMode() === 'fullscreen'"
22715
+ [class.jv-window-modal-panel--lg]="resolvedMode() === 'floating' && size() === 'lg'"
22716
+ [class.jv-window-modal-panel--xl]="resolvedMode() === 'floating' && size() === 'xl'"
22717
+ role="dialog"
22718
+ aria-modal="true"
22719
+ tabindex="-1"
22720
+ [attr.aria-labelledby]="title() ? titleId : null"
22721
+ [attr.aria-describedby]="descriptionId"
22722
+ (click)="$event.stopPropagation()"
22723
+ #panel
22724
+ >
22725
+ <header class="jv-window-modal-header">
22726
+ <div class="jv-window-modal-heading">
22727
+ @if (title()) {
22728
+ <h2 [id]="titleId">{{ title() }}</h2>
22729
+ }
22730
+
22731
+ @if (subtitle()) {
22732
+ <p class="jv-window-modal-subtitle">{{ subtitle() }}</p>
22733
+ }
22734
+ </div>
22735
+
22736
+ <div class="jv-window-modal-header-actions">
22737
+ <ng-content select="[window-modal-header-actions]"></ng-content>
22738
+
22739
+ @if (showCloseButton()) {
22740
+ <jv-icon-button icon="x" variant="ghost" [ariaLabel]="closeLabel()" (click)="requestClose()" />
22741
+ }
22742
+ </div>
22743
+ </header>
22744
+
22745
+ <div class="jv-window-modal-body" [id]="descriptionId">
22746
+ <ng-content></ng-content>
22747
+ </div>
22748
+
22749
+ <footer class="jv-window-modal-footer">
22750
+ <ng-content select="[window-modal-footer]"></ng-content>
22751
+ </footer>
22752
+ </section>
22753
+ </div>
22754
+ }
22755
+ `, 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"] }] });
22756
+ }
22757
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvWindowModalComponent, decorators: [{
22758
+ type: Component,
22759
+ args: [{ selector: 'jv-window-modal', standalone: true, imports: [JvIconButtonComponent], template: `
22760
+ @if (open()) {
22761
+ <div class="jv-window-modal-backdrop" (click)="backdropClose()">
22762
+ <section
22763
+ class="jv-window-modal-panel"
22764
+ [class.jv-window-modal-panel--floating]="resolvedMode() === 'floating'"
22765
+ [class.jv-window-modal-panel--fullscreen]="resolvedMode() === 'fullscreen'"
22766
+ [class.jv-window-modal-panel--lg]="resolvedMode() === 'floating' && size() === 'lg'"
22767
+ [class.jv-window-modal-panel--xl]="resolvedMode() === 'floating' && size() === 'xl'"
22768
+ role="dialog"
22769
+ aria-modal="true"
22770
+ tabindex="-1"
22771
+ [attr.aria-labelledby]="title() ? titleId : null"
22772
+ [attr.aria-describedby]="descriptionId"
22773
+ (click)="$event.stopPropagation()"
22774
+ #panel
22775
+ >
22776
+ <header class="jv-window-modal-header">
22777
+ <div class="jv-window-modal-heading">
22778
+ @if (title()) {
22779
+ <h2 [id]="titleId">{{ title() }}</h2>
22780
+ }
22781
+
22782
+ @if (subtitle()) {
22783
+ <p class="jv-window-modal-subtitle">{{ subtitle() }}</p>
22784
+ }
22785
+ </div>
22786
+
22787
+ <div class="jv-window-modal-header-actions">
22788
+ <ng-content select="[window-modal-header-actions]"></ng-content>
22789
+
22790
+ @if (showCloseButton()) {
22791
+ <jv-icon-button icon="x" variant="ghost" [ariaLabel]="closeLabel()" (click)="requestClose()" />
22792
+ }
22793
+ </div>
22794
+ </header>
22795
+
22796
+ <div class="jv-window-modal-body" [id]="descriptionId">
22797
+ <ng-content></ng-content>
22798
+ </div>
22799
+
22800
+ <footer class="jv-window-modal-footer">
22801
+ <ng-content select="[window-modal-footer]"></ng-content>
22802
+ </footer>
22803
+ </section>
22804
+ </div>
22805
+ }
22806
+ `, 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"] }]
22807
+ }], 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: [{
22808
+ type: HostListener,
22809
+ args: ['document:keydown', ['$event']]
22810
+ }] } });
22811
+
21875
22812
  class JvBreadcrumbComponent {
21876
22813
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
21877
22814
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
@@ -24899,5 +25836,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24899
25836
  * Generated bundle index. Do not edit.
24900
25837
  */
24901
25838
 
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 };
25839
+ 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
25840
  //# sourceMappingURL=devjuliovilla-jv-ui.mjs.map