@devjuliovilla/jv-ui 1.18.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.
@@ -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 */ []));
@@ -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,
@@ -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,
@@ -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,
@@ -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: [{
@@ -21717,8 +21724,17 @@ class JvModalSelectorComponent {
21717
21724
  value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
21718
21725
  disabled = false;
21719
21726
  resolvedDialogTitle = computed(() => this.dialogTitle() || this.label() || this.translation.translate('modalSelector.placeholder'), ...(ngDevMode ? [{ debugName: "resolvedDialogTitle" }] : /* istanbul ignore next */ []));
21720
- currentValue = computed(() => (this.valueInput() !== undefined ? this.valueInput() : this.value()), ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
21721
- resolvedDescribedBy = computed(() => [this.describedBy(), this.invalid() ? (this.error() ? `${this.inputId()}-error` : '') : (this.hint() ? `${this.inputId()}-hint` : '')]
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
+ ]
21722
21738
  .filter(Boolean)
21723
21739
  .join(' '), ...(ngDevMode ? [{ debugName: "resolvedDescribedBy" }] : /* istanbul ignore next */ []));
21724
21740
  selectedOption = computed(() => this.options().find((option) => Object.is(option.value, this.currentValue())) ?? null, ...(ngDevMode ? [{ debugName: "selectedOption" }] : /* istanbul ignore next */ []));
@@ -21735,7 +21751,9 @@ class JvModalSelectorComponent {
21735
21751
  return this.options();
21736
21752
  }
21737
21753
  return this.options().filter((option) => {
21738
- const haystack = [option.label, option.description ?? '', ...(option.keywords ?? [])].join(' ').toLocaleLowerCase();
21754
+ const haystack = [option.label, option.description ?? '', ...(option.keywords ?? [])]
21755
+ .join(' ')
21756
+ .toLocaleLowerCase();
21739
21757
  return haystack.includes(query);
21740
21758
  });
21741
21759
  }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
@@ -21883,23 +21901,40 @@ class JvModalSelectorComponent {
21883
21901
  </button>
21884
21902
  </jv-form-container>
21885
21903
 
21886
- <jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" [description]="dialogSubtitle()" (closed)="closeDialog()">
21904
+ <jv-dialog
21905
+ [open]="dialogOpen()"
21906
+ [title]="resolvedDialogTitle()"
21907
+ [description]="dialogSubtitle()"
21908
+ (closed)="closeDialog()"
21909
+ >
21887
21910
  <div [id]="dialogId" class="jv-modal-selector-dialog">
21888
21911
  @if (showSearch()) {
21889
21912
  <jv-input
21890
21913
  type="search"
21891
21914
  [inputId]="searchInputId"
21892
- [placeholder]="searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')"
21915
+ [placeholder]="
21916
+ searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')
21917
+ "
21918
+ [ariaLabel]="
21919
+ searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')
21920
+ "
21893
21921
  [describedBy]="resultsId"
21894
21922
  [ngModel]="searchQuery()"
21895
21923
  (ngModelChange)="searchQuery.set($event)"
21896
21924
  />
21897
21925
  }
21898
21926
 
21899
- <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>
21900
21930
 
21901
21931
  @if (filteredOptions().length > 0) {
21902
- <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
+ >
21903
21938
  @for (option of filteredOptions(); track option.value; let index = $index) {
21904
21939
  <li role="presentation">
21905
21940
  <div
@@ -21918,7 +21953,9 @@ class JvModalSelectorComponent {
21918
21953
  <div class="jv-modal-selector-option-copy">
21919
21954
  <span class="jv-modal-selector-option-label">{{ option.label }}</span>
21920
21955
  @if (option.description) {
21921
- <span class="jv-modal-selector-option-description">{{ option.description }}</span>
21956
+ <span class="jv-modal-selector-option-description">{{
21957
+ option.description
21958
+ }}</span>
21922
21959
  }
21923
21960
  </div>
21924
21961
  @if (isSelected(option)) {
@@ -21929,22 +21966,36 @@ class JvModalSelectorComponent {
21929
21966
  }
21930
21967
  </jv-list>
21931
21968
  } @else {
21932
- <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>
21933
21972
  }
21934
21973
  </div>
21935
21974
 
21936
21975
  <div dialog-actions class="jv-modal-selector-actions">
21937
21976
  @if (selectedOption()) {
21938
- <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>
21939
21980
  }
21940
- <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>
21941
21984
  </div>
21942
21985
  </jv-dialog>
21943
- `, 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", "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"] }] });
21944
21987
  }
21945
21988
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvModalSelectorComponent, decorators: [{
21946
21989
  type: Component,
21947
- 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: [
21948
21999
  {
21949
22000
  provide: NG_VALUE_ACCESSOR,
21950
22001
  useExisting: forwardRef(() => JvModalSelectorComponent),
@@ -21984,23 +22035,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
21984
22035
  </button>
21985
22036
  </jv-form-container>
21986
22037
 
21987
- <jv-dialog [open]="dialogOpen()" [title]="resolvedDialogTitle()" [description]="dialogSubtitle()" (closed)="closeDialog()">
22038
+ <jv-dialog
22039
+ [open]="dialogOpen()"
22040
+ [title]="resolvedDialogTitle()"
22041
+ [description]="dialogSubtitle()"
22042
+ (closed)="closeDialog()"
22043
+ >
21988
22044
  <div [id]="dialogId" class="jv-modal-selector-dialog">
21989
22045
  @if (showSearch()) {
21990
22046
  <jv-input
21991
22047
  type="search"
21992
22048
  [inputId]="searchInputId"
21993
- [placeholder]="searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')"
22049
+ [placeholder]="
22050
+ searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')
22051
+ "
22052
+ [ariaLabel]="
22053
+ searchPlaceholder() || translation.translate('modalSelector.searchPlaceholder')
22054
+ "
21994
22055
  [describedBy]="resultsId"
21995
22056
  [ngModel]="searchQuery()"
21996
22057
  (ngModelChange)="searchQuery.set($event)"
21997
22058
  />
21998
22059
  }
21999
22060
 
22000
- <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>
22001
22064
 
22002
22065
  @if (filteredOptions().length > 0) {
22003
- <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
+ >
22004
22072
  @for (option of filteredOptions(); track option.value; let index = $index) {
22005
22073
  <li role="presentation">
22006
22074
  <div
@@ -22019,7 +22087,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22019
22087
  <div class="jv-modal-selector-option-copy">
22020
22088
  <span class="jv-modal-selector-option-label">{{ option.label }}</span>
22021
22089
  @if (option.description) {
22022
- <span class="jv-modal-selector-option-description">{{ option.description }}</span>
22090
+ <span class="jv-modal-selector-option-description">{{
22091
+ option.description
22092
+ }}</span>
22023
22093
  }
22024
22094
  </div>
22025
22095
  @if (isSelected(option)) {
@@ -22030,15 +22100,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22030
22100
  }
22031
22101
  </jv-list>
22032
22102
  } @else {
22033
- <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>
22034
22106
  }
22035
22107
  </div>
22036
22108
 
22037
22109
  <div dialog-actions class="jv-modal-selector-actions">
22038
22110
  @if (selectedOption()) {
22039
- <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>
22040
22114
  }
22041
- <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>
22042
22118
  </div>
22043
22119
  </jv-dialog>
22044
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"] }]
@@ -22177,7 +22253,7 @@ class JvSwitchComponent {
22177
22253
  </span>
22178
22254
  <span>{{ label() }}</span>
22179
22255
  </label>
22180
- `, 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"] });
22181
22257
  }
22182
22258
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSwitchComponent, decorators: [{
22183
22259
  type: Component,
@@ -22205,7 +22281,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22205
22281
  </span>
22206
22282
  <span>{{ label() }}</span>
22207
22283
  </label>
22208
- `, 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"] }]
22209
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 }] }] } });
22210
22286
 
22211
22287
  let textareaIdSequence = 0;
@@ -22627,18 +22703,14 @@ class JvImageSliderComponent {
22627
22703
  if (!this.hasMultiple()) {
22628
22704
  return;
22629
22705
  }
22630
- const newIndex = this.currentIndex() === 0
22631
- ? this.images().length - 1
22632
- : this.currentIndex() - 1;
22706
+ const newIndex = this.currentIndex() === 0 ? this.images().length - 1 : this.currentIndex() - 1;
22633
22707
  this.goTo(newIndex);
22634
22708
  }
22635
22709
  next() {
22636
22710
  if (!this.hasMultiple()) {
22637
22711
  return;
22638
22712
  }
22639
- const newIndex = this.currentIndex() === this.images().length - 1
22640
- ? 0
22641
- : this.currentIndex() + 1;
22713
+ const newIndex = this.currentIndex() === this.images().length - 1 ? 0 : this.currentIndex() + 1;
22642
22714
  this.goTo(newIndex);
22643
22715
  }
22644
22716
  goTo(index) {
@@ -22683,13 +22755,12 @@ class JvImageSliderComponent {
22683
22755
  <div
22684
22756
  class="jv-slider-slide"
22685
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"
22686
22762
  >
22687
- <img
22688
- class="jv-slider-image"
22689
- [src]="image.src"
22690
- [alt]="image.alt"
22691
- loading="lazy"
22692
- />
22763
+ <img class="jv-slider-image" [src]="image.src" [alt]="image.alt" loading="lazy" />
22693
22764
  </div>
22694
22765
  }
22695
22766
  </div>
@@ -22715,14 +22786,22 @@ class JvImageSliderComponent {
22715
22786
  }
22716
22787
 
22717
22788
  @if (hasMultiple() && showThumbnails()) {
22718
- <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
+ >
22719
22795
  @for (image of images(); track image.src; let i = $index) {
22720
22796
  <button
22721
22797
  type="button"
22722
22798
  class="jv-slider-thumbnail"
22723
22799
  [class.jv-slider-thumbnail--active]="i === currentIndex()"
22724
22800
  role="tab"
22801
+ [id]="'jv-slider-tab-' + i"
22802
+ [attr.aria-controls]="'jv-slider-slide-' + i"
22725
22803
  [attr.aria-selected]="i === currentIndex() ? 'true' : 'false'"
22804
+ [attr.tabindex]="i === currentIndex() ? '0' : '-1'"
22726
22805
  [attr.aria-label]="image.alt"
22727
22806
  (click)="goTo(i)"
22728
22807
  >
@@ -22736,9 +22815,7 @@ class JvImageSliderComponent {
22736
22815
  }
22737
22816
  </div>
22738
22817
 
22739
- <div class="jv-slider-counter">
22740
- {{ currentIndex() + 1 }} / {{ images().length }}
22741
- </div>
22818
+ <div class="jv-slider-counter">{{ currentIndex() + 1 }} / {{ images().length }}</div>
22742
22819
  }
22743
22820
  </div>
22744
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"] }] });
@@ -22764,13 +22841,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22764
22841
  <div
22765
22842
  class="jv-slider-slide"
22766
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"
22767
22848
  >
22768
- <img
22769
- class="jv-slider-image"
22770
- [src]="image.src"
22771
- [alt]="image.alt"
22772
- loading="lazy"
22773
- />
22849
+ <img class="jv-slider-image" [src]="image.src" [alt]="image.alt" loading="lazy" />
22774
22850
  </div>
22775
22851
  }
22776
22852
  </div>
@@ -22796,14 +22872,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22796
22872
  }
22797
22873
 
22798
22874
  @if (hasMultiple() && showThumbnails()) {
22799
- <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
+ >
22800
22881
  @for (image of images(); track image.src; let i = $index) {
22801
22882
  <button
22802
22883
  type="button"
22803
22884
  class="jv-slider-thumbnail"
22804
22885
  [class.jv-slider-thumbnail--active]="i === currentIndex()"
22805
22886
  role="tab"
22887
+ [id]="'jv-slider-tab-' + i"
22888
+ [attr.aria-controls]="'jv-slider-slide-' + i"
22806
22889
  [attr.aria-selected]="i === currentIndex() ? 'true' : 'false'"
22890
+ [attr.tabindex]="i === currentIndex() ? '0' : '-1'"
22807
22891
  [attr.aria-label]="image.alt"
22808
22892
  (click)="goTo(i)"
22809
22893
  >
@@ -22817,9 +22901,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
22817
22901
  }
22818
22902
  </div>
22819
22903
 
22820
- <div class="jv-slider-counter">
22821
- {{ currentIndex() + 1 }} / {{ images().length }}
22822
- </div>
22904
+ <div class="jv-slider-counter">{{ currentIndex() + 1 }} / {{ images().length }}</div>
22823
22905
  }
22824
22906
  </div>
22825
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"] }]
@@ -23275,13 +23357,19 @@ class JvSidebarComponent {
23275
23357
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23276
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: `
23277
23359
  @if (mobileOpen()) {
23278
- <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>
23279
23366
  }
23280
23367
 
23281
23368
  <aside
23282
23369
  class="jv-sidebar"
23283
23370
  [class.is-collapsed]="collapsed()"
23284
23371
  [class.is-mobile-open]="mobileOpen()"
23372
+ [attr.aria-label]="title()"
23285
23373
  >
23286
23374
  <div class="jv-sidebar-brand">
23287
23375
  <div class="brand-mark">
@@ -23300,43 +23388,18 @@ class JvSidebarComponent {
23300
23388
 
23301
23389
  <nav class="jv-sidebar-nav" [attr.aria-label]="ariaLabel()">
23302
23390
  <ul class="jv-sidebar-list">
23303
- @for (item of normalizedItems(); track item.id) {
23304
- <li class="jv-sidebar-item">
23305
- @if (item.children.length > 0) {
23306
- <button
23307
- type="button"
23308
- class="jv-sidebar-link"
23309
- [class.is-active]="item.active"
23310
- [attr.aria-label]="item.label"
23311
- [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
23312
- [attr.aria-controls]="'jv-sidebar-section-' + item.id"
23313
- [attr.title]="item.label"
23314
- (click)="toggleSection(item.id)"
23315
- >
23316
- <span class="jv-sidebar-link-main">
23317
- @if (item.icon) {
23318
- <jv-icon [name]="item.icon" [size]="18" />
23319
- }
23320
-
23321
- @if (!collapsed()) {
23322
- <span>{{ item.label }}</span>
23323
- }
23324
- </span>
23325
-
23326
- @if (!collapsed()) {
23327
- <jv-icon [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'" [size]="16" />
23328
- }
23329
- </button>
23330
- } @else {
23331
- @if (isHashLink(item.href)) {
23391
+ @for (item of normalizedItems(); track item.id) {
23392
+ <li class="jv-sidebar-item">
23393
+ @if (item.children.length > 0) {
23332
23394
  <button
23333
23395
  type="button"
23334
23396
  class="jv-sidebar-link"
23335
23397
  [class.is-active]="item.active"
23336
23398
  [attr.aria-label]="item.label"
23337
- [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"
23338
23401
  [attr.title]="item.label"
23339
- (click)="navigateTo(item.href); mobileClose.emit()"
23402
+ (click)="toggleSection(item.id)"
23340
23403
  >
23341
23404
  <span class="jv-sidebar-link-main">
23342
23405
  @if (item.icon) {
@@ -23347,52 +23410,102 @@ class JvSidebarComponent {
23347
23410
  <span>{{ item.label }}</span>
23348
23411
  }
23349
23412
  </span>
23413
+
23414
+ @if (!collapsed()) {
23415
+ <jv-icon
23416
+ [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'"
23417
+ [size]="16"
23418
+ />
23419
+ }
23350
23420
  </button>
23351
23421
  } @else {
23352
- <a
23353
- class="jv-sidebar-link"
23354
- [class.is-active]="item.active"
23355
- [attr.aria-label]="item.label"
23356
- [attr.aria-current]="item.active ? 'page' : null"
23357
- [routerLink]="item.href"
23358
- [attr.title]="item.label"
23359
- (click)="mobileClose.emit()"
23360
- >
23361
- <span class="jv-sidebar-link-main">
23362
- @if (item.icon) {
23363
- <jv-icon [name]="item.icon" [size]="18" />
23364
- }
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
+ }
23365
23436
 
23366
- @if (!collapsed()) {
23367
- <span>{{ item.label }}</span>
23368
- }
23369
- </span>
23370
- </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
+ }
23371
23463
  }
23372
- }
23373
23464
 
23374
- @if (!collapsed() && item.children.length > 0 && isExpanded(item.id)) {
23375
- <div class="jv-sidebar-children" [id]="'jv-sidebar-section-' + item.id">
23376
- @for (child of item.children; track child.id) {
23377
- @if (isHashLink(child.href)) {
23378
- <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)">
23379
- {{ child.label }}
23380
- </button>
23381
- } @else {
23382
- <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()">
23383
- {{ child.label }}
23384
- </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
+ }
23385
23493
  }
23386
- }
23387
- </div>
23388
- }
23389
- </li>
23390
- }
23494
+ </div>
23495
+ }
23496
+ </li>
23497
+ }
23391
23498
  </ul>
23392
23499
  </nav>
23393
23500
 
23394
23501
  <div class="jv-sidebar-footer">
23395
- <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
+ >
23396
23509
  <jv-icon [name]="collapsed() ? 'menu' : 'panel-left-close'" [size]="18" />
23397
23510
  @if (!collapsed()) {
23398
23511
  <span>Collapse</span>
@@ -23407,6 +23520,7 @@ class JvSidebarComponent {
23407
23520
  type="button"
23408
23521
  class="theme-pill"
23409
23522
  [class.is-active]="currentTheme() === option.value"
23523
+ [attr.aria-pressed]="currentTheme() === option.value ? 'true' : 'false'"
23410
23524
  (click)="themeChange.emit(option.value)"
23411
23525
  >
23412
23526
  @if (option.icon) {
@@ -23420,7 +23534,14 @@ class JvSidebarComponent {
23420
23534
 
23421
23535
  <div class="mobile-actions">
23422
23536
  @for (action of topbarActions(); track action.id) {
23423
- <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
+ >
23424
23545
  <jv-icon [name]="action.icon" [size]="18" />
23425
23546
  <span>{{ action.label }}</span>
23426
23547
  </button>
@@ -23435,13 +23556,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23435
23556
  type: Component,
23436
23557
  args: [{ selector: 'jv-sidebar', standalone: true, imports: [JvIconComponent, RouterLink, JvTooltipDirective], template: `
23437
23558
  @if (mobileOpen()) {
23438
- <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>
23439
23565
  }
23440
23566
 
23441
23567
  <aside
23442
23568
  class="jv-sidebar"
23443
23569
  [class.is-collapsed]="collapsed()"
23444
23570
  [class.is-mobile-open]="mobileOpen()"
23571
+ [attr.aria-label]="title()"
23445
23572
  >
23446
23573
  <div class="jv-sidebar-brand">
23447
23574
  <div class="brand-mark">
@@ -23460,43 +23587,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23460
23587
 
23461
23588
  <nav class="jv-sidebar-nav" [attr.aria-label]="ariaLabel()">
23462
23589
  <ul class="jv-sidebar-list">
23463
- @for (item of normalizedItems(); track item.id) {
23464
- <li class="jv-sidebar-item">
23465
- @if (item.children.length > 0) {
23466
- <button
23467
- type="button"
23468
- class="jv-sidebar-link"
23469
- [class.is-active]="item.active"
23470
- [attr.aria-label]="item.label"
23471
- [attr.aria-expanded]="isExpanded(item.id) ? 'true' : 'false'"
23472
- [attr.aria-controls]="'jv-sidebar-section-' + item.id"
23473
- [attr.title]="item.label"
23474
- (click)="toggleSection(item.id)"
23475
- >
23476
- <span class="jv-sidebar-link-main">
23477
- @if (item.icon) {
23478
- <jv-icon [name]="item.icon" [size]="18" />
23479
- }
23480
-
23481
- @if (!collapsed()) {
23482
- <span>{{ item.label }}</span>
23483
- }
23484
- </span>
23485
-
23486
- @if (!collapsed()) {
23487
- <jv-icon [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'" [size]="16" />
23488
- }
23489
- </button>
23490
- } @else {
23491
- @if (isHashLink(item.href)) {
23590
+ @for (item of normalizedItems(); track item.id) {
23591
+ <li class="jv-sidebar-item">
23592
+ @if (item.children.length > 0) {
23492
23593
  <button
23493
23594
  type="button"
23494
23595
  class="jv-sidebar-link"
23495
23596
  [class.is-active]="item.active"
23496
23597
  [attr.aria-label]="item.label"
23497
- [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"
23498
23600
  [attr.title]="item.label"
23499
- (click)="navigateTo(item.href); mobileClose.emit()"
23601
+ (click)="toggleSection(item.id)"
23500
23602
  >
23501
23603
  <span class="jv-sidebar-link-main">
23502
23604
  @if (item.icon) {
@@ -23507,52 +23609,102 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23507
23609
  <span>{{ item.label }}</span>
23508
23610
  }
23509
23611
  </span>
23612
+
23613
+ @if (!collapsed()) {
23614
+ <jv-icon
23615
+ [name]="isExpanded(item.id) ? 'chevron-up' : 'chevron-down'"
23616
+ [size]="16"
23617
+ />
23618
+ }
23510
23619
  </button>
23511
23620
  } @else {
23512
- <a
23513
- class="jv-sidebar-link"
23514
- [class.is-active]="item.active"
23515
- [attr.aria-label]="item.label"
23516
- [attr.aria-current]="item.active ? 'page' : null"
23517
- [routerLink]="item.href"
23518
- [attr.title]="item.label"
23519
- (click)="mobileClose.emit()"
23520
- >
23521
- <span class="jv-sidebar-link-main">
23522
- @if (item.icon) {
23523
- <jv-icon [name]="item.icon" [size]="18" />
23524
- }
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
+ }
23525
23635
 
23526
- @if (!collapsed()) {
23527
- <span>{{ item.label }}</span>
23528
- }
23529
- </span>
23530
- </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
+ }
23531
23662
  }
23532
- }
23533
23663
 
23534
- @if (!collapsed() && item.children.length > 0 && isExpanded(item.id)) {
23535
- <div class="jv-sidebar-children" [id]="'jv-sidebar-section-' + item.id">
23536
- @for (child of item.children; track child.id) {
23537
- @if (isHashLink(child.href)) {
23538
- <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)">
23539
- {{ child.label }}
23540
- </button>
23541
- } @else {
23542
- <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()">
23543
- {{ child.label }}
23544
- </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
+ }
23545
23692
  }
23546
- }
23547
- </div>
23548
- }
23549
- </li>
23550
- }
23693
+ </div>
23694
+ }
23695
+ </li>
23696
+ }
23551
23697
  </ul>
23552
23698
  </nav>
23553
23699
 
23554
23700
  <div class="jv-sidebar-footer">
23555
- <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
+ >
23556
23708
  <jv-icon [name]="collapsed() ? 'menu' : 'panel-left-close'" [size]="18" />
23557
23709
  @if (!collapsed()) {
23558
23710
  <span>Collapse</span>
@@ -23567,6 +23719,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23567
23719
  type="button"
23568
23720
  class="theme-pill"
23569
23721
  [class.is-active]="currentTheme() === option.value"
23722
+ [attr.aria-pressed]="currentTheme() === option.value ? 'true' : 'false'"
23570
23723
  (click)="themeChange.emit(option.value)"
23571
23724
  >
23572
23725
  @if (option.icon) {
@@ -23580,7 +23733,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23580
23733
 
23581
23734
  <div class="mobile-actions">
23582
23735
  @for (action of topbarActions(); track action.id) {
23583
- <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
+ >
23584
23744
  <jv-icon [name]="action.icon" [size]="18" />
23585
23745
  <span>{{ action.label }}</span>
23586
23746
  </button>
@@ -23742,7 +23902,12 @@ class JvTopbarMenuComponent {
23742
23902
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvTopbarMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23743
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: `
23744
23904
  @if (mobileOpen()) {
23745
- <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>
23746
23911
  }
23747
23912
 
23748
23913
  <header class="jv-topbar-menu" [class.is-mobile-open]="mobileOpen()">
@@ -23758,11 +23923,22 @@ class JvTopbarMenuComponent {
23758
23923
  </div>
23759
23924
  </div>
23760
23925
 
23761
- <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
+ >
23762
23934
  <jv-icon name="menu" [size]="18" />
23763
23935
  </button>
23764
23936
 
23765
- <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
+ >
23766
23942
  <ul class="jv-topbar-menu-list">
23767
23943
  @for (item of normalizedItems(); track item.id) {
23768
23944
  <li class="jv-topbar-menu-item">
@@ -23779,18 +23955,32 @@ class JvTopbarMenuComponent {
23779
23955
  <jv-icon [name]="item.icon" [size]="17" />
23780
23956
  }
23781
23957
  <span>{{ item.label }}</span>
23782
- <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
+ />
23783
23962
  </button>
23784
23963
 
23785
23964
  @if (isExpanded(item.id)) {
23786
23965
  <div class="jv-topbar-menu-dropdown" [id]="'jv-topbar-menu-section-' + item.id">
23787
23966
  @for (child of item.children; track child.id) {
23788
23967
  @if (isHashLink(child.href)) {
23789
- <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
+ >
23790
23974
  {{ child.label }}
23791
23975
  </button>
23792
23976
  } @else {
23793
- <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
+ >
23794
23984
  {{ child.label }}
23795
23985
  </a>
23796
23986
  }
@@ -23799,14 +23989,25 @@ class JvTopbarMenuComponent {
23799
23989
  }
23800
23990
  } @else {
23801
23991
  @if (isHashLink(item.href)) {
23802
- <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
+ >
23803
23998
  @if (item.icon) {
23804
23999
  <jv-icon [name]="item.icon" [size]="17" />
23805
24000
  }
23806
24001
  <span>{{ item.label }}</span>
23807
24002
  </button>
23808
24003
  } @else {
23809
- <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
+ >
23810
24011
  @if (item.icon) {
23811
24012
  <jv-icon [name]="item.icon" [size]="17" />
23812
24013
  }
@@ -23823,7 +24024,13 @@ class JvTopbarMenuComponent {
23823
24024
  @if (showThemeSelector()) {
23824
24025
  <div class="theme-group" aria-label="Theme selector">
23825
24026
  @for (option of themeOptions(); track option.value) {
23826
- <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
+ >
23827
24034
  @if (option.icon) {
23828
24035
  <jv-icon [name]="option.icon" [size]="16" />
23829
24036
  }
@@ -23834,7 +24041,14 @@ class JvTopbarMenuComponent {
23834
24041
  }
23835
24042
 
23836
24043
  @for (action of actions(); track action.id) {
23837
- <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
+ >
23838
24052
  <jv-icon [name]="action.icon" [size]="18" />
23839
24053
  <span class="action-label">{{ action.label }}</span>
23840
24054
  </button>
@@ -23847,7 +24061,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23847
24061
  type: Component,
23848
24062
  args: [{ selector: 'jv-topbar-menu', standalone: true, imports: [JvIconComponent, RouterLink, JvTooltipDirective], template: `
23849
24063
  @if (mobileOpen()) {
23850
- <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>
23851
24070
  }
23852
24071
 
23853
24072
  <header class="jv-topbar-menu" [class.is-mobile-open]="mobileOpen()">
@@ -23863,11 +24082,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23863
24082
  </div>
23864
24083
  </div>
23865
24084
 
23866
- <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
+ >
23867
24093
  <jv-icon name="menu" [size]="18" />
23868
24094
  </button>
23869
24095
 
23870
- <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
+ >
23871
24101
  <ul class="jv-topbar-menu-list">
23872
24102
  @for (item of normalizedItems(); track item.id) {
23873
24103
  <li class="jv-topbar-menu-item">
@@ -23884,18 +24114,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23884
24114
  <jv-icon [name]="item.icon" [size]="17" />
23885
24115
  }
23886
24116
  <span>{{ item.label }}</span>
23887
- <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
+ />
23888
24121
  </button>
23889
24122
 
23890
24123
  @if (isExpanded(item.id)) {
23891
24124
  <div class="jv-topbar-menu-dropdown" [id]="'jv-topbar-menu-section-' + item.id">
23892
24125
  @for (child of item.children; track child.id) {
23893
24126
  @if (isHashLink(child.href)) {
23894
- <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
+ >
23895
24133
  {{ child.label }}
23896
24134
  </button>
23897
24135
  } @else {
23898
- <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
+ >
23899
24143
  {{ child.label }}
23900
24144
  </a>
23901
24145
  }
@@ -23904,14 +24148,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23904
24148
  }
23905
24149
  } @else {
23906
24150
  @if (isHashLink(item.href)) {
23907
- <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
+ >
23908
24157
  @if (item.icon) {
23909
24158
  <jv-icon [name]="item.icon" [size]="17" />
23910
24159
  }
23911
24160
  <span>{{ item.label }}</span>
23912
24161
  </button>
23913
24162
  } @else {
23914
- <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
+ >
23915
24170
  @if (item.icon) {
23916
24171
  <jv-icon [name]="item.icon" [size]="17" />
23917
24172
  }
@@ -23928,7 +24183,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23928
24183
  @if (showThemeSelector()) {
23929
24184
  <div class="theme-group" aria-label="Theme selector">
23930
24185
  @for (option of themeOptions(); track option.value) {
23931
- <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
+ >
23932
24193
  @if (option.icon) {
23933
24194
  <jv-icon [name]="option.icon" [size]="16" />
23934
24195
  }
@@ -23939,7 +24200,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
23939
24200
  }
23940
24201
 
23941
24202
  @for (action of actions(); track action.id) {
23942
- <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
+ >
23943
24211
  <jv-icon [name]="action.icon" [size]="18" />
23944
24212
  <span class="action-label">{{ action.label }}</span>
23945
24213
  </button>
@@ -24415,7 +24683,13 @@ class JvTabsComponent {
24415
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: `
24416
24684
  <div class="jv-tabs">
24417
24685
  <div class="jv-tabs-header">
24418
- <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
+ >
24419
24693
  @for (tab of tabs(); track tab.id) {
24420
24694
  <button
24421
24695
  type="button"
@@ -24471,11 +24745,16 @@ class JvTabsComponent {
24471
24745
  class="jv-tab-panel"
24472
24746
  [class.jv-tab-panel--hidden]="!isActive(tab.id)"
24473
24747
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24474
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24475
- [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
+ "
24476
24754
  [id]="panelId(tab.id)"
24477
24755
  role="tabpanel"
24478
24756
  [attr.aria-labelledby]="tabButtonId(tab.id)"
24757
+ [attr.aria-hidden]="isActive(tab.id) ? null : 'true'"
24479
24758
  [attr.tabindex]="isActive(tab.id) ? 0 : null"
24480
24759
  >
24481
24760
  <ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
@@ -24486,11 +24765,16 @@ class JvTabsComponent {
24486
24765
  <div
24487
24766
  class="jv-tab-panel jv-tab-panel--exit"
24488
24767
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24489
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24490
- [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
+ "
24491
24774
  [id]="panelId(outgoingId)"
24492
24775
  role="tabpanel"
24493
24776
  [attr.aria-labelledby]="tabButtonId(outgoingId)"
24777
+ aria-hidden="true"
24494
24778
  tabindex="-1"
24495
24779
  (transitionend)="handleTransitionEnd($event)"
24496
24780
  >
@@ -24502,11 +24786,16 @@ class JvTabsComponent {
24502
24786
  <div
24503
24787
  class="jv-tab-panel jv-tab-panel--entering"
24504
24788
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24505
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24506
- [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
+ "
24507
24795
  [id]="panelId(activeId)"
24508
24796
  role="tabpanel"
24509
24797
  [attr.aria-labelledby]="tabButtonId(activeId)"
24798
+ aria-hidden="false"
24510
24799
  tabindex="0"
24511
24800
  >
24512
24801
  <ng-container [ngTemplateOutlet]="panelTemplate(activeId) ?? null" />
@@ -24522,7 +24811,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24522
24811
  args: [{ selector: 'jv-tabs', standalone: true, imports: [NgTemplateOutlet, JvIconComponent], template: `
24523
24812
  <div class="jv-tabs">
24524
24813
  <div class="jv-tabs-header">
24525
- <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
+ >
24526
24821
  @for (tab of tabs(); track tab.id) {
24527
24822
  <button
24528
24823
  type="button"
@@ -24578,11 +24873,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24578
24873
  class="jv-tab-panel"
24579
24874
  [class.jv-tab-panel--hidden]="!isActive(tab.id)"
24580
24875
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24581
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24582
- [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
+ "
24583
24882
  [id]="panelId(tab.id)"
24584
24883
  role="tabpanel"
24585
24884
  [attr.aria-labelledby]="tabButtonId(tab.id)"
24885
+ [attr.aria-hidden]="isActive(tab.id) ? null : 'true'"
24586
24886
  [attr.tabindex]="isActive(tab.id) ? 0 : null"
24587
24887
  >
24588
24888
  <ng-container [ngTemplateOutlet]="panelTemplate(tab.id) ?? null" />
@@ -24593,11 +24893,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24593
24893
  <div
24594
24894
  class="jv-tab-panel jv-tab-panel--exit"
24595
24895
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24596
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24597
- [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
+ "
24598
24902
  [id]="panelId(outgoingId)"
24599
24903
  role="tabpanel"
24600
24904
  [attr.aria-labelledby]="tabButtonId(outgoingId)"
24905
+ aria-hidden="true"
24601
24906
  tabindex="-1"
24602
24907
  (transitionend)="handleTransitionEnd($event)"
24603
24908
  >
@@ -24609,11 +24914,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
24609
24914
  <div
24610
24915
  class="jv-tab-panel jv-tab-panel--entering"
24611
24916
  [class.jv-tab-panel--fade]="effectiveTransition() === 'fade'"
24612
- [class.jv-tab-panel--slide-left]="effectiveTransition() === 'slide' && slideDirection() === 'left'"
24613
- [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
+ "
24614
24923
  [id]="panelId(activeId)"
24615
24924
  role="tabpanel"
24616
24925
  [attr.aria-labelledby]="tabButtonId(activeId)"
24926
+ aria-hidden="false"
24617
24927
  tabindex="0"
24618
24928
  >
24619
24929
  <ng-container [ngTemplateOutlet]="panelTemplate(activeId) ?? null" />
@@ -25795,7 +26105,7 @@ class JvGridComponent {
25795
26105
  };
25796
26106
  }
25797
26107
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
25798
- 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"] }] });
25799
26109
  }
25800
26110
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JvGridComponent, decorators: [{
25801
26111
  type: Component,