@devjuliovilla/jv-ui 1.17.0 → 1.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19043,13 +19043,13 @@ class JvSelectComponent {
19043
19043
  inputId = input(`jv-select-${++selectIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
19044
19044
  modelValue = input('', ...(ngDevMode ? [{ debugName: "modelValue" }] : /* istanbul ignore next */ []));
19045
19045
  selectionChange = output();
19046
- value = '';
19046
+ value = signal('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
19047
19047
  disabled = false;
19048
19048
  onChange = () => undefined;
19049
19049
  onTouched = () => undefined;
19050
- currentValue = computed(() => this.modelValue() || this.value, ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
19050
+ currentValue = computed(() => this.modelValue() || this.value(), ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
19051
19051
  writeValue(value) {
19052
- this.value = value ?? '';
19052
+ this.value.set(value ?? '');
19053
19053
  }
19054
19054
  registerOnChange(fn) {
19055
19055
  this.onChange = fn;
@@ -19062,7 +19062,7 @@ class JvSelectComponent {
19062
19062
  }
19063
19063
  handleChange(event) {
19064
19064
  const nextValue = event.target.value;
19065
- this.value = nextValue;
19065
+ this.value.set(nextValue);
19066
19066
  this.onChange(nextValue);
19067
19067
  this.selectionChange.emit(nextValue);
19068
19068
  }
@@ -19746,6 +19746,7 @@ class JvInputComponent {
19746
19746
  required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
19747
19747
  invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
19748
19748
  describedBy = input('', ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
19749
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
19749
19750
  inputId = input(`jv-input-${++inputIdSequence}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
19750
19751
  value = '';
19751
19752
  disabled = false;
@@ -19772,7 +19773,7 @@ class JvInputComponent {
19772
19773
  this.onTouched();
19773
19774
  }
19774
19775
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19775
- 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: [
19776
+ 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
19776
19777
  {
19777
19778
  provide: NG_VALUE_ACCESSOR,
19778
19779
  useExisting: forwardRef(() => JvInputComponent),
@@ -19790,6 +19791,7 @@ class JvInputComponent {
19790
19791
  [disabled]="disabled"
19791
19792
  [attr.aria-invalid]="invalid() ? 'true' : null"
19792
19793
  [attr.aria-describedby]="describedBy() || null"
19794
+ [attr.aria-label]="ariaLabel() || null"
19793
19795
  (input)="handleInput($event)"
19794
19796
  (blur)="handleBlur()"
19795
19797
  />
@@ -19815,11 +19817,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
19815
19817
  [disabled]="disabled"
19816
19818
  [attr.aria-invalid]="invalid() ? 'true' : null"
19817
19819
  [attr.aria-describedby]="describedBy() || null"
19820
+ [attr.aria-label]="ariaLabel() || null"
19818
19821
  (input)="handleInput($event)"
19819
19822
  (blur)="handleBlur()"
19820
19823
  />
19821
19824
  `, 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"] }]
19822
- }], 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 }] }] } });
19825
+ }], 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 }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }] } });
19823
19826
 
19824
19827
  class JvSectionComponent {
19825
19828
  title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
@@ -19912,15 +19915,15 @@ class JvChangePasswordPageComponent {
19912
19915
 
19913
19916
  <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19914
19917
  <jv-form-container label="Current password" inputId="jv-current-password" error="Current password is required" [required]="true" [invalid]="currentInvalid()">
19915
- <jv-input inputId="jv-current-password" type="password" formControlName="currentPassword" [invalid]="currentInvalid()" />
19918
+ <jv-input inputId="jv-current-password" type="password" formControlName="currentPassword" [invalid]="currentInvalid()" [describedBy]="currentInvalid() ? 'jv-current-password-error' : ''" />
19916
19919
  </jv-form-container>
19917
19920
 
19918
19921
  <jv-form-container label="New password" inputId="jv-new-password" error="New password is required" [required]="true" [invalid]="newInvalid()">
19919
- <jv-input inputId="jv-new-password" type="password" formControlName="newPassword" [invalid]="newInvalid()" />
19922
+ <jv-input inputId="jv-new-password" type="password" formControlName="newPassword" [invalid]="newInvalid()" [describedBy]="newInvalid() ? 'jv-new-password-error' : ''" />
19920
19923
  </jv-form-container>
19921
19924
 
19922
19925
  <jv-form-container label="Confirm new password" inputId="jv-confirm-password" error="Passwords must match" [required]="true" [invalid]="confirmInvalid()">
19923
- <jv-input inputId="jv-confirm-password" type="password" formControlName="confirmPassword" [invalid]="confirmInvalid()" />
19926
+ <jv-input inputId="jv-confirm-password" type="password" formControlName="confirmPassword" [invalid]="confirmInvalid()" [describedBy]="confirmInvalid() ? 'jv-confirm-password-error' : ''" />
19924
19927
  </jv-form-container>
19925
19928
 
19926
19929
  <div class="auth-actions">
@@ -19930,7 +19933,7 @@ class JvChangePasswordPageComponent {
19930
19933
  </form>
19931
19934
  </jv-section>
19932
19935
  </jv-card>
19933
- `, 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"] }] });
19936
+ `, 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", "ariaLabel", "inputId"] }, { kind: "component", type: JvSectionComponent, selector: "jv-section", inputs: ["title", "description"] }] });
19934
19937
  }
19935
19938
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvChangePasswordPageComponent, decorators: [{
19936
19939
  type: Component,
@@ -19943,15 +19946,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
19943
19946
 
19944
19947
  <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
19945
19948
  <jv-form-container label="Current password" inputId="jv-current-password" error="Current password is required" [required]="true" [invalid]="currentInvalid()">
19946
- <jv-input inputId="jv-current-password" type="password" formControlName="currentPassword" [invalid]="currentInvalid()" />
19949
+ <jv-input inputId="jv-current-password" type="password" formControlName="currentPassword" [invalid]="currentInvalid()" [describedBy]="currentInvalid() ? 'jv-current-password-error' : ''" />
19947
19950
  </jv-form-container>
19948
19951
 
19949
19952
  <jv-form-container label="New password" inputId="jv-new-password" error="New password is required" [required]="true" [invalid]="newInvalid()">
19950
- <jv-input inputId="jv-new-password" type="password" formControlName="newPassword" [invalid]="newInvalid()" />
19953
+ <jv-input inputId="jv-new-password" type="password" formControlName="newPassword" [invalid]="newInvalid()" [describedBy]="newInvalid() ? 'jv-new-password-error' : ''" />
19951
19954
  </jv-form-container>
19952
19955
 
19953
19956
  <jv-form-container label="Confirm new password" inputId="jv-confirm-password" error="Passwords must match" [required]="true" [invalid]="confirmInvalid()">
19954
- <jv-input inputId="jv-confirm-password" type="password" formControlName="confirmPassword" [invalid]="confirmInvalid()" />
19957
+ <jv-input inputId="jv-confirm-password" type="password" formControlName="confirmPassword" [invalid]="confirmInvalid()" [describedBy]="confirmInvalid() ? 'jv-confirm-password-error' : ''" />
19955
19958
  </jv-form-container>
19956
19959
 
19957
19960
  <div class="auth-actions">
@@ -19998,7 +20001,7 @@ class JvForgotPasswordPageComponent {
19998
20001
 
19999
20002
  <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
20000
20003
  <jv-form-container label="Email" inputId="jv-forgot-email" error="Enter a valid email" [required]="true" [invalid]="emailInvalid()">
20001
- <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" placeholder="you@example.com" />
20004
+ <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" [describedBy]="emailInvalid() ? 'jv-forgot-email-error' : ''" placeholder="you@example.com" />
20002
20005
  </jv-form-container>
20003
20006
 
20004
20007
  <div class="auth-actions">
@@ -20008,7 +20011,7 @@ class JvForgotPasswordPageComponent {
20008
20011
  </form>
20009
20012
  </jv-section>
20010
20013
  </jv-card>
20011
- `, 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"] }] });
20014
+ `, 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", "ariaLabel", "inputId"] }, { kind: "component", type: JvSectionComponent, selector: "jv-section", inputs: ["title", "description"] }] });
20012
20015
  }
20013
20016
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvForgotPasswordPageComponent, decorators: [{
20014
20017
  type: Component,
@@ -20021,7 +20024,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
20021
20024
 
20022
20025
  <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
20023
20026
  <jv-form-container label="Email" inputId="jv-forgot-email" error="Enter a valid email" [required]="true" [invalid]="emailInvalid()">
20024
- <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" placeholder="you@example.com" />
20027
+ <jv-input inputId="jv-forgot-email" type="email" formControlName="email" [invalid]="emailInvalid()" [describedBy]="emailInvalid() ? 'jv-forgot-email-error' : ''" placeholder="you@example.com" />
20025
20028
  </jv-form-container>
20026
20029
 
20027
20030
  <div class="auth-actions">
@@ -20150,11 +20153,11 @@ class JvLoginPageComponent {
20150
20153
 
20151
20154
  <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
20152
20155
  <jv-form-container label="Email or username" inputId="jv-login-identifier" error="This field is required" [required]="true" [invalid]="identifierInvalid()">
20153
- <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" placeholder="you@example.com" />
20156
+ <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" [describedBy]="identifierInvalid() ? 'jv-login-identifier-error' : ''" placeholder="you@example.com" />
20154
20157
  </jv-form-container>
20155
20158
 
20156
20159
  <jv-form-container label="Password" inputId="jv-login-password" error="Password is required" [required]="true" [invalid]="passwordInvalid()">
20157
- <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" placeholder="Enter your password" />
20160
+ <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" [describedBy]="passwordInvalid() ? 'jv-login-password-error' : ''" placeholder="Enter your password" />
20158
20161
  </jv-form-container>
20159
20162
 
20160
20163
  <div class="auth-inline-row">
@@ -20166,7 +20169,7 @@ class JvLoginPageComponent {
20166
20169
  </form>
20167
20170
  </jv-section>
20168
20171
  </jv-card>
20169
- `, 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"] }] });
20172
+ `, 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", "ariaLabel", "inputId"] }, { kind: "component", type: JvSectionComponent, selector: "jv-section", inputs: ["title", "description"] }] });
20170
20173
  }
20171
20174
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvLoginPageComponent, decorators: [{
20172
20175
  type: Component,
@@ -20179,11 +20182,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
20179
20182
 
20180
20183
  <form class="auth-form" [formGroup]="form" (ngSubmit)="submit()">
20181
20184
  <jv-form-container label="Email or username" inputId="jv-login-identifier" error="This field is required" [required]="true" [invalid]="identifierInvalid()">
20182
- <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" placeholder="you@example.com" />
20185
+ <jv-input inputId="jv-login-identifier" formControlName="identifier" [invalid]="identifierInvalid()" [describedBy]="identifierInvalid() ? 'jv-login-identifier-error' : ''" placeholder="you@example.com" />
20183
20186
  </jv-form-container>
20184
20187
 
20185
20188
  <jv-form-container label="Password" inputId="jv-login-password" error="Password is required" [required]="true" [invalid]="passwordInvalid()">
20186
- <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" placeholder="Enter your password" />
20189
+ <jv-input inputId="jv-login-password" type="password" formControlName="password" [invalid]="passwordInvalid()" [describedBy]="passwordInvalid() ? 'jv-login-password-error' : ''" placeholder="Enter your password" />
20187
20190
  </jv-form-container>
20188
20191
 
20189
20192
  <div class="auth-inline-row">
@@ -20568,6 +20571,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
20568
20571
  class JvLoaderComponent {
20569
20572
  document = inject(DOCUMENT);
20570
20573
  loaderService = inject(JvLoaderService);
20574
+ loaderPanel = viewChild('loaderPanel', ...(ngDevMode ? [{ debugName: "loaderPanel" }] : /* istanbul ignore next */ []));
20571
20575
  constructor() {
20572
20576
  effect(() => {
20573
20577
  const locked = this.loaderService.isVisible();
@@ -20575,6 +20579,9 @@ class JvLoaderComponent {
20575
20579
  const root = this.document.documentElement;
20576
20580
  body.style.overflow = locked ? 'hidden' : '';
20577
20581
  root.style.overflow = locked ? 'hidden' : '';
20582
+ if (locked) {
20583
+ queueMicrotask(() => this.loaderPanel()?.nativeElement.focus());
20584
+ }
20578
20585
  });
20579
20586
  }
20580
20587
  handleWheel(event) {
@@ -20588,10 +20595,10 @@ class JvLoaderComponent {
20588
20595
  }
20589
20596
  }
20590
20597
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
20591
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvLoaderComponent, isStandalone: true, selector: "jv-loader", host: { listeners: { "document:wheel": "handleWheel($event)", "document:touchmove": "handleTouchMove($event)" } }, ngImport: i0, template: `
20598
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvLoaderComponent, isStandalone: true, selector: "jv-loader", host: { listeners: { "document:wheel": "handleWheel($event)", "document:touchmove": "handleTouchMove($event)" } }, viewQueries: [{ propertyName: "loaderPanel", first: true, predicate: ["loaderPanel"], descendants: true, isSignal: true }], ngImport: i0, template: `
20592
20599
  @if (loaderService.isVisible()) {
20593
20600
  <div class="jv-loader-backdrop" aria-live="polite" aria-atomic="true">
20594
- <div class="jv-loader-panel" role="status">
20601
+ <div #loaderPanel class="jv-loader-panel" role="status" tabindex="-1" aria-live="polite">
20595
20602
  <span class="spinner" aria-hidden="true"></span>
20596
20603
  <span>{{ loaderService.liveMessage() }}</span>
20597
20604
  </div>
@@ -20604,14 +20611,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
20604
20611
  args: [{ selector: 'jv-loader', standalone: true, template: `
20605
20612
  @if (loaderService.isVisible()) {
20606
20613
  <div class="jv-loader-backdrop" aria-live="polite" aria-atomic="true">
20607
- <div class="jv-loader-panel" role="status">
20614
+ <div #loaderPanel class="jv-loader-panel" role="status" tabindex="-1" aria-live="polite">
20608
20615
  <span class="spinner" aria-hidden="true"></span>
20609
20616
  <span>{{ loaderService.liveMessage() }}</span>
20610
20617
  </div>
20611
20618
  </div>
20612
20619
  }
20613
20620
  `, styles: [".jv-loader-backdrop{position:fixed;inset:0;z-index:1050;display:grid;place-items:center;background:#0f172a2e;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.jv-loader-panel{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);padding:var(--jv-spacing-md) var(--jv-spacing-lg);width:min(35vw,calc(100vw - 2rem));height:min(35vh,calc(100vh - 2rem));max-width:calc(100vw - 2rem);max-height:calc(100vh - 2rem);justify-content:center;border:1px solid #d6dce5;border-radius:var(--jv-radius-lg);background:#f8fafc;box-shadow:var(--jv-shadow-lg);color:#111827;text-align:center;forced-color-adjust:none}.spinner{width:1.25rem;height:1.25rem;border:2px solid currentColor;border-right-color:transparent;border-radius:999px;animation:jv-loader-spin .8s linear infinite}@media(forced-colors:active){.jv-loader-panel{border-color:#d6dce5;background:#f8fafc;color:#111827}}@keyframes jv-loader-spin{to{transform:rotate(360deg)}}\n"] }]
20614
- }], ctorParameters: () => [], propDecorators: { handleWheel: [{
20621
+ }], ctorParameters: () => [], propDecorators: { loaderPanel: [{ type: i0.ViewChild, args: ['loaderPanel', { isSignal: true }] }], handleWheel: [{
20615
20622
  type: HostListener,
20616
20623
  args: ['document:wheel', ['$event']]
20617
20624
  }], handleTouchMove: [{
@@ -20820,6 +20827,7 @@ class JvDialogComponent {
20820
20827
  previouslyFocusedElement = null;
20821
20828
  open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
20822
20829
  title = input('Dialog', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
20830
+ description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
20823
20831
  closed = output();
20824
20832
  titleId = `jv-dialog-title-${Math.random().toString(36).slice(2, 8)}`;
20825
20833
  descriptionId = `jv-dialog-description-${Math.random().toString(36).slice(2, 8)}`;
@@ -20889,15 +20897,18 @@ class JvDialogComponent {
20889
20897
  return Array.from(panel.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'));
20890
20898
  }
20891
20899
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
20892
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvDialogComponent, isStandalone: true, selector: "jv-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { listeners: { "document:keydown": "handleDocumentKeydown($event)" } }, viewQueries: [{ propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: `
20900
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvDialogComponent, isStandalone: true, selector: "jv-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { listeners: { "document:keydown": "handleDocumentKeydown($event)" } }, viewQueries: [{ propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: `
20893
20901
  @if (open()) {
20894
20902
  <div class="jv-dialog-backdrop" tabindex="-1" (click)="backdropClose()" (keydown.escape)="backdropClose()">
20895
- <div class="jv-dialog-panel" role="dialog" aria-modal="true" tabindex="-1" [attr.aria-labelledby]="titleId" [attr.aria-describedby]="descriptionId" (click)="$event.stopPropagation()" (keydown)="$event.stopPropagation()" #panel>
20903
+ <div class="jv-dialog-panel" role="dialog" aria-modal="true" tabindex="-1" [attr.aria-labelledby]="titleId" [attr.aria-describedby]="description() ? descriptionId : null" (click)="$event.stopPropagation()" (keydown)="$event.stopPropagation()" #panel>
20896
20904
  <header class="jv-dialog-header">
20897
20905
  <h2 [id]="titleId">{{ title() }}</h2>
20906
+ @if (description()) {
20907
+ <p class="jv-dialog-description" [id]="descriptionId">{{ description() }}</p>
20908
+ }
20898
20909
  </header>
20899
20910
 
20900
- <div class="jv-dialog-body" [id]="descriptionId">
20911
+ <div class="jv-dialog-body">
20901
20912
  <ng-content></ng-content>
20902
20913
  </div>
20903
20914
 
@@ -20914,12 +20925,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
20914
20925
  args: [{ selector: 'jv-dialog', standalone: true, template: `
20915
20926
  @if (open()) {
20916
20927
  <div class="jv-dialog-backdrop" tabindex="-1" (click)="backdropClose()" (keydown.escape)="backdropClose()">
20917
- <div class="jv-dialog-panel" role="dialog" aria-modal="true" tabindex="-1" [attr.aria-labelledby]="titleId" [attr.aria-describedby]="descriptionId" (click)="$event.stopPropagation()" (keydown)="$event.stopPropagation()" #panel>
20928
+ <div class="jv-dialog-panel" role="dialog" aria-modal="true" tabindex="-1" [attr.aria-labelledby]="titleId" [attr.aria-describedby]="description() ? descriptionId : null" (click)="$event.stopPropagation()" (keydown)="$event.stopPropagation()" #panel>
20918
20929
  <header class="jv-dialog-header">
20919
20930
  <h2 [id]="titleId">{{ title() }}</h2>
20931
+ @if (description()) {
20932
+ <p class="jv-dialog-description" [id]="descriptionId">{{ description() }}</p>
20933
+ }
20920
20934
  </header>
20921
20935
 
20922
- <div class="jv-dialog-body" [id]="descriptionId">
20936
+ <div class="jv-dialog-body">
20923
20937
  <ng-content></ng-content>
20924
20938
  </div>
20925
20939
 
@@ -20930,7 +20944,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
20930
20944
  </div>
20931
20945
  }
20932
20946
  `, styles: [".jv-dialog-backdrop{position:fixed;inset:0;z-index:1200;display:grid;place-items:center;padding:1rem;background:#0f172a80}.jv-dialog-panel{width:min(32rem,100%);max-height:calc(100vh - 2rem);overflow:auto;padding:var(--jv-spacing-lg);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-lg);background:var(--jv-color-surface);box-shadow:var(--jv-shadow-lg)}.jv-dialog-header,.jv-dialog-body,.jv-dialog-footer{display:grid;gap:var(--jv-spacing-sm)}.jv-dialog-footer{margin-top:var(--jv-spacing-lg)}h2,p{margin:0}\n"] }]
20933
- }], 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 }] }], closed: [{ type: i0.Output, args: ["closed"] }], handleDocumentKeydown: [{
20947
+ }], 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 }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], handleDocumentKeydown: [{
20934
20948
  type: HostListener,
20935
20949
  args: ['document:keydown', ['$event']]
20936
20950
  }] } });
@@ -20962,6 +20976,9 @@ class JvDatePickerComponent {
20962
20976
  disabled = false;
20963
20977
  resolvedDialogTitle = computed(() => this.dialogTitle() || this.translation.translate('datePicker.dialogTitle'), ...(ngDevMode ? [{ debugName: "resolvedDialogTitle" }] : /* istanbul ignore next */ []));
20964
20978
  currentValue = computed(() => this.valueInput() !== undefined ? this.valueInput() : this.value(), ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
20979
+ resolvedDescribedBy = computed(() => [this.describedBy(), this.invalid() ? (this.error() ? `${this.inputId()}-error` : '') : (this.hint() ? `${this.inputId()}-hint` : '')]
20980
+ .filter(Boolean)
20981
+ .join(' '), ...(ngDevMode ? [{ debugName: "resolvedDescribedBy" }] : /* istanbul ignore next */ []));
20965
20982
  triggerAriaLabel = computed(() => {
20966
20983
  const name = this.label() || this.resolvedDialogTitle();
20967
20984
  return `${name}. ${this.displayValue()}`;
@@ -21167,7 +21184,7 @@ class JvDatePickerComponent {
21167
21184
  [attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
21168
21185
  [attr.aria-controls]="dialogId"
21169
21186
  [attr.aria-invalid]="invalid() ? 'true' : null"
21170
- [attr.aria-describedby]="describedBy() || null"
21187
+ [attr.aria-describedby]="resolvedDescribedBy() || null"
21171
21188
  [attr.aria-label]="triggerAriaLabel()"
21172
21189
  [attr.title]="displayValue()"
21173
21190
  (click)="openDialog()"
@@ -21224,7 +21241,7 @@ class JvDatePickerComponent {
21224
21241
  <jv-button variant="outline" (click)="closeDialog()">{{ translation.translate('datePicker.close') }}</jv-button>
21225
21242
  </div>
21226
21243
  </jv-dialog>
21227
- `, isInline: true, styles: [".jv-date-picker-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-date-picker-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-date-picker-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-date-picker-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-placeholder{color:var(--jv-color-foreground-muted)}.jv-date-picker-dialog,.jv-date-picker-actions{display:grid;gap:var(--jv-spacing-md)}.jv-date-picker-toolbar,.jv-date-picker-selects,.jv-date-picker-weekdays,.jv-date-picker-grid{display:grid;gap:var(--jv-spacing-sm)}.jv-date-picker-toolbar{grid-template-columns:auto 1fr auto;align-items:center}.jv-date-picker-selects{grid-template-columns:1fr 1fr}.jv-date-picker-weekdays,.jv-date-picker-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.jv-date-picker-weekdays span{text-align:center;font-size:.8125rem;font-weight:600;color:var(--jv-color-foreground-muted)}.jv-date-picker-day{min-height:2.5rem;border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground);font:inherit;cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease}.jv-date-picker-day:hover,.jv-date-picker-day:focus-visible{background:var(--jv-color-surface-muted)}.jv-date-picker-day:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-day--outside{color:var(--jv-color-foreground-muted)}.jv-date-picker-day--today{border-color:var(--jv-color-primary)}.jv-date-picker-day--selected{background:var(--jv-color-primary);color:#fff}\n"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title"], outputs: ["closed"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconButtonComponent, selector: "jv-icon-button", inputs: ["icon", "ariaLabel", "variant", "disabled"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
21244
+ `, isInline: true, styles: [".jv-date-picker-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-date-picker-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-date-picker-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-date-picker-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-placeholder{color:var(--jv-color-foreground-muted)}.jv-date-picker-dialog,.jv-date-picker-actions{display:grid;gap:var(--jv-spacing-md)}.jv-date-picker-toolbar,.jv-date-picker-selects,.jv-date-picker-weekdays,.jv-date-picker-grid{display:grid;gap:var(--jv-spacing-sm)}.jv-date-picker-toolbar{grid-template-columns:auto 1fr auto;align-items:center}.jv-date-picker-selects{grid-template-columns:1fr 1fr}.jv-date-picker-weekdays,.jv-date-picker-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.jv-date-picker-weekdays span{text-align:center;font-size:.8125rem;font-weight:600;color:var(--jv-color-foreground-muted)}.jv-date-picker-day{min-height:2.5rem;border:1px solid transparent;border-radius:var(--jv-radius-md);background:transparent;color:var(--jv-color-foreground);font:inherit;cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease}.jv-date-picker-day:hover,.jv-date-picker-day:focus-visible{background:var(--jv-color-surface-muted)}.jv-date-picker-day:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-date-picker-day--outside{color:var(--jv-color-foreground-muted)}.jv-date-picker-day--today{border-color:var(--jv-color-primary)}.jv-date-picker-day--selected{background:var(--jv-color-primary);color:#fff}\n"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title", "description"], outputs: ["closed"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconButtonComponent, selector: "jv-icon-button", inputs: ["icon", "ariaLabel", "variant", "disabled"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
21228
21245
  }
21229
21246
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvDatePickerComponent, decorators: [{
21230
21247
  type: Component,
@@ -21254,7 +21271,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
21254
21271
  [attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
21255
21272
  [attr.aria-controls]="dialogId"
21256
21273
  [attr.aria-invalid]="invalid() ? 'true' : null"
21257
- [attr.aria-describedby]="describedBy() || null"
21274
+ [attr.aria-describedby]="resolvedDescribedBy() || null"
21258
21275
  [attr.aria-label]="triggerAriaLabel()"
21259
21276
  [attr.title]="displayValue()"
21260
21277
  (click)="openDialog()"
@@ -21356,6 +21373,7 @@ class JvFileInputComponent {
21356
21373
  filesRejected = output();
21357
21374
  dragActive = signal(false, ...(ngDevMode ? [{ debugName: "dragActive" }] : /* istanbul ignore next */ []));
21358
21375
  rejectionMessage = signal('', ...(ngDevMode ? [{ debugName: "rejectionMessage" }] : /* istanbul ignore next */ []));
21376
+ rejectionId = `jv-file-input-rejection-${this.instanceId}`;
21359
21377
  internalFiles = signal([], ...(ngDevMode ? [{ debugName: "internalFiles" }] : /* istanbul ignore next */ []));
21360
21378
  currentFiles = computed(() => {
21361
21379
  const externalFiles = this.filesInput();
@@ -21363,6 +21381,13 @@ class JvFileInputComponent {
21363
21381
  }, ...(ngDevMode ? [{ debugName: "currentFiles" }] : /* istanbul ignore next */ []));
21364
21382
  selectionSummary = computed(() => this.translation.translate('fileInput.selectionSummary', { count: this.currentFiles().length, max: this.maxFiles() }), ...(ngDevMode ? [{ debugName: "selectionSummary" }] : /* istanbul ignore next */ []));
21365
21383
  dropzoneAriaLabel = computed(() => `${this.label() || this.translation.translate('fileInput.dropLabel')}. ${this.selectionSummary()}`, ...(ngDevMode ? [{ debugName: "dropzoneAriaLabel" }] : /* istanbul ignore next */ []));
21384
+ resolvedDescribedBy = computed(() => [
21385
+ this.describedBy(),
21386
+ this.invalid() ? (this.error() ? `${this.inputId()}-error` : '') : (this.hint() ? `${this.inputId()}-hint` : ''),
21387
+ this.rejectionMessage() ? this.rejectionId : '',
21388
+ ]
21389
+ .filter(Boolean)
21390
+ .join(' '), ...(ngDevMode ? [{ debugName: "resolvedDescribedBy" }] : /* istanbul ignore next */ []));
21366
21391
  openFileDialog() {
21367
21392
  if (this.disabled())
21368
21393
  return;
@@ -21494,7 +21519,7 @@ class JvFileInputComponent {
21494
21519
  [attr.accept]="accept() || null"
21495
21520
  [attr.multiple]="multiple() ? '' : null"
21496
21521
  [disabled]="disabled()"
21497
- [attr.aria-describedby]="describedBy() || null"
21522
+ [attr.aria-describedby]="resolvedDescribedBy() || null"
21498
21523
  (change)="onNativeInputChange($any($event.target).files)"
21499
21524
  />
21500
21525
 
@@ -21523,7 +21548,7 @@ class JvFileInputComponent {
21523
21548
  </div>
21524
21549
 
21525
21550
  @if (rejectionMessage()) {
21526
- <p class="jv-file-input-rejection" aria-live="polite">{{ rejectionMessage() }}</p>
21551
+ <p class="jv-file-input-rejection" [id]="rejectionId" aria-live="polite">{{ rejectionMessage() }}</p>
21527
21552
  }
21528
21553
 
21529
21554
  @if (currentFiles().length > 0) {
@@ -21569,7 +21594,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
21569
21594
  [attr.accept]="accept() || null"
21570
21595
  [attr.multiple]="multiple() ? '' : null"
21571
21596
  [disabled]="disabled()"
21572
- [attr.aria-describedby]="describedBy() || null"
21597
+ [attr.aria-describedby]="resolvedDescribedBy() || null"
21573
21598
  (change)="onNativeInputChange($any($event.target).files)"
21574
21599
  />
21575
21600
 
@@ -21598,7 +21623,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
21598
21623
  </div>
21599
21624
 
21600
21625
  @if (rejectionMessage()) {
21601
- <p class="jv-file-input-rejection" aria-live="polite">{{ rejectionMessage() }}</p>
21626
+ <p class="jv-file-input-rejection" [id]="rejectionId" aria-live="polite">{{ rejectionMessage() }}</p>
21602
21627
  }
21603
21628
 
21604
21629
  @if (currentFiles().length > 0) {
@@ -21696,10 +21721,22 @@ class JvModalSelectorComponent {
21696
21721
  listboxId = `jv-modal-selector-listbox-${this.instanceId}`;
21697
21722
  resultsId = `jv-modal-selector-results-${this.instanceId}`;
21698
21723
  searchInputId = `jv-modal-selector-search-${this.instanceId}`;
21699
- value = null;
21724
+ value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
21700
21725
  disabled = false;
21701
21726
  resolvedDialogTitle = computed(() => this.dialogTitle() || this.label() || this.translation.translate('modalSelector.placeholder'), ...(ngDevMode ? [{ debugName: "resolvedDialogTitle" }] : /* istanbul ignore next */ []));
21702
- currentValue = computed(() => (this.valueInput() !== undefined ? this.valueInput() : this.value), ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
21727
+ currentValue = computed(() => this.valueInput() !== undefined ? this.valueInput() : this.value(), ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
21728
+ resolvedDescribedBy = computed(() => [
21729
+ this.describedBy(),
21730
+ this.invalid()
21731
+ ? this.error()
21732
+ ? `${this.inputId()}-error`
21733
+ : ''
21734
+ : this.hint()
21735
+ ? `${this.inputId()}-hint`
21736
+ : '',
21737
+ ]
21738
+ .filter(Boolean)
21739
+ .join(' '), ...(ngDevMode ? [{ debugName: "resolvedDescribedBy" }] : /* istanbul ignore next */ []));
21703
21740
  selectedOption = computed(() => this.options().find((option) => Object.is(option.value, this.currentValue())) ?? null, ...(ngDevMode ? [{ debugName: "selectedOption" }] : /* istanbul ignore next */ []));
21704
21741
  resolvedPlaceholder = computed(() => this.placeholder() || this.translation.translate('modalSelector.placeholder'), ...(ngDevMode ? [{ debugName: "resolvedPlaceholder" }] : /* istanbul ignore next */ []));
21705
21742
  triggerAriaLabel = computed(() => {
@@ -21714,14 +21751,16 @@ class JvModalSelectorComponent {
21714
21751
  return this.options();
21715
21752
  }
21716
21753
  return this.options().filter((option) => {
21717
- const haystack = [option.label, option.description ?? '', ...(option.keywords ?? [])].join(' ').toLocaleLowerCase();
21754
+ const haystack = [option.label, option.description ?? '', ...(option.keywords ?? [])]
21755
+ .join(' ')
21756
+ .toLocaleLowerCase();
21718
21757
  return haystack.includes(query);
21719
21758
  });
21720
21759
  }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
21721
21760
  onChange = () => undefined;
21722
21761
  onTouched = () => undefined;
21723
21762
  writeValue(value) {
21724
- this.value = value ?? null;
21763
+ this.value.set(value ?? null);
21725
21764
  }
21726
21765
  registerOnChange(fn) {
21727
21766
  this.onChange = fn;
@@ -21803,7 +21842,7 @@ class JvModalSelectorComponent {
21803
21842
  this.onTouched();
21804
21843
  }
21805
21844
  updateValue(value) {
21806
- this.value = value;
21845
+ this.value.set(value);
21807
21846
  this.onChange(value);
21808
21847
  this.selectionChange.emit(value);
21809
21848
  }
@@ -21848,7 +21887,7 @@ class JvModalSelectorComponent {
21848
21887
  [attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
21849
21888
  [attr.aria-controls]="dialogId"
21850
21889
  [attr.aria-invalid]="invalid() ? 'true' : null"
21851
- [attr.aria-describedby]="describedBy() || null"
21890
+ [attr.aria-describedby]="resolvedDescribedBy() || null"
21852
21891
  [attr.aria-label]="triggerAriaLabel()"
21853
21892
  (click)="openDialog()"
21854
21893
  (blur)="handleBlur()"
@@ -21862,27 +21901,40 @@ class JvModalSelectorComponent {
21862
21901
  </button>
21863
21902
  </jv-form-container>
21864
21903
 
21865
- <jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
21904
+ <jv-dialog
21905
+ [open]="dialogOpen()"
21906
+ [title]="resolvedDialogTitle()"
21907
+ [description]="dialogSubtitle()"
21908
+ (closed)="closeDialog()"
21909
+ >
21866
21910
  <div [id]="dialogId" class="jv-modal-selector-dialog">
21867
- @if (dialogSubtitle()) {
21868
- <p class="jv-modal-selector-subtitle">{{ dialogSubtitle() }}</p>
21869
- }
21870
-
21871
21911
  @if (showSearch()) {
21872
21912
  <jv-input
21873
21913
  type="search"
21874
21914
  [inputId]="searchInputId"
21875
- [placeholder]="searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')"
21915
+ [placeholder]="
21916
+ searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')
21917
+ "
21918
+ [ariaLabel]="
21919
+ searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')
21920
+ "
21876
21921
  [describedBy]="resultsId"
21877
21922
  [ngModel]="searchQuery()"
21878
21923
  (ngModelChange)="searchQuery.set($event)"
21879
21924
  />
21880
21925
  }
21881
21926
 
21882
- <p class="jv-modal-selector-results" [id]="resultsId" aria-live="polite">{{ resultsLabel() }}</p>
21927
+ <p class="jv-modal-selector-results" [id]="resultsId" aria-live="polite">
21928
+ {{ resultsLabel() }}
21929
+ </p>
21883
21930
 
21884
21931
  @if (filteredOptions().length > 0) {
21885
- <jv-list [listId]="listboxId" variant="bordered" [ariaRole]="'listbox'" [ariaLabel]="resolvedDialogTitle()">
21932
+ <jv-list
21933
+ [listId]="listboxId"
21934
+ variant="bordered"
21935
+ [ariaRole]="'listbox'"
21936
+ [ariaLabel]="resolvedDialogTitle()"
21937
+ >
21886
21938
  @for (option of filteredOptions(); track option.value; let index = $index) {
21887
21939
  <li role="presentation">
21888
21940
  <div
@@ -21901,7 +21953,9 @@ class JvModalSelectorComponent {
21901
21953
  <div class="jv-modal-selector-option-copy">
21902
21954
  <span class="jv-modal-selector-option-label">{{ option.label }}</span>
21903
21955
  @if (option.description) {
21904
- <span class="jv-modal-selector-option-description">{{ option.description }}</span>
21956
+ <span class="jv-modal-selector-option-description">{{
21957
+ option.description
21958
+ }}</span>
21905
21959
  }
21906
21960
  </div>
21907
21961
  @if (isSelected(option)) {
@@ -21912,22 +21966,36 @@ class JvModalSelectorComponent {
21912
21966
  }
21913
21967
  </jv-list>
21914
21968
  } @else {
21915
- <div class="jv-modal-selector-empty" aria-live="polite">{{ emptyMessage() || translation.translate('modalSelector.emptyMessage') }}</div>
21969
+ <div class="jv-modal-selector-empty" aria-live="polite">
21970
+ {{ emptyMessage() || translation.translate('modalSelector.emptyMessage') }}
21971
+ </div>
21916
21972
  }
21917
21973
  </div>
21918
21974
 
21919
21975
  <div dialog-actions class="jv-modal-selector-actions">
21920
21976
  @if (selectedOption()) {
21921
- <jv-button variant="ghost" (click)="clearSelection()">{{ clearLabel() || translation.translate('modalSelector.clear') }}</jv-button>
21977
+ <jv-button variant="ghost" (click)="clearSelection()">{{
21978
+ clearLabel() || translation.translate('modalSelector.clear')
21979
+ }}</jv-button>
21922
21980
  }
21923
- <jv-button variant="outline" (click)="closeDialog()">{{ closeLabel() || translation.translate('modalSelector.close') }}</jv-button>
21981
+ <jv-button variant="outline" (click)="closeDialog()">{{
21982
+ closeLabel() || translation.translate('modalSelector.close')
21983
+ }}</jv-button>
21924
21984
  </div>
21925
21985
  </jv-dialog>
21926
- `, isInline: true, styles: [".jv-modal-selector-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-modal-selector-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-modal-selector-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-modal-selector-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-modal-selector-trigger-copy{min-width:0;flex:1}.jv-modal-selector-trigger-placeholder{color:var(--jv-color-foreground-muted)}.jv-modal-selector-dialog,.jv-modal-selector-actions{display:grid;gap:var(--jv-spacing-md)}.jv-modal-selector-subtitle,.jv-modal-selector-results,.jv-modal-selector-option-description,.jv-modal-selector-empty{margin:0;color:var(--jv-color-foreground-muted)}.jv-modal-selector-empty{padding:var(--jv-spacing-md);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-md);text-align:center}.jv-modal-selector-option{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md);background:var(--jv-color-surface);cursor:pointer;outline:none;transition:background-color .16s ease}.jv-modal-selector-option:hover,.jv-modal-selector-option:focus-visible{background:var(--jv-color-surface-muted)}.jv-modal-selector-option:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-modal-selector-option--selected{background:color-mix(in srgb,var(--jv-color-primary) 8%,var(--jv-color-surface))}.jv-modal-selector-option--disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.jv-modal-selector-option-copy{min-width:0;display:grid;gap:.25rem}.jv-modal-selector-option-label{font-weight:600;color:var(--jv-color-foreground)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title"], outputs: ["closed"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvListComponent, selector: "jv-list", inputs: ["listId", "role", "ariaRole", "variant", "ariaLabel"] }] });
21986
+ `, isInline: true, styles: [".jv-modal-selector-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-modal-selector-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-modal-selector-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-modal-selector-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-modal-selector-trigger-copy{min-width:0;flex:1}.jv-modal-selector-trigger-placeholder{color:var(--jv-color-foreground-muted)}.jv-modal-selector-dialog,.jv-modal-selector-actions{display:grid;gap:var(--jv-spacing-md)}.jv-modal-selector-subtitle,.jv-modal-selector-results,.jv-modal-selector-option-description,.jv-modal-selector-empty{margin:0;color:var(--jv-color-foreground-muted)}.jv-modal-selector-empty{padding:var(--jv-spacing-md);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-md);text-align:center}.jv-modal-selector-option{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md);background:var(--jv-color-surface);cursor:pointer;outline:none;transition:background-color .16s ease}.jv-modal-selector-option:hover,.jv-modal-selector-option:focus-visible{background:var(--jv-color-surface-muted)}.jv-modal-selector-option:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-modal-selector-option--selected{background:color-mix(in srgb,var(--jv-color-primary) 8%,var(--jv-color-surface))}.jv-modal-selector-option--disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.jv-modal-selector-option-copy{min-width:0;display:grid;gap:.25rem}.jv-modal-selector-option-label{font-weight:600;color:var(--jv-color-foreground)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title", "description"], outputs: ["closed"] }, { kind: "component", type: JvFormContainerComponent, selector: "jv-form-container", inputs: ["label", "hint", "error", "inputId", "hintId", "errorId", "required", "invalid"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId"] }, { kind: "component", type: JvListComponent, selector: "jv-list", inputs: ["listId", "role", "ariaRole", "variant", "ariaLabel"] }] });
21927
21987
  }
21928
21988
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvModalSelectorComponent, decorators: [{
21929
21989
  type: Component,
21930
- args: [{ selector: 'jv-modal-selector', standalone: true, imports: [FormsModule, JvButtonComponent, JvDialogComponent, JvFormContainerComponent, JvIconComponent, JvInputComponent, JvListComponent], providers: [
21990
+ args: [{ selector: 'jv-modal-selector', standalone: true, imports: [
21991
+ FormsModule,
21992
+ JvButtonComponent,
21993
+ JvDialogComponent,
21994
+ JvFormContainerComponent,
21995
+ JvIconComponent,
21996
+ JvInputComponent,
21997
+ JvListComponent,
21998
+ ], providers: [
21931
21999
  {
21932
22000
  provide: NG_VALUE_ACCESSOR,
21933
22001
  useExisting: forwardRef(() => JvModalSelectorComponent),
@@ -21953,7 +22021,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
21953
22021
  [attr.aria-expanded]="dialogOpen() ? 'true' : 'false'"
21954
22022
  [attr.aria-controls]="dialogId"
21955
22023
  [attr.aria-invalid]="invalid() ? 'true' : null"
21956
- [attr.aria-describedby]="describedBy() || null"
22024
+ [attr.aria-describedby]="resolvedDescribedBy() || null"
21957
22025
  [attr.aria-label]="triggerAriaLabel()"
21958
22026
  (click)="openDialog()"
21959
22027
  (blur)="handleBlur()"
@@ -21967,27 +22035,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
21967
22035
  </button>
21968
22036
  </jv-form-container>
21969
22037
 
21970
- <jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" (closed)="closeDialog()">
22038
+ <jv-dialog
22039
+ [open]="dialogOpen()"
22040
+ [title]="resolvedDialogTitle()"
22041
+ [description]="dialogSubtitle()"
22042
+ (closed)="closeDialog()"
22043
+ >
21971
22044
  <div [id]="dialogId" class="jv-modal-selector-dialog">
21972
- @if (dialogSubtitle()) {
21973
- <p class="jv-modal-selector-subtitle">{{ dialogSubtitle() }}</p>
21974
- }
21975
-
21976
22045
  @if (showSearch()) {
21977
22046
  <jv-input
21978
22047
  type="search"
21979
22048
  [inputId]="searchInputId"
21980
- [placeholder]="searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')"
22049
+ [placeholder]="
22050
+ searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')
22051
+ "
22052
+ [ariaLabel]="
22053
+ searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')
22054
+ "
21981
22055
  [describedBy]="resultsId"
21982
22056
  [ngModel]="searchQuery()"
21983
22057
  (ngModelChange)="searchQuery.set($event)"
21984
22058
  />
21985
22059
  }
21986
22060
 
21987
- <p class="jv-modal-selector-results" [id]="resultsId" aria-live="polite">{{ resultsLabel() }}</p>
22061
+ <p class="jv-modal-selector-results" [id]="resultsId" aria-live="polite">
22062
+ {{ resultsLabel() }}
22063
+ </p>
21988
22064
 
21989
22065
  @if (filteredOptions().length > 0) {
21990
- <jv-list [listId]="listboxId" variant="bordered" [ariaRole]="'listbox'" [ariaLabel]="resolvedDialogTitle()">
22066
+ <jv-list
22067
+ [listId]="listboxId"
22068
+ variant="bordered"
22069
+ [ariaRole]="'listbox'"
22070
+ [ariaLabel]="resolvedDialogTitle()"
22071
+ >
21991
22072
  @for (option of filteredOptions(); track option.value; let index = $index) {
21992
22073
  <li role="presentation">
21993
22074
  <div
@@ -22006,7 +22087,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22006
22087
  <div class="jv-modal-selector-option-copy">
22007
22088
  <span class="jv-modal-selector-option-label">{{ option.label }}</span>
22008
22089
  @if (option.description) {
22009
- <span class="jv-modal-selector-option-description">{{ option.description }}</span>
22090
+ <span class="jv-modal-selector-option-description">{{
22091
+ option.description
22092
+ }}</span>
22010
22093
  }
22011
22094
  </div>
22012
22095
  @if (isSelected(option)) {
@@ -22017,15 +22100,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22017
22100
  }
22018
22101
  </jv-list>
22019
22102
  } @else {
22020
- <div class="jv-modal-selector-empty" aria-live="polite">{{ emptyMessage() || translation.translate('modalSelector.emptyMessage') }}</div>
22103
+ <div class="jv-modal-selector-empty" aria-live="polite">
22104
+ {{ emptyMessage() || translation.translate('modalSelector.emptyMessage') }}
22105
+ </div>
22021
22106
  }
22022
22107
  </div>
22023
22108
 
22024
22109
  <div dialog-actions class="jv-modal-selector-actions">
22025
22110
  @if (selectedOption()) {
22026
- <jv-button variant="ghost" (click)="clearSelection()">{{ clearLabel() || translation.translate('modalSelector.clear') }}</jv-button>
22111
+ <jv-button variant="ghost" (click)="clearSelection()">{{
22112
+ clearLabel() || translation.translate('modalSelector.clear')
22113
+ }}</jv-button>
22027
22114
  }
22028
- <jv-button variant="outline" (click)="closeDialog()">{{ closeLabel() || translation.translate('modalSelector.close') }}</jv-button>
22115
+ <jv-button variant="outline" (click)="closeDialog()">{{
22116
+ closeLabel() || translation.translate('modalSelector.close')
22117
+ }}</jv-button>
22029
22118
  </div>
22030
22119
  </jv-dialog>
22031
22120
  `, styles: [".jv-modal-selector-trigger{width:100%;min-height:var(--jv-density-control-height);display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-sm);padding:0 var(--jv-spacing-md);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);text-align:left;font:inherit;cursor:pointer}.jv-modal-selector-trigger.is-invalid{border-color:var(--jv-color-danger)}.jv-modal-selector-trigger:disabled{opacity:.7;cursor:not-allowed}.jv-modal-selector-trigger:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-modal-selector-trigger-copy{min-width:0;flex:1}.jv-modal-selector-trigger-placeholder{color:var(--jv-color-foreground-muted)}.jv-modal-selector-dialog,.jv-modal-selector-actions{display:grid;gap:var(--jv-spacing-md)}.jv-modal-selector-subtitle,.jv-modal-selector-results,.jv-modal-selector-option-description,.jv-modal-selector-empty{margin:0;color:var(--jv-color-foreground-muted)}.jv-modal-selector-empty{padding:var(--jv-spacing-md);border:1px dashed var(--jv-color-border);border-radius:var(--jv-radius-md);text-align:center}.jv-modal-selector-option{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);padding:var(--jv-spacing-md);background:var(--jv-color-surface);cursor:pointer;outline:none;transition:background-color .16s ease}.jv-modal-selector-option:hover,.jv-modal-selector-option:focus-visible{background:var(--jv-color-surface-muted)}.jv-modal-selector-option:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-modal-selector-option--selected{background:color-mix(in srgb,var(--jv-color-primary) 8%,var(--jv-color-surface))}.jv-modal-selector-option--disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.jv-modal-selector-option-copy{min-width:0;display:grid;gap:.25rem}.jv-modal-selector-option-label{font-weight:600;color:var(--jv-color-foreground)}\n"] }]
@@ -22164,7 +22253,7 @@ class JvSwitchComponent {
22164
22253
  </span>
22165
22254
  <span>{{ label() }}</span>
22166
22255
  </label>
22167
- `, isInline: true, styles: [".jv-switch{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);min-height:var(--jv-density-control-height);color:var(--jv-color-foreground)}.jv-switch.is-disabled{opacity:.7}.jv-switch-input{position:absolute;opacity:0;pointer-events:none}.jv-switch-track{position:relative;display:inline-flex;align-items:center;width:2.75rem;height:1.6rem;padding:.15rem;border-radius:999px;background:var(--jv-color-border);transition:background-color .16s ease}.jv-switch-thumb{width:1.25rem;height:1.25rem;border-radius:999px;background:#fff;box-shadow:var(--jv-shadow-sm);transition:transform .16s ease}.jv-switch-input:checked+.jv-switch-track{background:var(--jv-color-primary)}.jv-switch-input:checked+.jv-switch-track .jv-switch-thumb{transform:translate(1.1rem)}\n"] });
22256
+ `, isInline: true, styles: [".jv-switch{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);min-height:var(--jv-density-control-height);color:var(--jv-color-foreground)}.jv-switch.is-disabled{opacity:.7}.jv-switch-input{position:absolute;opacity:0;pointer-events:none}.jv-switch-track{position:relative;display:inline-flex;align-items:center;width:2.75rem;height:1.6rem;padding:.15rem;border-radius:999px;background:var(--jv-color-border);transition:background-color .16s ease}.jv-switch-thumb{width:1.25rem;height:1.25rem;border-radius:999px;background:#fff;box-shadow:var(--jv-shadow-sm);transition:transform .16s ease}.jv-switch-input:checked+.jv-switch-track{background:var(--jv-color-primary)}.jv-switch-input:checked+.jv-switch-track .jv-switch-thumb{transform:translate(1.1rem)}.jv-switch-input:focus-visible+.jv-switch-track{outline:2px solid var(--jv-color-primary);outline-offset:2px}\n"] });
22168
22257
  }
22169
22258
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSwitchComponent, decorators: [{
22170
22259
  type: Component,
@@ -22192,7 +22281,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22192
22281
  </span>
22193
22282
  <span>{{ label() }}</span>
22194
22283
  </label>
22195
- `, styles: [".jv-switch{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);min-height:var(--jv-density-control-height);color:var(--jv-color-foreground)}.jv-switch.is-disabled{opacity:.7}.jv-switch-input{position:absolute;opacity:0;pointer-events:none}.jv-switch-track{position:relative;display:inline-flex;align-items:center;width:2.75rem;height:1.6rem;padding:.15rem;border-radius:999px;background:var(--jv-color-border);transition:background-color .16s ease}.jv-switch-thumb{width:1.25rem;height:1.25rem;border-radius:999px;background:#fff;box-shadow:var(--jv-shadow-sm);transition:transform .16s ease}.jv-switch-input:checked+.jv-switch-track{background:var(--jv-color-primary)}.jv-switch-input:checked+.jv-switch-track .jv-switch-thumb{transform:translate(1.1rem)}\n"] }]
22284
+ `, styles: [".jv-switch{display:inline-flex;align-items:center;gap:var(--jv-spacing-sm);min-height:var(--jv-density-control-height);color:var(--jv-color-foreground)}.jv-switch.is-disabled{opacity:.7}.jv-switch-input{position:absolute;opacity:0;pointer-events:none}.jv-switch-track{position:relative;display:inline-flex;align-items:center;width:2.75rem;height:1.6rem;padding:.15rem;border-radius:999px;background:var(--jv-color-border);transition:background-color .16s ease}.jv-switch-thumb{width:1.25rem;height:1.25rem;border-radius:999px;background:#fff;box-shadow:var(--jv-shadow-sm);transition:transform .16s ease}.jv-switch-input:checked+.jv-switch-track{background:var(--jv-color-primary)}.jv-switch-input:checked+.jv-switch-track .jv-switch-thumb{transform:translate(1.1rem)}.jv-switch-input:focus-visible+.jv-switch-track{outline:2px solid var(--jv-color-primary);outline-offset:2px}\n"] }]
22196
22285
  }], 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 }] }] } });
22197
22286
 
22198
22287
  let textareaIdSequence = 0;
@@ -22473,7 +22562,7 @@ class JvImageGalleryComponent {
22473
22562
  </div>
22474
22563
  </jv-dialog>
22475
22564
  </div>
22476
- `, isInline: true, styles: [".jv-gallery{display:block;width:100%;max-width:100vw}.jv-gallery-strip{display:flex;gap:5px;width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:none;-ms-overflow-style:none;scroll-snap-type:x proximity;scroll-behavior:smooth;-webkit-overflow-scrolling:touch}.jv-gallery-strip::-webkit-scrollbar{display:none}.jv-gallery-thumb{flex:0 0 auto;width:calc((100vw - 20px)/4);min-width:120px;height:100%;padding:0;border:2px solid transparent;border-radius:var(--jv-radius-sm);background:transparent;cursor:pointer;overflow:hidden;scroll-snap-align:start;transition:border-color .16s ease,opacity .16s ease}.jv-gallery-thumb:hover{opacity:.85}.jv-gallery-thumb--active{border-color:var(--jv-color-primary)}.jv-gallery-thumb:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-gallery-thumb-image{display:block;width:100%;height:100%;object-fit:cover;pointer-events:none}.jv-gallery-viewer{position:relative;display:flex;align-items:center;justify-content:center;width:100%;height:70vh;min-height:300px;background:#000;border-radius:var(--jv-radius-md);overflow:hidden}.jv-gallery-viewer:focus{outline:none}.jv-gallery-viewer-image{display:block;max-width:100%;max-height:100%;object-fit:contain;-webkit-user-select:none;user-select:none}@keyframes gallery-slide-left{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes gallery-slide-right{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}.jv-gallery-viewer-image--slide-left{animation:gallery-slide-left .28s ease-out}.jv-gallery-viewer-image--slide-right{animation:gallery-slide-right .28s ease-out}.jv-gallery-viewer-nav{position:absolute;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:3rem;height:3rem;border:none;border-radius:var(--jv-radius-md);background:#00000080;color:#fff;cursor:pointer;transition:background-color .16s ease;z-index:1}.jv-gallery-viewer-nav:hover{background:#000000bf}.jv-gallery-viewer-nav:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-gallery-viewer-nav--prev{left:var(--jv-spacing-md)}.jv-gallery-viewer-nav--next{right:var(--jv-spacing-md)}.jv-gallery-viewer-counter{position:absolute;bottom:var(--jv-spacing-md);left:50%;transform:translate(-50%);padding:var(--jv-spacing-xs) var(--jv-spacing-sm);border-radius:var(--jv-radius-sm);background:#0009;color:#fff;font-size:.8125rem;font-variant-numeric:tabular-nums;pointer-events:none}@media(max-width:768px){.jv-gallery-thumb{width:calc(100vw - 20px);min-width:200px}.jv-gallery-viewer-nav{width:2.5rem;height:2.5rem}.jv-gallery-viewer-nav--prev{left:var(--jv-spacing-sm)}.jv-gallery-viewer-nav--next{right:var(--jv-spacing-sm)}}@media(prefers-reduced-motion:reduce){.jv-gallery-strip{scroll-behavior:auto}.jv-gallery-viewer-image--slide-left,.jv-gallery-viewer-image--slide-right{animation:none}}\n"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title"], outputs: ["closed"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
22565
+ `, isInline: true, styles: [".jv-gallery{display:block;width:100%;max-width:100vw}.jv-gallery-strip{display:flex;gap:5px;width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:none;-ms-overflow-style:none;scroll-snap-type:x proximity;scroll-behavior:smooth;-webkit-overflow-scrolling:touch}.jv-gallery-strip::-webkit-scrollbar{display:none}.jv-gallery-thumb{flex:0 0 auto;width:calc((100vw - 20px)/4);min-width:120px;height:100%;padding:0;border:2px solid transparent;border-radius:var(--jv-radius-sm);background:transparent;cursor:pointer;overflow:hidden;scroll-snap-align:start;transition:border-color .16s ease,opacity .16s ease}.jv-gallery-thumb:hover{opacity:.85}.jv-gallery-thumb--active{border-color:var(--jv-color-primary)}.jv-gallery-thumb:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-gallery-thumb-image{display:block;width:100%;height:100%;object-fit:cover;pointer-events:none}.jv-gallery-viewer{position:relative;display:flex;align-items:center;justify-content:center;width:100%;height:70vh;min-height:300px;background:#000;border-radius:var(--jv-radius-md);overflow:hidden}.jv-gallery-viewer:focus{outline:none}.jv-gallery-viewer-image{display:block;max-width:100%;max-height:100%;object-fit:contain;-webkit-user-select:none;user-select:none}@keyframes gallery-slide-left{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes gallery-slide-right{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}.jv-gallery-viewer-image--slide-left{animation:gallery-slide-left .28s ease-out}.jv-gallery-viewer-image--slide-right{animation:gallery-slide-right .28s ease-out}.jv-gallery-viewer-nav{position:absolute;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:3rem;height:3rem;border:none;border-radius:var(--jv-radius-md);background:#00000080;color:#fff;cursor:pointer;transition:background-color .16s ease;z-index:1}.jv-gallery-viewer-nav:hover{background:#000000bf}.jv-gallery-viewer-nav:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-gallery-viewer-nav--prev{left:var(--jv-spacing-md)}.jv-gallery-viewer-nav--next{right:var(--jv-spacing-md)}.jv-gallery-viewer-counter{position:absolute;bottom:var(--jv-spacing-md);left:50%;transform:translate(-50%);padding:var(--jv-spacing-xs) var(--jv-spacing-sm);border-radius:var(--jv-radius-sm);background:#0009;color:#fff;font-size:.8125rem;font-variant-numeric:tabular-nums;pointer-events:none}@media(max-width:768px){.jv-gallery-thumb{width:calc(100vw - 20px);min-width:200px}.jv-gallery-viewer-nav{width:2.5rem;height:2.5rem}.jv-gallery-viewer-nav--prev{left:var(--jv-spacing-sm)}.jv-gallery-viewer-nav--next{right:var(--jv-spacing-sm)}}@media(prefers-reduced-motion:reduce){.jv-gallery-strip{scroll-behavior:auto}.jv-gallery-viewer-image--slide-left,.jv-gallery-viewer-image--slide-right{animation:none}}\n"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title", "description"], outputs: ["closed"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
22477
22566
  }
22478
22567
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvImageGalleryComponent, decorators: [{
22479
22568
  type: Component,
@@ -22614,18 +22703,14 @@ class JvImageSliderComponent {
22614
22703
  if (!this.hasMultiple()) {
22615
22704
  return;
22616
22705
  }
22617
- const newIndex = this.currentIndex() === 0
22618
- ? this.images().length - 1
22619
- : this.currentIndex() - 1;
22706
+ const newIndex = this.currentIndex() === 0 ? this.images().length - 1 : this.currentIndex() - 1;
22620
22707
  this.goTo(newIndex);
22621
22708
  }
22622
22709
  next() {
22623
22710
  if (!this.hasMultiple()) {
22624
22711
  return;
22625
22712
  }
22626
- const newIndex = this.currentIndex() === this.images().length - 1
22627
- ? 0
22628
- : this.currentIndex() + 1;
22713
+ const newIndex = this.currentIndex() === this.images().length - 1 ? 0 : this.currentIndex() + 1;
22629
22714
  this.goTo(newIndex);
22630
22715
  }
22631
22716
  goTo(index) {
@@ -22670,13 +22755,12 @@ class JvImageSliderComponent {
22670
22755
  <div
22671
22756
  class="jv-slider-slide"
22672
22757
  [class.jv-slider-slide--active]="i === currentIndex()"
22758
+ [id]="'jv-slider-slide-' + i"
22759
+ role="tabpanel"
22760
+ [attr.aria-hidden]="i === currentIndex() ? 'false' : 'true'"
22761
+ [attr.aria-label]="image.alt"
22673
22762
  >
22674
- <img
22675
- class="jv-slider-image"
22676
- [src]="image.src"
22677
- [alt]="image.alt"
22678
- loading="lazy"
22679
- />
22763
+ <img class="jv-slider-image" [src]="image.src" [alt]="image.alt" loading="lazy" />
22680
22764
  </div>
22681
22765
  }
22682
22766
  </div>
@@ -22702,14 +22786,22 @@ class JvImageSliderComponent {
22702
22786
  }
22703
22787
 
22704
22788
  @if (hasMultiple() && showThumbnails()) {
22705
- <div class="jv-slider-thumbnails" #thumbnailStrip role="tablist" [attr.aria-label]="translatedAriaLabels().thumbnailList">
22789
+ <div
22790
+ class="jv-slider-thumbnails"
22791
+ #thumbnailStrip
22792
+ role="tablist"
22793
+ [attr.aria-label]="translatedAriaLabels().thumbnailList"
22794
+ >
22706
22795
  @for (image of images(); track image.src; let i = $index) {
22707
22796
  <button
22708
22797
  type="button"
22709
22798
  class="jv-slider-thumbnail"
22710
22799
  [class.jv-slider-thumbnail--active]="i === currentIndex()"
22711
22800
  role="tab"
22801
+ [id]="'jv-slider-tab-' + i"
22802
+ [attr.aria-controls]="'jv-slider-slide-' + i"
22712
22803
  [attr.aria-selected]="i === currentIndex() ? 'true' : 'false'"
22804
+ [attr.tabindex]="i === currentIndex() ? '0' : '-1'"
22713
22805
  [attr.aria-label]="image.alt"
22714
22806
  (click)="goTo(i)"
22715
22807
  >
@@ -22723,9 +22815,7 @@ class JvImageSliderComponent {
22723
22815
  }
22724
22816
  </div>
22725
22817
 
22726
- <div class="jv-slider-counter">
22727
- {{ currentIndex() + 1 }} / {{ images().length }}
22728
- </div>
22818
+ <div class="jv-slider-counter">{{ currentIndex() + 1 }} / {{ images().length }}</div>
22729
22819
  }
22730
22820
  </div>
22731
22821
  `, isInline: true, styles: [".jv-slider{display:grid;gap:var(--jv-spacing-sm);width:100%;max-width:100%}.jv-slider-main{position:relative;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--jv-spacing-xs)}.jv-slider-stage{position:relative;aspect-ratio:16 / 9;overflow:hidden;border-radius:var(--jv-radius-md);background:var(--jv-color-surface-muted)}.jv-slider-slide{position:absolute;inset:0;opacity:0;transition:opacity .2s ease;pointer-events:none}.jv-slider-slide--active{opacity:1;pointer-events:auto}.jv-slider-image{display:block;width:100%;height:100%;object-fit:contain;-webkit-user-select:none;user-select:none}.jv-slider-nav{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease;flex-shrink:0;z-index:1}.jv-slider-nav:hover{background:var(--jv-color-surface-muted);border-color:var(--jv-color-foreground-muted)}.jv-slider-nav:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-slider-description{padding:var(--jv-spacing-sm) 0}.jv-slider-description p{margin:0;font-size:var(--jv-density-font-size);color:var(--jv-color-foreground-muted);line-height:1.5}.jv-slider-thumbnails{display:flex;gap:var(--jv-spacing-xs);overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;padding:var(--jv-spacing-xs) 0}.jv-slider-thumbnails::-webkit-scrollbar{display:none}.jv-slider-thumbnail{flex:0 0 auto;width:3.5rem;height:3.5rem;padding:0;border:2px solid transparent;border-radius:var(--jv-radius-sm);background:transparent;cursor:pointer;overflow:hidden;transition:border-color .16s ease,opacity .16s ease;opacity:.6}.jv-slider-thumbnail:hover{opacity:.85}.jv-slider-thumbnail--active{border-color:var(--jv-color-primary);opacity:1}.jv-slider-thumbnail:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-slider-thumbnail-image{display:block;width:100%;height:100%;object-fit:cover}.jv-slider-counter{text-align:center;font-size:.8125rem;color:var(--jv-color-foreground-muted);font-variant-numeric:tabular-nums}@media(max-width:640px){.jv-slider-nav{width:2rem;height:2rem}.jv-slider-thumbnail{width:2.75rem;height:2.75rem}}@media(prefers-reduced-motion:reduce){.jv-slider-slide{transition:none}}\n"], dependencies: [{ kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }] });
@@ -22751,13 +22841,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22751
22841
  <div
22752
22842
  class="jv-slider-slide"
22753
22843
  [class.jv-slider-slide--active]="i === currentIndex()"
22844
+ [id]="'jv-slider-slide-' + i"
22845
+ role="tabpanel"
22846
+ [attr.aria-hidden]="i === currentIndex() ? 'false' : 'true'"
22847
+ [attr.aria-label]="image.alt"
22754
22848
  >
22755
- <img
22756
- class="jv-slider-image"
22757
- [src]="image.src"
22758
- [alt]="image.alt"
22759
- loading="lazy"
22760
- />
22849
+ <img class="jv-slider-image" [src]="image.src" [alt]="image.alt" loading="lazy" />
22761
22850
  </div>
22762
22851
  }
22763
22852
  </div>
@@ -22783,14 +22872,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22783
22872
  }
22784
22873
 
22785
22874
  @if (hasMultiple() && showThumbnails()) {
22786
- <div class="jv-slider-thumbnails" #thumbnailStrip role="tablist" [attr.aria-label]="translatedAriaLabels().thumbnailList">
22875
+ <div
22876
+ class="jv-slider-thumbnails"
22877
+ #thumbnailStrip
22878
+ role="tablist"
22879
+ [attr.aria-label]="translatedAriaLabels().thumbnailList"
22880
+ >
22787
22881
  @for (image of images(); track image.src; let i = $index) {
22788
22882
  <button
22789
22883
  type="button"
22790
22884
  class="jv-slider-thumbnail"
22791
22885
  [class.jv-slider-thumbnail--active]="i === currentIndex()"
22792
22886
  role="tab"
22887
+ [id]="'jv-slider-tab-' + i"
22888
+ [attr.aria-controls]="'jv-slider-slide-' + i"
22793
22889
  [attr.aria-selected]="i === currentIndex() ? 'true' : 'false'"
22890
+ [attr.tabindex]="i === currentIndex() ? '0' : '-1'"
22794
22891
  [attr.aria-label]="image.alt"
22795
22892
  (click)="goTo(i)"
22796
22893
  >
@@ -22804,9 +22901,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22804
22901
  }
22805
22902
  </div>
22806
22903
 
22807
- <div class="jv-slider-counter">
22808
- {{ currentIndex() + 1 }} / {{ images().length }}
22809
- </div>
22904
+ <div class="jv-slider-counter">{{ currentIndex() + 1 }} / {{ images().length }}</div>
22810
22905
  }
22811
22906
  </div>
22812
22907
  `, styles: [".jv-slider{display:grid;gap:var(--jv-spacing-sm);width:100%;max-width:100%}.jv-slider-main{position:relative;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--jv-spacing-xs)}.jv-slider-stage{position:relative;aspect-ratio:16 / 9;overflow:hidden;border-radius:var(--jv-radius-md);background:var(--jv-color-surface-muted)}.jv-slider-slide{position:absolute;inset:0;opacity:0;transition:opacity .2s ease;pointer-events:none}.jv-slider-slide--active{opacity:1;pointer-events:auto}.jv-slider-image{display:block;width:100%;height:100%;object-fit:contain;-webkit-user-select:none;user-select:none}.jv-slider-nav{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);background:var(--jv-color-surface);color:var(--jv-color-foreground);cursor:pointer;transition:background-color .16s ease,border-color .16s ease,color .16s ease;flex-shrink:0;z-index:1}.jv-slider-nav:hover{background:var(--jv-color-surface-muted);border-color:var(--jv-color-foreground-muted)}.jv-slider-nav:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-slider-description{padding:var(--jv-spacing-sm) 0}.jv-slider-description p{margin:0;font-size:var(--jv-density-font-size);color:var(--jv-color-foreground-muted);line-height:1.5}.jv-slider-thumbnails{display:flex;gap:var(--jv-spacing-xs);overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;padding:var(--jv-spacing-xs) 0}.jv-slider-thumbnails::-webkit-scrollbar{display:none}.jv-slider-thumbnail{flex:0 0 auto;width:3.5rem;height:3.5rem;padding:0;border:2px solid transparent;border-radius:var(--jv-radius-sm);background:transparent;cursor:pointer;overflow:hidden;transition:border-color .16s ease,opacity .16s ease;opacity:.6}.jv-slider-thumbnail:hover{opacity:.85}.jv-slider-thumbnail--active{border-color:var(--jv-color-primary);opacity:1}.jv-slider-thumbnail:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:1px}.jv-slider-thumbnail-image{display:block;width:100%;height:100%;object-fit:cover}.jv-slider-counter{text-align:center;font-size:.8125rem;color:var(--jv-color-foreground-muted);font-variant-numeric:tabular-nums}@media(max-width:640px){.jv-slider-nav{width:2rem;height:2rem}.jv-slider-thumbnail{width:2.75rem;height:2.75rem}}@media(prefers-reduced-motion:reduce){.jv-slider-slide{transition:none}}\n"] }]
@@ -22874,16 +22969,15 @@ class JvConfirmDialogComponent {
22874
22969
  <jv-dialog
22875
22970
  [open]="isOpen()"
22876
22971
  [title]="dialogTitle()"
22972
+ [description]="dialogMessage()"
22877
22973
  (closed)="dialogService.resolve(false)"
22878
22974
  >
22879
- <p>{{ dialogMessage() }}</p>
22880
-
22881
22975
  <div dialog-actions class="actions">
22882
22976
  <jv-button [variant]="confirmVariant()" (click)="dialogService.resolve(true)">{{ confirmLabel() }}</jv-button>
22883
22977
  <jv-button variant="ghost" (click)="dialogService.resolve(false)">{{ cancelLabel() }}</jv-button>
22884
22978
  </div>
22885
22979
  </jv-dialog>
22886
- `, isInline: true, 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"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title"], outputs: ["closed"] }] });
22980
+ `, isInline: true, 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"], dependencies: [{ kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvDialogComponent, selector: "jv-dialog", inputs: ["open", "title", "description"], outputs: ["closed"] }] });
22887
22981
  }
22888
22982
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvConfirmDialogComponent, decorators: [{
22889
22983
  type: Component,
@@ -22891,10 +22985,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22891
22985
  <jv-dialog
22892
22986
  [open]="isOpen()"
22893
22987
  [title]="dialogTitle()"
22988
+ [description]="dialogMessage()"
22894
22989
  (closed)="dialogService.resolve(false)"
22895
22990
  >
22896
- <p>{{ dialogMessage() }}</p>
22897
-
22898
22991
  <div dialog-actions class="actions">
22899
22992
  <jv-button [variant]="confirmVariant()" (click)="dialogService.resolve(true)">{{ confirmLabel() }}</jv-button>
22900
22993
  <jv-button variant="ghost" (click)="dialogService.resolve(false)">{{ cancelLabel() }}</jv-button>
@@ -22909,6 +23002,7 @@ class JvWindowModalComponent {
22909
23002
  open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
22910
23003
  title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
22911
23004
  subtitle = input('', ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
23005
+ description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
22912
23006
  mode = input('floating', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
22913
23007
  size = input('xl', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
22914
23008
  showCloseButton = input(true, ...(ngDevMode ? [{ debugName: "showCloseButton" }] : /* istanbul ignore next */ []));
@@ -22918,6 +23012,7 @@ class JvWindowModalComponent {
22918
23012
  closed = output();
22919
23013
  close = output();
22920
23014
  resolvedMode = computed(() => (this.size() === 'fullscreen' ? 'fullscreen' : this.mode()), ...(ngDevMode ? [{ debugName: "resolvedMode" }] : /* istanbul ignore next */ []));
23015
+ resolvedDescription = computed(() => this.description() || this.subtitle(), ...(ngDevMode ? [{ debugName: "resolvedDescription" }] : /* istanbul ignore next */ []));
22921
23016
  titleId = `jv-window-modal-title-${Math.random().toString(36).slice(2, 8)}`;
22922
23017
  descriptionId = `jv-window-modal-description-${Math.random().toString(36).slice(2, 8)}`;
22923
23018
  previousFocusedElement = null;
@@ -23006,7 +23101,7 @@ class JvWindowModalComponent {
23006
23101
  return Array.from(panel.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'));
23007
23102
  }
23008
23103
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvWindowModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23009
- 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: `
23104
+ 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 }, description: { classPropertyName: "description", publicName: "description", 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: `
23010
23105
  @if (open()) {
23011
23106
  <div class="jv-window-modal-backdrop" tabindex="-1" (click)="backdropClose()" (keydown.escape)="backdropClose()">
23012
23107
  <section
@@ -23019,7 +23114,7 @@ class JvWindowModalComponent {
23019
23114
  aria-modal="true"
23020
23115
  tabindex="-1"
23021
23116
  [attr.aria-labelledby]="title() ? titleId : null"
23022
- [attr.aria-describedby]="descriptionId"
23117
+ [attr.aria-describedby]="resolvedDescription() ? descriptionId : null"
23023
23118
  (click)="$event.stopPropagation()"
23024
23119
  (keydown)="$event.stopPropagation()"
23025
23120
  #panel
@@ -23030,8 +23125,10 @@ class JvWindowModalComponent {
23030
23125
  <h2 [id]="titleId">{{ title() }}</h2>
23031
23126
  }
23032
23127
 
23033
- @if (subtitle()) {
23034
- <p class="jv-window-modal-subtitle">{{ subtitle() }}</p>
23128
+ @if (description()) {
23129
+ <p class="jv-window-modal-description" [id]="descriptionId">{{ description() }}</p>
23130
+ } @else if (subtitle()) {
23131
+ <p class="jv-window-modal-subtitle" [id]="descriptionId">{{ subtitle() }}</p>
23035
23132
  }
23036
23133
  </div>
23037
23134
 
@@ -23044,7 +23141,7 @@ class JvWindowModalComponent {
23044
23141
  </div>
23045
23142
  </header>
23046
23143
 
23047
- <div class="jv-window-modal-body" [id]="descriptionId">
23144
+ <div class="jv-window-modal-body">
23048
23145
  <ng-content></ng-content>
23049
23146
  </div>
23050
23147
 
@@ -23071,7 +23168,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23071
23168
  aria-modal="true"
23072
23169
  tabindex="-1"
23073
23170
  [attr.aria-labelledby]="title() ? titleId : null"
23074
- [attr.aria-describedby]="descriptionId"
23171
+ [attr.aria-describedby]="resolvedDescription() ? descriptionId : null"
23075
23172
  (click)="$event.stopPropagation()"
23076
23173
  (keydown)="$event.stopPropagation()"
23077
23174
  #panel
@@ -23082,8 +23179,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23082
23179
  <h2 [id]="titleId">{{ title() }}</h2>
23083
23180
  }
23084
23181
 
23085
- @if (subtitle()) {
23086
- <p class="jv-window-modal-subtitle">{{ subtitle() }}</p>
23182
+ @if (description()) {
23183
+ <p class="jv-window-modal-description" [id]="descriptionId">{{ description() }}</p>
23184
+ } @else if (subtitle()) {
23185
+ <p class="jv-window-modal-subtitle" [id]="descriptionId">{{ subtitle() }}</p>
23087
23186
  }
23088
23187
  </div>
23089
23188
 
@@ -23096,7 +23195,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23096
23195
  </div>
23097
23196
  </header>
23098
23197
 
23099
- <div class="jv-window-modal-body" [id]="descriptionId">
23198
+ <div class="jv-window-modal-body">
23100
23199
  <ng-content></ng-content>
23101
23200
  </div>
23102
23201
 
@@ -23107,7 +23206,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23107
23206
  </div>
23108
23207
  }
23109
23208
  `, 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"] }]
23110
- }], 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: [{
23209
+ }], 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 }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", 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: [{
23111
23210
  type: HostListener,
23112
23211
  args: ['document:keydown', ['$event']]
23113
23212
  }] } });
@@ -23258,13 +23357,19 @@ class JvSidebarComponent {
23258
23357
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23259
23358
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvSidebarComponent, isStandalone: true, selector: "jv-sidebar", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, brandIcon: { classPropertyName: "brandIcon", publicName: "brandIcon", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, mobileOpen: { classPropertyName: "mobileOpen", publicName: "mobileOpen", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, currentTheme: { classPropertyName: "currentTheme", publicName: "currentTheme", isSignal: true, isRequired: false, transformFunction: null }, themeOptions: { classPropertyName: "themeOptions", publicName: "themeOptions", isSignal: true, isRequired: false, transformFunction: null }, topbarActions: { classPropertyName: "topbarActions", publicName: "topbarActions", isSignal: true, isRequired: false, transformFunction: null }, showThemeSelector: { classPropertyName: "showThemeSelector", publicName: "showThemeSelector", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapseToggle: "collapseToggle", mobileClose: "mobileClose", themeChange: "themeChange", actionClick: "actionClick" }, ngImport: i0, template: `
23260
23359
  @if (mobileOpen()) {
23261
- <div class="jv-sidebar-backdrop" tabindex="-1" (click)="mobileClose.emit()" (keydown.escape)="mobileClose.emit()"></div>
23360
+ <div
23361
+ class="jv-sidebar-backdrop"
23362
+ tabindex="-1"
23363
+ (click)="mobileClose.emit()"
23364
+ (keydown.escape)="mobileClose.emit()"
23365
+ ></div>
23262
23366
  }
23263
23367
 
23264
23368
  <aside
23265
23369
  class="jv-sidebar"
23266
23370
  [class.is-collapsed]="collapsed()"
23267
23371
  [class.is-mobile-open]="mobileOpen()"
23372
+ [attr.aria-label]="title()"
23268
23373
  >
23269
23374
  <div class="jv-sidebar-brand">
23270
23375
  <div class="brand-mark">
@@ -23283,43 +23388,18 @@ class JvSidebarComponent {
23283
23388
 
23284
23389
  <nav class="jv-sidebar-nav" [attr.aria-label]="ariaLabel()">
23285
23390
  <ul class="jv-sidebar-list">
23286
- @for (item of normalizedItems(); track item.id) {
23287
- <li class="jv-sidebar-item">
23288
- @if (item.children.length > 0) {
23289
- <button
23290
- type="button"
23291
- class="jv-sidebar-link"
23292
- [class.is-active]="item.active"
23293
- [attr.aria-label]="item.label"
23294
- [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
23295
- [attr.aria-controls]="'jv-sidebar-section-' + item.id"
23296
- [attr.title]="item.label"
23297
- (click)="toggleSection(item.id)"
23298
- >
23299
- <span class="jv-sidebar-link-main">
23300
- @if (item.icon) {
23301
- <jv-icon [name]="item.icon" [size]="18" />
23302
- }
23303
-
23304
- @if (!collapsed()) {
23305
- <span>{{ item.label }}</span>
23306
- }
23307
- </span>
23308
-
23309
- @if (!collapsed()) {
23310
- <jv-icon [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'" [size]="16" />
23311
- }
23312
- </button>
23313
- } @else {
23314
- @if (isHashLink(item.href)) {
23391
+ @for (item of normalizedItems(); track item.id) {
23392
+ <li class="jv-sidebar-item">
23393
+ @if (item.children.length > 0) {
23315
23394
  <button
23316
23395
  type="button"
23317
23396
  class="jv-sidebar-link"
23318
23397
  [class.is-active]="item.active"
23319
23398
  [attr.aria-label]="item.label"
23320
- [attr.aria-current]="item.active ? 'page' : null"
23399
+ [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
23400
+ [attr.aria-controls]="'jv-sidebar-section-' + item.id"
23321
23401
  [attr.title]="item.label"
23322
- (click)="navigateTo(item.href); mobileClose.emit()"
23402
+ (click)="toggleSection(item.id)"
23323
23403
  >
23324
23404
  <span class="jv-sidebar-link-main">
23325
23405
  @if (item.icon) {
@@ -23330,52 +23410,102 @@ class JvSidebarComponent {
23330
23410
  <span>{{ item.label }}</span>
23331
23411
  }
23332
23412
  </span>
23413
+
23414
+ @if (!collapsed()) {
23415
+ <jv-icon
23416
+ [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'"
23417
+ [size]="16"
23418
+ />
23419
+ }
23333
23420
  </button>
23334
23421
  } @else {
23335
- <a
23336
- class="jv-sidebar-link"
23337
- [class.is-active]="item.active"
23338
- [attr.aria-label]="item.label"
23339
- [attr.aria-current]="item.active ? 'page' : null"
23340
- [routerLink]="item.href"
23341
- [attr.title]="item.label"
23342
- (click)="mobileClose.emit()"
23343
- >
23344
- <span class="jv-sidebar-link-main">
23345
- @if (item.icon) {
23346
- <jv-icon [name]="item.icon" [size]="18" />
23347
- }
23422
+ @if (isHashLink(item.href)) {
23423
+ <button
23424
+ type="button"
23425
+ class="jv-sidebar-link"
23426
+ [class.is-active]="item.active"
23427
+ [attr.aria-label]="item.label"
23428
+ [attr.aria-current]="item.active ? 'page' : null"
23429
+ [attr.title]="item.label"
23430
+ (click)="navigateTo(item.href); mobileClose.emit()"
23431
+ >
23432
+ <span class="jv-sidebar-link-main">
23433
+ @if (item.icon) {
23434
+ <jv-icon [name]="item.icon" [size]="18" />
23435
+ }
23348
23436
 
23349
- @if (!collapsed()) {
23350
- <span>{{ item.label }}</span>
23351
- }
23352
- </span>
23353
- </a>
23437
+ @if (!collapsed()) {
23438
+ <span>{{ item.label }}</span>
23439
+ }
23440
+ </span>
23441
+ </button>
23442
+ } @else {
23443
+ <a
23444
+ class="jv-sidebar-link"
23445
+ [class.is-active]="item.active"
23446
+ [attr.aria-label]="item.label"
23447
+ [attr.aria-current]="item.active ? 'page' : null"
23448
+ [routerLink]="item.href"
23449
+ [attr.title]="item.label"
23450
+ (click)="mobileClose.emit()"
23451
+ >
23452
+ <span class="jv-sidebar-link-main">
23453
+ @if (item.icon) {
23454
+ <jv-icon [name]="item.icon" [size]="18" />
23455
+ }
23456
+
23457
+ @if (!collapsed()) {
23458
+ <span>{{ item.label }}</span>
23459
+ }
23460
+ </span>
23461
+ </a>
23462
+ }
23354
23463
  }
23355
- }
23356
23464
 
23357
- @if (!collapsed() && item.children.length > 0 && isExpanded(item.id)) {
23358
- <div class="jv-sidebar-children" [id]="'jv-sidebar-section-' + item.id">
23359
- @for (child of item.children; track child.id) {
23360
- @if (isHashLink(child.href)) {
23361
- <button type="button" class="jv-sidebar-child-link" [class.is-active]="child.active" [attr.aria-label]="child.label" [attr.aria-current]="child.active ? 'page' : null" [attr.title]="child.label" (click)="navigateTo(child.href)">
23362
- {{ child.label }}
23363
- </button>
23364
- } @else {
23365
- <a class="jv-sidebar-child-link" [class.is-active]="child.active" [attr.aria-label]="child.label" [attr.aria-current]="child.active ? 'page' : null" [routerLink]="child.href" [attr.title]="child.label" (click)="mobileClose.emit()">
23366
- {{ child.label }}
23367
- </a>
23465
+ @if (!collapsed() && item.children.length > 0 && isExpanded(item.id)) {
23466
+ <div class="jv-sidebar-children" [id]="'jv-sidebar-section-' + item.id">
23467
+ @for (child of item.children; track child.id) {
23468
+ @if (isHashLink(child.href)) {
23469
+ <button
23470
+ type="button"
23471
+ class="jv-sidebar-child-link"
23472
+ [class.is-active]="child.active"
23473
+ [attr.aria-label]="child.label"
23474
+ [attr.aria-current]="child.active ? 'page' : null"
23475
+ [attr.title]="child.label"
23476
+ (click)="navigateTo(child.href)"
23477
+ >
23478
+ {{ child.label }}
23479
+ </button>
23480
+ } @else {
23481
+ <a
23482
+ class="jv-sidebar-child-link"
23483
+ [class.is-active]="child.active"
23484
+ [attr.aria-label]="child.label"
23485
+ [attr.aria-current]="child.active ? 'page' : null"
23486
+ [routerLink]="child.href"
23487
+ [attr.title]="child.label"
23488
+ (click)="mobileClose.emit()"
23489
+ >
23490
+ {{ child.label }}
23491
+ </a>
23492
+ }
23368
23493
  }
23369
- }
23370
- </div>
23371
- }
23372
- </li>
23373
- }
23494
+ </div>
23495
+ }
23496
+ </li>
23497
+ }
23374
23498
  </ul>
23375
23499
  </nav>
23376
23500
 
23377
23501
  <div class="jv-sidebar-footer">
23378
- <button type="button" class="jv-sidebar-toggle" (click)="collapseToggle.emit()">
23502
+ <button
23503
+ type="button"
23504
+ class="jv-sidebar-toggle"
23505
+ [attr.aria-label]="collapsed() ? 'Expand navigation' : 'Collapse navigation'"
23506
+ [attr.aria-expanded]="collapsed() ? 'false' : 'true'"
23507
+ (click)="collapseToggle.emit()"
23508
+ >
23379
23509
  <jv-icon [name]="collapsed() ? 'menu' : 'panel-left-close'" [size]="18" />
23380
23510
  @if (!collapsed()) {
23381
23511
  <span>Collapse</span>
@@ -23390,6 +23520,7 @@ class JvSidebarComponent {
23390
23520
  type="button"
23391
23521
  class="theme-pill"
23392
23522
  [class.is-active]="currentTheme() === option.value"
23523
+ [attr.aria-pressed]="currentTheme() === option.value ? 'true' : 'false'"
23393
23524
  (click)="themeChange.emit(option.value)"
23394
23525
  >
23395
23526
  @if (option.icon) {
@@ -23403,7 +23534,14 @@ class JvSidebarComponent {
23403
23534
 
23404
23535
  <div class="mobile-actions">
23405
23536
  @for (action of topbarActions(); track action.id) {
23406
- <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id); mobileClose.emit()">
23537
+ <button
23538
+ type="button"
23539
+ class="icon-button"
23540
+ [attr.aria-label]="action.label"
23541
+ [attr.title]="action.label"
23542
+ [jvTooltip]="action.label"
23543
+ (click)="actionClick.emit(action.id); mobileClose.emit()"
23544
+ >
23407
23545
  <jv-icon [name]="action.icon" [size]="18" />
23408
23546
  <span>{{ action.label }}</span>
23409
23547
  </button>
@@ -23418,13 +23556,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23418
23556
  type: Component,
23419
23557
  args: [{ selector: 'jv-sidebar', standalone: true, imports: [JvIconComponent, RouterLink, JvTooltipDirective], template: `
23420
23558
  @if (mobileOpen()) {
23421
- <div class="jv-sidebar-backdrop" tabindex="-1" (click)="mobileClose.emit()" (keydown.escape)="mobileClose.emit()"></div>
23559
+ <div
23560
+ class="jv-sidebar-backdrop"
23561
+ tabindex="-1"
23562
+ (click)="mobileClose.emit()"
23563
+ (keydown.escape)="mobileClose.emit()"
23564
+ ></div>
23422
23565
  }
23423
23566
 
23424
23567
  <aside
23425
23568
  class="jv-sidebar"
23426
23569
  [class.is-collapsed]="collapsed()"
23427
23570
  [class.is-mobile-open]="mobileOpen()"
23571
+ [attr.aria-label]="title()"
23428
23572
  >
23429
23573
  <div class="jv-sidebar-brand">
23430
23574
  <div class="brand-mark">
@@ -23443,43 +23587,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23443
23587
 
23444
23588
  <nav class="jv-sidebar-nav" [attr.aria-label]="ariaLabel()">
23445
23589
  <ul class="jv-sidebar-list">
23446
- @for (item of normalizedItems(); track item.id) {
23447
- <li class="jv-sidebar-item">
23448
- @if (item.children.length > 0) {
23449
- <button
23450
- type="button"
23451
- class="jv-sidebar-link"
23452
- [class.is-active]="item.active"
23453
- [attr.aria-label]="item.label"
23454
- [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
23455
- [attr.aria-controls]="'jv-sidebar-section-' + item.id"
23456
- [attr.title]="item.label"
23457
- (click)="toggleSection(item.id)"
23458
- >
23459
- <span class="jv-sidebar-link-main">
23460
- @if (item.icon) {
23461
- <jv-icon [name]="item.icon" [size]="18" />
23462
- }
23463
-
23464
- @if (!collapsed()) {
23465
- <span>{{ item.label }}</span>
23466
- }
23467
- </span>
23468
-
23469
- @if (!collapsed()) {
23470
- <jv-icon [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'" [size]="16" />
23471
- }
23472
- </button>
23473
- } @else {
23474
- @if (isHashLink(item.href)) {
23590
+ @for (item of normalizedItems(); track item.id) {
23591
+ <li class="jv-sidebar-item">
23592
+ @if (item.children.length > 0) {
23475
23593
  <button
23476
23594
  type="button"
23477
23595
  class="jv-sidebar-link"
23478
23596
  [class.is-active]="item.active"
23479
23597
  [attr.aria-label]="item.label"
23480
- [attr.aria-current]="item.active ? 'page' : null"
23598
+ [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
23599
+ [attr.aria-controls]="'jv-sidebar-section-' + item.id"
23481
23600
  [attr.title]="item.label"
23482
- (click)="navigateTo(item.href); mobileClose.emit()"
23601
+ (click)="toggleSection(item.id)"
23483
23602
  >
23484
23603
  <span class="jv-sidebar-link-main">
23485
23604
  @if (item.icon) {
@@ -23490,52 +23609,102 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23490
23609
  <span>{{ item.label }}</span>
23491
23610
  }
23492
23611
  </span>
23612
+
23613
+ @if (!collapsed()) {
23614
+ <jv-icon
23615
+ [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'"
23616
+ [size]="16"
23617
+ />
23618
+ }
23493
23619
  </button>
23494
23620
  } @else {
23495
- <a
23496
- class="jv-sidebar-link"
23497
- [class.is-active]="item.active"
23498
- [attr.aria-label]="item.label"
23499
- [attr.aria-current]="item.active ? 'page' : null"
23500
- [routerLink]="item.href"
23501
- [attr.title]="item.label"
23502
- (click)="mobileClose.emit()"
23503
- >
23504
- <span class="jv-sidebar-link-main">
23505
- @if (item.icon) {
23506
- <jv-icon [name]="item.icon" [size]="18" />
23507
- }
23621
+ @if (isHashLink(item.href)) {
23622
+ <button
23623
+ type="button"
23624
+ class="jv-sidebar-link"
23625
+ [class.is-active]="item.active"
23626
+ [attr.aria-label]="item.label"
23627
+ [attr.aria-current]="item.active ? 'page' : null"
23628
+ [attr.title]="item.label"
23629
+ (click)="navigateTo(item.href); mobileClose.emit()"
23630
+ >
23631
+ <span class="jv-sidebar-link-main">
23632
+ @if (item.icon) {
23633
+ <jv-icon [name]="item.icon" [size]="18" />
23634
+ }
23508
23635
 
23509
- @if (!collapsed()) {
23510
- <span>{{ item.label }}</span>
23511
- }
23512
- </span>
23513
- </a>
23636
+ @if (!collapsed()) {
23637
+ <span>{{ item.label }}</span>
23638
+ }
23639
+ </span>
23640
+ </button>
23641
+ } @else {
23642
+ <a
23643
+ class="jv-sidebar-link"
23644
+ [class.is-active]="item.active"
23645
+ [attr.aria-label]="item.label"
23646
+ [attr.aria-current]="item.active ? 'page' : null"
23647
+ [routerLink]="item.href"
23648
+ [attr.title]="item.label"
23649
+ (click)="mobileClose.emit()"
23650
+ >
23651
+ <span class="jv-sidebar-link-main">
23652
+ @if (item.icon) {
23653
+ <jv-icon [name]="item.icon" [size]="18" />
23654
+ }
23655
+
23656
+ @if (!collapsed()) {
23657
+ <span>{{ item.label }}</span>
23658
+ }
23659
+ </span>
23660
+ </a>
23661
+ }
23514
23662
  }
23515
- }
23516
23663
 
23517
- @if (!collapsed() && item.children.length > 0 && isExpanded(item.id)) {
23518
- <div class="jv-sidebar-children" [id]="'jv-sidebar-section-' + item.id">
23519
- @for (child of item.children; track child.id) {
23520
- @if (isHashLink(child.href)) {
23521
- <button type="button" class="jv-sidebar-child-link" [class.is-active]="child.active" [attr.aria-label]="child.label" [attr.aria-current]="child.active ? 'page' : null" [attr.title]="child.label" (click)="navigateTo(child.href)">
23522
- {{ child.label }}
23523
- </button>
23524
- } @else {
23525
- <a class="jv-sidebar-child-link" [class.is-active]="child.active" [attr.aria-label]="child.label" [attr.aria-current]="child.active ? 'page' : null" [routerLink]="child.href" [attr.title]="child.label" (click)="mobileClose.emit()">
23526
- {{ child.label }}
23527
- </a>
23664
+ @if (!collapsed() && item.children.length > 0 && isExpanded(item.id)) {
23665
+ <div class="jv-sidebar-children" [id]="'jv-sidebar-section-' + item.id">
23666
+ @for (child of item.children; track child.id) {
23667
+ @if (isHashLink(child.href)) {
23668
+ <button
23669
+ type="button"
23670
+ class="jv-sidebar-child-link"
23671
+ [class.is-active]="child.active"
23672
+ [attr.aria-label]="child.label"
23673
+ [attr.aria-current]="child.active ? 'page' : null"
23674
+ [attr.title]="child.label"
23675
+ (click)="navigateTo(child.href)"
23676
+ >
23677
+ {{ child.label }}
23678
+ </button>
23679
+ } @else {
23680
+ <a
23681
+ class="jv-sidebar-child-link"
23682
+ [class.is-active]="child.active"
23683
+ [attr.aria-label]="child.label"
23684
+ [attr.aria-current]="child.active ? 'page' : null"
23685
+ [routerLink]="child.href"
23686
+ [attr.title]="child.label"
23687
+ (click)="mobileClose.emit()"
23688
+ >
23689
+ {{ child.label }}
23690
+ </a>
23691
+ }
23528
23692
  }
23529
- }
23530
- </div>
23531
- }
23532
- </li>
23533
- }
23693
+ </div>
23694
+ }
23695
+ </li>
23696
+ }
23534
23697
  </ul>
23535
23698
  </nav>
23536
23699
 
23537
23700
  <div class="jv-sidebar-footer">
23538
- <button type="button" class="jv-sidebar-toggle" (click)="collapseToggle.emit()">
23701
+ <button
23702
+ type="button"
23703
+ class="jv-sidebar-toggle"
23704
+ [attr.aria-label]="collapsed() ? 'Expand navigation' : 'Collapse navigation'"
23705
+ [attr.aria-expanded]="collapsed() ? 'false' : 'true'"
23706
+ (click)="collapseToggle.emit()"
23707
+ >
23539
23708
  <jv-icon [name]="collapsed() ? 'menu' : 'panel-left-close'" [size]="18" />
23540
23709
  @if (!collapsed()) {
23541
23710
  <span>Collapse</span>
@@ -23550,6 +23719,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23550
23719
  type="button"
23551
23720
  class="theme-pill"
23552
23721
  [class.is-active]="currentTheme() === option.value"
23722
+ [attr.aria-pressed]="currentTheme() === option.value ? 'true' : 'false'"
23553
23723
  (click)="themeChange.emit(option.value)"
23554
23724
  >
23555
23725
  @if (option.icon) {
@@ -23563,7 +23733,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23563
23733
 
23564
23734
  <div class="mobile-actions">
23565
23735
  @for (action of topbarActions(); track action.id) {
23566
- <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id); mobileClose.emit()">
23736
+ <button
23737
+ type="button"
23738
+ class="icon-button"
23739
+ [attr.aria-label]="action.label"
23740
+ [attr.title]="action.label"
23741
+ [jvTooltip]="action.label"
23742
+ (click)="actionClick.emit(action.id); mobileClose.emit()"
23743
+ >
23567
23744
  <jv-icon [name]="action.icon" [size]="18" />
23568
23745
  <span>{{ action.label }}</span>
23569
23746
  </button>
@@ -23725,7 +23902,12 @@ class JvTopbarMenuComponent {
23725
23902
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTopbarMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23726
23903
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvTopbarMenuComponent, isStandalone: true, selector: "jv-topbar-menu", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, brandIcon: { classPropertyName: "brandIcon", publicName: "brandIcon", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, mobileOpen: { classPropertyName: "mobileOpen", publicName: "mobileOpen", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, currentTheme: { classPropertyName: "currentTheme", publicName: "currentTheme", isSignal: true, isRequired: false, transformFunction: null }, themeOptions: { classPropertyName: "themeOptions", publicName: "themeOptions", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, showThemeSelector: { classPropertyName: "showThemeSelector", publicName: "showThemeSelector", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuClick: "menuClick", mobileClose: "mobileClose", themeChange: "themeChange", actionClick: "actionClick" }, ngImport: i0, template: `
23727
23904
  @if (mobileOpen()) {
23728
- <div class="jv-topbar-menu-backdrop" tabindex="-1" (click)="mobileClose.emit()" (keydown.escape)="mobileClose.emit()"></div>
23905
+ <div
23906
+ class="jv-topbar-menu-backdrop"
23907
+ tabindex="-1"
23908
+ (click)="mobileClose.emit()"
23909
+ (keydown.escape)="mobileClose.emit()"
23910
+ ></div>
23729
23911
  }
23730
23912
 
23731
23913
  <header class="jv-topbar-menu" [class.is-mobile-open]="mobileOpen()">
@@ -23741,11 +23923,22 @@ class JvTopbarMenuComponent {
23741
23923
  </div>
23742
23924
  </div>
23743
23925
 
23744
- <button type="button" class="mobile-menu-button" aria-label="Toggle navigation menu" (click)="menuClick.emit()">
23926
+ <button
23927
+ type="button"
23928
+ class="mobile-menu-button"
23929
+ aria-label="Toggle navigation menu"
23930
+ aria-controls="jv-topbar-menu-navigation"
23931
+ [attr.aria-expanded]="mobileOpen() ? 'true' : 'false'"
23932
+ (click)="menuClick.emit()"
23933
+ >
23745
23934
  <jv-icon name="menu" [size]="18" />
23746
23935
  </button>
23747
23936
 
23748
- <nav class="jv-topbar-menu-nav" [attr.aria-label]="ariaLabel()">
23937
+ <nav
23938
+ id="jv-topbar-menu-navigation"
23939
+ class="jv-topbar-menu-nav"
23940
+ [attr.aria-label]="ariaLabel()"
23941
+ >
23749
23942
  <ul class="jv-topbar-menu-list">
23750
23943
  @for (item of normalizedItems(); track item.id) {
23751
23944
  <li class="jv-topbar-menu-item">
@@ -23762,18 +23955,32 @@ class JvTopbarMenuComponent {
23762
23955
  <jv-icon [name]="item.icon" [size]="17" />
23763
23956
  }
23764
23957
  <span>{{ item.label }}</span>
23765
- <jv-icon [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'" [size]="15" />
23958
+ <jv-icon
23959
+ [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'"
23960
+ [size]="15"
23961
+ />
23766
23962
  </button>
23767
23963
 
23768
23964
  @if (isExpanded(item.id)) {
23769
23965
  <div class="jv-topbar-menu-dropdown" [id]="'jv-topbar-menu-section-' + item.id">
23770
23966
  @for (child of item.children; track child.id) {
23771
23967
  @if (isHashLink(child.href)) {
23772
- <button type="button" class="jv-topbar-menu-child" [class.is-active]="child.active" (click)="navigateTo(child.href, item.id)">
23968
+ <button
23969
+ type="button"
23970
+ class="jv-topbar-menu-child"
23971
+ [class.is-active]="child.active"
23972
+ (click)="navigateTo(child.href, item.id)"
23973
+ >
23773
23974
  {{ child.label }}
23774
23975
  </button>
23775
23976
  } @else {
23776
- <a class="jv-topbar-menu-child" [class.is-active]="child.active" [routerLink]="child.href" [attr.aria-current]="child.active ? 'page' : null" (click)="closeSection(item.id); mobileClose.emit()">
23977
+ <a
23978
+ class="jv-topbar-menu-child"
23979
+ [class.is-active]="child.active"
23980
+ [routerLink]="child.href"
23981
+ [attr.aria-current]="child.active ? 'page' : null"
23982
+ (click)="closeSection(item.id); mobileClose.emit()"
23983
+ >
23777
23984
  {{ child.label }}
23778
23985
  </a>
23779
23986
  }
@@ -23782,14 +23989,25 @@ class JvTopbarMenuComponent {
23782
23989
  }
23783
23990
  } @else {
23784
23991
  @if (isHashLink(item.href)) {
23785
- <button type="button" class="jv-topbar-menu-link" [class.is-active]="item.active" (click)="navigateTo(item.href)">
23992
+ <button
23993
+ type="button"
23994
+ class="jv-topbar-menu-link"
23995
+ [class.is-active]="item.active"
23996
+ (click)="navigateTo(item.href)"
23997
+ >
23786
23998
  @if (item.icon) {
23787
23999
  <jv-icon [name]="item.icon" [size]="17" />
23788
24000
  }
23789
24001
  <span>{{ item.label }}</span>
23790
24002
  </button>
23791
24003
  } @else {
23792
- <a class="jv-topbar-menu-link" [class.is-active]="item.active" [routerLink]="item.href" [attr.aria-current]="item.active ? 'page' : null" (click)="mobileClose.emit()">
24004
+ <a
24005
+ class="jv-topbar-menu-link"
24006
+ [class.is-active]="item.active"
24007
+ [routerLink]="item.href"
24008
+ [attr.aria-current]="item.active ? 'page' : null"
24009
+ (click)="mobileClose.emit()"
24010
+ >
23793
24011
  @if (item.icon) {
23794
24012
  <jv-icon [name]="item.icon" [size]="17" />
23795
24013
  }
@@ -23806,7 +24024,13 @@ class JvTopbarMenuComponent {
23806
24024
  @if (showThemeSelector()) {
23807
24025
  <div class="theme-group" aria-label="Theme selector">
23808
24026
  @for (option of themeOptions(); track option.value) {
23809
- <button type="button" class="theme-pill" [class.is-active]="currentTheme() === option.value" (click)="themeChange.emit(option.value)">
24027
+ <button
24028
+ type="button"
24029
+ class="theme-pill"
24030
+ [class.is-active]="currentTheme() === option.value"
24031
+ [attr.aria-pressed]="currentTheme() === option.value ? 'true' : 'false'"
24032
+ (click)="themeChange.emit(option.value)"
24033
+ >
23810
24034
  @if (option.icon) {
23811
24035
  <jv-icon [name]="option.icon" [size]="16" />
23812
24036
  }
@@ -23817,7 +24041,14 @@ class JvTopbarMenuComponent {
23817
24041
  }
23818
24042
 
23819
24043
  @for (action of actions(); track action.id) {
23820
- <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id)">
24044
+ <button
24045
+ type="button"
24046
+ class="icon-button"
24047
+ [attr.aria-label]="action.label"
24048
+ [attr.title]="action.label"
24049
+ [jvTooltip]="action.label"
24050
+ (click)="actionClick.emit(action.id)"
24051
+ >
23821
24052
  <jv-icon [name]="action.icon" [size]="18" />
23822
24053
  <span class="action-label">{{ action.label }}</span>
23823
24054
  </button>
@@ -23830,7 +24061,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23830
24061
  type: Component,
23831
24062
  args: [{ selector: 'jv-topbar-menu', standalone: true, imports: [JvIconComponent, RouterLink, JvTooltipDirective], template: `
23832
24063
  @if (mobileOpen()) {
23833
- <div class="jv-topbar-menu-backdrop" tabindex="-1" (click)="mobileClose.emit()" (keydown.escape)="mobileClose.emit()"></div>
24064
+ <div
24065
+ class="jv-topbar-menu-backdrop"
24066
+ tabindex="-1"
24067
+ (click)="mobileClose.emit()"
24068
+ (keydown.escape)="mobileClose.emit()"
24069
+ ></div>
23834
24070
  }
23835
24071
 
23836
24072
  <header class="jv-topbar-menu" [class.is-mobile-open]="mobileOpen()">
@@ -23846,11 +24082,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23846
24082
  </div>
23847
24083
  </div>
23848
24084
 
23849
- <button type="button" class="mobile-menu-button" aria-label="Toggle navigation menu" (click)="menuClick.emit()">
24085
+ <button
24086
+ type="button"
24087
+ class="mobile-menu-button"
24088
+ aria-label="Toggle navigation menu"
24089
+ aria-controls="jv-topbar-menu-navigation"
24090
+ [attr.aria-expanded]="mobileOpen() ? 'true' : 'false'"
24091
+ (click)="menuClick.emit()"
24092
+ >
23850
24093
  <jv-icon name="menu" [size]="18" />
23851
24094
  </button>
23852
24095
 
23853
- <nav class="jv-topbar-menu-nav" [attr.aria-label]="ariaLabel()">
24096
+ <nav
24097
+ id="jv-topbar-menu-navigation"
24098
+ class="jv-topbar-menu-nav"
24099
+ [attr.aria-label]="ariaLabel()"
24100
+ >
23854
24101
  <ul class="jv-topbar-menu-list">
23855
24102
  @for (item of normalizedItems(); track item.id) {
23856
24103
  <li class="jv-topbar-menu-item">
@@ -23867,18 +24114,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23867
24114
  <jv-icon [name]="item.icon" [size]="17" />
23868
24115
  }
23869
24116
  <span>{{ item.label }}</span>
23870
- <jv-icon [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'" [size]="15" />
24117
+ <jv-icon
24118
+ [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'"
24119
+ [size]="15"
24120
+ />
23871
24121
  </button>
23872
24122
 
23873
24123
  @if (isExpanded(item.id)) {
23874
24124
  <div class="jv-topbar-menu-dropdown" [id]="'jv-topbar-menu-section-' + item.id">
23875
24125
  @for (child of item.children; track child.id) {
23876
24126
  @if (isHashLink(child.href)) {
23877
- <button type="button" class="jv-topbar-menu-child" [class.is-active]="child.active" (click)="navigateTo(child.href, item.id)">
24127
+ <button
24128
+ type="button"
24129
+ class="jv-topbar-menu-child"
24130
+ [class.is-active]="child.active"
24131
+ (click)="navigateTo(child.href, item.id)"
24132
+ >
23878
24133
  {{ child.label }}
23879
24134
  </button>
23880
24135
  } @else {
23881
- <a class="jv-topbar-menu-child" [class.is-active]="child.active" [routerLink]="child.href" [attr.aria-current]="child.active ? 'page' : null" (click)="closeSection(item.id); mobileClose.emit()">
24136
+ <a
24137
+ class="jv-topbar-menu-child"
24138
+ [class.is-active]="child.active"
24139
+ [routerLink]="child.href"
24140
+ [attr.aria-current]="child.active ? 'page' : null"
24141
+ (click)="closeSection(item.id); mobileClose.emit()"
24142
+ >
23882
24143
  {{ child.label }}
23883
24144
  </a>
23884
24145
  }
@@ -23887,14 +24148,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23887
24148
  }
23888
24149
  } @else {
23889
24150
  @if (isHashLink(item.href)) {
23890
- <button type="button" class="jv-topbar-menu-link" [class.is-active]="item.active" (click)="navigateTo(item.href)">
24151
+ <button
24152
+ type="button"
24153
+ class="jv-topbar-menu-link"
24154
+ [class.is-active]="item.active"
24155
+ (click)="navigateTo(item.href)"
24156
+ >
23891
24157
  @if (item.icon) {
23892
24158
  <jv-icon [name]="item.icon" [size]="17" />
23893
24159
  }
23894
24160
  <span>{{ item.label }}</span>
23895
24161
  </button>
23896
24162
  } @else {
23897
- <a class="jv-topbar-menu-link" [class.is-active]="item.active" [routerLink]="item.href" [attr.aria-current]="item.active ? 'page' : null" (click)="mobileClose.emit()">
24163
+ <a
24164
+ class="jv-topbar-menu-link"
24165
+ [class.is-active]="item.active"
24166
+ [routerLink]="item.href"
24167
+ [attr.aria-current]="item.active ? 'page' : null"
24168
+ (click)="mobileClose.emit()"
24169
+ >
23898
24170
  @if (item.icon) {
23899
24171
  <jv-icon [name]="item.icon" [size]="17" />
23900
24172
  }
@@ -23911,7 +24183,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23911
24183
  @if (showThemeSelector()) {
23912
24184
  <div class="theme-group" aria-label="Theme selector">
23913
24185
  @for (option of themeOptions(); track option.value) {
23914
- <button type="button" class="theme-pill" [class.is-active]="currentTheme() === option.value" (click)="themeChange.emit(option.value)">
24186
+ <button
24187
+ type="button"
24188
+ class="theme-pill"
24189
+ [class.is-active]="currentTheme() === option.value"
24190
+ [attr.aria-pressed]="currentTheme() === option.value ? 'true' : 'false'"
24191
+ (click)="themeChange.emit(option.value)"
24192
+ >
23915
24193
  @if (option.icon) {
23916
24194
  <jv-icon [name]="option.icon" [size]="16" />
23917
24195
  }
@@ -23922,7 +24200,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23922
24200
  }
23923
24201
 
23924
24202
  @for (action of actions(); track action.id) {
23925
- <button type="button" class="icon-button" [attr.aria-label]="action.label" [attr.title]="action.label" [jvTooltip]="action.label" (click)="actionClick.emit(action.id)">
24203
+ <button
24204
+ type="button"
24205
+ class="icon-button"
24206
+ [attr.aria-label]="action.label"
24207
+ [attr.title]="action.label"
24208
+ [jvTooltip]="action.label"
24209
+ (click)="actionClick.emit(action.id)"
24210
+ >
23926
24211
  <jv-icon [name]="action.icon" [size]="18" />
23927
24212
  <span class="action-label">{{ action.label }}</span>
23928
24213
  </button>
@@ -24398,7 +24683,13 @@ class JvTabsComponent {
24398
24683
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvTabsComponent, isStandalone: true, selector: "jv-tabs", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, activeTabId: { classPropertyName: "activeTabId", publicName: "activeTabId", isSignal: true, isRequired: false, transformFunction: null }, keepMounted: { classPropertyName: "keepMounted", publicName: "keepMounted", isSignal: true, isRequired: false, transformFunction: null }, transition: { classPropertyName: "transition", publicName: "transition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeTabChange: "activeTabChange" }, host: { listeners: { "window:resize": "handleWindowResize()" } }, queries: [{ propertyName: "panelTemplates", predicate: JvTabPanelDirective, isSignal: true }], viewQueries: [{ propertyName: "tabListRef", first: true, predicate: ["tabList"], descendants: true, isSignal: true }], ngImport: i0, template: `
24399
24684
  <div class="jv-tabs">
24400
24685
  <div class="jv-tabs-header">
24401
- <div class="jv-tabs-scroll" #tabList role="tablist" aria-orientation="horizontal" (scroll)="updateScrollControls()">
24686
+ <div
24687
+ class="jv-tabs-scroll"
24688
+ #tabList
24689
+ role="tablist"
24690
+ aria-orientation="horizontal"
24691
+ (scroll)="updateScrollControls()"
24692
+ >
24402
24693
  @for (tab of tabs(); track tab.id) {
24403
24694
  <button
24404
24695
  type="button"
@@ -24454,11 +24745,16 @@ class JvTabsComponent {
24454
24745
  class="jv-tab-panel"
24455
24746
  [class.jv-tab-panel--hidden]="!isActive(tab.id)"
24456
24747
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24457
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24458
- [class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
24748
+ [class.jv-tab-panel--slide-left]="
24749
+ effectiveTransition() === 'slide' && slideDirection() === 'left'
24750
+ "
24751
+ [class.jv-tab-panel--slide-right]="
24752
+ effectiveTransition() === 'slide' && slideDirection() === 'right'
24753
+ "
24459
24754
  [id]="panelId(tab.id)"
24460
24755
  role="tabpanel"
24461
24756
  [attr.aria-labelledby]="tabButtonId(tab.id)"
24757
+ [attr.aria-hidden]="isActive(tab.id) ? null : 'true'"
24462
24758
  [attr.tabindex]="isActive(tab.id) ? 0 : null"
24463
24759
  >
24464
24760
  <ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
@@ -24469,11 +24765,16 @@ class JvTabsComponent {
24469
24765
  <div
24470
24766
  class="jv-tab-panel jv-tab-panel--exit"
24471
24767
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24472
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24473
- [class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
24768
+ [class.jv-tab-panel--slide-left]="
24769
+ effectiveTransition() === 'slide' && slideDirection() === 'left'
24770
+ "
24771
+ [class.jv-tab-panel--slide-right]="
24772
+ effectiveTransition() === 'slide' && slideDirection() === 'right'
24773
+ "
24474
24774
  [id]="panelId(outgoingId)"
24475
24775
  role="tabpanel"
24476
24776
  [attr.aria-labelledby]="tabButtonId(outgoingId)"
24777
+ aria-hidden="true"
24477
24778
  tabindex="-1"
24478
24779
  (transitionend)="handleTransitionEnd($event)"
24479
24780
  >
@@ -24485,11 +24786,16 @@ class JvTabsComponent {
24485
24786
  <div
24486
24787
  class="jv-tab-panel jv-tab-panel--entering"
24487
24788
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24488
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24489
- [class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
24789
+ [class.jv-tab-panel--slide-left]="
24790
+ effectiveTransition() === 'slide' && slideDirection() === 'left'
24791
+ "
24792
+ [class.jv-tab-panel--slide-right]="
24793
+ effectiveTransition() === 'slide' && slideDirection() === 'right'
24794
+ "
24490
24795
  [id]="panelId(activeId)"
24491
24796
  role="tabpanel"
24492
24797
  [attr.aria-labelledby]="tabButtonId(activeId)"
24798
+ aria-hidden="false"
24493
24799
  tabindex="0"
24494
24800
  >
24495
24801
  <ng-container [ngTemplateOutlet]="panelTemplate(activeId) ?? null" />
@@ -24505,7 +24811,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24505
24811
  args: [{ selector: 'jv-tabs', standalone: true, imports: [NgTemplateOutlet, JvIconComponent], template: `
24506
24812
  <div class="jv-tabs">
24507
24813
  <div class="jv-tabs-header">
24508
- <div class="jv-tabs-scroll" #tabList role="tablist" aria-orientation="horizontal" (scroll)="updateScrollControls()">
24814
+ <div
24815
+ class="jv-tabs-scroll"
24816
+ #tabList
24817
+ role="tablist"
24818
+ aria-orientation="horizontal"
24819
+ (scroll)="updateScrollControls()"
24820
+ >
24509
24821
  @for (tab of tabs(); track tab.id) {
24510
24822
  <button
24511
24823
  type="button"
@@ -24561,11 +24873,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24561
24873
  class="jv-tab-panel"
24562
24874
  [class.jv-tab-panel--hidden]="!isActive(tab.id)"
24563
24875
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24564
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24565
- [class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
24876
+ [class.jv-tab-panel--slide-left]="
24877
+ effectiveTransition() === 'slide' && slideDirection() === 'left'
24878
+ "
24879
+ [class.jv-tab-panel--slide-right]="
24880
+ effectiveTransition() === 'slide' && slideDirection() === 'right'
24881
+ "
24566
24882
  [id]="panelId(tab.id)"
24567
24883
  role="tabpanel"
24568
24884
  [attr.aria-labelledby]="tabButtonId(tab.id)"
24885
+ [attr.aria-hidden]="isActive(tab.id) ? null : 'true'"
24569
24886
  [attr.tabindex]="isActive(tab.id) ? 0 : null"
24570
24887
  >
24571
24888
  <ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
@@ -24576,11 +24893,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24576
24893
  <div
24577
24894
  class="jv-tab-panel jv-tab-panel--exit"
24578
24895
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24579
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24580
- [class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
24896
+ [class.jv-tab-panel--slide-left]="
24897
+ effectiveTransition() === 'slide' && slideDirection() === 'left'
24898
+ "
24899
+ [class.jv-tab-panel--slide-right]="
24900
+ effectiveTransition() === 'slide' && slideDirection() === 'right'
24901
+ "
24581
24902
  [id]="panelId(outgoingId)"
24582
24903
  role="tabpanel"
24583
24904
  [attr.aria-labelledby]="tabButtonId(outgoingId)"
24905
+ aria-hidden="true"
24584
24906
  tabindex="-1"
24585
24907
  (transitionend)="handleTransitionEnd($event)"
24586
24908
  >
@@ -24592,11 +24914,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24592
24914
  <div
24593
24915
  class="jv-tab-panel jv-tab-panel--entering"
24594
24916
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24595
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24596
- [class.jv-tab-panel--slide-right]="effectiveTransition() === 'slide' && slideDirection() === 'right'"
24917
+ [class.jv-tab-panel--slide-left]="
24918
+ effectiveTransition() === 'slide' && slideDirection() === 'left'
24919
+ "
24920
+ [class.jv-tab-panel--slide-right]="
24921
+ effectiveTransition() === 'slide' && slideDirection() === 'right'
24922
+ "
24597
24923
  [id]="panelId(activeId)"
24598
24924
  role="tabpanel"
24599
24925
  [attr.aria-labelledby]="tabButtonId(activeId)"
24926
+ aria-hidden="false"
24600
24927
  tabindex="0"
24601
24928
  >
24602
24929
  <ng-container [ngTemplateOutlet]="panelTemplate(activeId) ?? null" />
@@ -25778,7 +26105,7 @@ class JvGridComponent {
25778
26105
  };
25779
26106
  }
25780
26107
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
25781
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvGridComponent, isStandalone: true, selector: "jv-grid", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClick: "rowClick", rowDoubleClick: "rowDoubleClick", actionClick: "actionClick", selectionChange: "selectionChange", pageChange: "pageChange", searchChange: "searchChange", sortChange: "sortChange", columnFilter: "columnFilter", columnResize: "columnResize", columnReorder: "columnReorder", rowEdit: "rowEdit" }, ngImport: i0, template: "<div class=\"jv-grid\" role=\"region\" [attr.aria-label]=\"resolvedOptions().ariaLabel || gridLabel()\">\n @if (resolvedOptions().searchable || resolvedOptions().exportable) {\n <div class=\"jv-grid-toolbar\">\n @if (resolvedOptions().searchable) {\n <div class=\"jv-grid-search\">\n <jv-icon name=\"search\" [size]=\"16\" />\n <jv-input\n [inputId]=\"gridSearchInputId\"\n [placeholder]=\"t('grid.searchPlaceholder')\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchInput($event)\"\n />\n </div>\n }\n @if (resolvedOptions().exportable) {\n <div class=\"jv-grid-export-actions\">\n <jv-button variant=\"outline\" icon=\"download\" (click)=\"exportCsv()\">{{\n t('grid.exportCsv')\n }}</jv-button>\n <jv-button variant=\"outline\" icon=\"file-spreadsheet\" (click)=\"exportExcel()\">{{\n t('grid.exportExcel')\n }}</jv-button>\n </div>\n }\n </div>\n }\n\n @if (resolvedOptions().loading) {\n <div class=\"jv-grid-loading\" role=\"status\" aria-live=\"polite\">\n <span class=\"jv-grid-spinner\" aria-hidden=\"true\"></span>\n <span>{{ t('grid.loading') }}</span>\n </div>\n } @else {\n <div\n class=\"jv-grid-table-wrap\"\n [class.jv-grid-virtual]=\"virtualScrollEnabled()\"\n #tableWrap\n (scroll)=\"onVirtualScroll($any($event.target))\"\n >\n @if (virtualScrollEnabled()) {\n <div class=\"jv-grid-virtual-spacer\" [style.height.px]=\"virtualTotalHeight()\"></div>\n }\n <table\n class=\"jv-grid-table\"\n role=\"grid\"\n [attr.aria-label]=\"resolvedOptions().ariaLabel || gridLabel()\"\n [attr.aria-rowcount]=\"effectiveTotalItems()\"\n [attr.aria-colcount]=\"colspan()\"\n [class]=\"densityClass()\"\n [style.position]=\"virtualScrollEnabled() ? 'relative' : null\"\n [style.top.px]=\"virtualOffsetY()\"\n >\n <caption class=\"sr-only\">\n {{\n resolvedOptions().ariaLabel || gridLabel()\n }}\n </caption>\n\n @let hasGroupedHeaders = groupedHeaders().length > 0;\n\n <thead class=\"jv-grid-thead\">\n @if (hasGroupedHeaders) {\n <tr>\n @if (resolvedOptions().selectable) {\n <th class=\"jv-grid-th jv-grid-th-select\" scope=\"col\" [attr.rowspan]=\"2\">\n <input\n type=\"checkbox\"\n class=\"jv-grid-checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"toggleSelectAll($any($event.target).checked)\"\n [attr.aria-label]=\"allSelected() ? t('grid.deselectAll') : t('grid.selectAll')\"\n [indeterminate]=\"someSelected()\"\n />\n </th>\n }\n @for (group of groupedHeaders(); track colKey(group)) {\n <th\n class=\"jv-grid-th\"\n [class]=\"group.headerClass || ''\"\n [class.jv-grid-th-sticky-left]=\"isStickyLeft(group)\"\n [class.jv-grid-th-sticky-right]=\"isStickyRight(group)\"\n [attr.colspan]=\"groupColspan(group)\"\n scope=\"colgroup\"\n [style.text-align]=\"group.align ?? 'start'\"\n >\n <div class=\"jv-grid-th-content\">{{ group.header }}</div>\n </th>\n }\n @if (actions().length > 0) {\n <th class=\"jv-grid-th jv-grid-th-actions\" scope=\"col\" [attr.rowspan]=\"2\">\n <span class=\"sr-only\">{{ t('grid.actionsLabel', { label: '' }) }}</span>\n </th>\n }\n </tr>\n }\n\n <tr>\n @if (!hasGroupedHeaders && resolvedOptions().selectable) {\n <th class=\"jv-grid-th jv-grid-th-select\" scope=\"col\">\n <input\n type=\"checkbox\"\n class=\"jv-grid-checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"toggleSelectAll($any($event.target).checked)\"\n [attr.aria-label]=\"allSelected() ? t('grid.deselectAll') : t('grid.selectAll')\"\n [indeterminate]=\"someSelected()\"\n />\n </th>\n }\n @for (col of visibleColumns(); track colKey(col); let colIdx = $index) {\n <th\n class=\"jv-grid-th\"\n [class]=\"col.headerClass || ''\"\n [class.jv-grid-th-sortable]=\"col.sortable !== false && resolvedOptions().sortable\"\n [class.jv-grid-th-sticky-left]=\"isStickyLeft(col)\"\n [class.jv-grid-th-sticky-right]=\"isStickyRight(col)\"\n [class.jv-grid-th-reorderable]=\"resolvedOptions().reorderableColumns\"\n [style.text-align]=\"col.align ?? 'start'\"\n [style.width]=\"getColumnWidth(col)\"\n [style.min-width]=\"col.minWidth || undefined\"\n [style.max-width]=\"col.maxWidth || undefined\"\n scope=\"col\"\n role=\"columnheader\"\n [attr.data-column-index]=\"colIdx\"\n [attr.aria-sort]=\"getAriaSort(col)\"\n [attr.aria-label]=\"getSortLabel(col)\"\n [tabindex]=\"\n resolvedOptions().keyboardNavigation\n ? activeCell().column === colIdx\n ? 0\n : -1\n : col.sortable !== false && resolvedOptions().sortable\n ? 0\n : -1\n \"\n (click)=\"toggleSort(col)\"\n (focus)=\"onHeaderFocus(colIdx)\"\n (keydown)=\"onHeaderKeydown($event, colIdx)\"\n (keydown.enter)=\"toggleSort(col)\"\n (keydown.space)=\"toggleSort(col, $event)\"\n draggable=\"{{ resolvedOptions().reorderableColumns ? 'true' : 'false' }}\"\n (dragstart)=\"onDragStart($event, colIdx)\"\n (dragover)=\"onDragOver($event, colIdx)\"\n (drop)=\"onDrop($event, colIdx)\"\n (dragend)=\"onDragEnd($event)\"\n >\n <div class=\"jv-grid-th-content\">\n <span>{{ col.header }}</span>\n @if (col.sortable !== false && resolvedOptions().sortable) {\n <span class=\"jv-grid-sort-icon\" aria-hidden=\"true\">\n @if (sortState().columnKey === colKey(col)) {\n @if (sortState().direction === 'asc') {\n \u25B2\n }\n @if (sortState().direction === 'desc') {\n \u25BC\n }\n }\n </span>\n }\n </div>\n @if (isColumnResizable(col)) {\n <div\n class=\"jv-grid-resize-handle\"\n (mousedown)=\"onResizeStart($event, col, colIdx)\"\n ></div>\n }\n </th>\n }\n @if (!hasGroupedHeaders && actions().length > 0) {\n <th class=\"jv-grid-th jv-grid-th-actions\" scope=\"col\">\n <span class=\"sr-only\">{{ t('grid.actionsLabel', { label: '' }) }}</span>\n </th>\n }\n </tr>\n\n @if (resolvedOptions().columnFilters) {\n <tr class=\"jv-grid-filter-row\">\n @if (resolvedOptions().selectable) {\n <th class=\"jv-grid-th jv-grid-th-select\"></th>\n }\n @for (col of visibleColumns(); track colKey(col)) {\n <th class=\"jv-grid-th jv-grid-th-filter\">\n @if (col.filterable !== false) {\n <input\n class=\"jv-grid-filter-input\"\n [placeholder]=\"t('grid.filterPlaceholder')\"\n [attr.aria-label]=\"t('grid.filterForColumn', { column: col.header })\"\n [ngModel]=\"colFilters()[colKey(col)]?.value ?? ''\"\n (ngModelChange)=\"onColumnFilterChange(col, $event)\"\n />\n }\n </th>\n }\n @if (actions().length > 0) {\n <th class=\"jv-grid-th jv-grid-th-actions\"></th>\n }\n </tr>\n }\n </thead>\n\n <tbody class=\"jv-grid-tbody\">\n @if (displayData().length === 0 && !searchTerm().trim() && !hasActiveFilters()) {\n <tr>\n <td class=\"jv-grid-empty\" [attr.colspan]=\"colspan()\">\n {{ resolvedOptions().emptyMessage || t('grid.emptyMessage') }}\n </td>\n </tr>\n } @else if (displayData().length === 0 && (searchTerm().trim() || hasActiveFilters())) {\n <tr>\n <td class=\"jv-grid-empty\" [attr.colspan]=\"colspan()\">\n {{ resolvedOptions().noResultsMessage || t('grid.noResults') }}\n </td>\n </tr>\n } @else {\n @for (row of displayData(); track getRowId(row, $index); let rowIdx = $index) {\n <tr\n class=\"jv-grid-tr\"\n role=\"row\"\n [class.jv-grid-tr-editing]=\"isRowEditing(row)\"\n [class.jv-grid-tr-selected]=\"isSelected(row)\"\n [attr.aria-selected]=\"resolvedOptions().selectable ? isSelected(row) : null\"\n (click)=\"onRowClick(row)\"\n (dblclick)=\"onRowDblClick(row)\"\n (keydown.enter)=\"onRowClick(row)\"\n (keydown.space)=\"onRowClick($event, row)\"\n [tabindex]=\"-1\"\n >\n @if (resolvedOptions().selectable) {\n <td\n class=\"jv-grid-td jv-grid-td-select\"\n [class.jv-grid-td-sticky-left]=\"resolvedOptions().stickyColumns\"\n >\n <input\n type=\"checkbox\"\n class=\"jv-grid-checkbox\"\n [checked]=\"isSelected(row)\"\n (change)=\"toggleRow(row); $event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"getRowLabel(row, $index)\"\n />\n </td>\n }\n @for (col of visibleColumns(); track colKey(col); let colIdx = $index) {\n <td\n class=\"jv-grid-td\"\n [attr.role]=\"resolvedOptions().keyboardNavigation ? 'gridcell' : null\"\n [class]=\"col.cellClass || ''\"\n [class.jv-grid-td-sticky-left]=\"isStickyLeft(col)\"\n [class.jv-grid-td-sticky-right]=\"isStickyRight(col)\"\n [class.jv-grid-td-editable]=\"isCellEditable(col)\"\n [style.text-align]=\"col.align ?? 'start'\"\n (dblclick)=\"startEdit(row, col, $event)\"\n (keydown.enter)=\"startEdit(row, col, $event)\"\n [attr.data-row-index]=\"rowIdx\"\n [attr.data-column-index]=\"colIdx\"\n [class.jv-grid-keyboard-cell]=\"resolvedOptions().keyboardNavigation\"\n [attr.tabindex]=\"cellTabIndex(rowIdx, colIdx, col)\"\n (focus)=\"onCellFocus(rowIdx, colIdx)\"\n (keydown.f2)=\"onCellF2($event, rowIdx, colIdx)\"\n (keydown)=\"onCellKeydown($event, rowIdx, colIdx)\"\n >\n @if (isEditingCell(row, col)) {\n @if (editType(col) === 'select' && col.editOptions) {\n <jv-select\n [options]=\"getEditOptions(col)\"\n [modelValue]=\"getEditValue(row, col)\"\n (selectionChange)=\"onEditValueChange(row, col, $event)\"\n />\n } @else if (editType(col) === 'boolean') {\n <input\n type=\"checkbox\"\n class=\"jv-grid-checkbox\"\n [checked]=\"getBooleanEditValue(row, col)\"\n (change)=\"\n commitEdit(\n row,\n col,\n normalizeEditValue(col, $any($event.target).checked)\n )\n \"\n (keydown.enter)=\"\n commitEditFromKeyboard(\n $event,\n row,\n col,\n normalizeEditValue(col, $any($event.target).checked)\n )\n \"\n (keydown.escape)=\"cancelEdit()\"\n [attr.aria-label]=\"col.header\"\n />\n } @else {\n <input\n class=\"jv-grid-edit-input\"\n [type]=\"inputType(col)\"\n [value]=\"getEditValue(row, col)\"\n (blur)=\"\n commitEdit(row, col, normalizeEditValue(col, $any($event.target).value))\n \"\n (keydown.enter)=\"\n commitEditFromKeyboard(\n $event,\n row,\n col,\n normalizeEditValue(col, $any($event.target).value)\n )\n \"\n (keydown.escape)=\"cancelEdit()\"\n />\n }\n } @else {\n @let value = getCellValue(row, col);\n @if (col.type === 'boolean') {\n @if (isBooleanTrue(value)) {\n <span\n class=\"jv-grid-boolean jv-grid-boolean-true\"\n [attr.aria-label]=\"t('grid.booleanYes')\"\n >{{ t('grid.booleanYes') }}</span\n >\n } @else {\n <span\n class=\"jv-grid-boolean jv-grid-boolean-false\"\n [attr.aria-label]=\"t('grid.booleanNo')\"\n >{{ t('grid.booleanNo') }}</span\n >\n }\n } @else if (col.format) {\n {{ col.format(value, row) }}\n } @else {\n {{ formatValue(value, col, row) }}\n }\n }\n </td>\n }\n @if (actions().length > 0) {\n <td\n class=\"jv-grid-td jv-grid-td-actions\"\n [class.jv-grid-td-sticky-right]=\"resolvedOptions().stickyColumns\"\n >\n <div class=\"jv-grid-actions-group\">\n @for (action of actions(); track action.id) {\n <jv-button\n [variant]=\"actionVariant(action.variant)\"\n [icon]=\"action.icon ?? null\"\n [disabled]=\"action.disabled?.(row) ?? false\"\n [attr.aria-label]=\"action.label\"\n [title]=\"action.label\"\n (click)=\"onActionClick(action, row); $event.stopPropagation()\"\n ></jv-button>\n }\n </div>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (\n resolvedOptions().pageable &&\n !virtualScrollEnabled() &&\n effectiveTotalPages() > 1 &&\n !resolvedOptions().loading\n ) {\n <nav\n class=\"jv-grid-pagination\"\n role=\"navigation\"\n [attr.aria-label]=\"t('grid.paginationLabel', { label: '' })\"\n >\n <div class=\"jv-grid-pagination-info\" aria-live=\"polite\" aria-atomic=\"true\">\n {{\n t('grid.itemsShowing', {\n start: pageStart(),\n end: pageEnd(),\n total: effectiveTotalItems(),\n })\n }}\n </div>\n <div class=\"jv-grid-pagination-controls\">\n @if (pageSizeOptions().length > 0) {\n <jv-select\n [options]=\"pageSizeOptions()\"\n [modelValue]=\"pageSizeStr()\"\n [ariaLabel]=\"t('grid.itemsPerPage')\"\n (selectionChange)=\"onPageSizeChange($event)\"\n />\n }\n <jv-button\n variant=\"outline\"\n icon=\"chevrons-left\"\n [disabled]=\"pageIndex() === 0\"\n (click)=\"goToPage(0)\"\n [attr.aria-label]=\"t('grid.pageFirst')\"\n ></jv-button>\n <jv-button\n variant=\"outline\"\n icon=\"chevron-left\"\n [disabled]=\"pageIndex() === 0\"\n (click)=\"goToPage(pageIndex() - 1)\"\n [attr.aria-label]=\"t('grid.pagePrev')\"\n ></jv-button>\n @for (p of pageRange(); track p) {\n <jv-button\n [variant]=\"p === pageIndex() ? 'primary' : 'outline'\"\n [attr.aria-current]=\"p === pageIndex() ? 'page' : null\"\n [attr.aria-label]=\"t('grid.pageOfTotal', { page: p + 1, total: effectiveTotalPages() })\"\n (click)=\"goToPage(p)\"\n >{{ p + 1 }}</jv-button\n >\n }\n <jv-button\n variant=\"outline\"\n icon=\"chevron-right\"\n [disabled]=\"pageIndex() >= effectiveTotalPages() - 1\"\n (click)=\"goToPage(pageIndex() + 1)\"\n [attr.aria-label]=\"t('grid.pageNext')\"\n ></jv-button>\n <jv-button\n variant=\"outline\"\n icon=\"chevrons-right\"\n [disabled]=\"pageIndex() >= effectiveTotalPages() - 1\"\n (click)=\"goToPage(effectiveTotalPages() - 1)\"\n [attr.aria-label]=\"t('grid.pageLast')\"\n ></jv-button>\n </div>\n </nav>\n }\n</div>\n", styles: [".jv-grid{display:flex;flex-direction:column;gap:var(--jv-spacing-md)}.jv-grid-toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-grid-search{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-grid-export-actions{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-table-wrap{overflow-x:auto;overflow-y:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);position:relative}.jv-grid-virtual{max-height:600px}.jv-grid-virtual-spacer{pointer-events:none}.jv-grid-table{width:100%;border-collapse:collapse;background:var(--jv-color-surface)}.jv-grid-thead{background:var(--jv-color-surface-muted)}.jv-grid-th{padding:var(--jv-spacing-sm) var(--jv-spacing-md);font-weight:600;font-size:.875rem;color:var(--jv-color-foreground-muted);text-align:start;white-space:nowrap;border-bottom:1px solid var(--jv-color-border);-webkit-user-select:none;user-select:none;position:relative}.jv-grid-th-sortable{cursor:pointer}.jv-grid-th-sortable:hover{background:var(--jv-color-surface)}.jv-grid-th-reorderable{cursor:grab}.jv-grid-th-reorderable:active{cursor:grabbing}.jv-grid-th-sticky-left{position:sticky;left:0;z-index:2;background:var(--jv-color-surface-muted);border-right:1px solid var(--jv-color-border)}.jv-grid-th-sticky-right{position:sticky;right:0;z-index:2;background:var(--jv-color-surface-muted);border-left:1px solid var(--jv-color-border)}.jv-grid-th-content{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-sort-icon{font-size:.75rem;line-height:1}.jv-grid-th-select,.jv-grid-td-select{width:3rem;text-align:center}.jv-grid-th-actions,.jv-grid-td-actions{width:1%;white-space:nowrap}.jv-grid-td{padding:var(--jv-spacing-sm) var(--jv-spacing-md);color:var(--jv-color-foreground);font-size:var(--jv-density-font-size);border-bottom:1px solid var(--jv-color-border)}.jv-grid-keyboard-cell:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-td-sticky-left{position:sticky;left:0;z-index:1;background:var(--jv-color-surface);border-right:1px solid var(--jv-color-border)}.jv-grid-td-sticky-right{position:sticky;right:0;z-index:1;background:var(--jv-color-surface);border-left:1px solid var(--jv-color-border)}.jv-grid-t:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-tr{transition:background-color .12s ease}.jv-grid-tr:hover{background:var(--jv-color-surface-muted)}.jv-grid-tr:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-tr-editing{background:var(--jv-color-surface-highlight, rgba(59, 130, 246, .05))}.jv-grid-tr-selected{background:var(--jv-color-primary-light, rgba(59, 130, 246, .08))}.jv-grid-checkbox{width:1rem;height:1rem;accent-color:var(--jv-color-primary);cursor:pointer}.jv-grid-boolean{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:999px;font-size:.75rem;font-weight:700}.jv-grid-boolean-true{background:var(--jv-color-success);color:#fff}.jv-grid-boolean-false{background:var(--jv-color-danger);color:#fff}.jv-grid-empty{padding:var(--jv-spacing-xl) var(--jv-spacing-md);text-align:center;color:var(--jv-color-foreground-muted);font-style:italic}.jv-grid-actions-group{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-loading{display:flex;align-items:center;justify-content:center;gap:var(--jv-spacing-md);padding:var(--jv-spacing-xl);color:var(--jv-color-foreground-muted)}.jv-grid-spinner{width:1.25rem;height:1.25rem;border:2px solid var(--jv-color-border);border-right-color:var(--jv-color-primary);border-radius:999px;animation:jv-grid-spin .8s linear infinite}@keyframes jv-grid-spin{to{transform:rotate(360deg)}}.jv-grid-pagination{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-grid-pagination-info{font-size:.875rem;color:var(--jv-color-foreground-muted)}.jv-grid-pagination-controls{display:flex;align-items:center;gap:var(--jv-spacing-xs);flex-wrap:wrap}@media(max-width:640px){.jv-grid-pagination{flex-direction:column;align-items:stretch;gap:var(--jv-spacing-sm)}.jv-grid-pagination-info{text-align:center}.jv-grid-pagination-controls{justify-content:center}.jv-grid-toolbar{flex-direction:column;align-items:stretch}.jv-grid-search{width:100%}.jv-grid-export-actions{justify-content:stretch}.jv-grid-export-actions jv-button{flex:1}}.jv-grid-resize-handle{position:absolute;top:0;right:0;width:4px;height:100%;cursor:col-resize;background:transparent;z-index:3}.jv-grid-resize-handle:hover,.jv-grid-resize-handle:active{background:var(--jv-color-primary)}.jv-grid-filter-row .jv-grid-th{padding:var(--jv-spacing-xs) var(--jv-spacing-sm)}.jv-grid-filter-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-sm);background:var(--jv-color-surface);color:var(--jv-color-foreground);font-size:.8rem;box-sizing:border-box}.jv-grid-td-editable{cursor:pointer}.jv-grid-td-editable:hover{box-shadow:inset 0 0 0 1px var(--jv-color-primary)}.jv-grid-edit-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-primary);border-radius:var(--jv-radius-sm);background:var(--jv-color-surface);color:var(--jv-color-foreground);font-size:var(--jv-density-font-size);box-sizing:border-box}.jv-grid-edit-input:focus{outline:2px solid var(--jv-color-primary);outline-offset:-1px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "inputId"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
26108
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JvGridComponent, isStandalone: true, selector: "jv-grid", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClick: "rowClick", rowDoubleClick: "rowDoubleClick", actionClick: "actionClick", selectionChange: "selectionChange", pageChange: "pageChange", searchChange: "searchChange", sortChange: "sortChange", columnFilter: "columnFilter", columnResize: "columnResize", columnReorder: "columnReorder", rowEdit: "rowEdit" }, ngImport: i0, template: "<div class=\"jv-grid\" role=\"region\" [attr.aria-label]=\"resolvedOptions().ariaLabel || gridLabel()\">\n @if (resolvedOptions().searchable || resolvedOptions().exportable) {\n <div class=\"jv-grid-toolbar\">\n @if (resolvedOptions().searchable) {\n <div class=\"jv-grid-search\">\n <jv-icon name=\"search\" [size]=\"16\" />\n <jv-input\n [inputId]=\"gridSearchInputId\"\n [placeholder]=\"t('grid.searchPlaceholder')\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchInput($event)\"\n />\n </div>\n }\n @if (resolvedOptions().exportable) {\n <div class=\"jv-grid-export-actions\">\n <jv-button variant=\"outline\" icon=\"download\" (click)=\"exportCsv()\">{{\n t('grid.exportCsv')\n }}</jv-button>\n <jv-button variant=\"outline\" icon=\"file-spreadsheet\" (click)=\"exportExcel()\">{{\n t('grid.exportExcel')\n }}</jv-button>\n </div>\n }\n </div>\n }\n\n @if (resolvedOptions().loading) {\n <div class=\"jv-grid-loading\" role=\"status\" aria-live=\"polite\">\n <span class=\"jv-grid-spinner\" aria-hidden=\"true\"></span>\n <span>{{ t('grid.loading') }}</span>\n </div>\n } @else {\n <div\n class=\"jv-grid-table-wrap\"\n [class.jv-grid-virtual]=\"virtualScrollEnabled()\"\n #tableWrap\n (scroll)=\"onVirtualScroll($any($event.target))\"\n >\n @if (virtualScrollEnabled()) {\n <div class=\"jv-grid-virtual-spacer\" [style.height.px]=\"virtualTotalHeight()\"></div>\n }\n <table\n class=\"jv-grid-table\"\n role=\"grid\"\n [attr.aria-label]=\"resolvedOptions().ariaLabel || gridLabel()\"\n [attr.aria-rowcount]=\"effectiveTotalItems()\"\n [attr.aria-colcount]=\"colspan()\"\n [class]=\"densityClass()\"\n [style.position]=\"virtualScrollEnabled() ? 'relative' : null\"\n [style.top.px]=\"virtualOffsetY()\"\n >\n <caption class=\"sr-only\">\n {{\n resolvedOptions().ariaLabel || gridLabel()\n }}\n </caption>\n\n @let hasGroupedHeaders = groupedHeaders().length > 0;\n\n <thead class=\"jv-grid-thead\">\n @if (hasGroupedHeaders) {\n <tr>\n @if (resolvedOptions().selectable) {\n <th class=\"jv-grid-th jv-grid-th-select\" scope=\"col\" [attr.rowspan]=\"2\">\n <input\n type=\"checkbox\"\n class=\"jv-grid-checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"toggleSelectAll($any($event.target).checked)\"\n [attr.aria-label]=\"allSelected() ? t('grid.deselectAll') : t('grid.selectAll')\"\n [indeterminate]=\"someSelected()\"\n />\n </th>\n }\n @for (group of groupedHeaders(); track colKey(group)) {\n <th\n class=\"jv-grid-th\"\n [class]=\"group.headerClass || ''\"\n [class.jv-grid-th-sticky-left]=\"isStickyLeft(group)\"\n [class.jv-grid-th-sticky-right]=\"isStickyRight(group)\"\n [attr.colspan]=\"groupColspan(group)\"\n scope=\"colgroup\"\n [style.text-align]=\"group.align ?? 'start'\"\n >\n <div class=\"jv-grid-th-content\">{{ group.header }}</div>\n </th>\n }\n @if (actions().length > 0) {\n <th class=\"jv-grid-th jv-grid-th-actions\" scope=\"col\" [attr.rowspan]=\"2\">\n <span class=\"sr-only\">{{ t('grid.actionsLabel', { label: '' }) }}</span>\n </th>\n }\n </tr>\n }\n\n <tr>\n @if (!hasGroupedHeaders && resolvedOptions().selectable) {\n <th class=\"jv-grid-th jv-grid-th-select\" scope=\"col\">\n <input\n type=\"checkbox\"\n class=\"jv-grid-checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"toggleSelectAll($any($event.target).checked)\"\n [attr.aria-label]=\"allSelected() ? t('grid.deselectAll') : t('grid.selectAll')\"\n [indeterminate]=\"someSelected()\"\n />\n </th>\n }\n @for (col of visibleColumns(); track colKey(col); let colIdx = $index) {\n <th\n class=\"jv-grid-th\"\n [class]=\"col.headerClass || ''\"\n [class.jv-grid-th-sortable]=\"col.sortable !== false && resolvedOptions().sortable\"\n [class.jv-grid-th-sticky-left]=\"isStickyLeft(col)\"\n [class.jv-grid-th-sticky-right]=\"isStickyRight(col)\"\n [class.jv-grid-th-reorderable]=\"resolvedOptions().reorderableColumns\"\n [style.text-align]=\"col.align ?? 'start'\"\n [style.width]=\"getColumnWidth(col)\"\n [style.min-width]=\"col.minWidth || undefined\"\n [style.max-width]=\"col.maxWidth || undefined\"\n scope=\"col\"\n role=\"columnheader\"\n [attr.data-column-index]=\"colIdx\"\n [attr.aria-sort]=\"getAriaSort(col)\"\n [attr.aria-label]=\"getSortLabel(col)\"\n [tabindex]=\"\n resolvedOptions().keyboardNavigation\n ? activeCell().column === colIdx\n ? 0\n : -1\n : col.sortable !== false && resolvedOptions().sortable\n ? 0\n : -1\n \"\n (click)=\"toggleSort(col)\"\n (focus)=\"onHeaderFocus(colIdx)\"\n (keydown)=\"onHeaderKeydown($event, colIdx)\"\n (keydown.enter)=\"toggleSort(col)\"\n (keydown.space)=\"toggleSort(col, $event)\"\n draggable=\"{{ resolvedOptions().reorderableColumns ? 'true' : 'false' }}\"\n (dragstart)=\"onDragStart($event, colIdx)\"\n (dragover)=\"onDragOver($event, colIdx)\"\n (drop)=\"onDrop($event, colIdx)\"\n (dragend)=\"onDragEnd($event)\"\n >\n <div class=\"jv-grid-th-content\">\n <span>{{ col.header }}</span>\n @if (col.sortable !== false && resolvedOptions().sortable) {\n <span class=\"jv-grid-sort-icon\" aria-hidden=\"true\">\n @if (sortState().columnKey === colKey(col)) {\n @if (sortState().direction === 'asc') {\n \u25B2\n }\n @if (sortState().direction === 'desc') {\n \u25BC\n }\n }\n </span>\n }\n </div>\n @if (isColumnResizable(col)) {\n <div\n class=\"jv-grid-resize-handle\"\n (mousedown)=\"onResizeStart($event, col, colIdx)\"\n ></div>\n }\n </th>\n }\n @if (!hasGroupedHeaders && actions().length > 0) {\n <th class=\"jv-grid-th jv-grid-th-actions\" scope=\"col\">\n <span class=\"sr-only\">{{ t('grid.actionsLabel', { label: '' }) }}</span>\n </th>\n }\n </tr>\n\n @if (resolvedOptions().columnFilters) {\n <tr class=\"jv-grid-filter-row\">\n @if (resolvedOptions().selectable) {\n <th class=\"jv-grid-th jv-grid-th-select\"></th>\n }\n @for (col of visibleColumns(); track colKey(col)) {\n <th class=\"jv-grid-th jv-grid-th-filter\">\n @if (col.filterable !== false) {\n <input\n class=\"jv-grid-filter-input\"\n [placeholder]=\"t('grid.filterPlaceholder')\"\n [attr.aria-label]=\"t('grid.filterForColumn', { column: col.header })\"\n [ngModel]=\"colFilters()[colKey(col)]?.value ?? ''\"\n (ngModelChange)=\"onColumnFilterChange(col, $event)\"\n />\n }\n </th>\n }\n @if (actions().length > 0) {\n <th class=\"jv-grid-th jv-grid-th-actions\"></th>\n }\n </tr>\n }\n </thead>\n\n <tbody class=\"jv-grid-tbody\">\n @if (displayData().length === 0 && !searchTerm().trim() && !hasActiveFilters()) {\n <tr>\n <td class=\"jv-grid-empty\" [attr.colspan]=\"colspan()\">\n {{ resolvedOptions().emptyMessage || t('grid.emptyMessage') }}\n </td>\n </tr>\n } @else if (displayData().length === 0 && (searchTerm().trim() || hasActiveFilters())) {\n <tr>\n <td class=\"jv-grid-empty\" [attr.colspan]=\"colspan()\">\n {{ resolvedOptions().noResultsMessage || t('grid.noResults') }}\n </td>\n </tr>\n } @else {\n @for (row of displayData(); track getRowId(row, $index); let rowIdx = $index) {\n <tr\n class=\"jv-grid-tr\"\n role=\"row\"\n [class.jv-grid-tr-editing]=\"isRowEditing(row)\"\n [class.jv-grid-tr-selected]=\"isSelected(row)\"\n [attr.aria-selected]=\"resolvedOptions().selectable ? isSelected(row) : null\"\n (click)=\"onRowClick(row)\"\n (dblclick)=\"onRowDblClick(row)\"\n (keydown.enter)=\"onRowClick(row)\"\n (keydown.space)=\"onRowClick($event, row)\"\n [tabindex]=\"-1\"\n >\n @if (resolvedOptions().selectable) {\n <td\n class=\"jv-grid-td jv-grid-td-select\"\n [class.jv-grid-td-sticky-left]=\"resolvedOptions().stickyColumns\"\n >\n <input\n type=\"checkbox\"\n class=\"jv-grid-checkbox\"\n [checked]=\"isSelected(row)\"\n (change)=\"toggleRow(row); $event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"getRowLabel(row, $index)\"\n />\n </td>\n }\n @for (col of visibleColumns(); track colKey(col); let colIdx = $index) {\n <td\n class=\"jv-grid-td\"\n [attr.role]=\"resolvedOptions().keyboardNavigation ? 'gridcell' : null\"\n [class]=\"col.cellClass || ''\"\n [class.jv-grid-td-sticky-left]=\"isStickyLeft(col)\"\n [class.jv-grid-td-sticky-right]=\"isStickyRight(col)\"\n [class.jv-grid-td-editable]=\"isCellEditable(col)\"\n [style.text-align]=\"col.align ?? 'start'\"\n (dblclick)=\"startEdit(row, col, $event)\"\n (keydown.enter)=\"startEdit(row, col, $event)\"\n [attr.data-row-index]=\"rowIdx\"\n [attr.data-column-index]=\"colIdx\"\n [class.jv-grid-keyboard-cell]=\"resolvedOptions().keyboardNavigation\"\n [attr.tabindex]=\"cellTabIndex(rowIdx, colIdx, col)\"\n (focus)=\"onCellFocus(rowIdx, colIdx)\"\n (keydown.f2)=\"onCellF2($event, rowIdx, colIdx)\"\n (keydown)=\"onCellKeydown($event, rowIdx, colIdx)\"\n >\n @if (isEditingCell(row, col)) {\n @if (editType(col) === 'select' && col.editOptions) {\n <jv-select\n [options]=\"getEditOptions(col)\"\n [modelValue]=\"getEditValue(row, col)\"\n (selectionChange)=\"onEditValueChange(row, col, $event)\"\n />\n } @else if (editType(col) === 'boolean') {\n <input\n type=\"checkbox\"\n class=\"jv-grid-checkbox\"\n [checked]=\"getBooleanEditValue(row, col)\"\n (change)=\"\n commitEdit(\n row,\n col,\n normalizeEditValue(col, $any($event.target).checked)\n )\n \"\n (keydown.enter)=\"\n commitEditFromKeyboard(\n $event,\n row,\n col,\n normalizeEditValue(col, $any($event.target).checked)\n )\n \"\n (keydown.escape)=\"cancelEdit()\"\n [attr.aria-label]=\"col.header\"\n />\n } @else {\n <input\n class=\"jv-grid-edit-input\"\n [type]=\"inputType(col)\"\n [value]=\"getEditValue(row, col)\"\n (blur)=\"\n commitEdit(row, col, normalizeEditValue(col, $any($event.target).value))\n \"\n (keydown.enter)=\"\n commitEditFromKeyboard(\n $event,\n row,\n col,\n normalizeEditValue(col, $any($event.target).value)\n )\n \"\n (keydown.escape)=\"cancelEdit()\"\n />\n }\n } @else {\n @let value = getCellValue(row, col);\n @if (col.type === 'boolean') {\n @if (isBooleanTrue(value)) {\n <span\n class=\"jv-grid-boolean jv-grid-boolean-true\"\n [attr.aria-label]=\"t('grid.booleanYes')\"\n >{{ t('grid.booleanYes') }}</span\n >\n } @else {\n <span\n class=\"jv-grid-boolean jv-grid-boolean-false\"\n [attr.aria-label]=\"t('grid.booleanNo')\"\n >{{ t('grid.booleanNo') }}</span\n >\n }\n } @else if (col.format) {\n {{ col.format(value, row) }}\n } @else {\n {{ formatValue(value, col, row) }}\n }\n }\n </td>\n }\n @if (actions().length > 0) {\n <td\n class=\"jv-grid-td jv-grid-td-actions\"\n [class.jv-grid-td-sticky-right]=\"resolvedOptions().stickyColumns\"\n >\n <div class=\"jv-grid-actions-group\">\n @for (action of actions(); track action.id) {\n <jv-button\n [variant]=\"actionVariant(action.variant)\"\n [icon]=\"action.icon ?? null\"\n [disabled]=\"action.disabled?.(row) ?? false\"\n [attr.aria-label]=\"action.label\"\n [title]=\"action.label\"\n (click)=\"onActionClick(action, row); $event.stopPropagation()\"\n ></jv-button>\n }\n </div>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (\n resolvedOptions().pageable &&\n !virtualScrollEnabled() &&\n effectiveTotalPages() > 1 &&\n !resolvedOptions().loading\n ) {\n <nav\n class=\"jv-grid-pagination\"\n role=\"navigation\"\n [attr.aria-label]=\"t('grid.paginationLabel', { label: '' })\"\n >\n <div class=\"jv-grid-pagination-info\" aria-live=\"polite\" aria-atomic=\"true\">\n {{\n t('grid.itemsShowing', {\n start: pageStart(),\n end: pageEnd(),\n total: effectiveTotalItems(),\n })\n }}\n </div>\n <div class=\"jv-grid-pagination-controls\">\n @if (pageSizeOptions().length > 0) {\n <jv-select\n [options]=\"pageSizeOptions()\"\n [modelValue]=\"pageSizeStr()\"\n [ariaLabel]=\"t('grid.itemsPerPage')\"\n (selectionChange)=\"onPageSizeChange($event)\"\n />\n }\n <jv-button\n variant=\"outline\"\n icon=\"chevrons-left\"\n [disabled]=\"pageIndex() === 0\"\n (click)=\"goToPage(0)\"\n [attr.aria-label]=\"t('grid.pageFirst')\"\n ></jv-button>\n <jv-button\n variant=\"outline\"\n icon=\"chevron-left\"\n [disabled]=\"pageIndex() === 0\"\n (click)=\"goToPage(pageIndex() - 1)\"\n [attr.aria-label]=\"t('grid.pagePrev')\"\n ></jv-button>\n @for (p of pageRange(); track p) {\n <jv-button\n [variant]=\"p === pageIndex() ? 'primary' : 'outline'\"\n [attr.aria-current]=\"p === pageIndex() ? 'page' : null\"\n [attr.aria-label]=\"t('grid.pageOfTotal', { page: p + 1, total: effectiveTotalPages() })\"\n (click)=\"goToPage(p)\"\n >{{ p + 1 }}</jv-button\n >\n }\n <jv-button\n variant=\"outline\"\n icon=\"chevron-right\"\n [disabled]=\"pageIndex() >= effectiveTotalPages() - 1\"\n (click)=\"goToPage(pageIndex() + 1)\"\n [attr.aria-label]=\"t('grid.pageNext')\"\n ></jv-button>\n <jv-button\n variant=\"outline\"\n icon=\"chevrons-right\"\n [disabled]=\"pageIndex() >= effectiveTotalPages() - 1\"\n (click)=\"goToPage(effectiveTotalPages() - 1)\"\n [attr.aria-label]=\"t('grid.pageLast')\"\n ></jv-button>\n </div>\n </nav>\n }\n</div>\n", styles: [".jv-grid{display:flex;flex-direction:column;gap:var(--jv-spacing-md)}.jv-grid-toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-grid-search{display:flex;align-items:center;gap:var(--jv-spacing-sm)}.jv-grid-export-actions{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-table-wrap{overflow-x:auto;overflow-y:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-md);position:relative}.jv-grid-virtual{max-height:600px}.jv-grid-virtual-spacer{pointer-events:none}.jv-grid-table{width:100%;border-collapse:collapse;background:var(--jv-color-surface)}.jv-grid-thead{background:var(--jv-color-surface-muted)}.jv-grid-th{padding:var(--jv-spacing-sm) var(--jv-spacing-md);font-weight:600;font-size:.875rem;color:var(--jv-color-foreground-muted);text-align:start;white-space:nowrap;border-bottom:1px solid var(--jv-color-border);-webkit-user-select:none;user-select:none;position:relative}.jv-grid-th-sortable{cursor:pointer}.jv-grid-th-sortable:hover{background:var(--jv-color-surface)}.jv-grid-th-reorderable{cursor:grab}.jv-grid-th-reorderable:active{cursor:grabbing}.jv-grid-th-sticky-left{position:sticky;left:0;z-index:2;background:var(--jv-color-surface-muted);border-right:1px solid var(--jv-color-border)}.jv-grid-th-sticky-right{position:sticky;right:0;z-index:2;background:var(--jv-color-surface-muted);border-left:1px solid var(--jv-color-border)}.jv-grid-th-content{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-sort-icon{font-size:.75rem;line-height:1}.jv-grid-th-select,.jv-grid-td-select{width:3rem;text-align:center}.jv-grid-th-actions,.jv-grid-td-actions{width:1%;white-space:nowrap}.jv-grid-td{padding:var(--jv-spacing-sm) var(--jv-spacing-md);color:var(--jv-color-foreground);font-size:var(--jv-density-font-size);border-bottom:1px solid var(--jv-color-border)}.jv-grid-keyboard-cell:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-td-sticky-left{position:sticky;left:0;z-index:1;background:var(--jv-color-surface);border-right:1px solid var(--jv-color-border)}.jv-grid-td-sticky-right{position:sticky;right:0;z-index:1;background:var(--jv-color-surface);border-left:1px solid var(--jv-color-border)}.jv-grid-t:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-tr{transition:background-color .12s ease}.jv-grid-tr:hover{background:var(--jv-color-surface-muted)}.jv-grid-tr:focus-visible{outline:2px solid var(--jv-color-primary);outline-offset:-2px}.jv-grid-tr-editing{background:var(--jv-color-surface-highlight, rgba(59, 130, 246, .05))}.jv-grid-tr-selected{background:var(--jv-color-primary-light, rgba(59, 130, 246, .08))}.jv-grid-checkbox{width:1rem;height:1rem;accent-color:var(--jv-color-primary);cursor:pointer}.jv-grid-boolean{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:999px;font-size:.75rem;font-weight:700}.jv-grid-boolean-true{background:var(--jv-color-success);color:#fff}.jv-grid-boolean-false{background:var(--jv-color-danger);color:#fff}.jv-grid-empty{padding:var(--jv-spacing-xl) var(--jv-spacing-md);text-align:center;color:var(--jv-color-foreground-muted);font-style:italic}.jv-grid-actions-group{display:flex;align-items:center;gap:var(--jv-spacing-xs)}.jv-grid-loading{display:flex;align-items:center;justify-content:center;gap:var(--jv-spacing-md);padding:var(--jv-spacing-xl);color:var(--jv-color-foreground-muted)}.jv-grid-spinner{width:1.25rem;height:1.25rem;border:2px solid var(--jv-color-border);border-right-color:var(--jv-color-primary);border-radius:999px;animation:jv-grid-spin .8s linear infinite}@keyframes jv-grid-spin{to{transform:rotate(360deg)}}.jv-grid-pagination{display:flex;align-items:center;justify-content:space-between;gap:var(--jv-spacing-md);flex-wrap:wrap}.jv-grid-pagination-info{font-size:.875rem;color:var(--jv-color-foreground-muted)}.jv-grid-pagination-controls{display:flex;align-items:center;gap:var(--jv-spacing-xs);flex-wrap:wrap}@media(max-width:640px){.jv-grid-pagination{flex-direction:column;align-items:stretch;gap:var(--jv-spacing-sm)}.jv-grid-pagination-info{text-align:center}.jv-grid-pagination-controls{justify-content:center}.jv-grid-toolbar{flex-direction:column;align-items:stretch}.jv-grid-search{width:100%}.jv-grid-export-actions{justify-content:stretch}.jv-grid-export-actions jv-button{flex:1}}.jv-grid-resize-handle{position:absolute;top:0;right:0;width:4px;height:100%;cursor:col-resize;background:transparent;z-index:3}.jv-grid-resize-handle:hover,.jv-grid-resize-handle:active{background:var(--jv-color-primary)}.jv-grid-filter-row .jv-grid-th{padding:var(--jv-spacing-xs) var(--jv-spacing-sm)}.jv-grid-filter-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-border);border-radius:var(--jv-radius-sm);background:var(--jv-color-surface);color:var(--jv-color-foreground);font-size:.8rem;box-sizing:border-box}.jv-grid-td-editable{cursor:pointer}.jv-grid-td-editable:hover{box-shadow:inset 0 0 0 1px var(--jv-color-primary)}.jv-grid-edit-input{width:100%;min-height:var(--jv-density-control-height);padding:0 var(--jv-spacing-sm);border:1px solid var(--jv-color-primary);border-radius:var(--jv-radius-sm);background:var(--jv-color-surface);color:var(--jv-color-foreground);font-size:var(--jv-density-font-size);box-sizing:border-box}.jv-grid-edit-input:focus{outline:2px solid var(--jv-color-primary);outline-offset:-1px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: JvButtonComponent, selector: "jv-button", inputs: ["type", "variant", "icon", "iconPosition", "loading", "disabled"] }, { kind: "component", type: JvIconComponent, selector: "jv-icon", inputs: ["name", "size", "strokeWidth", "decorative", "ariaLabel"] }, { kind: "component", type: JvInputComponent, selector: "jv-input", inputs: ["type", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId"] }, { kind: "component", type: JvSelectComponent, selector: "jv-select", inputs: ["options", "placeholder", "required", "invalid", "describedBy", "ariaLabel", "inputId", "modelValue"], outputs: ["selectionChange"] }] });
25782
26109
  }
25783
26110
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvGridComponent, decorators: [{
25784
26111
  type: Component,