@gilav21/shadcn-angular-rte 0.2.1 → 0.2.2

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.
@@ -20251,7 +20251,7 @@ class DialogComponent {
20251
20251
  this.open.update(v => !v);
20252
20252
  }
20253
20253
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
20254
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: DialogComponent, isStandalone: true, selector: "ui-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { classAttribute: "contents" }, providers: [{ provide: DIALOG, useExisting: forwardRef(() => DialogComponent) }], ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20254
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: DialogComponent, isStandalone: true, selector: "ui-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { properties: { "attr.data-slot": "\"dialog\"" }, classAttribute: "contents" }, providers: [{ provide: DIALOG, useExisting: forwardRef(() => DialogComponent) }], ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20255
20255
  }
20256
20256
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogComponent, decorators: [{
20257
20257
  type: Component,
@@ -20260,7 +20260,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
20260
20260
  changeDetection: ChangeDetectionStrategy.OnPush,
20261
20261
  providers: [{ provide: DIALOG, useExisting: forwardRef(() => DialogComponent) }],
20262
20262
  template: `<ng-content />`,
20263
- host: { class: 'contents' },
20263
+ host: { class: 'contents', '[attr.data-slot]': '"dialog"' },
20264
20264
  }]
20265
20265
  }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }] } });
20266
20266
 
@@ -20414,6 +20414,8 @@ function focusFirstTabbable(container) {
20414
20414
 
20415
20415
  class DialogTriggerComponent {
20416
20416
  constructor() {
20417
+ /** Extra classes for the element that wraps the projected trigger. */
20418
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
20417
20419
  this.dialog = inject(DIALOG, { optional: true });
20418
20420
  this.host = inject(ElementRef);
20419
20421
  /** See `lib/a11y.ts` — stays transparent when the projected content is already a control. */
@@ -20439,8 +20441,9 @@ class DialogTriggerComponent {
20439
20441
  this.onClick();
20440
20442
  }
20441
20443
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogTriggerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
20442
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: DialogTriggerComponent, isStandalone: true, selector: "ui-dialog-trigger", host: { classAttribute: "contents" }, ngImport: i0, template: `
20444
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: DialogTriggerComponent, isStandalone: true, selector: "ui-dialog-trigger", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
20443
20445
  <span
20446
+ [class]="class()"
20444
20447
  [attr.tabindex]="wrapsInteractive() ? null : 0"
20445
20448
  [attr.role]="wrapsInteractive() ? null : 'button'"
20446
20449
  [attr.data-slot]="'dialog-trigger'"
@@ -20459,6 +20462,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
20459
20462
  changeDetection: ChangeDetectionStrategy.OnPush,
20460
20463
  template: `
20461
20464
  <span
20465
+ [class]="class()"
20462
20466
  [attr.tabindex]="wrapsInteractive() ? null : 0"
20463
20467
  [attr.role]="wrapsInteractive() ? null : 'button'"
20464
20468
  [attr.data-slot]="'dialog-trigger'"
@@ -20471,7 +20475,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
20471
20475
  `,
20472
20476
  host: { class: 'contents' },
20473
20477
  }]
20474
- }], ctorParameters: () => [] });
20478
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
20475
20479
 
20476
20480
  const COMMON_LOCALES = {
20477
20481
  en: {
@@ -20679,20 +20683,30 @@ const COMMON_LOCALES = {
20679
20683
  };
20680
20684
 
20681
20685
  class DialogHeaderComponent {
20686
+ constructor() {
20687
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
20688
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
20689
+ this.classes = computed(() => cn('flex flex-col text-center sm:text-left', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
20690
+ }
20682
20691
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
20683
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: DialogHeaderComponent, isStandalone: true, selector: "ui-dialog-header", host: { properties: { "attr.data-slot": "\"dialog-header\"" }, classAttribute: "flex flex-col text-center sm:text-left" }, ngImport: i0, template: `<ng-content />`, isInline: true, styles: [":host{--_d: var(--density-dialog, var(--density, 1))}@layer components{:host([data-slot=\"dialog-header\"]){gap:calc(.375rem * var(--_d))}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20692
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: DialogHeaderComponent, isStandalone: true, selector: "ui-dialog-header", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"dialog-header\"" } }, ngImport: i0, template: `<ng-content />`, isInline: true, styles: [":host{--_d: var(--density-dialog, var(--density, 1))}@layer components{:host([data-slot=\"dialog-header\"]){gap:calc(.375rem * var(--_d))}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20684
20693
  }
20685
20694
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogHeaderComponent, decorators: [{
20686
20695
  type: Component,
20687
20696
  args: [{ selector: 'ui-dialog-header', changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, host: {
20688
- class: 'flex flex-col text-center sm:text-left',
20697
+ '[class]': 'classes()',
20689
20698
  '[attr.data-slot]': '"dialog-header"',
20690
20699
  }, styles: [":host{--_d: var(--density-dialog, var(--density, 1))}@layer components{:host([data-slot=\"dialog-header\"]){gap:calc(.375rem * var(--_d))}}\n"] }]
20691
- }] });
20700
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
20692
20701
 
20693
20702
  class DialogTitleComponent {
20703
+ constructor() {
20704
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
20705
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
20706
+ this.classes = computed(() => cn('text-lg font-semibold leading-none tracking-tight flex justify-start', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
20707
+ }
20694
20708
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
20695
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: DialogTitleComponent, isStandalone: true, selector: "ui-dialog-title", host: { properties: { "attr.data-slot": "\"dialog-title\"" }, classAttribute: "text-lg font-semibold leading-none tracking-tight flex justify-start" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20709
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: DialogTitleComponent, isStandalone: true, selector: "ui-dialog-title", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"dialog-title\"" } }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20696
20710
  }
20697
20711
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogTitleComponent, decorators: [{
20698
20712
  type: Component,
@@ -20701,15 +20715,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
20701
20715
  changeDetection: ChangeDetectionStrategy.OnPush,
20702
20716
  template: `<ng-content />`,
20703
20717
  host: {
20704
- class: 'text-lg font-semibold leading-none tracking-tight flex justify-start',
20718
+ '[class]': 'classes()',
20705
20719
  '[attr.data-slot]': '"dialog-title"',
20706
20720
  },
20707
20721
  }]
20708
- }] });
20722
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
20709
20723
 
20710
20724
  class DialogDescriptionComponent {
20725
+ constructor() {
20726
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
20727
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
20728
+ this.classes = computed(() => cn('text-sm text-muted-foreground flex justify-start', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
20729
+ }
20711
20730
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogDescriptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
20712
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: DialogDescriptionComponent, isStandalone: true, selector: "ui-dialog-description", host: { properties: { "attr.data-slot": "\"dialog-description\"" }, classAttribute: "text-sm text-muted-foreground flex justify-start" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20731
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: DialogDescriptionComponent, isStandalone: true, selector: "ui-dialog-description", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"dialog-description\"" } }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20713
20732
  }
20714
20733
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogDescriptionComponent, decorators: [{
20715
20734
  type: Component,
@@ -20718,11 +20737,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
20718
20737
  changeDetection: ChangeDetectionStrategy.OnPush,
20719
20738
  template: `<ng-content />`,
20720
20739
  host: {
20721
- class: 'text-sm text-muted-foreground flex justify-start',
20740
+ '[class]': 'classes()',
20722
20741
  '[attr.data-slot]': '"dialog-description"',
20723
20742
  },
20724
20743
  }]
20725
- }] });
20744
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
20726
20745
 
20727
20746
  class DialogContentComponent {
20728
20747
  constructor() {
@@ -20797,7 +20816,7 @@ class DialogContentComponent {
20797
20816
  trapTabKey(event, this.contentEl);
20798
20817
  }
20799
20818
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
20800
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: DialogContentComponent, isStandalone: true, selector: "ui-dialog-content", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: "@if (dialog?.open()) {\n <div class=\"fixed inset-0 z-50 flex items-center justify-center\" [attr.dir]=\"dir()\">\n <!-- Overlay -->\n <button\n type=\"button\"\n class=\"fixed inset-0 bg-black/80 animate-in fade-in-0\"\n [attr.data-slot]=\"'dialog-overlay'\"\n [attr.aria-label]=\"t().close\"\n (click)=\"onOverlayClick()\"\n ></button>\n <!-- Content -->\n <div\n #contentEl\n [class]=\"classes()\"\n [attr.data-slot]=\"'dialog-content'\"\n (keydown)=\"onKeydown($event)\"\n tabindex=\"-1\"\n >\n @if (title()) {\n <ui-dialog-header>\n <ui-dialog-title>{{ title() }}</ui-dialog-title>\n @if (description()) {\n <ui-dialog-description>{{ description() }}</ui-dialog-description>\n }\n </ui-dialog-header>\n }\n <ng-content />\n <!-- Close button -->\n <button\n type=\"button\"\n class=\"absolute end-4 top-4 inline-flex items-center justify-center rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none pointer-coarse:end-0.5 pointer-coarse:top-0.5 pointer-coarse:size-11\"\n [attr.aria-label]=\"t().close\"\n (click)=\"close()\"\n >\n <svg class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">{{ t().close }}</span>\n </button>\n </div>\n </div>\n}\n", styles: [":host{--_d: var(--density-dialog, var(--density, 1))}@layer components{[data-slot=dialog-content]{gap:calc(.75rem * var(--_d));padding:calc(1rem * var(--_d))}@media(min-width:640px){[data-slot=dialog-content]{gap:calc(1rem * var(--_d));padding:calc(1.5rem * var(--_d))}}}\n"], dependencies: [{ kind: "component", type: DialogHeaderComponent, selector: "ui-dialog-header" }, { kind: "component", type: DialogTitleComponent, selector: "ui-dialog-title" }, { kind: "component", type: DialogDescriptionComponent, selector: "ui-dialog-description" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20819
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: DialogContentComponent, isStandalone: true, selector: "ui-dialog-content", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: "@if (dialog?.open()) {\n <div class=\"fixed inset-0 z-50 flex items-center justify-center\" [attr.dir]=\"dir()\">\n <!-- Overlay -->\n <button\n type=\"button\"\n class=\"fixed inset-0 bg-black/80 animate-in fade-in-0\"\n [attr.data-slot]=\"'dialog-overlay'\"\n [attr.aria-label]=\"t().close\"\n (click)=\"onOverlayClick()\"\n ></button>\n <!-- Content -->\n <div\n #contentEl\n [class]=\"classes()\"\n [attr.data-slot]=\"'dialog-content'\"\n (keydown)=\"onKeydown($event)\"\n tabindex=\"-1\"\n >\n @if (title()) {\n <ui-dialog-header>\n <ui-dialog-title>{{ title() }}</ui-dialog-title>\n @if (description()) {\n <ui-dialog-description>{{ description() }}</ui-dialog-description>\n }\n </ui-dialog-header>\n }\n <ng-content />\n <!-- Close button -->\n <button\n type=\"button\"\n class=\"absolute end-4 top-4 inline-flex items-center justify-center rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none pointer-coarse:end-0.5 pointer-coarse:top-0.5 pointer-coarse:size-11\"\n [attr.aria-label]=\"t().close\"\n (click)=\"close()\"\n >\n <svg class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">{{ t().close }}</span>\n </button>\n </div>\n </div>\n}\n", styles: [":host{--_d: var(--density-dialog, var(--density, 1))}@layer components{[data-slot=dialog-content]{gap:calc(.75rem * var(--_d));padding:calc(1rem * var(--_d))}@media(min-width:640px){[data-slot=dialog-content]{gap:calc(1rem * var(--_d));padding:calc(1.5rem * var(--_d))}}}\n"], dependencies: [{ kind: "component", type: DialogHeaderComponent, selector: "ui-dialog-header", inputs: ["class"] }, { kind: "component", type: DialogTitleComponent, selector: "ui-dialog-title", inputs: ["class"] }, { kind: "component", type: DialogDescriptionComponent, selector: "ui-dialog-description", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20801
20820
  }
20802
20821
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogContentComponent, decorators: [{
20803
20822
  type: Component,
@@ -20809,16 +20828,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
20809
20828
  }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }] } });
20810
20829
 
20811
20830
  class DialogFooterComponent {
20831
+ constructor() {
20832
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
20833
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
20834
+ this.classes = computed(() => cn('flex flex-col-reverse sm:flex-row sm:justify-end', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
20835
+ }
20812
20836
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
20813
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: DialogFooterComponent, isStandalone: true, selector: "ui-dialog-footer", host: { properties: { "attr.data-slot": "\"dialog-footer\"" }, classAttribute: "flex flex-col-reverse sm:flex-row sm:justify-end" }, ngImport: i0, template: `<ng-content />`, isInline: true, styles: [":host{--_d: var(--density-dialog, var(--density, 1))}@layer components{:host([data-slot=\"dialog-footer\"]){gap:calc(.5rem * var(--_d))}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20837
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: DialogFooterComponent, isStandalone: true, selector: "ui-dialog-footer", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"dialog-footer\"" } }, ngImport: i0, template: `<ng-content />`, isInline: true, styles: [":host{--_d: var(--density-dialog, var(--density, 1))}@layer components{:host([data-slot=\"dialog-footer\"]){gap:calc(.5rem * var(--_d))}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20814
20838
  }
20815
20839
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: DialogFooterComponent, decorators: [{
20816
20840
  type: Component,
20817
20841
  args: [{ selector: 'ui-dialog-footer', changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, host: {
20818
- class: 'flex flex-col-reverse sm:flex-row sm:justify-end',
20842
+ '[class]': 'classes()',
20819
20843
  '[attr.data-slot]': '"dialog-footer"',
20820
20844
  }, styles: [":host{--_d: var(--density-dialog, var(--density, 1))}@layer components{:host([data-slot=\"dialog-footer\"]){gap:calc(.5rem * var(--_d))}}\n"] }]
20821
- }] });
20845
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
20822
20846
 
20823
20847
  /**
20824
20848
  * Media-query reads that degrade where `matchMedia` does not exist.
@@ -21253,7 +21277,7 @@ class AlertDialogComponent {
21253
21277
  this.open.update(v => !v);
21254
21278
  }
21255
21279
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
21256
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: AlertDialogComponent, isStandalone: true, selector: "ui-alert-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { classAttribute: "contents" }, providers: [{ provide: ALERT_DIALOG, useExisting: forwardRef(() => AlertDialogComponent) }], ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21280
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: AlertDialogComponent, isStandalone: true, selector: "ui-alert-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { properties: { "attr.data-slot": "\"alert-dialog\"" }, classAttribute: "contents" }, providers: [{ provide: ALERT_DIALOG, useExisting: forwardRef(() => AlertDialogComponent) }], ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21257
21281
  }
21258
21282
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogComponent, decorators: [{
21259
21283
  type: Component,
@@ -21262,12 +21286,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21262
21286
  changeDetection: ChangeDetectionStrategy.OnPush,
21263
21287
  providers: [{ provide: ALERT_DIALOG, useExisting: forwardRef(() => AlertDialogComponent) }],
21264
21288
  template: `<ng-content />`,
21265
- host: { class: 'contents' },
21289
+ host: { class: 'contents', '[attr.data-slot]': '"alert-dialog"' },
21266
21290
  }]
21267
21291
  }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }] } });
21268
21292
 
21269
21293
  class AlertDialogTriggerComponent {
21270
21294
  constructor() {
21295
+ /** Extra classes for the element that wraps the projected trigger. */
21296
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
21271
21297
  this.alertDialog = inject(ALERT_DIALOG, { optional: true });
21272
21298
  this.host = inject(ElementRef);
21273
21299
  /** See `lib/a11y.ts` — stays transparent when the projected content is already a control. */
@@ -21293,8 +21319,9 @@ class AlertDialogTriggerComponent {
21293
21319
  this.onClick();
21294
21320
  }
21295
21321
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogTriggerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
21296
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: AlertDialogTriggerComponent, isStandalone: true, selector: "ui-alert-dialog-trigger", host: { classAttribute: "contents" }, ngImport: i0, template: `
21322
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: AlertDialogTriggerComponent, isStandalone: true, selector: "ui-alert-dialog-trigger", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
21297
21323
  <span
21324
+ [class]="class()"
21298
21325
  (click)="onClick()"
21299
21326
  (keydown.enter)="onKeydown($event)"
21300
21327
  (keydown.space)="onKeydown($event)"
@@ -21313,6 +21340,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21313
21340
  changeDetection: ChangeDetectionStrategy.OnPush,
21314
21341
  template: `
21315
21342
  <span
21343
+ [class]="class()"
21316
21344
  (click)="onClick()"
21317
21345
  (keydown.enter)="onKeydown($event)"
21318
21346
  (keydown.space)="onKeydown($event)"
@@ -21325,11 +21353,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21325
21353
  `,
21326
21354
  host: { class: 'contents' },
21327
21355
  }]
21328
- }], ctorParameters: () => [] });
21356
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
21329
21357
 
21330
21358
  class AlertDialogHeaderComponent {
21359
+ constructor() {
21360
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
21361
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
21362
+ this.classes = computed(() => cn('flex flex-col space-y-2 text-center sm:text-left rtl:text-right', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
21363
+ }
21331
21364
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
21332
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: AlertDialogHeaderComponent, isStandalone: true, selector: "ui-alert-dialog-header", host: { properties: { "attr.data-slot": "\"alert-dialog-header\"" }, classAttribute: "flex flex-col space-y-2 text-center sm:text-left rtl:text-right" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21365
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: AlertDialogHeaderComponent, isStandalone: true, selector: "ui-alert-dialog-header", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"alert-dialog-header\"" } }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21333
21366
  }
21334
21367
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogHeaderComponent, decorators: [{
21335
21368
  type: Component,
@@ -21338,15 +21371,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21338
21371
  changeDetection: ChangeDetectionStrategy.OnPush,
21339
21372
  template: `<ng-content />`,
21340
21373
  host: {
21341
- class: 'flex flex-col space-y-2 text-center sm:text-left rtl:text-right',
21374
+ '[class]': 'classes()',
21342
21375
  '[attr.data-slot]': '"alert-dialog-header"',
21343
21376
  },
21344
21377
  }]
21345
- }] });
21378
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
21346
21379
 
21347
21380
  class AlertDialogTitleComponent {
21381
+ constructor() {
21382
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
21383
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
21384
+ this.classes = computed(() => cn('text-lg font-semibold', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
21385
+ }
21348
21386
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
21349
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: AlertDialogTitleComponent, isStandalone: true, selector: "ui-alert-dialog-title", host: { properties: { "attr.data-slot": "\"alert-dialog-title\"" }, classAttribute: "text-lg font-semibold" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21387
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: AlertDialogTitleComponent, isStandalone: true, selector: "ui-alert-dialog-title", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"alert-dialog-title\"" } }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21350
21388
  }
21351
21389
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogTitleComponent, decorators: [{
21352
21390
  type: Component,
@@ -21355,15 +21393,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21355
21393
  changeDetection: ChangeDetectionStrategy.OnPush,
21356
21394
  template: `<ng-content />`,
21357
21395
  host: {
21358
- class: 'text-lg font-semibold',
21396
+ '[class]': 'classes()',
21359
21397
  '[attr.data-slot]': '"alert-dialog-title"',
21360
21398
  },
21361
21399
  }]
21362
- }] });
21400
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
21363
21401
 
21364
21402
  class AlertDialogDescriptionComponent {
21403
+ constructor() {
21404
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
21405
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
21406
+ this.classes = computed(() => cn('text-sm text-muted-foreground', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
21407
+ }
21365
21408
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogDescriptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
21366
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: AlertDialogDescriptionComponent, isStandalone: true, selector: "ui-alert-dialog-description", host: { properties: { "attr.data-slot": "\"alert-dialog-description\"" }, classAttribute: "text-sm text-muted-foreground" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21409
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: AlertDialogDescriptionComponent, isStandalone: true, selector: "ui-alert-dialog-description", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"alert-dialog-description\"" } }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21367
21410
  }
21368
21411
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogDescriptionComponent, decorators: [{
21369
21412
  type: Component,
@@ -21372,15 +21415,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21372
21415
  changeDetection: ChangeDetectionStrategy.OnPush,
21373
21416
  template: `<ng-content />`,
21374
21417
  host: {
21375
- class: 'text-sm text-muted-foreground',
21418
+ '[class]': 'classes()',
21376
21419
  '[attr.data-slot]': '"alert-dialog-description"',
21377
21420
  },
21378
21421
  }]
21379
- }] });
21422
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
21380
21423
 
21381
21424
  class AlertDialogFooterComponent {
21425
+ constructor() {
21426
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
21427
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
21428
+ this.classes = computed(() => cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 gap-[10px]', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
21429
+ }
21382
21430
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
21383
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: AlertDialogFooterComponent, isStandalone: true, selector: "ui-alert-dialog-footer", host: { properties: { "attr.data-slot": "\"alert-dialog-footer\"" }, classAttribute: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 gap-[10px]" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21431
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: AlertDialogFooterComponent, isStandalone: true, selector: "ui-alert-dialog-footer", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"alert-dialog-footer\"" } }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21384
21432
  }
21385
21433
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogFooterComponent, decorators: [{
21386
21434
  type: Component,
@@ -21389,11 +21437,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21389
21437
  changeDetection: ChangeDetectionStrategy.OnPush,
21390
21438
  template: `<ng-content />`,
21391
21439
  host: {
21392
- class: 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 gap-[10px]',
21440
+ '[class]': 'classes()',
21393
21441
  '[attr.data-slot]': '"alert-dialog-footer"',
21394
21442
  },
21395
21443
  }]
21396
- }] });
21444
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
21397
21445
 
21398
21446
  class AlertDialogActionComponent {
21399
21447
  constructor() {
@@ -21611,7 +21659,7 @@ class AlertDialogContentComponent {
21611
21659
  </div>
21612
21660
  </div>
21613
21661
  }
21614
- `, isInline: true, dependencies: [{ kind: "component", type: AlertDialogHeaderComponent, selector: "ui-alert-dialog-header" }, { kind: "component", type: AlertDialogTitleComponent, selector: "ui-alert-dialog-title" }, { kind: "component", type: AlertDialogDescriptionComponent, selector: "ui-alert-dialog-description" }, { kind: "component", type: AlertDialogFooterComponent, selector: "ui-alert-dialog-footer" }, { kind: "component", type: AlertDialogActionComponent, selector: "ui-alert-dialog-action", inputs: ["class"] }, { kind: "component", type: AlertDialogCancelComponent, selector: "ui-alert-dialog-cancel", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21662
+ `, isInline: true, dependencies: [{ kind: "component", type: AlertDialogHeaderComponent, selector: "ui-alert-dialog-header", inputs: ["class"] }, { kind: "component", type: AlertDialogTitleComponent, selector: "ui-alert-dialog-title", inputs: ["class"] }, { kind: "component", type: AlertDialogDescriptionComponent, selector: "ui-alert-dialog-description", inputs: ["class"] }, { kind: "component", type: AlertDialogFooterComponent, selector: "ui-alert-dialog-footer", inputs: ["class"] }, { kind: "component", type: AlertDialogActionComponent, selector: "ui-alert-dialog-action", inputs: ["class"] }, { kind: "component", type: AlertDialogCancelComponent, selector: "ui-alert-dialog-cancel", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21615
21663
  }
21616
21664
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AlertDialogContentComponent, decorators: [{
21617
21665
  type: Component,
@@ -21677,6 +21725,8 @@ class ConfirmDialogComponent {
21677
21725
  * they never double-emit through this path.
21678
21726
  */
21679
21727
  constructor() {
21728
+ /** Extra classes merged onto the dialog panel, e.g. a width utility. */
21729
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
21680
21730
  this.open = signal(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
21681
21731
  this.title = signal('Confirm', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
21682
21732
  this.description = signal('Are you sure?', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
@@ -21720,9 +21770,10 @@ class ConfirmDialogComponent {
21720
21770
  this.cancelled.emit();
21721
21771
  }
21722
21772
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: ConfirmDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
21723
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: ConfirmDialogComponent, isStandalone: true, selector: "ui-confirm-dialog", outputs: { confirmed: "confirmed", cancelled: "cancelled" }, ngImport: i0, template: `
21773
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: ConfirmDialogComponent, isStandalone: true, selector: "ui-confirm-dialog", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirmed: "confirmed", cancelled: "cancelled" }, host: { properties: { "attr.data-slot": "\"confirm-dialog\"" }, classAttribute: "contents" }, ngImport: i0, template: `
21724
21774
  <ui-alert-dialog [open]="open()">
21725
21775
  <ui-alert-dialog-content
21776
+ [class]="class()"
21726
21777
  [title]="title()"
21727
21778
  [description]="description()"
21728
21779
  [actionText]="confirmLabel()"
@@ -21742,6 +21793,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21742
21793
  template: `
21743
21794
  <ui-alert-dialog [open]="open()">
21744
21795
  <ui-alert-dialog-content
21796
+ [class]="class()"
21745
21797
  [title]="title()"
21746
21798
  [description]="description()"
21747
21799
  [actionText]="confirmLabel()"
@@ -21751,8 +21803,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21751
21803
  />
21752
21804
  </ui-alert-dialog>
21753
21805
  `,
21806
+ host: { class: 'contents', '[attr.data-slot]': '"confirm-dialog"' },
21754
21807
  }]
21755
- }], ctorParameters: () => [], propDecorators: { confirmed: [{ type: i0.Output, args: ["confirmed"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }] } });
21808
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], confirmed: [{ type: i0.Output, args: ["confirmed"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }] } });
21756
21809
 
21757
21810
  class ConfirmDirective {
21758
21811
  constructor() {
@@ -21834,12 +21887,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
21834
21887
  /** Renders declarative action fields (tier 1) and emits params + validity. */
21835
21888
  class RichTextActionsFormComponent {
21836
21889
  constructor() {
21837
- /**
21838
- * Conventional style hook. The form's own markup carries fixed layout
21839
- * classes and does not consume this value, so styling it from the outside
21840
- * means targeting the `block` host element or `data-slot`.
21841
- */
21890
+ /** Extra classes merged onto the `block` host. The form's inner markup keeps its own fixed layout. */
21842
21891
  this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
21892
+ this.classes = computed(() => cn('block', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
21843
21893
  /**
21844
21894
  * The tier-1 field descriptors to render, in order — one control each,
21845
21895
  * chosen by `field.type` (textarea / checkbox / select / number / text).
@@ -21928,11 +21978,11 @@ class RichTextActionsFormComponent {
21928
21978
  this.paramsChange.emit(next);
21929
21979
  }
21930
21980
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextActionsFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
21931
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextActionsFormComponent, isStandalone: true, selector: "ui-rich-text-actions-form", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null }, params: { classPropertyName: "params", publicName: "params", isSignal: true, isRequired: false, transformFunction: null }, requiredTemplate: { classPropertyName: "requiredTemplate", publicName: "requiredTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { paramsChange: "paramsChange", validChange: "validChange" }, host: { properties: { "attr.data-slot": "'rich-text-actions-form'" }, classAttribute: "block" }, ngImport: i0, template: "<div class=\"space-y-3\">\n @for (field of fields(); track field.key) {\n <div class=\"space-y-1\">\n <label [for]=\"'rtaf-' + field.key\" class=\"text-sm font-medium block\">\n {{ field.label }}@if (field.required) {<span class=\"text-destructive\"> *</span>}\n </label>\n\n @switch (field.type) {\n @case ('textarea') {\n <textarea\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\" [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex min-h-[72px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm\"\n ></textarea>\n }\n @case ('checkbox') {\n <input\n type=\"checkbox\" [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [checked]=\"boolValue(field.key)\"\n (change)=\"onFieldInput(field, $any($event.target).checked)\"\n />\n }\n @case ('select') {\n <select\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\"\n (change)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm\"\n >\n <option value=\"\" disabled>{{ field.placeholder ?? 'Select\u2026' }}</option>\n @for (opt of field.options ?? []; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @default {\n <input\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\" [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm\"\n />\n }\n }\n\n @if (field.description) {\n <p class=\"text-xs text-muted-foreground\">{{ field.description }}</p>\n }\n @if (errors()[field.key]; as err) {\n <p class=\"text-xs text-destructive\">{{ err }}</p>\n }\n </div>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21981
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextActionsFormComponent, isStandalone: true, selector: "ui-rich-text-actions-form", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null }, params: { classPropertyName: "params", publicName: "params", isSignal: true, isRequired: false, transformFunction: null }, requiredTemplate: { classPropertyName: "requiredTemplate", publicName: "requiredTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { paramsChange: "paramsChange", validChange: "validChange" }, host: { properties: { "class": "classes()", "attr.data-slot": "'rich-text-actions-form'" } }, ngImport: i0, template: "<div class=\"space-y-3\">\n @for (field of fields(); track field.key) {\n <div class=\"space-y-1\">\n <label [for]=\"'rtaf-' + field.key\" class=\"text-sm font-medium block\">\n {{ field.label }}@if (field.required) {<span class=\"text-destructive\"> *</span>}\n </label>\n\n @switch (field.type) {\n @case ('textarea') {\n <textarea\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\" [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex min-h-[72px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm\"\n ></textarea>\n }\n @case ('checkbox') {\n <input\n type=\"checkbox\" [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [checked]=\"boolValue(field.key)\"\n (change)=\"onFieldInput(field, $any($event.target).checked)\"\n />\n }\n @case ('select') {\n <select\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\"\n (change)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm\"\n >\n <option value=\"\" disabled>{{ field.placeholder ?? 'Select\u2026' }}</option>\n @for (opt of field.options ?? []; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @default {\n <input\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\" [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm\"\n />\n }\n }\n\n @if (field.description) {\n <p class=\"text-xs text-muted-foreground\">{{ field.description }}</p>\n }\n @if (errors()[field.key]; as err) {\n <p class=\"text-xs text-destructive\">{{ err }}</p>\n }\n </div>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
21932
21982
  }
21933
21983
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextActionsFormComponent, decorators: [{
21934
21984
  type: Component,
21935
- args: [{ selector: 'ui-rich-text-actions-form', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'block', '[attr.data-slot]': "'rich-text-actions-form'" }, template: "<div class=\"space-y-3\">\n @for (field of fields(); track field.key) {\n <div class=\"space-y-1\">\n <label [for]=\"'rtaf-' + field.key\" class=\"text-sm font-medium block\">\n {{ field.label }}@if (field.required) {<span class=\"text-destructive\"> *</span>}\n </label>\n\n @switch (field.type) {\n @case ('textarea') {\n <textarea\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\" [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex min-h-[72px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm\"\n ></textarea>\n }\n @case ('checkbox') {\n <input\n type=\"checkbox\" [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [checked]=\"boolValue(field.key)\"\n (change)=\"onFieldInput(field, $any($event.target).checked)\"\n />\n }\n @case ('select') {\n <select\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\"\n (change)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm\"\n >\n <option value=\"\" disabled>{{ field.placeholder ?? 'Select\u2026' }}</option>\n @for (opt of field.options ?? []; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @default {\n <input\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\" [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm\"\n />\n }\n }\n\n @if (field.description) {\n <p class=\"text-xs text-muted-foreground\">{{ field.description }}</p>\n }\n @if (errors()[field.key]; as err) {\n <p class=\"text-xs text-destructive\">{{ err }}</p>\n }\n </div>\n }\n</div>\n" }]
21985
+ args: [{ selector: 'ui-rich-text-actions-form', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'classes()', '[attr.data-slot]': "'rich-text-actions-form'" }, template: "<div class=\"space-y-3\">\n @for (field of fields(); track field.key) {\n <div class=\"space-y-1\">\n <label [for]=\"'rtaf-' + field.key\" class=\"text-sm font-medium block\">\n {{ field.label }}@if (field.required) {<span class=\"text-destructive\"> *</span>}\n </label>\n\n @switch (field.type) {\n @case ('textarea') {\n <textarea\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\" [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex min-h-[72px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm\"\n ></textarea>\n }\n @case ('checkbox') {\n <input\n type=\"checkbox\" [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [checked]=\"boolValue(field.key)\"\n (change)=\"onFieldInput(field, $any($event.target).checked)\"\n />\n }\n @case ('select') {\n <select\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\"\n (change)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm\"\n >\n <option value=\"\" disabled>{{ field.placeholder ?? 'Select\u2026' }}</option>\n @for (opt of field.options ?? []; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @default {\n <input\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [id]=\"'rtaf-' + field.key\" [attr.data-field]=\"field.key\"\n [value]=\"stringValue(field.key)\" [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"onFieldInput(field, $any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm\"\n />\n }\n }\n\n @if (field.description) {\n <p class=\"text-xs text-muted-foreground\">{{ field.description }}</p>\n }\n @if (errors()[field.key]; as err) {\n <p class=\"text-xs text-destructive\">{{ err }}</p>\n }\n </div>\n }\n</div>\n" }]
21936
21986
  }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], fields: [{ type: i0.Input, args: [{ isSignal: true, alias: "fields", required: false }] }], params: [{ type: i0.Input, args: [{ isSignal: true, alias: "params", required: false }] }], requiredTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "requiredTemplate", required: false }] }], paramsChange: [{ type: i0.Output, args: ["paramsChange"] }], validChange: [{ type: i0.Output, args: ["validChange"] }] } });
21937
21987
 
21938
21988
  const en = {
@@ -22000,6 +22050,9 @@ const RICH_TEXT_ACTIONS_LOCALES = { en, he };
22000
22050
  /** Attach/edit dialog: searchable action picker + generated tier-1 form. */
22001
22051
  class RichTextActionsDialogComponent {
22002
22052
  constructor() {
22053
+ /** Extra classes merged onto the dialog panel, after its bounded `sm:max-w-md` width. */
22054
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
22055
+ this.classes = computed(() => cn('max-w-[calc(100vw-2rem)] sm:max-w-md', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
22003
22056
  /**
22004
22057
  * The full catalogue of registered actions. The picker shows only those
22005
22058
  * whose `targets` include the context's `targetKind` and that match the
@@ -22284,19 +22337,22 @@ class RichTextActionsDialogComponent {
22284
22337
  this.dismiss.emit();
22285
22338
  }
22286
22339
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextActionsDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
22287
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextActionsDialogComponent, isStandalone: true, selector: "ui-rich-text-actions-dialog", inputs: { definitions: { classPropertyName: "definitions", publicName: "definitions", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: true, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirm: "confirm", dismiss: "dismiss", pick: "pick" }, host: { properties: { "attr.data-slot": "'rich-text-actions-dialog'" } }, viewQueries: [{ propertyName: "formHost", first: true, predicate: ["formHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<ui-dialog [open]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-dialog-content class=\"max-w-[calc(100vw-2rem)] sm:max-w-md\" [attr.dir]=\"dir()\">\n <ui-dialog-header>\n <ui-dialog-title>\n @if (context().mode === 'edit') {\n {{ locale().dialog.editTitle }}\n } @else if (context().targetKind === 'image') {\n {{ locale().dialog.attachToImage }}\n } @else {\n {{ attachTitle() }}\n }\n </ui-dialog-title>\n </ui-dialog-header>\n\n <div class=\"space-y-4\">\n <input\n type=\"text\" [value]=\"query()\"\n [placeholder]=\"locale().dialog.searchPlaceholder\" [attr.aria-label]=\"locale().dialog.searchLabel\"\n (input)=\"query.set($any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm\"\n />\n\n <div\n class=\"max-h-56 overflow-y-auto rounded-md border\"\n [class.pointer-events-none]=\"busy()\" [class.opacity-50]=\"busy()\"\n >\n @for (def of visibleDefs(); track def.id) {\n <button\n type=\"button\" [attr.data-action-option]=\"def.id\"\n [attr.aria-pressed]=\"selectedDef()?.id === def.id\"\n (click)=\"pickAction(def.id)\"\n class=\"flex w-full items-center justify-between gap-2 px-3 py-2 text-left text-sm hover:bg-accent\"\n [class.bg-accent]=\"selectedDef()?.id === def.id\"\n >\n <span class=\"truncate\">{{ def.label }}</span>\n <span class=\"text-xs text-muted-foreground\">{{ triggerLabels(def.triggers) }}</span>\n </button>\n } @empty {\n <p class=\"px-3 py-2 text-sm text-muted-foreground\">{{ locale().dialog.noActions }}</p>\n }\n </div>\n\n @if (selectedDef(); as def) {\n @if (!isCombined() && def.triggers.length > 1) {\n <div class=\"flex flex-wrap items-center gap-3\">\n @for (t of def.triggers; track t) {\n <label class=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"radio\" name=\"rta-trigger\" [checked]=\"selectedTrigger() === t\"\n (change)=\"selectTrigger(t)\"\n />\n {{ triggerLabel(t) }}\n @if (occupiedByTrigger().has(t)) {\n <span class=\"text-xs text-muted-foreground\">{{ locale().dialog.replacesExisting }}</span>\n }\n </label>\n }\n </div>\n }\n\n @if (isCombined()) {\n <span class=\"inline-flex rounded bg-accent px-2 py-0.5 text-xs\">{{ locale().dialog.combinedBadge }}</span>\n }\n\n @if (isCombined() && paramsMode() === 'separate') {\n <div class=\"space-y-2\">\n <p data-slot=\"rich-text-actions-dialog-section-header\" class=\"text-sm font-medium\">{{ locale().triggers.hover }}</p>\n <ui-rich-text-actions-form\n [fields]=\"def.fieldsByTrigger?.hover ?? []\" [params]=\"hoverParams()\"\n [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onHoverParamsChange($event)\" (validChange)=\"onHoverValidChange($event)\"\n />\n <p data-slot=\"rich-text-actions-dialog-section-header\" class=\"text-sm font-medium\">{{ locale().triggers.click }}</p>\n <ui-rich-text-actions-form\n [fields]=\"def.fieldsByTrigger?.click ?? []\" [params]=\"currentParams()\"\n [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onParamsChange($event)\" (validChange)=\"onValidChange($event)\"\n />\n </div>\n } @else if (def.formComponent) {\n <ng-container #formHost />\n } @else if (def.fields && def.fields.length > 0) {\n <ui-rich-text-actions-form\n [fields]=\"def.fields\" [params]=\"currentParams()\" [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onParamsChange($event)\" (validChange)=\"onValidChange($event)\"\n />\n }\n }\n </div>\n\n <ui-dialog-footer>\n <ui-button data-testid=\"rta-cancel\" variant=\"ghost\" (click)=\"dismiss.emit()\">{{ locale().dialog.cancel }}</ui-button>\n <ui-button data-testid=\"rta-confirm\" [disabled]=\"!canConfirm()\" (click)=\"onConfirm()\">\n {{ confirmLabel() }}\n </ui-button>\n </ui-dialog-footer>\n </ui-dialog-content>\n</ui-dialog>\n", dependencies: [{ kind: "component", type: DialogComponent, selector: "ui-dialog", inputs: ["open"], outputs: ["openChange"] }, { kind: "component", type: DialogContentComponent, selector: "ui-dialog-content", inputs: ["class", "title", "description", "locale"] }, { kind: "component", type: DialogHeaderComponent, selector: "ui-dialog-header" }, { kind: "component", type: DialogTitleComponent, selector: "ui-dialog-title" }, { kind: "component", type: DialogFooterComponent, selector: "ui-dialog-footer" }, { kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }, { kind: "component", type: RichTextActionsFormComponent, selector: "ui-rich-text-actions-form", inputs: ["class", "fields", "params", "requiredTemplate"], outputs: ["paramsChange", "validChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
22340
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextActionsDialogComponent, isStandalone: true, selector: "ui-rich-text-actions-dialog", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, definitions: { classPropertyName: "definitions", publicName: "definitions", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: true, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirm: "confirm", dismiss: "dismiss", pick: "pick" }, host: { properties: { "attr.data-slot": "'rich-text-actions-dialog'" } }, viewQueries: [{ propertyName: "formHost", first: true, predicate: ["formHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<ui-dialog [open]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-dialog-content [class]=\"classes()\" [attr.dir]=\"dir()\">\n <ui-dialog-header>\n <ui-dialog-title>\n @if (context().mode === 'edit') {\n {{ locale().dialog.editTitle }}\n } @else if (context().targetKind === 'image') {\n {{ locale().dialog.attachToImage }}\n } @else {\n {{ attachTitle() }}\n }\n </ui-dialog-title>\n </ui-dialog-header>\n\n <div class=\"space-y-4\">\n <input\n type=\"text\" [value]=\"query()\"\n [placeholder]=\"locale().dialog.searchPlaceholder\" [attr.aria-label]=\"locale().dialog.searchLabel\"\n (input)=\"query.set($any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm\"\n />\n\n <div\n class=\"max-h-56 overflow-y-auto rounded-md border\"\n [class.pointer-events-none]=\"busy()\" [class.opacity-50]=\"busy()\"\n >\n @for (def of visibleDefs(); track def.id) {\n <button\n type=\"button\" [attr.data-action-option]=\"def.id\"\n [attr.aria-pressed]=\"selectedDef()?.id === def.id\"\n (click)=\"pickAction(def.id)\"\n class=\"flex w-full items-center justify-between gap-2 px-3 py-2 text-left text-sm hover:bg-accent\"\n [class.bg-accent]=\"selectedDef()?.id === def.id\"\n >\n <span class=\"truncate\">{{ def.label }}</span>\n <span class=\"text-xs text-muted-foreground\">{{ triggerLabels(def.triggers) }}</span>\n </button>\n } @empty {\n <p class=\"px-3 py-2 text-sm text-muted-foreground\">{{ locale().dialog.noActions }}</p>\n }\n </div>\n\n @if (selectedDef(); as def) {\n @if (!isCombined() && def.triggers.length > 1) {\n <div class=\"flex flex-wrap items-center gap-3\">\n @for (t of def.triggers; track t) {\n <label class=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"radio\" name=\"rta-trigger\" [checked]=\"selectedTrigger() === t\"\n (change)=\"selectTrigger(t)\"\n />\n {{ triggerLabel(t) }}\n @if (occupiedByTrigger().has(t)) {\n <span class=\"text-xs text-muted-foreground\">{{ locale().dialog.replacesExisting }}</span>\n }\n </label>\n }\n </div>\n }\n\n @if (isCombined()) {\n <span class=\"inline-flex rounded bg-accent px-2 py-0.5 text-xs\">{{ locale().dialog.combinedBadge }}</span>\n }\n\n @if (isCombined() && paramsMode() === 'separate') {\n <div class=\"space-y-2\">\n <p data-slot=\"rich-text-actions-dialog-section-header\" class=\"text-sm font-medium\">{{ locale().triggers.hover }}</p>\n <ui-rich-text-actions-form\n [fields]=\"def.fieldsByTrigger?.hover ?? []\" [params]=\"hoverParams()\"\n [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onHoverParamsChange($event)\" (validChange)=\"onHoverValidChange($event)\"\n />\n <p data-slot=\"rich-text-actions-dialog-section-header\" class=\"text-sm font-medium\">{{ locale().triggers.click }}</p>\n <ui-rich-text-actions-form\n [fields]=\"def.fieldsByTrigger?.click ?? []\" [params]=\"currentParams()\"\n [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onParamsChange($event)\" (validChange)=\"onValidChange($event)\"\n />\n </div>\n } @else if (def.formComponent) {\n <ng-container #formHost />\n } @else if (def.fields && def.fields.length > 0) {\n <ui-rich-text-actions-form\n [fields]=\"def.fields\" [params]=\"currentParams()\" [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onParamsChange($event)\" (validChange)=\"onValidChange($event)\"\n />\n }\n }\n </div>\n\n <ui-dialog-footer>\n <ui-button data-testid=\"rta-cancel\" variant=\"ghost\" (click)=\"dismiss.emit()\">{{ locale().dialog.cancel }}</ui-button>\n <ui-button data-testid=\"rta-confirm\" [disabled]=\"!canConfirm()\" (click)=\"onConfirm()\">\n {{ confirmLabel() }}\n </ui-button>\n </ui-dialog-footer>\n </ui-dialog-content>\n</ui-dialog>\n", dependencies: [{ kind: "component", type: DialogComponent, selector: "ui-dialog", inputs: ["open"], outputs: ["openChange"] }, { kind: "component", type: DialogContentComponent, selector: "ui-dialog-content", inputs: ["class", "title", "description", "locale"] }, { kind: "component", type: DialogHeaderComponent, selector: "ui-dialog-header", inputs: ["class"] }, { kind: "component", type: DialogTitleComponent, selector: "ui-dialog-title", inputs: ["class"] }, { kind: "component", type: DialogFooterComponent, selector: "ui-dialog-footer", inputs: ["class"] }, { kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }, { kind: "component", type: RichTextActionsFormComponent, selector: "ui-rich-text-actions-form", inputs: ["class", "fields", "params", "requiredTemplate"], outputs: ["paramsChange", "validChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
22288
22341
  }
22289
22342
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextActionsDialogComponent, decorators: [{
22290
22343
  type: Component,
22291
22344
  args: [{ selector: 'ui-rich-text-actions-dialog', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
22292
22345
  DialogComponent, DialogContentComponent, DialogHeaderComponent,
22293
22346
  DialogTitleComponent, DialogFooterComponent, ButtonComponent, RichTextActionsFormComponent,
22294
- ], host: { '[attr.data-slot]': "'rich-text-actions-dialog'" }, template: "<ui-dialog [open]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-dialog-content class=\"max-w-[calc(100vw-2rem)] sm:max-w-md\" [attr.dir]=\"dir()\">\n <ui-dialog-header>\n <ui-dialog-title>\n @if (context().mode === 'edit') {\n {{ locale().dialog.editTitle }}\n } @else if (context().targetKind === 'image') {\n {{ locale().dialog.attachToImage }}\n } @else {\n {{ attachTitle() }}\n }\n </ui-dialog-title>\n </ui-dialog-header>\n\n <div class=\"space-y-4\">\n <input\n type=\"text\" [value]=\"query()\"\n [placeholder]=\"locale().dialog.searchPlaceholder\" [attr.aria-label]=\"locale().dialog.searchLabel\"\n (input)=\"query.set($any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm\"\n />\n\n <div\n class=\"max-h-56 overflow-y-auto rounded-md border\"\n [class.pointer-events-none]=\"busy()\" [class.opacity-50]=\"busy()\"\n >\n @for (def of visibleDefs(); track def.id) {\n <button\n type=\"button\" [attr.data-action-option]=\"def.id\"\n [attr.aria-pressed]=\"selectedDef()?.id === def.id\"\n (click)=\"pickAction(def.id)\"\n class=\"flex w-full items-center justify-between gap-2 px-3 py-2 text-left text-sm hover:bg-accent\"\n [class.bg-accent]=\"selectedDef()?.id === def.id\"\n >\n <span class=\"truncate\">{{ def.label }}</span>\n <span class=\"text-xs text-muted-foreground\">{{ triggerLabels(def.triggers) }}</span>\n </button>\n } @empty {\n <p class=\"px-3 py-2 text-sm text-muted-foreground\">{{ locale().dialog.noActions }}</p>\n }\n </div>\n\n @if (selectedDef(); as def) {\n @if (!isCombined() && def.triggers.length > 1) {\n <div class=\"flex flex-wrap items-center gap-3\">\n @for (t of def.triggers; track t) {\n <label class=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"radio\" name=\"rta-trigger\" [checked]=\"selectedTrigger() === t\"\n (change)=\"selectTrigger(t)\"\n />\n {{ triggerLabel(t) }}\n @if (occupiedByTrigger().has(t)) {\n <span class=\"text-xs text-muted-foreground\">{{ locale().dialog.replacesExisting }}</span>\n }\n </label>\n }\n </div>\n }\n\n @if (isCombined()) {\n <span class=\"inline-flex rounded bg-accent px-2 py-0.5 text-xs\">{{ locale().dialog.combinedBadge }}</span>\n }\n\n @if (isCombined() && paramsMode() === 'separate') {\n <div class=\"space-y-2\">\n <p data-slot=\"rich-text-actions-dialog-section-header\" class=\"text-sm font-medium\">{{ locale().triggers.hover }}</p>\n <ui-rich-text-actions-form\n [fields]=\"def.fieldsByTrigger?.hover ?? []\" [params]=\"hoverParams()\"\n [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onHoverParamsChange($event)\" (validChange)=\"onHoverValidChange($event)\"\n />\n <p data-slot=\"rich-text-actions-dialog-section-header\" class=\"text-sm font-medium\">{{ locale().triggers.click }}</p>\n <ui-rich-text-actions-form\n [fields]=\"def.fieldsByTrigger?.click ?? []\" [params]=\"currentParams()\"\n [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onParamsChange($event)\" (validChange)=\"onValidChange($event)\"\n />\n </div>\n } @else if (def.formComponent) {\n <ng-container #formHost />\n } @else if (def.fields && def.fields.length > 0) {\n <ui-rich-text-actions-form\n [fields]=\"def.fields\" [params]=\"currentParams()\" [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onParamsChange($event)\" (validChange)=\"onValidChange($event)\"\n />\n }\n }\n </div>\n\n <ui-dialog-footer>\n <ui-button data-testid=\"rta-cancel\" variant=\"ghost\" (click)=\"dismiss.emit()\">{{ locale().dialog.cancel }}</ui-button>\n <ui-button data-testid=\"rta-confirm\" [disabled]=\"!canConfirm()\" (click)=\"onConfirm()\">\n {{ confirmLabel() }}\n </ui-button>\n </ui-dialog-footer>\n </ui-dialog-content>\n</ui-dialog>\n" }]
22295
- }], ctorParameters: () => [], propDecorators: { definitions: [{ type: i0.Input, args: [{ isSignal: true, alias: "definitions", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: true }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], confirm: [{ type: i0.Output, args: ["confirm"] }], dismiss: [{ type: i0.Output, args: ["dismiss"] }], pick: [{ type: i0.Output, args: ["pick"] }], formHost: [{ type: i0.ViewChild, args: ['formHost', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
22347
+ ], host: { '[attr.data-slot]': "'rich-text-actions-dialog'" }, template: "<ui-dialog [open]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-dialog-content [class]=\"classes()\" [attr.dir]=\"dir()\">\n <ui-dialog-header>\n <ui-dialog-title>\n @if (context().mode === 'edit') {\n {{ locale().dialog.editTitle }}\n } @else if (context().targetKind === 'image') {\n {{ locale().dialog.attachToImage }}\n } @else {\n {{ attachTitle() }}\n }\n </ui-dialog-title>\n </ui-dialog-header>\n\n <div class=\"space-y-4\">\n <input\n type=\"text\" [value]=\"query()\"\n [placeholder]=\"locale().dialog.searchPlaceholder\" [attr.aria-label]=\"locale().dialog.searchLabel\"\n (input)=\"query.set($any($event.target).value)\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm\"\n />\n\n <div\n class=\"max-h-56 overflow-y-auto rounded-md border\"\n [class.pointer-events-none]=\"busy()\" [class.opacity-50]=\"busy()\"\n >\n @for (def of visibleDefs(); track def.id) {\n <button\n type=\"button\" [attr.data-action-option]=\"def.id\"\n [attr.aria-pressed]=\"selectedDef()?.id === def.id\"\n (click)=\"pickAction(def.id)\"\n class=\"flex w-full items-center justify-between gap-2 px-3 py-2 text-left text-sm hover:bg-accent\"\n [class.bg-accent]=\"selectedDef()?.id === def.id\"\n >\n <span class=\"truncate\">{{ def.label }}</span>\n <span class=\"text-xs text-muted-foreground\">{{ triggerLabels(def.triggers) }}</span>\n </button>\n } @empty {\n <p class=\"px-3 py-2 text-sm text-muted-foreground\">{{ locale().dialog.noActions }}</p>\n }\n </div>\n\n @if (selectedDef(); as def) {\n @if (!isCombined() && def.triggers.length > 1) {\n <div class=\"flex flex-wrap items-center gap-3\">\n @for (t of def.triggers; track t) {\n <label class=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"radio\" name=\"rta-trigger\" [checked]=\"selectedTrigger() === t\"\n (change)=\"selectTrigger(t)\"\n />\n {{ triggerLabel(t) }}\n @if (occupiedByTrigger().has(t)) {\n <span class=\"text-xs text-muted-foreground\">{{ locale().dialog.replacesExisting }}</span>\n }\n </label>\n }\n </div>\n }\n\n @if (isCombined()) {\n <span class=\"inline-flex rounded bg-accent px-2 py-0.5 text-xs\">{{ locale().dialog.combinedBadge }}</span>\n }\n\n @if (isCombined() && paramsMode() === 'separate') {\n <div class=\"space-y-2\">\n <p data-slot=\"rich-text-actions-dialog-section-header\" class=\"text-sm font-medium\">{{ locale().triggers.hover }}</p>\n <ui-rich-text-actions-form\n [fields]=\"def.fieldsByTrigger?.hover ?? []\" [params]=\"hoverParams()\"\n [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onHoverParamsChange($event)\" (validChange)=\"onHoverValidChange($event)\"\n />\n <p data-slot=\"rich-text-actions-dialog-section-header\" class=\"text-sm font-medium\">{{ locale().triggers.click }}</p>\n <ui-rich-text-actions-form\n [fields]=\"def.fieldsByTrigger?.click ?? []\" [params]=\"currentParams()\"\n [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onParamsChange($event)\" (validChange)=\"onValidChange($event)\"\n />\n </div>\n } @else if (def.formComponent) {\n <ng-container #formHost />\n } @else if (def.fields && def.fields.length > 0) {\n <ui-rich-text-actions-form\n [fields]=\"def.fields\" [params]=\"currentParams()\" [requiredTemplate]=\"locale().form.required\"\n (paramsChange)=\"onParamsChange($event)\" (validChange)=\"onValidChange($event)\"\n />\n }\n }\n </div>\n\n <ui-dialog-footer>\n <ui-button data-testid=\"rta-cancel\" variant=\"ghost\" (click)=\"dismiss.emit()\">{{ locale().dialog.cancel }}</ui-button>\n <ui-button data-testid=\"rta-confirm\" [disabled]=\"!canConfirm()\" (click)=\"onConfirm()\">\n {{ confirmLabel() }}\n </ui-button>\n </ui-dialog-footer>\n </ui-dialog-content>\n</ui-dialog>\n" }]
22348
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], definitions: [{ type: i0.Input, args: [{ isSignal: true, alias: "definitions", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: true }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], confirm: [{ type: i0.Output, args: ["confirm"] }], dismiss: [{ type: i0.Output, args: ["dismiss"] }], pick: [{ type: i0.Output, args: ["pick"] }], formHost: [{ type: i0.ViewChild, args: ['formHost', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
22296
22349
 
22297
22350
  /** Compact editor-side popover listing an element's actions with edit/remove/add. */
22298
22351
  class RichTextActionsPopoverComponent {
22299
22352
  constructor() {
22353
+ /** Extra classes merged onto the popover panel, after its bordered `min-w-56` default. */
22354
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
22355
+ this.classes = computed(() => cn('min-w-56 max-w-[calc(100vw-2rem)] rounded-md border bg-popover p-1 shadow-md', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
22300
22356
  /**
22301
22357
  * The rows to list, tracked by `trigger` — so at most one click row and one
22302
22358
  * hover row, or a single row for a combined action covering both. A row
@@ -22345,12 +22401,12 @@ class RichTextActionsPopoverComponent {
22345
22401
  return `${this.triggerLabel('click')} / ${this.triggerLabel('hover')}`;
22346
22402
  }
22347
22403
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextActionsPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
22348
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextActionsPopoverComponent, isStandalone: true, selector: "ui-rich-text-actions-popover", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, canAdd: { classPropertyName: "canAdd", publicName: "canAdd", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { edit: "edit", remove: "remove", add: "add" }, host: { properties: { "attr.data-slot": "'rich-text-actions-popover'" } }, ngImport: i0, template: "<div class=\"min-w-56 max-w-[calc(100vw-2rem)] rounded-md border bg-popover p-1 shadow-md\" [attr.dir]=\"dir()\">\n @for (row of actions(); track row.trigger) {\n <div class=\"flex items-center justify-between gap-3 rounded-sm px-2 py-1.5 text-sm\">\n <span class=\"truncate\">\n {{ row.label }} \u00B7 {{ rowTriggerLabel(row) }}\n @if (!row.available) {\n <span class=\"text-xs text-muted-foreground\">{{ locale().popover.unavailable }}</span>\n }\n </span>\n <span class=\"flex shrink-0 items-center gap-3\">\n @if (row.available) {\n <button\n type=\"button\" data-testid=\"rta-edit\" class=\"text-xs underline\"\n (click)=\"edit.emit(row.trigger)\"\n >{{ locale().popover.edit }}</button>\n }\n <button\n type=\"button\" data-testid=\"rta-remove\" class=\"text-xs text-destructive underline\"\n (click)=\"remove.emit(row)\"\n >{{ locale().popover.remove }}</button>\n </span>\n </div>\n }\n @if (canAdd()) {\n <button\n type=\"button\" data-testid=\"rta-add\"\n class=\"w-full rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent\"\n (click)=\"add.emit()\"\n >{{ locale().popover.add }}</button>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
22404
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextActionsPopoverComponent, isStandalone: true, selector: "ui-rich-text-actions-popover", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, canAdd: { classPropertyName: "canAdd", publicName: "canAdd", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { edit: "edit", remove: "remove", add: "add" }, host: { properties: { "attr.data-slot": "'rich-text-actions-popover'" } }, ngImport: i0, template: "<div [class]=\"classes()\" [attr.dir]=\"dir()\">\n @for (row of actions(); track row.trigger) {\n <div class=\"flex items-center justify-between gap-3 rounded-sm px-2 py-1.5 text-sm\">\n <span class=\"truncate\">\n {{ row.label }} \u00B7 {{ rowTriggerLabel(row) }}\n @if (!row.available) {\n <span class=\"text-xs text-muted-foreground\">{{ locale().popover.unavailable }}</span>\n }\n </span>\n <span class=\"flex shrink-0 items-center gap-3\">\n @if (row.available) {\n <button\n type=\"button\" data-testid=\"rta-edit\" class=\"text-xs underline\"\n (click)=\"edit.emit(row.trigger)\"\n >{{ locale().popover.edit }}</button>\n }\n <button\n type=\"button\" data-testid=\"rta-remove\" class=\"text-xs text-destructive underline\"\n (click)=\"remove.emit(row)\"\n >{{ locale().popover.remove }}</button>\n </span>\n </div>\n }\n @if (canAdd()) {\n <button\n type=\"button\" data-testid=\"rta-add\"\n class=\"w-full rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent\"\n (click)=\"add.emit()\"\n >{{ locale().popover.add }}</button>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
22349
22405
  }
22350
22406
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextActionsPopoverComponent, decorators: [{
22351
22407
  type: Component,
22352
- args: [{ selector: 'ui-rich-text-actions-popover', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { '[attr.data-slot]': "'rich-text-actions-popover'" }, template: "<div class=\"min-w-56 max-w-[calc(100vw-2rem)] rounded-md border bg-popover p-1 shadow-md\" [attr.dir]=\"dir()\">\n @for (row of actions(); track row.trigger) {\n <div class=\"flex items-center justify-between gap-3 rounded-sm px-2 py-1.5 text-sm\">\n <span class=\"truncate\">\n {{ row.label }} \u00B7 {{ rowTriggerLabel(row) }}\n @if (!row.available) {\n <span class=\"text-xs text-muted-foreground\">{{ locale().popover.unavailable }}</span>\n }\n </span>\n <span class=\"flex shrink-0 items-center gap-3\">\n @if (row.available) {\n <button\n type=\"button\" data-testid=\"rta-edit\" class=\"text-xs underline\"\n (click)=\"edit.emit(row.trigger)\"\n >{{ locale().popover.edit }}</button>\n }\n <button\n type=\"button\" data-testid=\"rta-remove\" class=\"text-xs text-destructive underline\"\n (click)=\"remove.emit(row)\"\n >{{ locale().popover.remove }}</button>\n </span>\n </div>\n }\n @if (canAdd()) {\n <button\n type=\"button\" data-testid=\"rta-add\"\n class=\"w-full rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent\"\n (click)=\"add.emit()\"\n >{{ locale().popover.add }}</button>\n }\n</div>\n" }]
22353
- }], propDecorators: { actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], canAdd: [{ type: i0.Input, args: [{ isSignal: true, alias: "canAdd", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], edit: [{ type: i0.Output, args: ["edit"] }], remove: [{ type: i0.Output, args: ["remove"] }], add: [{ type: i0.Output, args: ["add"] }] } });
22408
+ args: [{ selector: 'ui-rich-text-actions-popover', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { '[attr.data-slot]': "'rich-text-actions-popover'" }, template: "<div [class]=\"classes()\" [attr.dir]=\"dir()\">\n @for (row of actions(); track row.trigger) {\n <div class=\"flex items-center justify-between gap-3 rounded-sm px-2 py-1.5 text-sm\">\n <span class=\"truncate\">\n {{ row.label }} \u00B7 {{ rowTriggerLabel(row) }}\n @if (!row.available) {\n <span class=\"text-xs text-muted-foreground\">{{ locale().popover.unavailable }}</span>\n }\n </span>\n <span class=\"flex shrink-0 items-center gap-3\">\n @if (row.available) {\n <button\n type=\"button\" data-testid=\"rta-edit\" class=\"text-xs underline\"\n (click)=\"edit.emit(row.trigger)\"\n >{{ locale().popover.edit }}</button>\n }\n <button\n type=\"button\" data-testid=\"rta-remove\" class=\"text-xs text-destructive underline\"\n (click)=\"remove.emit(row)\"\n >{{ locale().popover.remove }}</button>\n </span>\n </div>\n }\n @if (canAdd()) {\n <button\n type=\"button\" data-testid=\"rta-add\"\n class=\"w-full rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent\"\n (click)=\"add.emit()\"\n >{{ locale().popover.add }}</button>\n }\n</div>\n" }]
22409
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], canAdd: [{ type: i0.Input, args: [{ isSignal: true, alias: "canAdd", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], edit: [{ type: i0.Output, args: ["edit"] }], remove: [{ type: i0.Output, args: ["remove"] }], add: [{ type: i0.Output, args: ["add"] }] } });
22354
22410
 
22355
22411
  const ATTACH_ID = 'actions.attach';
22356
22412
  const ATTACH_ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" ' +
@@ -23188,6 +23244,9 @@ function hoverCardAction(o = {}) {
23188
23244
  /** The card rendered on the published page for the hover-card preset. */
23189
23245
  class PresetHoverCardComponent {
23190
23246
  constructor() {
23247
+ /** Extra classes merged onto the card, after its bordered popover styling. */
23248
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
23249
+ this.classes = computed(() => cn('max-w-[calc(100vw-2rem)] sm:max-w-xs rounded-md border bg-popover p-3 text-popover-foreground shadow-md', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
23191
23250
  /** Bold heading line; omitted entirely when empty. Fed from the action's `title` param. */
23192
23251
  this.title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
23193
23252
  /** Muted card text, always rendered. Fed from the action's required `body` param. */
@@ -23196,11 +23255,8 @@ class PresetHoverCardComponent {
23196
23255
  this.dir = input('ltr', ...(ngDevMode ? [{ debugName: "dir" }] : /* istanbul ignore next */ []));
23197
23256
  }
23198
23257
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PresetHoverCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23199
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PresetHoverCardComponent, isStandalone: true, selector: "ui-preset-hover-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, body: { classPropertyName: "body", publicName: "body", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-slot": "'preset-hover-card'" } }, ngImport: i0, template: `
23200
- <div
23201
- class="max-w-[calc(100vw-2rem)] sm:max-w-xs rounded-md border bg-popover p-3 text-popover-foreground shadow-md"
23202
- [attr.dir]="dir()"
23203
- >
23258
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PresetHoverCardComponent, isStandalone: true, selector: "ui-preset-hover-card", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, body: { classPropertyName: "body", publicName: "body", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-slot": "'preset-hover-card'" } }, ngImport: i0, template: `
23259
+ <div [class]="classes()" [attr.dir]="dir()">
23204
23260
  @if (title()) {
23205
23261
  <p class="mb-1 text-sm font-semibold">{{ title() }}</p>
23206
23262
  }
@@ -23215,10 +23271,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
23215
23271
  standalone: true,
23216
23272
  changeDetection: ChangeDetectionStrategy.OnPush,
23217
23273
  template: `
23218
- <div
23219
- class="max-w-[calc(100vw-2rem)] sm:max-w-xs rounded-md border bg-popover p-3 text-popover-foreground shadow-md"
23220
- [attr.dir]="dir()"
23221
- >
23274
+ <div [class]="classes()" [attr.dir]="dir()">
23222
23275
  @if (title()) {
23223
23276
  <p class="mb-1 text-sm font-semibold">{{ title() }}</p>
23224
23277
  }
@@ -23227,7 +23280,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
23227
23280
  `,
23228
23281
  host: { '[attr.data-slot]': "'preset-hover-card'" },
23229
23282
  }]
23230
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], body: [{ type: i0.Input, args: [{ isSignal: true, alias: "body", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }] } });
23283
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], body: [{ type: i0.Input, args: [{ isSignal: true, alias: "body", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }] } });
23231
23284
  /**
23232
23285
  * Handlers for the hover-card preset. Spread the returned map into your
23233
23286
  * `[uiRichTextActions]` handler object. Renders a real floating card in the
@@ -23304,6 +23357,9 @@ function openDialogAction(o = {}) {
23304
23357
  /** The modal rendered on the published page for the open-dialog preset. */
23305
23358
  class PresetDialogComponent {
23306
23359
  constructor() {
23360
+ /** Extra classes merged onto the dialog panel, after its bounded `sm:max-w-md` width. */
23361
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
23362
+ this.classes = computed(() => cn('relative max-w-[calc(100vw-2rem)] sm:max-w-md rounded-lg border bg-background p-4 shadow-xl', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
23307
23363
  /** Dialog heading; the `<h2>` is omitted entirely when empty. Fed from the action's required `title` param. */
23308
23364
  this.title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
23309
23365
  /** Body text, rendered only when {@link contentComponent} is null. Fed from the action's `body` param. */
@@ -23328,14 +23384,14 @@ class PresetDialogComponent {
23328
23384
  this.dismiss = output();
23329
23385
  }
23330
23386
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PresetDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23331
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PresetDialogComponent, isStandalone: true, selector: "ui-preset-dialog", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, body: { classPropertyName: "body", publicName: "body", isSignal: true, isRequired: false, transformFunction: null }, confirmLabel: { classPropertyName: "confirmLabel", publicName: "confirmLabel", isSignal: true, isRequired: false, transformFunction: null }, contentComponent: { classPropertyName: "contentComponent", publicName: "contentComponent", isSignal: true, isRequired: false, transformFunction: null }, contentInjector: { classPropertyName: "contentInjector", publicName: "contentInjector", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirm: "confirm", dismiss: "dismiss" }, host: { properties: { "attr.data-slot": "'preset-dialog'" } }, ngImport: i0, template: `
23387
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PresetDialogComponent, isStandalone: true, selector: "ui-preset-dialog", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, body: { classPropertyName: "body", publicName: "body", isSignal: true, isRequired: false, transformFunction: null }, confirmLabel: { classPropertyName: "confirmLabel", publicName: "confirmLabel", isSignal: true, isRequired: false, transformFunction: null }, contentComponent: { classPropertyName: "contentComponent", publicName: "contentComponent", isSignal: true, isRequired: false, transformFunction: null }, contentInjector: { classPropertyName: "contentInjector", publicName: "contentInjector", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirm: "confirm", dismiss: "dismiss" }, host: { properties: { "attr.data-slot": "'preset-dialog'" } }, ngImport: i0, template: `
23332
23388
  <div class="fixed inset-0 flex items-center justify-center">
23333
23389
  <button
23334
23390
  type="button" aria-label="Close" class="fixed inset-0 bg-black/50"
23335
23391
  (click)="dismiss.emit()"
23336
23392
  ></button>
23337
23393
  <div
23338
- class="relative max-w-[calc(100vw-2rem)] sm:max-w-md rounded-lg border bg-background p-4 shadow-xl"
23394
+ [class]="classes()"
23339
23395
  role="dialog" aria-modal="true" [attr.dir]="dir()"
23340
23396
  >
23341
23397
  @if (title()) {
@@ -23370,7 +23426,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
23370
23426
  (click)="dismiss.emit()"
23371
23427
  ></button>
23372
23428
  <div
23373
- class="relative max-w-[calc(100vw-2rem)] sm:max-w-md rounded-lg border bg-background p-4 shadow-xl"
23429
+ [class]="classes()"
23374
23430
  role="dialog" aria-modal="true" [attr.dir]="dir()"
23375
23431
  >
23376
23432
  @if (title()) {
@@ -23392,7 +23448,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
23392
23448
  `,
23393
23449
  host: { '[attr.data-slot]': "'preset-dialog'" },
23394
23450
  }]
23395
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], body: [{ type: i0.Input, args: [{ isSignal: true, alias: "body", required: false }] }], confirmLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "confirmLabel", required: false }] }], contentComponent: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentComponent", required: false }] }], contentInjector: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentInjector", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], confirm: [{ type: i0.Output, args: ["confirm"] }], dismiss: [{ type: i0.Output, args: ["dismiss"] }] } });
23451
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], body: [{ type: i0.Input, args: [{ isSignal: true, alias: "body", required: false }] }], confirmLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "confirmLabel", required: false }] }], contentComponent: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentComponent", required: false }] }], contentInjector: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentInjector", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], confirm: [{ type: i0.Output, args: ["confirm"] }], dismiss: [{ type: i0.Output, args: ["dismiss"] }] } });
23396
23452
  /**
23397
23453
  * Handlers for the open-dialog preset. Spread the returned map into your
23398
23454
  * `[uiRichTextActions]` handler object. Opens a real modal on click, showing
@@ -23718,14 +23774,17 @@ const RICH_TEXT_AI_CONTEXT = new InjectionToken('RICH_TEXT_AI_CONTEXT');
23718
23774
  class RichTextAiChipComponent {
23719
23775
  constructor() {
23720
23776
  this.ctx = inject(RICH_TEXT_AI_CONTEXT);
23777
+ /** Extra classes merged onto the chip button, after its floating popover styling. */
23778
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
23779
+ this.classes = computed(() => cn('fixed z-[9999] inline-flex items-center gap-1 rounded-md border bg-popover px-2 py-1 text-xs font-medium shadow-lg hover:bg-accent', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
23721
23780
  }
23722
23781
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextAiChipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23723
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextAiChipComponent, isStandalone: true, selector: "ui-rte-ai-chip", host: { classAttribute: "contents" }, ngImport: i0, template: "@if (ctx.chipVisible()) {\n <button\n type=\"button\"\n data-slot=\"rich-text-ai-trigger\"\n class=\"fixed z-[9999] inline-flex items-center gap-1 rounded-md border bg-popover px-2 py-1 text-xs font-medium shadow-lg hover:bg-accent\"\n [style.left.px]=\"ctx.chipPosition().x\"\n [style.top.px]=\"ctx.chipPosition().y\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"ctx.openPanel()\"\n >\n {{ ctx.locale().trigger }}\n </button>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23782
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextAiChipComponent, isStandalone: true, selector: "ui-rte-ai-chip", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: "@if (ctx.chipVisible()) {\n <button\n type=\"button\"\n data-slot=\"rich-text-ai-trigger\"\n [class]=\"classes()\"\n [style.left.px]=\"ctx.chipPosition().x\"\n [style.top.px]=\"ctx.chipPosition().y\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"ctx.openPanel()\"\n >\n {{ ctx.locale().trigger }}\n </button>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23724
23783
  }
23725
23784
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextAiChipComponent, decorators: [{
23726
23785
  type: Component,
23727
- args: [{ selector: 'ui-rte-ai-chip', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'contents' }, template: "@if (ctx.chipVisible()) {\n <button\n type=\"button\"\n data-slot=\"rich-text-ai-trigger\"\n class=\"fixed z-[9999] inline-flex items-center gap-1 rounded-md border bg-popover px-2 py-1 text-xs font-medium shadow-lg hover:bg-accent\"\n [style.left.px]=\"ctx.chipPosition().x\"\n [style.top.px]=\"ctx.chipPosition().y\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"ctx.openPanel()\"\n >\n {{ ctx.locale().trigger }}\n </button>\n}\n" }]
23728
- }] });
23786
+ args: [{ selector: 'ui-rte-ai-chip', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'contents' }, template: "@if (ctx.chipVisible()) {\n <button\n type=\"button\"\n data-slot=\"rich-text-ai-trigger\"\n [class]=\"classes()\"\n [style.left.px]=\"ctx.chipPosition().x\"\n [style.top.px]=\"ctx.chipPosition().y\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"ctx.openPanel()\"\n >\n {{ ctx.locale().trigger }}\n </button>\n}\n" }]
23787
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
23729
23788
 
23730
23789
  /**
23731
23790
  * The AI addon's task panel: a fixed, viewport-clamped popover anchored under
@@ -23740,6 +23799,9 @@ class RichTextAiPanelComponent {
23740
23799
  constructor() {
23741
23800
  this.ctx = inject(RICH_TEXT_AI_CONTEXT);
23742
23801
  this.customPrompt = signal('', ...(ngDevMode ? [{ debugName: "customPrompt" }] : /* istanbul ignore next */ []));
23802
+ /** Extra classes merged onto the panel, after its bounded `w-72` popover styling. */
23803
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
23804
+ this.classes = computed(() => cn('fixed z-[9999] w-72 max-w-[calc(100vw-2rem)] rounded-lg border bg-popover p-2 shadow-xl', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
23743
23805
  effect(() => {
23744
23806
  if (this.ctx.panelOpen() && this.ctx.phase() === 'menu') {
23745
23807
  this.customPrompt.set('');
@@ -23755,12 +23817,12 @@ class RichTextAiPanelComponent {
23755
23817
  this.ctx.runCustom(prompt);
23756
23818
  }
23757
23819
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextAiPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23758
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextAiPanelComponent, isStandalone: true, selector: "ui-rte-ai-panel", host: { classAttribute: "contents" }, ngImport: i0, template: "@if (ctx.panelOpen()) {\n <div\n data-slot=\"rich-text-ai-panel\"\n role=\"dialog\"\n [attr.aria-label]=\"ctx.locale().panelLabel\"\n class=\"fixed z-[9999] w-72 max-w-[calc(100vw-2rem)] rounded-lg border bg-popover p-2 shadow-xl\"\n [style.left.px]=\"ctx.panelPosition().x\"\n [style.top.px]=\"ctx.panelPosition().y\"\n >\n @if (ctx.phase() === 'menu') {\n <div class=\"flex flex-col gap-0.5\" data-slot=\"rich-text-ai-menu\">\n @for (t of ctx.tasks(); track t.task) {\n <button\n type=\"button\"\n class=\"flex w-full items-center rounded px-2 py-1.5 text-left text-sm hover:bg-accent\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"ctx.runTask(t.task)\"\n >\n {{ t.label }}\n </button>\n }\n <div class=\"mt-1 flex items-center gap-1 border-t pt-2\">\n <input\n type=\"text\"\n class=\"h-8 min-w-0 flex-1 rounded-md border bg-background px-2 text-sm outline-none focus:ring-1 focus:ring-ring\"\n [placeholder]=\"ctx.locale().promptPlaceholder\"\n [attr.aria-label]=\"ctx.locale().promptPlaceholder\"\n [value]=\"customPrompt()\"\n (input)=\"onCustomInput($event)\"\n (keydown.enter)=\"runCustom()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n <ui-button size=\"sm\" [disabled]=\"!customPrompt().trim()\" (click)=\"runCustom()\">{{ ctx.locale().go }}</ui-button>\n </div>\n </div>\n } @else {\n <div class=\"flex flex-col gap-2\" data-slot=\"rich-text-ai-review\">\n @if (ctx.phase() === 'loading') {\n <output\n class=\"block px-1 text-xs text-muted-foreground\"\n aria-live=\"polite\"\n data-slot=\"rich-text-ai-loading\"\n >{{ ctx.locale().generating }}</output>\n }\n @if (ctx.errorMessage()) {\n <p class=\"px-1 text-xs text-destructive\" role=\"alert\" data-slot=\"rich-text-ai-error\">{{ ctx.errorMessage() }}</p>\n }\n <div class=\"flex flex-wrap gap-1\">\n <ui-button size=\"sm\" [disabled]=\"ctx.phase() === 'loading'\" (click)=\"ctx.accept()\">{{ ctx.locale().accept }}</ui-button>\n <ui-button size=\"sm\" variant=\"outline\" (click)=\"ctx.discard()\">{{ ctx.locale().discard }}</ui-button>\n <ui-button size=\"sm\" variant=\"ghost\" [disabled]=\"ctx.phase() === 'loading'\" (click)=\"ctx.retryLast()\">{{ ctx.locale().retry }}</ui-button>\n </div>\n </div>\n }\n </div>\n}\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23820
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextAiPanelComponent, isStandalone: true, selector: "ui-rte-ai-panel", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: "@if (ctx.panelOpen()) {\n <div\n data-slot=\"rich-text-ai-panel\"\n role=\"dialog\"\n [attr.aria-label]=\"ctx.locale().panelLabel\"\n [class]=\"classes()\"\n [style.left.px]=\"ctx.panelPosition().x\"\n [style.top.px]=\"ctx.panelPosition().y\"\n >\n @if (ctx.phase() === 'menu') {\n <div class=\"flex flex-col gap-0.5\" data-slot=\"rich-text-ai-menu\">\n @for (t of ctx.tasks(); track t.task) {\n <button\n type=\"button\"\n class=\"flex w-full items-center rounded px-2 py-1.5 text-left text-sm hover:bg-accent\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"ctx.runTask(t.task)\"\n >\n {{ t.label }}\n </button>\n }\n <div class=\"mt-1 flex items-center gap-1 border-t pt-2\">\n <input\n type=\"text\"\n class=\"h-8 min-w-0 flex-1 rounded-md border bg-background px-2 text-sm outline-none focus:ring-1 focus:ring-ring\"\n [placeholder]=\"ctx.locale().promptPlaceholder\"\n [attr.aria-label]=\"ctx.locale().promptPlaceholder\"\n [value]=\"customPrompt()\"\n (input)=\"onCustomInput($event)\"\n (keydown.enter)=\"runCustom()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n <ui-button size=\"sm\" [disabled]=\"!customPrompt().trim()\" (click)=\"runCustom()\">{{ ctx.locale().go }}</ui-button>\n </div>\n </div>\n } @else {\n <div class=\"flex flex-col gap-2\" data-slot=\"rich-text-ai-review\">\n @if (ctx.phase() === 'loading') {\n <output\n class=\"block px-1 text-xs text-muted-foreground\"\n aria-live=\"polite\"\n data-slot=\"rich-text-ai-loading\"\n >{{ ctx.locale().generating }}</output>\n }\n @if (ctx.errorMessage()) {\n <p class=\"px-1 text-xs text-destructive\" role=\"alert\" data-slot=\"rich-text-ai-error\">{{ ctx.errorMessage() }}</p>\n }\n <div class=\"flex flex-wrap gap-1\">\n <ui-button size=\"sm\" [disabled]=\"ctx.phase() === 'loading'\" (click)=\"ctx.accept()\">{{ ctx.locale().accept }}</ui-button>\n <ui-button size=\"sm\" variant=\"outline\" (click)=\"ctx.discard()\">{{ ctx.locale().discard }}</ui-button>\n <ui-button size=\"sm\" variant=\"ghost\" [disabled]=\"ctx.phase() === 'loading'\" (click)=\"ctx.retryLast()\">{{ ctx.locale().retry }}</ui-button>\n </div>\n </div>\n }\n </div>\n}\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23759
23821
  }
23760
23822
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextAiPanelComponent, decorators: [{
23761
23823
  type: Component,
23762
- args: [{ selector: 'ui-rte-ai-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ButtonComponent], host: { class: 'contents' }, template: "@if (ctx.panelOpen()) {\n <div\n data-slot=\"rich-text-ai-panel\"\n role=\"dialog\"\n [attr.aria-label]=\"ctx.locale().panelLabel\"\n class=\"fixed z-[9999] w-72 max-w-[calc(100vw-2rem)] rounded-lg border bg-popover p-2 shadow-xl\"\n [style.left.px]=\"ctx.panelPosition().x\"\n [style.top.px]=\"ctx.panelPosition().y\"\n >\n @if (ctx.phase() === 'menu') {\n <div class=\"flex flex-col gap-0.5\" data-slot=\"rich-text-ai-menu\">\n @for (t of ctx.tasks(); track t.task) {\n <button\n type=\"button\"\n class=\"flex w-full items-center rounded px-2 py-1.5 text-left text-sm hover:bg-accent\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"ctx.runTask(t.task)\"\n >\n {{ t.label }}\n </button>\n }\n <div class=\"mt-1 flex items-center gap-1 border-t pt-2\">\n <input\n type=\"text\"\n class=\"h-8 min-w-0 flex-1 rounded-md border bg-background px-2 text-sm outline-none focus:ring-1 focus:ring-ring\"\n [placeholder]=\"ctx.locale().promptPlaceholder\"\n [attr.aria-label]=\"ctx.locale().promptPlaceholder\"\n [value]=\"customPrompt()\"\n (input)=\"onCustomInput($event)\"\n (keydown.enter)=\"runCustom()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n <ui-button size=\"sm\" [disabled]=\"!customPrompt().trim()\" (click)=\"runCustom()\">{{ ctx.locale().go }}</ui-button>\n </div>\n </div>\n } @else {\n <div class=\"flex flex-col gap-2\" data-slot=\"rich-text-ai-review\">\n @if (ctx.phase() === 'loading') {\n <output\n class=\"block px-1 text-xs text-muted-foreground\"\n aria-live=\"polite\"\n data-slot=\"rich-text-ai-loading\"\n >{{ ctx.locale().generating }}</output>\n }\n @if (ctx.errorMessage()) {\n <p class=\"px-1 text-xs text-destructive\" role=\"alert\" data-slot=\"rich-text-ai-error\">{{ ctx.errorMessage() }}</p>\n }\n <div class=\"flex flex-wrap gap-1\">\n <ui-button size=\"sm\" [disabled]=\"ctx.phase() === 'loading'\" (click)=\"ctx.accept()\">{{ ctx.locale().accept }}</ui-button>\n <ui-button size=\"sm\" variant=\"outline\" (click)=\"ctx.discard()\">{{ ctx.locale().discard }}</ui-button>\n <ui-button size=\"sm\" variant=\"ghost\" [disabled]=\"ctx.phase() === 'loading'\" (click)=\"ctx.retryLast()\">{{ ctx.locale().retry }}</ui-button>\n </div>\n </div>\n }\n </div>\n}\n" }]
23763
- }], ctorParameters: () => [] });
23824
+ args: [{ selector: 'ui-rte-ai-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ButtonComponent], host: { class: 'contents' }, template: "@if (ctx.panelOpen()) {\n <div\n data-slot=\"rich-text-ai-panel\"\n role=\"dialog\"\n [attr.aria-label]=\"ctx.locale().panelLabel\"\n [class]=\"classes()\"\n [style.left.px]=\"ctx.panelPosition().x\"\n [style.top.px]=\"ctx.panelPosition().y\"\n >\n @if (ctx.phase() === 'menu') {\n <div class=\"flex flex-col gap-0.5\" data-slot=\"rich-text-ai-menu\">\n @for (t of ctx.tasks(); track t.task) {\n <button\n type=\"button\"\n class=\"flex w-full items-center rounded px-2 py-1.5 text-left text-sm hover:bg-accent\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"ctx.runTask(t.task)\"\n >\n {{ t.label }}\n </button>\n }\n <div class=\"mt-1 flex items-center gap-1 border-t pt-2\">\n <input\n type=\"text\"\n class=\"h-8 min-w-0 flex-1 rounded-md border bg-background px-2 text-sm outline-none focus:ring-1 focus:ring-ring\"\n [placeholder]=\"ctx.locale().promptPlaceholder\"\n [attr.aria-label]=\"ctx.locale().promptPlaceholder\"\n [value]=\"customPrompt()\"\n (input)=\"onCustomInput($event)\"\n (keydown.enter)=\"runCustom()\"\n (mousedown)=\"$event.stopPropagation()\"\n />\n <ui-button size=\"sm\" [disabled]=\"!customPrompt().trim()\" (click)=\"runCustom()\">{{ ctx.locale().go }}</ui-button>\n </div>\n </div>\n } @else {\n <div class=\"flex flex-col gap-2\" data-slot=\"rich-text-ai-review\">\n @if (ctx.phase() === 'loading') {\n <output\n class=\"block px-1 text-xs text-muted-foreground\"\n aria-live=\"polite\"\n data-slot=\"rich-text-ai-loading\"\n >{{ ctx.locale().generating }}</output>\n }\n @if (ctx.errorMessage()) {\n <p class=\"px-1 text-xs text-destructive\" role=\"alert\" data-slot=\"rich-text-ai-error\">{{ ctx.errorMessage() }}</p>\n }\n <div class=\"flex flex-wrap gap-1\">\n <ui-button size=\"sm\" [disabled]=\"ctx.phase() === 'loading'\" (click)=\"ctx.accept()\">{{ ctx.locale().accept }}</ui-button>\n <ui-button size=\"sm\" variant=\"outline\" (click)=\"ctx.discard()\">{{ ctx.locale().discard }}</ui-button>\n <ui-button size=\"sm\" variant=\"ghost\" [disabled]=\"ctx.phase() === 'loading'\" (click)=\"ctx.retryLast()\">{{ ctx.locale().retry }}</ui-button>\n </div>\n </div>\n }\n </div>\n}\n" }]
23825
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
23764
23826
 
23765
23827
  const CHIP_OFFSET_Y = 40;
23766
23828
  const PANEL_OFFSET_Y = 8;
@@ -24317,8 +24379,14 @@ function parseHex(input) {
24317
24379
  }
24318
24380
  return null;
24319
24381
  }
24382
+ /**
24383
+ * `scale` is the value 100% stands for. CSS Color 4 `none` is a missing
24384
+ * component, which converts as 0.
24385
+ */
24320
24386
  function parseChannel(s, scale) {
24321
24387
  const t = s.trim();
24388
+ if (t === 'none')
24389
+ return 0;
24322
24390
  if (t.endsWith('%')) {
24323
24391
  return (Number.parseFloat(t) / 100) * scale;
24324
24392
  }
@@ -24339,6 +24407,31 @@ function parseRgbFunc(input) {
24339
24407
  return null;
24340
24408
  return { r: clamp255(r), g: clamp255(g), b: clamp255(b), a: clamp01(a) };
24341
24409
  }
24410
+ const DEGREES_PER_ANGLE_UNIT = {
24411
+ deg: 1,
24412
+ grad: 0.9,
24413
+ rad: 180 / Math.PI,
24414
+ turn: 360,
24415
+ };
24416
+ /**
24417
+ * Chroma that 100% stands for in CSS Color 4's `oklch()`; the other
24418
+ * percentage references are 100 for `hsl()` s/l and 1 for lightness/alpha.
24419
+ */
24420
+ const OKLCH_CHROMA_AT_100_PERCENT = 0.4;
24421
+ /**
24422
+ * A CSS `<hue>` in degrees: a bare number (degrees), a number with a
24423
+ * `deg` / `grad` / `rad` / `turn` unit, or `none`. NaN when it is none of those.
24424
+ */
24425
+ function parseHue(token) {
24426
+ if (token === 'none')
24427
+ return 0;
24428
+ // 'grad' is tried before its suffix 'rad'.
24429
+ const unit = Object.keys(DEGREES_PER_ANGLE_UNIT).find(u => token.endsWith(u));
24430
+ const digits = unit ? token.slice(0, -unit.length) : token;
24431
+ if (!/^[+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/.test(digits))
24432
+ return Number.NaN;
24433
+ return Number(digits) * DEGREES_PER_ANGLE_UNIT[unit ?? 'deg'];
24434
+ }
24342
24435
  function parseHslFunc(input) {
24343
24436
  const m = /^hsla?\(([^)]+)\)$/i.exec(input.trim());
24344
24437
  if (!m)
@@ -24346,9 +24439,9 @@ function parseHslFunc(input) {
24346
24439
  const parts = m[1].split(/[\s,/]+/).filter(Boolean);
24347
24440
  if (parts.length < 3)
24348
24441
  return null;
24349
- const h = Number.parseFloat(parts[0]);
24350
- const s = Number.parseFloat(parts[1]);
24351
- const l = Number.parseFloat(parts[2]);
24442
+ const h = parseHue(parts[0]);
24443
+ const s = parseChannel(parts[1], 100);
24444
+ const l = parseChannel(parts[2], 100);
24352
24445
  const a = parts.length >= 4 ? parseChannel(parts[3], 1) : 1;
24353
24446
  if ([h, s, l, a].some(Number.isNaN))
24354
24447
  return null;
@@ -24362,10 +24455,9 @@ function parseOklchFunc(input) {
24362
24455
  const parts = m[1].split(/[\s,/]+/).filter(Boolean);
24363
24456
  if (parts.length < 3)
24364
24457
  return null;
24365
- const lStr = parts[0];
24366
- const l = lStr.endsWith('%') ? Number.parseFloat(lStr) / 100 : Number.parseFloat(lStr);
24367
- const c = Number.parseFloat(parts[1]);
24368
- const h = Number.parseFloat(parts[2]);
24458
+ const l = parseChannel(parts[0], 1);
24459
+ const c = Math.max(0, parseChannel(parts[1], OKLCH_CHROMA_AT_100_PERCENT));
24460
+ const h = parseHue(parts[2]);
24369
24461
  const a = parts.length >= 4 ? parseChannel(parts[3], 1) : 1;
24370
24462
  if ([l, c, h, a].some(Number.isNaN))
24371
24463
  return null;
@@ -24450,6 +24542,15 @@ function roundTo(v, places) {
24450
24542
  return Math.round(v * f) / f;
24451
24543
  }
24452
24544
  function rgbToHsl(c) {
24545
+ const exact = rgbToHslExact(c);
24546
+ return { h: Math.round(exact.h), s: Math.round(exact.s), l: Math.round(exact.l) };
24547
+ }
24548
+ /**
24549
+ * {@link rgbToHsl} without rounding (h in degrees, s and l in percent), for
24550
+ * callers that interpolate: rounding to whole degrees first would add up to
24551
+ * half a degree of hue error at each endpoint.
24552
+ */
24553
+ function rgbToHslExact(c) {
24453
24554
  const r = c.r / 255;
24454
24555
  const g = c.g / 255;
24455
24556
  const b = c.b / 255;
@@ -24463,7 +24564,7 @@ function rgbToHsl(c) {
24463
24564
  s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
24464
24565
  h = hueFromMaxChannel(r, g, b, max, d);
24465
24566
  }
24466
- return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) };
24567
+ return { h: h * 360, s: s * 100, l: l * 100 };
24467
24568
  }
24468
24569
  function hueFromMaxChannel(r, g, b, max, d) {
24469
24570
  if (max === r)
@@ -24618,14 +24719,23 @@ const WHITE = { r: 255, g: 255, b: 255 };
24618
24719
  * `color-contrast` failure. Deriving the foreground from the background's
24619
24720
  * luminance keeps the caller's colour and makes the text legible on all of them.
24620
24721
  *
24621
- * Falls back to white when `background` cannot be parsed.
24722
+ * A translucent `background` is judged as it is seen: composited over
24723
+ * `backdrop` (assumed opaque; its own alpha is ignored). The backdrop defaults
24724
+ * to white and falls back to it when unparseable.
24725
+ *
24726
+ * Falls back to white text when `background` cannot be parsed.
24622
24727
  */
24623
- function readableForeground(background) {
24728
+ function readableForeground(background, backdrop = '#ffffff') {
24624
24729
  const bg = parseColor(background);
24625
24730
  if (!bg)
24626
24731
  return '#ffffff';
24627
- const rgb = { r: bg.r, g: bg.g, b: bg.b };
24628
- return contrastRatio(rgb, BLACK) >= contrastRatio(rgb, WHITE) ? '#000000' : '#ffffff';
24732
+ const seen = compositeOver(bg, parseColor(backdrop) ?? WHITE);
24733
+ return contrastRatio(seen, BLACK) >= contrastRatio(seen, WHITE) ? '#000000' : '#ffffff';
24734
+ }
24735
+ /** Unrounded so a near-tie contrast decision is not flipped by 8-bit rounding. */
24736
+ function compositeOver(fg, backdrop) {
24737
+ const over = (f, b) => f * fg.a + b * (1 - fg.a);
24738
+ return { r: over(fg.r, backdrop.r), g: over(fg.g, backdrop.g), b: over(fg.b, backdrop.b) };
24629
24739
  }
24630
24740
  function rotateHue(c, deltaDeg) {
24631
24741
  const hsl = rgbToHsl(c);
@@ -24662,6 +24772,9 @@ class PopoverComponent {
24662
24772
  this.portalEl = el;
24663
24773
  }
24664
24774
  constructor() {
24775
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
24776
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
24777
+ this.classes = computed(() => cn('relative inline-block', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
24665
24778
  this.el = inject(ElementRef);
24666
24779
  this.document = inject(DOCUMENT);
24667
24780
  this.destroyRef = inject(DestroyRef);
@@ -24763,7 +24876,7 @@ class PopoverComponent {
24763
24876
  return this.el.nativeElement.querySelector('[data-slot="popover-trigger"]');
24764
24877
  }
24765
24878
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24766
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: PopoverComponent, isStandalone: true, selector: "ui-popover", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, closeOnScroll: { classPropertyName: "closeOnScroll", publicName: "closeOnScroll", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { classAttribute: "relative inline-block" }, providers: [{ provide: POPOVER, useExisting: forwardRef(() => PopoverComponent) }], ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
24879
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: PopoverComponent, isStandalone: true, selector: "ui-popover", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, closeOnScroll: { classPropertyName: "closeOnScroll", publicName: "closeOnScroll", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-slot": "popover" }, properties: { "class": "classes()" } }, providers: [{ provide: POPOVER, useExisting: forwardRef(() => PopoverComponent) }], ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
24767
24880
  }
24768
24881
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PopoverComponent, decorators: [{
24769
24882
  type: Component,
@@ -24772,12 +24885,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
24772
24885
  changeDetection: ChangeDetectionStrategy.OnPush,
24773
24886
  providers: [{ provide: POPOVER, useExisting: forwardRef(() => PopoverComponent) }],
24774
24887
  template: `<ng-content />`,
24775
- host: { class: 'relative inline-block' },
24888
+ // Static, not bound: a template `data-slot` (tree-select sets its own on this host) must win.
24889
+ host: { '[class]': 'classes()', 'data-slot': 'popover' },
24776
24890
  }]
24777
- }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], closeOnScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnScroll", required: false }] }] } });
24891
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], closeOnScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnScroll", required: false }] }] } });
24778
24892
 
24779
24893
  class PopoverTriggerComponent {
24780
24894
  constructor() {
24895
+ /** Extra classes for the element that wraps the projected trigger. */
24896
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
24781
24897
  this.popover = inject(POPOVER, { optional: true });
24782
24898
  this.host = inject(ElementRef);
24783
24899
  /**
@@ -24809,8 +24925,9 @@ class PopoverTriggerComponent {
24809
24925
  this.popover?.toggle();
24810
24926
  }
24811
24927
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PopoverTriggerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24812
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: PopoverTriggerComponent, isStandalone: true, selector: "ui-popover-trigger", host: { classAttribute: "contents" }, ngImport: i0, template: `
24928
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: PopoverTriggerComponent, isStandalone: true, selector: "ui-popover-trigger", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
24813
24929
  <span
24930
+ [class]="class()"
24814
24931
  [attr.role]="wrapsInteractive() ? null : 'button'"
24815
24932
  [attr.tabindex]="wrapsInteractive() ? null : 0"
24816
24933
  (click)="onClick($event)"
@@ -24829,6 +24946,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
24829
24946
  changeDetection: ChangeDetectionStrategy.OnPush,
24830
24947
  template: `
24831
24948
  <span
24949
+ [class]="class()"
24832
24950
  [attr.role]="wrapsInteractive() ? null : 'button'"
24833
24951
  [attr.tabindex]="wrapsInteractive() ? null : 0"
24834
24952
  (click)="onClick($event)"
@@ -24841,7 +24959,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
24841
24959
  `,
24842
24960
  host: { class: 'contents' },
24843
24961
  }]
24844
- }], ctorParameters: () => [] });
24962
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
24845
24963
 
24846
24964
  class PopoverContentComponent {
24847
24965
  constructor() {
@@ -24878,6 +24996,7 @@ class PopoverContentComponent {
24878
24996
  this.portalHost = null;
24879
24997
  this.usedPopoverApi = false;
24880
24998
  this.wasOpen = false;
24999
+ this.destroyed = false;
24881
25000
  this.portalReady = signal(false, ...(ngDevMode ? [{ debugName: "portalReady" }] : /* istanbul ignore next */ []));
24882
25001
  /**
24883
25002
  * Trigger geometry captured on a settled frame. `positionStyles` reads this
@@ -24966,7 +25085,7 @@ class PopoverContentComponent {
24966
25085
  this.calculatePosition();
24967
25086
  }
24968
25087
  portalAndPosition(attempt) {
24969
- if (!this.popover?.open())
25088
+ if (this.destroyed || !this.popover?.open())
24970
25089
  return;
24971
25090
  const placed = this.placeContent();
24972
25091
  if (!placed && this.strategy() === 'fixed' && attempt < 10) {
@@ -24991,11 +25110,11 @@ class PopoverContentComponent {
24991
25110
  * adjustment runs and the content is revealed.
24992
25111
  */
24993
25112
  finalizeFixedPosition() {
24994
- if (!this.popover?.open())
25113
+ if (this.destroyed || !this.popover?.open())
24995
25114
  return;
24996
25115
  this.triggerRectSig.set(this.popover.getTriggerRect());
24997
25116
  requestAnimationFrame(() => {
24998
- if (!this.popover?.open())
25117
+ if (this.destroyed || !this.popover?.open())
24999
25118
  return;
25000
25119
  this.triggerRectSig.set(this.popover.getTriggerRect());
25001
25120
  const el = this.contentEl?.nativeElement;
@@ -25005,6 +25124,9 @@ class PopoverContentComponent {
25005
25124
  });
25006
25125
  }
25007
25126
  ngOnDestroy() {
25127
+ // Destroying the content does not close the popover, so `open()` is still true when a frame
25128
+ // scheduled at open fires; without this flag that frame portals the detached panel into <body>.
25129
+ this.destroyed = true;
25008
25130
  this.removeContent();
25009
25131
  }
25010
25132
  /**
@@ -25243,6 +25365,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
25243
25365
 
25244
25366
  class PopoverCloseComponent {
25245
25367
  constructor() {
25368
+ /** Extra classes for the element that wraps the projected trigger. */
25369
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
25246
25370
  this.popover = inject(POPOVER, { optional: true });
25247
25371
  this.host = inject(ElementRef);
25248
25372
  /** See `lib/a11y.ts` — stays transparent when the projected content is already a control. */
@@ -25267,8 +25391,9 @@ class PopoverCloseComponent {
25267
25391
  this.onClick();
25268
25392
  }
25269
25393
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PopoverCloseComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
25270
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: PopoverCloseComponent, isStandalone: true, selector: "ui-popover-close", host: { classAttribute: "contents" }, ngImport: i0, template: `
25394
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: PopoverCloseComponent, isStandalone: true, selector: "ui-popover-close", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
25271
25395
  <span
25396
+ [class]="class()"
25272
25397
  [attr.role]="wrapsInteractive() ? null : 'button'"
25273
25398
  [attr.tabindex]="wrapsInteractive() ? null : 0"
25274
25399
  (click)="onClick()"
@@ -25287,6 +25412,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
25287
25412
  changeDetection: ChangeDetectionStrategy.OnPush,
25288
25413
  template: `
25289
25414
  <span
25415
+ [class]="class()"
25290
25416
  [attr.role]="wrapsInteractive() ? null : 'button'"
25291
25417
  [attr.tabindex]="wrapsInteractive() ? null : 0"
25292
25418
  (click)="onClick()"
@@ -25299,7 +25425,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
25299
25425
  `,
25300
25426
  host: { class: 'contents' },
25301
25427
  }]
25302
- }], ctorParameters: () => [] });
25428
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
25303
25429
 
25304
25430
  const COLOR_PICKER_LOCALES = {
25305
25431
  en: {
@@ -26071,50 +26197,58 @@ function vboxLongestAxis(box) {
26071
26197
  function vboxVolume(box) {
26072
26198
  return (box.rMax - box.rMin + 1) * (box.gMax - box.gMin + 1) * (box.bMax - box.bMin + 1);
26073
26199
  }
26200
+ /**
26201
+ * Splits along the longest axis at the median pixel (Heckbert), so both halves
26202
+ * hold about as many pixels. Pixels of one value stay together, so the cut
26203
+ * moves to the nearest change of value; null when the box is a single colour.
26204
+ */
26074
26205
  function splitVBox(box) {
26075
26206
  if (box.pixels.length < 2)
26076
26207
  return null;
26077
26208
  const axis = vboxLongestAxis(box);
26078
- const [min, max] = axisRange(box, axis);
26079
- if (max === min)
26209
+ const sorted = [...box.pixels].sort((a, b) => a[axis] - b[axis]);
26210
+ const cut = nearestValueChange(sorted, axis, sorted.length >> 1);
26211
+ if (cut === null)
26080
26212
  return null;
26081
- const midValue = (min + max) / 2;
26082
- const left = [];
26083
- const right = [];
26084
- for (const p of box.pixels) {
26085
- if (p[axis] <= midValue)
26086
- left.push(p);
26087
- else
26088
- right.push(p);
26089
- }
26090
- if (left.length === 0 || right.length === 0)
26091
- return null;
26092
- return [makeVBox(left), makeVBox(right)];
26213
+ return [makeVBox(sorted.slice(0, cut)), makeVBox(sorted.slice(cut))];
26093
26214
  }
26094
- function axisRange(box, axis) {
26095
- if (axis === 'r')
26096
- return [box.rMin, box.rMax];
26097
- if (axis === 'g')
26098
- return [box.gMin, box.gMax];
26099
- return [box.bMin, box.bMax];
26215
+ /** Index `i` closest to `target` with `sorted[i]` and `sorted[i - 1]` differing on `axis`, or null. */
26216
+ function nearestValueChange(sorted, axis, target) {
26217
+ const changesAt = (i) => i >= 1 && i < sorted.length && sorted[i][axis] !== sorted[i - 1][axis];
26218
+ for (let distance = 0; distance < sorted.length; distance++) {
26219
+ if (changesAt(target - distance))
26220
+ return target - distance;
26221
+ if (changesAt(target + distance))
26222
+ return target + distance;
26223
+ }
26224
+ return null;
26100
26225
  }
26101
26226
  function medianCutPalette(pixels, count) {
26102
26227
  if (count <= 1)
26103
26228
  return [averageColor(pixels)];
26104
- const boxes = [makeVBox(pixels)];
26105
- while (boxes.length < count) {
26106
- boxes.sort((a, b) => vboxVolume(b) * b.pixels.length - vboxVolume(a) * a.pixels.length);
26107
- const target = boxes.shift();
26108
- if (!target)
26109
- break;
26229
+ const splittable = [makeVBox(pixels)];
26230
+ const single = [];
26231
+ while (splittable.length + single.length < count && splittable.length > 0) {
26232
+ splittable.sort((a, b) => vboxVolume(b) * b.pixels.length - vboxVolume(a) * a.pixels.length);
26233
+ const [target] = splittable.splice(0, 1);
26110
26234
  const split = splitVBox(target);
26111
- if (!split) {
26112
- boxes.push(target);
26113
- break;
26235
+ if (split) {
26236
+ splittable.push(...split);
26237
+ }
26238
+ else {
26239
+ // A single flat colour must not stop the boxes that can still split.
26240
+ single.push(target);
26114
26241
  }
26115
- boxes.push(split[0], split[1]);
26116
26242
  }
26117
- return boxes.map(b => averageColor(b.pixels));
26243
+ return [...splittable, ...single].sort(byDominance).map(b => averageColor(b.pixels));
26244
+ }
26245
+ /**
26246
+ * Most pixels first, so the palette's first colour is the dominant one; equal
26247
+ * populations fall back to the box's channel minimums so the order never
26248
+ * depends on the order the splits happened in.
26249
+ */
26250
+ function byDominance(a, b) {
26251
+ return b.pixels.length - a.pixels.length || a.rMin - b.rMin || a.gMin - b.gMin || a.bMin - b.bMin;
26118
26252
  }
26119
26253
  function averageColor(pixels) {
26120
26254
  let r = 0, g = 0, b = 0;
@@ -28278,7 +28412,7 @@ class TooltipContentComponent {
28278
28412
  left: 'right-full top-1/2 -translate-y-1/2 mr-2',
28279
28413
  right: 'left-full top-1/2 -translate-y-1/2 ml-2',
28280
28414
  };
28281
- return cn('absolute z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground', sideClasses[side], this.class());
28415
+ return cn('absolute z-50 w-max max-w-[calc(100vw-2rem)] break-words overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground', sideClasses[side], this.class());
28282
28416
  }, ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
28283
28417
  }
28284
28418
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: TooltipContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
@@ -28293,6 +28427,9 @@ const TOUCH_AUTO_DISMISS_MS = 2500;
28293
28427
  const TOOLTIP = new InjectionToken('TOOLTIP');
28294
28428
  class TooltipComponent {
28295
28429
  constructor() {
28430
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
28431
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
28432
+ this.classes = computed(() => cn('relative inline-block', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
28296
28433
  this.open = signal(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
28297
28434
  /**
28298
28435
  * Simple mode: the tooltip text. When set, a `ui-tooltip-content` is
@@ -28328,7 +28465,7 @@ class TooltipComponent {
28328
28465
  this.open.set(false);
28329
28466
  }
28330
28467
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
28331
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: TooltipComponent, isStandalone: true, selector: "ui-tooltip", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, delayDuration: { classPropertyName: "delayDuration", publicName: "delayDuration", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "relative inline-block" }, providers: [{ provide: TOOLTIP, useExisting: forwardRef(() => TooltipComponent) }], ngImport: i0, template: `
28468
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: TooltipComponent, isStandalone: true, selector: "ui-tooltip", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, delayDuration: { classPropertyName: "delayDuration", publicName: "delayDuration", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"tooltip\"" } }, providers: [{ provide: TOOLTIP, useExisting: forwardRef(() => TooltipComponent) }], ngImport: i0, template: `
28332
28469
  <ng-content />
28333
28470
  @if (content()) {
28334
28471
  <ui-tooltip-content>{{ content() }}</ui-tooltip-content>
@@ -28348,12 +28485,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
28348
28485
  <ui-tooltip-content>{{ content() }}</ui-tooltip-content>
28349
28486
  }
28350
28487
  `,
28351
- host: { class: 'relative inline-block' },
28488
+ host: { '[class]': 'classes()', '[attr.data-slot]': '"tooltip"' },
28352
28489
  }]
28353
- }], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], delayDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "delayDuration", required: false }] }] } });
28490
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], delayDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "delayDuration", required: false }] }] } });
28354
28491
 
28355
28492
  class TooltipTriggerComponent {
28356
28493
  constructor() {
28494
+ /** Extra classes for the element that wraps the projected trigger. */
28495
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
28357
28496
  this.tooltip = inject(TooltipComponent, { optional: true });
28358
28497
  this.zone = inject(NgZone);
28359
28498
  this.host = inject(ElementRef).nativeElement;
@@ -28448,8 +28587,9 @@ class TooltipTriggerComponent {
28448
28587
  }
28449
28588
  }
28450
28589
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: TooltipTriggerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
28451
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: TooltipTriggerComponent, isStandalone: true, selector: "ui-tooltip-trigger", host: { classAttribute: "contents" }, ngImport: i0, template: `
28590
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: TooltipTriggerComponent, isStandalone: true, selector: "ui-tooltip-trigger", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
28452
28591
  <span
28592
+ [class]="class()"
28453
28593
  (mouseenter)="onMouseEnter()"
28454
28594
  (mouseleave)="onMouseLeave()"
28455
28595
  (touchstart)="onTouchStart()"
@@ -28468,6 +28608,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
28468
28608
  changeDetection: ChangeDetectionStrategy.OnPush,
28469
28609
  template: `
28470
28610
  <span
28611
+ [class]="class()"
28471
28612
  (mouseenter)="onMouseEnter()"
28472
28613
  (mouseleave)="onMouseLeave()"
28473
28614
  (touchstart)="onTouchStart()"
@@ -28480,7 +28621,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
28480
28621
  `,
28481
28622
  host: { class: 'contents' },
28482
28623
  }]
28483
- }] });
28624
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
28484
28625
 
28485
28626
  class TooltipDirective {
28486
28627
  constructor() {
@@ -28599,7 +28740,7 @@ class TooltipDirective {
28599
28740
  const tooltipEl = this.renderer.createElement('div');
28600
28741
  const text = this.renderer.createText(this.uiTooltip());
28601
28742
  this.renderer.appendChild(tooltipEl, text);
28602
- this.renderer.setAttribute(tooltipEl, 'class', 'fixed z-50 whitespace-nowrap rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground pointer-events-none');
28743
+ this.renderer.setAttribute(tooltipEl, 'class', 'fixed z-50 w-max max-w-[calc(100vw-2rem)] break-words rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground pointer-events-none');
28603
28744
  this.renderer.appendChild(document.body, tooltipEl);
28604
28745
  inheritThemeTokens(this.el.nativeElement, tooltipEl);
28605
28746
  return tooltipEl;
@@ -29332,7 +29473,7 @@ class ColorPickerComponent {
29332
29473
  useExisting: forwardRef(() => ColorPickerComponent),
29333
29474
  multi: true,
29334
29475
  },
29335
- ], viewQueries: [{ propertyName: "colorArea", first: true, predicate: ["colorArea"], descendants: true, isSignal: true }, { propertyName: "imageFile", first: true, predicate: ["imageFile"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #colorPanel>\n <div class=\"flex flex-col gap-3\">\n\n @if (enableEyedropper() || enableImagePick()) {\n <div class=\"flex items-center justify-end gap-1\">\n @if (enableEyedropper()) {\n <ui-eyedropper\n variant=\"icon\"\n [fallbackTarget]=\"fallbackTarget()\"\n (colorPick)=\"onEyedropperPick($event)\"\n uiTooltip=\"Pick color from screen\"\n />\n }\n @if (enableImagePick()) {\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-9 items-center justify-center rounded-md border border-input bg-background text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n (click)=\"openImagePicker()\"\n [attr.aria-label]=\"t().pickColorFromImage\"\n data-slot=\"image-pick-trigger\"\n uiTooltip=\"Pick color from image\"\n >\n <ui-icon name=\"pipette-image\" class=\"h-4 w-4\" />\n </button>\n <input\n #imageFile\n type=\"file\"\n accept=\"image/*\"\n hidden\n (change)=\"onImageSelected($event)\"\n />\n }\n </div>\n }\n\n <div\n #colorArea\n class=\"relative h-32 w-full cursor-crosshair rounded-md outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n style=\"touch-action: none\"\n [style.background]=\"areaBackground()\"\n tabindex=\"0\"\n role=\"slider\"\n [attr.aria-label]=\"t().saturationValue\"\n [attr.aria-valuenow]=\"saturation()\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-valuetext]=\"'S ' + saturation() + '%, V ' + hsvValue() + '%'\"\n (mousedown)=\"onAreaMouseDown($event)\"\n (touchstart)=\"onAreaTouchStart($event)\"\n (keydown)=\"onAreaKeyDown($event)\"\n >\n <div\n class=\"absolute h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm pointer-events-none\"\n [style.left.%]=\"saturation()\"\n [style.top.%]=\"100 - hsvValue()\"\n [style.backgroundColor]=\"currentColor()\"\n ></div>\n </div>\n\n <div class=\"space-y-1\">\n <label for=\"ui-color-picker-hue\" class=\"text-xs text-muted-foreground\">Hue</label>\n <input\n id=\"ui-color-picker-hue\"\n type=\"range\"\n min=\"0\"\n max=\"360\"\n [value]=\"hue()\"\n (input)=\"onHueChange($event)\"\n [attr.aria-label]=\"t().hue\"\n class=\"w-full h-3 rounded-md cursor-pointer appearance-none\"\n [style.background]=\"hueGradient\"\n />\n </div>\n\n @if (alpha()) {\n <div class=\"space-y-1\">\n <label for=\"ui-color-picker-alpha\" class=\"text-xs text-muted-foreground\">Alpha</label>\n <div class=\"relative h-3 w-full rounded-md ui-color-picker-checker\">\n <input\n id=\"ui-color-picker-alpha\"\n type=\"range\"\n min=\"0\"\n max=\"100\"\n step=\"1\"\n [value]=\"alphaValue() * 100\"\n (input)=\"onAlphaChange($event)\"\n [attr.aria-label]=\"t().alpha\"\n class=\"absolute inset-0 w-full h-3 rounded-md cursor-pointer appearance-none\"\n [style.background]=\"alphaGradient()\"\n />\n </div>\n </div>\n }\n\n @if (showRecent() && recents().length > 0) {\n <fieldset class=\"space-y-1 border-0 p-0 m-0\">\n <legend class=\"text-xs text-muted-foreground p-0\">{{ t().recent }}</legend>\n <ul class=\"flex flex-wrap gap-1 list-none p-0 m-0\" [attr.aria-label]=\"t().recentColors\">\n @for (color of recents(); track color) {\n <li>\n <button\n type=\"button\"\n class=\"aspect-square w-6 rounded border cursor-pointer hover:scale-110 transition-transform ui-color-picker-checker\"\n [style.backgroundColor]=\"color\"\n (click)=\"selectPreset(color)\"\n [attr.aria-label]=\"'Apply recent ' + color\"\n ></button>\n </li>\n }\n </ul>\n </fieldset>\n }\n\n @if (extractedPalette().length > 0) {\n <fieldset class=\"space-y-1 border-0 p-0 m-0\">\n <div class=\"flex items-center justify-between\">\n <legend class=\"text-xs text-muted-foreground p-0\">From image</legend>\n <button\n type=\"button\"\n class=\"text-xs text-muted-foreground hover:text-foreground\"\n (click)=\"clearExtractedPalette()\"\n >Clear</button>\n </div>\n <ul class=\"flex flex-wrap gap-1 list-none p-0 m-0\" [attr.aria-label]=\"t().extractedPalette\">\n @for (color of extractedPalette(); track color) {\n <li>\n <button\n type=\"button\"\n class=\"aspect-square w-6 rounded border cursor-pointer hover:scale-110 transition-transform\"\n [style.backgroundColor]=\"color\"\n (click)=\"applyExtracted(color)\"\n [attr.aria-label]=\"'Apply extracted ' + color\"\n ></button>\n </li>\n }\n </ul>\n </fieldset>\n }\n\n @if (presets().length > 0) {\n <fieldset class=\"space-y-1 border-0 p-0 m-0\">\n <legend class=\"text-xs text-muted-foreground p-0\">Presets</legend>\n <div class=\"flex flex-wrap gap-1\">\n @for (color of presets(); track color) {\n <button\n type=\"button\"\n data-color-btn\n class=\"aspect-square w-6 rounded border cursor-pointer hover:scale-110 transition-transform\"\n [style.backgroundColor]=\"color\"\n [class.ring-2]=\"currentColor() === color\"\n [class.ring-primary]=\"currentColor() === color\"\n (click)=\"selectPreset(color)\"\n [attr.aria-label]=\"'Select ' + color\"\n ></button>\n }\n </div>\n </fieldset>\n }\n\n @if (showHarmonies()) {\n <fieldset class=\"space-y-1 border-0 p-0 m-0\">\n <legend class=\"text-xs text-muted-foreground p-0\">Harmonies</legend>\n <div class=\"space-y-1\">\n @for (group of harmonyGroups(); track group.label) {\n <div class=\"flex items-center gap-2\">\n <span\n class=\"w-20 text-[10px] text-muted-foreground cursor-help underline decoration-dotted underline-offset-2\"\n [uiTooltip]=\"group.hint\"\n >{{ group.label }}</span>\n <div class=\"flex items-center gap-1\">\n @for (color of group.swatches; track color) {\n <button\n type=\"button\"\n class=\"relative aspect-square w-5 rounded border cursor-pointer hover:scale-110 transition-transform\"\n [style.backgroundColor]=\"color\"\n (click)=\"copyHarmony(color)\"\n [uiTooltip]=\"copiedHarmony() === color ? 'Copied ' + color : 'Click to copy ' + color\"\n [attr.aria-label]=\"'Copy ' + color\"\n >\n @if (copiedHarmony() === color) {\n <span class=\"absolute inset-0 flex items-center justify-center rounded bg-foreground/80 text-background\">\n <ui-icon name=\"check\" class=\"h-3 w-3\" />\n </span>\n }\n </button>\n }\n @if (copiedHarmony(); as copied) {\n @if (groupContains(group, copied)) {\n <span class=\"ml-1 inline-flex items-center gap-1 rounded bg-green-500/15 px-1.5 py-0.5 text-[10px] font-medium text-green-700 dark:text-green-300\">\n <ui-icon name=\"check\" class=\"h-3 w-3\" />\n {{ copied }}\n </span>\n }\n }\n </div>\n </div>\n }\n </div>\n </fieldset>\n }\n\n @if (showContrast() && contrastBadge(); as badge) {\n <div class=\"mt-3 flex items-center justify-between gap-2 rounded-md border border-input px-2 py-1.5\">\n <div class=\"flex items-center gap-2 min-w-0\">\n <button\n type=\"button\"\n class=\"flex flex-col items-center gap-0.5 rounded p-1 transition focus:outline-none\"\n [class.ring-2]=\"compareActive() === 'a'\"\n [class.ring-ring]=\"compareActive() === 'a'\"\n (click)=\"setCompareSlot('a')\"\n uiTooltip=\"Edit color A with the picker above\"\n [attr.aria-label]=\"t().editColorA\"\n >\n <span\n class=\"block h-6 w-6 rounded border\"\n [style.backgroundColor]=\"compareAHex()\"\n ></span>\n <span class=\"font-mono text-[9px] text-muted-foreground\">{{ compareAHex() }}</span>\n </button>\n <span class=\"text-xs text-muted-foreground shrink-0\">vs</span>\n <button\n type=\"button\"\n class=\"flex flex-col items-center gap-0.5 rounded p-1 transition focus:outline-none\"\n [class.ring-2]=\"compareActive() === 'b'\"\n [class.ring-ring]=\"compareActive() === 'b'\"\n (click)=\"setCompareSlot('b')\"\n uiTooltip=\"Edit color B with the picker above\"\n [attr.aria-label]=\"t().editColorB\"\n >\n <span\n class=\"block h-6 w-6 rounded border\"\n [style.backgroundColor]=\"compareBHex()\"\n ></span>\n <span class=\"font-mono text-[9px] text-muted-foreground\">{{ compareBHex() }}</span>\n </button>\n </div>\n <div class=\"flex items-center gap-2 shrink-0\">\n <span class=\"font-mono text-xs\">{{ contrastRatioDisplay() }}:1</span>\n <span\n class=\"rounded px-1.5 py-0.5 text-[10px] font-semibold\"\n [class.bg-green-500]=\"badge.pass\"\n [class.text-white]=\"badge.pass\"\n [class.bg-destructive]=\"!badge.pass\"\n [class.text-destructive-foreground]=\"!badge.pass\"\n >{{ badge.label }}</span>\n </div>\n </div>\n }\n\n <ui-tabs [defaultValue]=\"formats()[0]\">\n <ui-tabs-list class=\"flex justify-start w-full h-8 gap-1\">\n @for (fmt of formats(); track fmt) {\n <ui-tabs-trigger [value]=\"fmt\" class=\"text-xs uppercase\">{{ fmt }}</ui-tabs-trigger>\n }\n </ui-tabs-list>\n\n @if (formats().includes('hex')) {\n <ui-tabs-content value=\"hex\" class=\"mt-2\">\n <div class=\"flex items-center gap-1\">\n <ui-input\n type=\"text\"\n [ngModel]=\"formatValues().hex\"\n (ngModelChange)=\"onHexInput($event)\"\n placeholder=\"#000000\"\n class=\"h-8 text-xs font-mono flex-1\"\n />\n <button\n type=\"button\"\n class=\"inline-flex h-8 w-8 pointer-coarse:size-11 items-center justify-center rounded-md text-muted-foreground hover:text-foreground\"\n (click)=\"copy('hex')\"\n [attr.aria-label]=\"t().copyHex\"\n >\n <ui-icon [name]=\"copiedFormat() === 'hex' ? 'check' : 'copy'\" class=\"h-4 w-4\" />\n </button>\n </div>\n </ui-tabs-content>\n }\n\n @if (formats().includes('rgb')) {\n <ui-tabs-content value=\"rgb\" class=\"mt-2\">\n <div class=\"space-y-2\">\n <div class=\"grid grid-cols-3 gap-2\">\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">R</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"255\"\n [ngModel]=\"rgb().r\"\n (ngModelChange)=\"onRgbChange('r', $event)\"\n [attr.aria-label]=\"t().red\"\n class=\"h-8 text-xs\"\n />\n </div>\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">G</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"255\"\n [ngModel]=\"rgb().g\"\n (ngModelChange)=\"onRgbChange('g', $event)\"\n [attr.aria-label]=\"t().green\"\n class=\"h-8 text-xs\"\n />\n </div>\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">B</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"255\"\n [ngModel]=\"rgb().b\"\n (ngModelChange)=\"onRgbChange('b', $event)\"\n [attr.aria-label]=\"t().blue\"\n class=\"h-8 text-xs\"\n />\n </div>\n </div>\n <div class=\"flex items-center gap-1\">\n <span class=\"flex-1 truncate text-xs font-mono text-muted-foreground\">{{ formatValues().rgb }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-7 w-7 pointer-coarse:size-11 items-center justify-center rounded-md text-muted-foreground hover:text-foreground\"\n (click)=\"copy('rgb')\"\n [attr.aria-label]=\"t().copyRgb\"\n >\n <ui-icon [name]=\"copiedFormat() === 'rgb' ? 'check' : 'copy'\" class=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </ui-tabs-content>\n }\n\n @if (formats().includes('hsl')) {\n <ui-tabs-content value=\"hsl\" class=\"mt-2\">\n <div class=\"space-y-2\">\n <div class=\"grid grid-cols-3 gap-2\">\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">H</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"360\"\n [ngModel]=\"hsl().h\"\n (ngModelChange)=\"onHslHueChange($event)\"\n [attr.aria-label]=\"t().hue\"\n class=\"h-8 text-xs\"\n />\n </div>\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">S</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"100\"\n [ngModel]=\"hsl().s\"\n (ngModelChange)=\"onHslChange('s', $event)\"\n [attr.aria-label]=\"t().saturation\"\n class=\"h-8 text-xs\"\n />\n </div>\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">L</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"100\"\n [ngModel]=\"hsl().l\"\n (ngModelChange)=\"onHslChange('l', $event)\"\n [attr.aria-label]=\"t().lightness\"\n class=\"h-8 text-xs\"\n />\n </div>\n </div>\n <div class=\"flex items-center gap-1\">\n <span class=\"flex-1 truncate text-xs font-mono text-muted-foreground\">{{ formatValues().hsl }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-7 w-7 pointer-coarse:size-11 items-center justify-center rounded-md text-muted-foreground hover:text-foreground\"\n (click)=\"copy('hsl')\"\n [attr.aria-label]=\"t().copyHsl\"\n >\n <ui-icon [name]=\"copiedFormat() === 'hsl' ? 'check' : 'copy'\" class=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </ui-tabs-content>\n }\n\n @if (formats().includes('oklch')) {\n <ui-tabs-content value=\"oklch\" class=\"mt-2\">\n <div class=\"flex items-center gap-1\">\n <span class=\"flex-1 truncate text-xs font-mono text-muted-foreground\">{{ formatValues().oklch }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-7 w-7 pointer-coarse:size-11 items-center justify-center rounded-md text-muted-foreground hover:text-foreground\"\n (click)=\"copy('oklch')\"\n [attr.aria-label]=\"t().copyOklch\"\n >\n <ui-icon [name]=\"copiedFormat() === 'oklch' ? 'check' : 'copy'\" class=\"h-4 w-4\" />\n </button>\n </div>\n </ui-tabs-content>\n }\n </ui-tabs>\n </div>\n</ng-template>\n\n@if (inline()) {\n <ng-container [ngTemplateOutlet]=\"colorPanel\" />\n} @else {\n <ui-popover [open]=\"open()\" (openChange)=\"open.set($event)\" [attr.dir]=\"dir()\">\n <ui-popover-trigger>\n <ng-content select=\"[colorPickerTrigger]\" />\n @if (!hasTrigger()) {\n <button\n type=\"button\"\n [class]=\"triggerClasses()\"\n [disabled]=\"isDisabled()\"\n [attr.data-slot]=\"'color-picker-trigger'\"\n >\n <span\n class=\"h-6 w-6 rounded border ui-color-picker-checker\"\n [style.backgroundColor]=\"currentColor()\"\n ></span>\n <span class=\"flex-1 text-start text-sm truncate font-mono\">{{ currentColor() || 'Select color' }}</span>\n <ui-icon name=\"chevron-down\" class=\"h-4 w-4 opacity-50\" />\n </button>\n }\n </ui-popover-trigger>\n <ui-popover-content class=\"w-72 p-3\" align=\"start\" [restoreFocus]=\"false\">\n <ng-container [ngTemplateOutlet]=\"colorPanel\" />\n </ui-popover-content>\n </ui-popover>\n}\n", styles: [":host{--_d: var(--density-picker, var(--density, 1))}@layer components{[data-slot=color-picker-trigger]{height:calc(2.5rem * var(--_d));padding-inline:calc(.75rem * var(--_d));padding-block:calc(.5rem * var(--_d));gap:calc(.5rem * var(--_d))}.ui-color-picker-checker{background-image:linear-gradient(45deg,hsl(0 0% 80%) 25%,transparent 25%),linear-gradient(-45deg,hsl(0 0% 80%) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,hsl(0 0% 80%) 75%),linear-gradient(-45deg,transparent 75%,hsl(0 0% 80%) 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}}\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: PopoverComponent, selector: "ui-popover", inputs: ["open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger" }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: InputComponent, selector: "ui-input", inputs: ["type", "placeholder", "disabled", "class", "elementId", "name", "ariaLabel", "ariaLabelledby", "ariaDescribedby", "variant", "loading", "skeleton", "autofocus", "clearable", "floating", "label", "labelClass", "inputMode", "lang", "prefix", "suffix", "value"], outputs: ["valueChange"] }, { kind: "component", type: TabsComponent, selector: "ui-tabs", inputs: ["defaultValue", "class", "tabs"], outputs: ["tabChange"] }, { kind: "component", type: TabsListComponent, selector: "ui-tabs-list", inputs: ["class", "ariaLabel", "skeleton", "skeletonCount"] }, { kind: "component", type: TabsTriggerComponent, selector: "ui-tabs-trigger", inputs: ["value", "class"] }, { kind: "component", type: TabsContentComponent, selector: "ui-tabs-content", inputs: ["value", "class"] }, { kind: "component", type: IconComponent, selector: "ui-icon", inputs: ["name", "class", "size", "weight", "strokeWidth", "color", "fillColor"] }, { kind: "component", type: EyedropperComponent, selector: "ui-eyedropper", inputs: ["class", "disabled", "label", "variant", "locale", "fallbackTarget"], outputs: ["colorPick", "pickStart", "pickCancel"] }, { kind: "directive", type: TooltipDirective, selector: "[uiTooltip]", inputs: ["uiTooltip", "tooltipSide", "tooltipDisabled"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
29476
+ ], viewQueries: [{ propertyName: "colorArea", first: true, predicate: ["colorArea"], descendants: true, isSignal: true }, { propertyName: "imageFile", first: true, predicate: ["imageFile"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #colorPanel>\n <div class=\"flex flex-col gap-3\">\n\n @if (enableEyedropper() || enableImagePick()) {\n <div class=\"flex items-center justify-end gap-1\">\n @if (enableEyedropper()) {\n <ui-eyedropper\n variant=\"icon\"\n [fallbackTarget]=\"fallbackTarget()\"\n (colorPick)=\"onEyedropperPick($event)\"\n uiTooltip=\"Pick color from screen\"\n />\n }\n @if (enableImagePick()) {\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-9 items-center justify-center rounded-md border border-input bg-background text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n (click)=\"openImagePicker()\"\n [attr.aria-label]=\"t().pickColorFromImage\"\n data-slot=\"image-pick-trigger\"\n uiTooltip=\"Pick color from image\"\n >\n <ui-icon name=\"pipette-image\" class=\"h-4 w-4\" />\n </button>\n <input\n #imageFile\n type=\"file\"\n accept=\"image/*\"\n hidden\n (change)=\"onImageSelected($event)\"\n />\n }\n </div>\n }\n\n <div\n #colorArea\n class=\"relative h-32 w-full cursor-crosshair rounded-md outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n style=\"touch-action: none\"\n [style.background]=\"areaBackground()\"\n tabindex=\"0\"\n role=\"slider\"\n [attr.aria-label]=\"t().saturationValue\"\n [attr.aria-valuenow]=\"saturation()\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-valuetext]=\"'S ' + saturation() + '%, V ' + hsvValue() + '%'\"\n (mousedown)=\"onAreaMouseDown($event)\"\n (touchstart)=\"onAreaTouchStart($event)\"\n (keydown)=\"onAreaKeyDown($event)\"\n >\n <div\n class=\"absolute h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm pointer-events-none\"\n [style.left.%]=\"saturation()\"\n [style.top.%]=\"100 - hsvValue()\"\n [style.backgroundColor]=\"currentColor()\"\n ></div>\n </div>\n\n <div class=\"space-y-1\">\n <label for=\"ui-color-picker-hue\" class=\"text-xs text-muted-foreground\">Hue</label>\n <input\n id=\"ui-color-picker-hue\"\n type=\"range\"\n min=\"0\"\n max=\"360\"\n [value]=\"hue()\"\n (input)=\"onHueChange($event)\"\n [attr.aria-label]=\"t().hue\"\n class=\"w-full h-3 rounded-md cursor-pointer appearance-none\"\n [style.background]=\"hueGradient\"\n />\n </div>\n\n @if (alpha()) {\n <div class=\"space-y-1\">\n <label for=\"ui-color-picker-alpha\" class=\"text-xs text-muted-foreground\">Alpha</label>\n <div class=\"relative h-3 w-full rounded-md ui-color-picker-checker\">\n <input\n id=\"ui-color-picker-alpha\"\n type=\"range\"\n min=\"0\"\n max=\"100\"\n step=\"1\"\n [value]=\"alphaValue() * 100\"\n (input)=\"onAlphaChange($event)\"\n [attr.aria-label]=\"t().alpha\"\n class=\"absolute inset-0 w-full h-3 rounded-md cursor-pointer appearance-none\"\n [style.background]=\"alphaGradient()\"\n />\n </div>\n </div>\n }\n\n @if (showRecent() && recents().length > 0) {\n <fieldset class=\"space-y-1 border-0 p-0 m-0\">\n <legend class=\"text-xs text-muted-foreground p-0\">{{ t().recent }}</legend>\n <ul class=\"flex flex-wrap gap-1 list-none p-0 m-0\" [attr.aria-label]=\"t().recentColors\">\n @for (color of recents(); track color) {\n <li>\n <button\n type=\"button\"\n class=\"aspect-square w-6 rounded border cursor-pointer hover:scale-110 transition-transform ui-color-picker-checker\"\n [style.backgroundColor]=\"color\"\n (click)=\"selectPreset(color)\"\n [attr.aria-label]=\"'Apply recent ' + color\"\n ></button>\n </li>\n }\n </ul>\n </fieldset>\n }\n\n @if (extractedPalette().length > 0) {\n <fieldset class=\"space-y-1 border-0 p-0 m-0\">\n <div class=\"flex items-center justify-between\">\n <legend class=\"text-xs text-muted-foreground p-0\">From image</legend>\n <button\n type=\"button\"\n class=\"text-xs text-muted-foreground hover:text-foreground\"\n (click)=\"clearExtractedPalette()\"\n >Clear</button>\n </div>\n <ul class=\"flex flex-wrap gap-1 list-none p-0 m-0\" [attr.aria-label]=\"t().extractedPalette\">\n @for (color of extractedPalette(); track color) {\n <li>\n <button\n type=\"button\"\n class=\"aspect-square w-6 rounded border cursor-pointer hover:scale-110 transition-transform\"\n [style.backgroundColor]=\"color\"\n (click)=\"applyExtracted(color)\"\n [attr.aria-label]=\"'Apply extracted ' + color\"\n ></button>\n </li>\n }\n </ul>\n </fieldset>\n }\n\n @if (presets().length > 0) {\n <fieldset class=\"space-y-1 border-0 p-0 m-0\">\n <legend class=\"text-xs text-muted-foreground p-0\">Presets</legend>\n <div class=\"flex flex-wrap gap-1\">\n @for (color of presets(); track color) {\n <button\n type=\"button\"\n data-color-btn\n class=\"aspect-square w-6 rounded border cursor-pointer hover:scale-110 transition-transform\"\n [style.backgroundColor]=\"color\"\n [class.ring-2]=\"currentColor() === color\"\n [class.ring-primary]=\"currentColor() === color\"\n (click)=\"selectPreset(color)\"\n [attr.aria-label]=\"'Select ' + color\"\n ></button>\n }\n </div>\n </fieldset>\n }\n\n @if (showHarmonies()) {\n <fieldset class=\"space-y-1 border-0 p-0 m-0\">\n <legend class=\"text-xs text-muted-foreground p-0\">Harmonies</legend>\n <div class=\"space-y-1\">\n @for (group of harmonyGroups(); track group.label) {\n <div class=\"flex items-center gap-2\">\n <span\n class=\"w-20 text-[10px] text-muted-foreground cursor-help underline decoration-dotted underline-offset-2\"\n [uiTooltip]=\"group.hint\"\n >{{ group.label }}</span>\n <div class=\"flex items-center gap-1\">\n @for (color of group.swatches; track color) {\n <button\n type=\"button\"\n class=\"relative aspect-square w-5 rounded border cursor-pointer hover:scale-110 transition-transform\"\n [style.backgroundColor]=\"color\"\n (click)=\"copyHarmony(color)\"\n [uiTooltip]=\"copiedHarmony() === color ? 'Copied ' + color : 'Click to copy ' + color\"\n [attr.aria-label]=\"'Copy ' + color\"\n >\n @if (copiedHarmony() === color) {\n <span class=\"absolute inset-0 flex items-center justify-center rounded bg-foreground/80 text-background\">\n <ui-icon name=\"check\" class=\"h-3 w-3\" />\n </span>\n }\n </button>\n }\n @if (copiedHarmony(); as copied) {\n @if (groupContains(group, copied)) {\n <span class=\"ml-1 inline-flex items-center gap-1 rounded bg-green-500/15 px-1.5 py-0.5 text-[10px] font-medium text-green-700 dark:text-green-300\">\n <ui-icon name=\"check\" class=\"h-3 w-3\" />\n {{ copied }}\n </span>\n }\n }\n </div>\n </div>\n }\n </div>\n </fieldset>\n }\n\n @if (showContrast() && contrastBadge(); as badge) {\n <div class=\"mt-3 flex items-center justify-between gap-2 rounded-md border border-input px-2 py-1.5\">\n <div class=\"flex items-center gap-2 min-w-0\">\n <button\n type=\"button\"\n class=\"flex flex-col items-center gap-0.5 rounded p-1 transition focus:outline-none\"\n [class.ring-2]=\"compareActive() === 'a'\"\n [class.ring-ring]=\"compareActive() === 'a'\"\n (click)=\"setCompareSlot('a')\"\n uiTooltip=\"Edit color A with the picker above\"\n [attr.aria-label]=\"t().editColorA\"\n >\n <span\n class=\"block h-6 w-6 rounded border\"\n [style.backgroundColor]=\"compareAHex()\"\n ></span>\n <span class=\"font-mono text-[9px] text-muted-foreground\">{{ compareAHex() }}</span>\n </button>\n <span class=\"text-xs text-muted-foreground shrink-0\">vs</span>\n <button\n type=\"button\"\n class=\"flex flex-col items-center gap-0.5 rounded p-1 transition focus:outline-none\"\n [class.ring-2]=\"compareActive() === 'b'\"\n [class.ring-ring]=\"compareActive() === 'b'\"\n (click)=\"setCompareSlot('b')\"\n uiTooltip=\"Edit color B with the picker above\"\n [attr.aria-label]=\"t().editColorB\"\n >\n <span\n class=\"block h-6 w-6 rounded border\"\n [style.backgroundColor]=\"compareBHex()\"\n ></span>\n <span class=\"font-mono text-[9px] text-muted-foreground\">{{ compareBHex() }}</span>\n </button>\n </div>\n <div class=\"flex items-center gap-2 shrink-0\">\n <span class=\"font-mono text-xs\">{{ contrastRatioDisplay() }}:1</span>\n <span\n class=\"rounded px-1.5 py-0.5 text-[10px] font-semibold\"\n [class.bg-green-500]=\"badge.pass\"\n [class.text-white]=\"badge.pass\"\n [class.bg-destructive]=\"!badge.pass\"\n [class.text-destructive-foreground]=\"!badge.pass\"\n >{{ badge.label }}</span>\n </div>\n </div>\n }\n\n <ui-tabs [defaultValue]=\"formats()[0]\">\n <ui-tabs-list class=\"flex justify-start w-full h-8 gap-1\">\n @for (fmt of formats(); track fmt) {\n <ui-tabs-trigger [value]=\"fmt\" class=\"text-xs uppercase\">{{ fmt }}</ui-tabs-trigger>\n }\n </ui-tabs-list>\n\n @if (formats().includes('hex')) {\n <ui-tabs-content value=\"hex\" class=\"mt-2\">\n <div class=\"flex items-center gap-1\">\n <ui-input\n type=\"text\"\n [ngModel]=\"formatValues().hex\"\n (ngModelChange)=\"onHexInput($event)\"\n placeholder=\"#000000\"\n class=\"h-8 text-xs font-mono flex-1\"\n />\n <button\n type=\"button\"\n class=\"inline-flex h-8 w-8 pointer-coarse:size-11 items-center justify-center rounded-md text-muted-foreground hover:text-foreground\"\n (click)=\"copy('hex')\"\n [attr.aria-label]=\"t().copyHex\"\n >\n <ui-icon [name]=\"copiedFormat() === 'hex' ? 'check' : 'copy'\" class=\"h-4 w-4\" />\n </button>\n </div>\n </ui-tabs-content>\n }\n\n @if (formats().includes('rgb')) {\n <ui-tabs-content value=\"rgb\" class=\"mt-2\">\n <div class=\"space-y-2\">\n <div class=\"grid grid-cols-3 gap-2\">\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">R</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"255\"\n [ngModel]=\"rgb().r\"\n (ngModelChange)=\"onRgbChange('r', $event)\"\n [attr.aria-label]=\"t().red\"\n class=\"h-8 text-xs\"\n />\n </div>\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">G</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"255\"\n [ngModel]=\"rgb().g\"\n (ngModelChange)=\"onRgbChange('g', $event)\"\n [attr.aria-label]=\"t().green\"\n class=\"h-8 text-xs\"\n />\n </div>\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">B</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"255\"\n [ngModel]=\"rgb().b\"\n (ngModelChange)=\"onRgbChange('b', $event)\"\n [attr.aria-label]=\"t().blue\"\n class=\"h-8 text-xs\"\n />\n </div>\n </div>\n <div class=\"flex items-center gap-1\">\n <span class=\"flex-1 truncate text-xs font-mono text-muted-foreground\">{{ formatValues().rgb }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-7 w-7 pointer-coarse:size-11 items-center justify-center rounded-md text-muted-foreground hover:text-foreground\"\n (click)=\"copy('rgb')\"\n [attr.aria-label]=\"t().copyRgb\"\n >\n <ui-icon [name]=\"copiedFormat() === 'rgb' ? 'check' : 'copy'\" class=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </ui-tabs-content>\n }\n\n @if (formats().includes('hsl')) {\n <ui-tabs-content value=\"hsl\" class=\"mt-2\">\n <div class=\"space-y-2\">\n <div class=\"grid grid-cols-3 gap-2\">\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">H</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"360\"\n [ngModel]=\"hsl().h\"\n (ngModelChange)=\"onHslHueChange($event)\"\n [attr.aria-label]=\"t().hue\"\n class=\"h-8 text-xs\"\n />\n </div>\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">S</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"100\"\n [ngModel]=\"hsl().s\"\n (ngModelChange)=\"onHslChange('s', $event)\"\n [attr.aria-label]=\"t().saturation\"\n class=\"h-8 text-xs\"\n />\n </div>\n <div>\n <span class=\"text-xs text-muted-foreground\" aria-hidden=\"true\">L</span>\n <ui-input\n type=\"number\"\n min=\"0\"\n max=\"100\"\n [ngModel]=\"hsl().l\"\n (ngModelChange)=\"onHslChange('l', $event)\"\n [attr.aria-label]=\"t().lightness\"\n class=\"h-8 text-xs\"\n />\n </div>\n </div>\n <div class=\"flex items-center gap-1\">\n <span class=\"flex-1 truncate text-xs font-mono text-muted-foreground\">{{ formatValues().hsl }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-7 w-7 pointer-coarse:size-11 items-center justify-center rounded-md text-muted-foreground hover:text-foreground\"\n (click)=\"copy('hsl')\"\n [attr.aria-label]=\"t().copyHsl\"\n >\n <ui-icon [name]=\"copiedFormat() === 'hsl' ? 'check' : 'copy'\" class=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </ui-tabs-content>\n }\n\n @if (formats().includes('oklch')) {\n <ui-tabs-content value=\"oklch\" class=\"mt-2\">\n <div class=\"flex items-center gap-1\">\n <span class=\"flex-1 truncate text-xs font-mono text-muted-foreground\">{{ formatValues().oklch }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-7 w-7 pointer-coarse:size-11 items-center justify-center rounded-md text-muted-foreground hover:text-foreground\"\n (click)=\"copy('oklch')\"\n [attr.aria-label]=\"t().copyOklch\"\n >\n <ui-icon [name]=\"copiedFormat() === 'oklch' ? 'check' : 'copy'\" class=\"h-4 w-4\" />\n </button>\n </div>\n </ui-tabs-content>\n }\n </ui-tabs>\n </div>\n</ng-template>\n\n@if (inline()) {\n <ng-container [ngTemplateOutlet]=\"colorPanel\" />\n} @else {\n <ui-popover [open]=\"open()\" (openChange)=\"open.set($event)\" [attr.dir]=\"dir()\">\n <ui-popover-trigger>\n <ng-content select=\"[colorPickerTrigger]\" />\n @if (!hasTrigger()) {\n <button\n type=\"button\"\n [class]=\"triggerClasses()\"\n [disabled]=\"isDisabled()\"\n [attr.data-slot]=\"'color-picker-trigger'\"\n >\n <span\n class=\"h-6 w-6 rounded border ui-color-picker-checker\"\n [style.backgroundColor]=\"currentColor()\"\n ></span>\n <span class=\"flex-1 text-start text-sm truncate font-mono\">{{ currentColor() || 'Select color' }}</span>\n <ui-icon name=\"chevron-down\" class=\"h-4 w-4 opacity-50\" />\n </button>\n }\n </ui-popover-trigger>\n <ui-popover-content class=\"w-72 p-3\" align=\"start\" [restoreFocus]=\"false\">\n <ng-container [ngTemplateOutlet]=\"colorPanel\" />\n </ui-popover-content>\n </ui-popover>\n}\n", styles: [":host{--_d: var(--density-picker, var(--density, 1))}@layer components{[data-slot=color-picker-trigger]{height:calc(2.5rem * var(--_d));padding-inline:calc(.75rem * var(--_d));padding-block:calc(.5rem * var(--_d));gap:calc(.5rem * var(--_d))}.ui-color-picker-checker{background-image:linear-gradient(45deg,hsl(0 0% 80%) 25%,transparent 25%),linear-gradient(-45deg,hsl(0 0% 80%) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,hsl(0 0% 80%) 75%),linear-gradient(-45deg,transparent 75%,hsl(0 0% 80%) 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}}\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: PopoverComponent, selector: "ui-popover", inputs: ["class", "open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger", inputs: ["class"] }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: InputComponent, selector: "ui-input", inputs: ["type", "placeholder", "disabled", "class", "elementId", "name", "ariaLabel", "ariaLabelledby", "ariaDescribedby", "variant", "loading", "skeleton", "autofocus", "clearable", "floating", "label", "labelClass", "inputMode", "lang", "prefix", "suffix", "value"], outputs: ["valueChange"] }, { kind: "component", type: TabsComponent, selector: "ui-tabs", inputs: ["defaultValue", "class", "tabs"], outputs: ["tabChange"] }, { kind: "component", type: TabsListComponent, selector: "ui-tabs-list", inputs: ["class", "ariaLabel", "skeleton", "skeletonCount"] }, { kind: "component", type: TabsTriggerComponent, selector: "ui-tabs-trigger", inputs: ["value", "class"] }, { kind: "component", type: TabsContentComponent, selector: "ui-tabs-content", inputs: ["value", "class"] }, { kind: "component", type: IconComponent, selector: "ui-icon", inputs: ["name", "class", "size", "weight", "strokeWidth", "color", "fillColor"] }, { kind: "component", type: EyedropperComponent, selector: "ui-eyedropper", inputs: ["class", "disabled", "label", "variant", "locale", "fallbackTarget"], outputs: ["colorPick", "pickStart", "pickCancel"] }, { kind: "directive", type: TooltipDirective, selector: "[uiTooltip]", inputs: ["uiTooltip", "tooltipSide", "tooltipDisabled"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
29336
29477
  }
29337
29478
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: ColorPickerComponent, decorators: [{
29338
29479
  type: Component,
@@ -29409,11 +29550,13 @@ class RichTextColorsButtonComponent {
29409
29550
  */
29410
29551
  this.emptyIndicatorClass = this.context.kind === 'foreground' ? 'bg-foreground' : 'bg-muted-foreground/30';
29411
29552
  this.indicatorClasses = computed(() => cn('h-[3px] w-4 rounded-[1px] ring-1 ring-border', this.context.activeColor() ? '' : this.emptyIndicatorClass), ...(ngDevMode ? [{ debugName: "indicatorClasses" }] : /* istanbul ignore next */ []));
29553
+ /** Extra classes merged onto the toolbar button, after the built-in icon-button styling. */
29554
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
29412
29555
  this.buttonClasses = computed(() => cn('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors', 'hover:bg-accent hover:text-accent-foreground', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', 'disabled:pointer-events-none disabled:opacity-50',
29413
29556
  // The global (pointer: coarse) floor targets `button:not([data-slot])`,
29414
29557
  // and these addon buttons carry a data-slot for testing — so they must
29415
29558
  // state the 44px touch minimum themselves rather than inherit it.
29416
- 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5'), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
29559
+ 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5', this.class()), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
29417
29560
  inject(DestroyRef).onDestroy(() => this.exclusive.release());
29418
29561
  }
29419
29562
  /**
@@ -29447,7 +29590,7 @@ class RichTextColorsButtonComponent {
29447
29590
  this.context.onSelect(color);
29448
29591
  }
29449
29592
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextColorsButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
29450
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextColorsButtonComponent, isStandalone: true, selector: "ui-rte-colors-button", host: { listeners: { "pointerdown": "onUserInteract()", "keydown": "onUserInteract()" }, classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span class=\"flex size-4 flex-col items-center justify-between\">\n <span class=\"flex h-[13px] w-4 items-center justify-center [&>svg]:size-[13px]\" [innerHTML]=\"icon\"></span>\n <span\n data-slot=\"rte-color-indicator\"\n [class]=\"indicatorClasses()\"\n [style.background-color]=\"indicatorColor()\"\n ></span>\n </span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-72 max-w-[calc(100vw-2rem)] p-3\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium block m-0\">{{ context.heading() }}</p>\n <!-- Built fresh on each open. The popover reuses its content, so a picker\n kept alive holds the colour from the previous session; seeding it with\n the caret's colour then changes nothing, and re-picking that same\n colour emits nothing at all \u2014 the pick is silently lost. -->\n @if (open()) {\n <ui-color-picker\n [inline]=\"true\"\n [presets]=\"context.presets()\"\n [showRecent]=\"context.showRecent()\"\n [alpha]=\"context.alpha()\"\n [ngModel]=\"context.seededColor()\"\n [disabled]=\"interactionDisabled()\"\n (colorChange)=\"onColorChange($event)\"\n />\n }\n </div>\n </ui-popover-content>\n</ui-popover>\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: PopoverComponent, selector: "ui-popover", inputs: ["open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger" }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: ColorPickerComponent, selector: "ui-color-picker", inputs: ["presets", "inline", "disabled", "class", "alpha", "recentColors", "showRecent", "maxRecent", "storageKey", "enableEyedropper", "fallbackTarget", "locale", "enableImagePick", "imageExtractAlgorithm", "imageExtractCount", "showHarmonies", "showContrast", "contrastBackground", "formats", "value"], outputs: ["colorChange", "valueChange", "recentColorsChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
29593
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextColorsButtonComponent, isStandalone: true, selector: "ui-rte-colors-button", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "pointerdown": "onUserInteract()", "keydown": "onUserInteract()" }, classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span class=\"flex size-4 flex-col items-center justify-between\">\n <span class=\"flex h-[13px] w-4 items-center justify-center [&>svg]:size-[13px]\" [innerHTML]=\"icon\"></span>\n <span\n data-slot=\"rte-color-indicator\"\n [class]=\"indicatorClasses()\"\n [style.background-color]=\"indicatorColor()\"\n ></span>\n </span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-72 max-w-[calc(100vw-2rem)] p-3\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium block m-0\">{{ context.heading() }}</p>\n <!-- Built fresh on each open. The popover reuses its content, so a picker\n kept alive holds the colour from the previous session; seeding it with\n the caret's colour then changes nothing, and re-picking that same\n colour emits nothing at all \u2014 the pick is silently lost. -->\n @if (open()) {\n <ui-color-picker\n [inline]=\"true\"\n [presets]=\"context.presets()\"\n [showRecent]=\"context.showRecent()\"\n [alpha]=\"context.alpha()\"\n [ngModel]=\"context.seededColor()\"\n [disabled]=\"interactionDisabled()\"\n (colorChange)=\"onColorChange($event)\"\n />\n }\n </div>\n </ui-popover-content>\n</ui-popover>\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: PopoverComponent, selector: "ui-popover", inputs: ["class", "open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger", inputs: ["class"] }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: ColorPickerComponent, selector: "ui-color-picker", inputs: ["presets", "inline", "disabled", "class", "alpha", "recentColors", "showRecent", "maxRecent", "storageKey", "enableEyedropper", "fallbackTarget", "locale", "enableImagePick", "imageExtractAlgorithm", "imageExtractCount", "showHarmonies", "showContrast", "contrastBackground", "formats", "value"], outputs: ["colorChange", "valueChange", "recentColorsChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
29451
29594
  }
29452
29595
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextColorsButtonComponent, decorators: [{
29453
29596
  type: Component,
@@ -29462,7 +29605,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
29462
29605
  '(pointerdown)': 'onUserInteract()',
29463
29606
  '(keydown)': 'onUserInteract()',
29464
29607
  }, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span class=\"flex size-4 flex-col items-center justify-between\">\n <span class=\"flex h-[13px] w-4 items-center justify-center [&>svg]:size-[13px]\" [innerHTML]=\"icon\"></span>\n <span\n data-slot=\"rte-color-indicator\"\n [class]=\"indicatorClasses()\"\n [style.background-color]=\"indicatorColor()\"\n ></span>\n </span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-72 max-w-[calc(100vw-2rem)] p-3\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium block m-0\">{{ context.heading() }}</p>\n <!-- Built fresh on each open. The popover reuses its content, so a picker\n kept alive holds the colour from the previous session; seeding it with\n the caret's colour then changes nothing, and re-picking that same\n colour emits nothing at all \u2014 the pick is silently lost. -->\n @if (open()) {\n <ui-color-picker\n [inline]=\"true\"\n [presets]=\"context.presets()\"\n [showRecent]=\"context.showRecent()\"\n [alpha]=\"context.alpha()\"\n [ngModel]=\"context.seededColor()\"\n [disabled]=\"interactionDisabled()\"\n (colorChange)=\"onColorChange($event)\"\n />\n }\n </div>\n </ui-popover-content>\n</ui-popover>\n" }]
29465
- }], ctorParameters: () => [] });
29608
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
29466
29609
 
29467
29610
  /** Built-in locales for the colors addon. */
29468
29611
  const RICH_TEXT_COLORS_LOCALES = {
@@ -29949,6 +30092,9 @@ const EMOJI_CATEGORIES = [
29949
30092
  ];
29950
30093
  class EmojiPickerComponent {
29951
30094
  constructor() {
30095
+ /** Extra classes merged onto the element this component renders, after its built-in styling. */
30096
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
30097
+ this.classes = computed(() => cn('relative inline-block', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
29952
30098
  this.el = inject(ElementRef);
29953
30099
  this.destroyRef = inject(DestroyRef);
29954
30100
  /**
@@ -30046,8 +30192,8 @@ class EmojiPickerComponent {
30046
30192
  }
30047
30193
  }
30048
30194
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: EmojiPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
30049
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: EmojiPickerComponent, isStandalone: true, selector: "ui-emoji-picker", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, closeOnSelect: { classPropertyName: "closeOnSelect", publicName: "closeOnSelect", isSignal: true, isRequired: false, transformFunction: null }, closeOnScroll: { classPropertyName: "closeOnScroll", publicName: "closeOnScroll", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", emojiSelect: "emojiSelect" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, classAttribute: "contents" }, providers: [{ provide: EMOJI_PICKER, useExisting: forwardRef(() => EmojiPickerComponent) }], ngImport: i0, template: `
30050
- <div class="relative inline-block" [attr.data-slot]="'emoji-picker'">
30195
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: EmojiPickerComponent, isStandalone: true, selector: "ui-emoji-picker", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, closeOnSelect: { classPropertyName: "closeOnSelect", publicName: "closeOnSelect", isSignal: true, isRequired: false, transformFunction: null }, closeOnScroll: { classPropertyName: "closeOnScroll", publicName: "closeOnScroll", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", emojiSelect: "emojiSelect" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, classAttribute: "contents" }, providers: [{ provide: EMOJI_PICKER, useExisting: forwardRef(() => EmojiPickerComponent) }], ngImport: i0, template: `
30196
+ <div [class]="classes()" [attr.data-slot]="'emoji-picker'">
30051
30197
  <ng-content />
30052
30198
  </div>
30053
30199
  `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
@@ -30059,7 +30205,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
30059
30205
  changeDetection: ChangeDetectionStrategy.OnPush,
30060
30206
  providers: [{ provide: EMOJI_PICKER, useExisting: forwardRef(() => EmojiPickerComponent) }],
30061
30207
  template: `
30062
- <div class="relative inline-block" [attr.data-slot]="'emoji-picker'">
30208
+ <div [class]="classes()" [attr.data-slot]="'emoji-picker'">
30063
30209
  <ng-content />
30064
30210
  </div>
30065
30211
  `,
@@ -30068,10 +30214,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
30068
30214
  '(document:click)': 'onDocumentClick($event)',
30069
30215
  },
30070
30216
  }]
30071
- }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], closeOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnSelect", required: false }] }], closeOnScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnScroll", required: false }] }], emojiSelect: [{ type: i0.Output, args: ["emojiSelect"] }] } });
30217
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], closeOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnSelect", required: false }] }], closeOnScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnScroll", required: false }] }], emojiSelect: [{ type: i0.Output, args: ["emojiSelect"] }] } });
30072
30218
 
30073
30219
  class EmojiPickerTriggerComponent {
30074
30220
  constructor() {
30221
+ /** Extra classes for the element that wraps the projected trigger. */
30222
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
30075
30223
  this.picker = inject(EMOJI_PICKER, { optional: true });
30076
30224
  this.host = inject(ElementRef);
30077
30225
  /** See `lib/a11y.ts` — stays transparent when the projected content is already a control. */
@@ -30101,8 +30249,9 @@ class EmojiPickerTriggerComponent {
30101
30249
  this.onClick(event);
30102
30250
  }
30103
30251
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: EmojiPickerTriggerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
30104
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: EmojiPickerTriggerComponent, isStandalone: true, selector: "ui-emoji-picker-trigger", host: { classAttribute: "contents" }, ngImport: i0, template: `
30252
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: EmojiPickerTriggerComponent, isStandalone: true, selector: "ui-emoji-picker-trigger", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
30105
30253
  <span
30254
+ [class]="class()"
30106
30255
  [attr.tabindex]="wrapsInteractive() ? null : 0"
30107
30256
  [attr.role]="wrapsInteractive() ? null : 'button'"
30108
30257
  (click)="onClick($event)"
@@ -30121,6 +30270,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
30121
30270
  changeDetection: ChangeDetectionStrategy.OnPush,
30122
30271
  template: `
30123
30272
  <span
30273
+ [class]="class()"
30124
30274
  [attr.tabindex]="wrapsInteractive() ? null : 0"
30125
30275
  [attr.role]="wrapsInteractive() ? null : 'button'"
30126
30276
  (click)="onClick($event)"
@@ -30133,7 +30283,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
30133
30283
  `,
30134
30284
  host: { class: 'contents' },
30135
30285
  }]
30136
- }], ctorParameters: () => [] });
30286
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
30137
30287
 
30138
30288
  /**
30139
30289
  * Promote a popup panel into the browser's top layer so it escapes every
@@ -32644,11 +32794,13 @@ class RichTextEmojiButtonComponent {
32644
32794
  this.exclusive = this.host.registerExclusivePopover(() => this.picker().hide());
32645
32795
  this.icon = this.domSanitizer.bypassSecurityTrustHtml(EMOJI_ICON);
32646
32796
  this.interactionDisabled = computed(() => this.host.isDisabled() || this.host.readonly(), ...(ngDevMode ? [{ debugName: "interactionDisabled" }] : /* istanbul ignore next */ []));
32797
+ /** Extra classes merged onto the toolbar button, after the built-in icon-button styling. */
32798
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
32647
32799
  this.buttonClasses = computed(() => cn('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors', 'hover:bg-accent hover:text-accent-foreground', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', 'disabled:pointer-events-none disabled:opacity-50',
32648
32800
  // The global (pointer: coarse) floor targets `button:not([data-slot])`,
32649
32801
  // and these addon buttons carry a data-slot for testing — so they must
32650
32802
  // state the 44px touch minimum themselves rather than inherit it.
32651
- 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5'), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
32803
+ 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5', this.class()), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
32652
32804
  inject(DestroyRef).onDestroy(() => this.exclusive.release());
32653
32805
  }
32654
32806
  onOpenChange(next) {
@@ -32662,7 +32814,7 @@ class RichTextEmojiButtonComponent {
32662
32814
  this.context.onInsert(emoji);
32663
32815
  }
32664
32816
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextEmojiButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
32665
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.22", type: RichTextEmojiButtonComponent, isStandalone: true, selector: "ui-rte-emoji-button", host: { classAttribute: "contents" }, viewQueries: [{ propertyName: "picker", first: true, predicate: EmojiPickerComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<ui-emoji-picker\n (openChange)=\"onOpenChange($event)\"\n [closeOnSelect]=\"false\"\n [closeOnScroll]=\"true\"\n (emojiSelect)=\"onEmoji($event)\"\n>\n <ui-emoji-picker-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-emoji-picker-trigger>\n <ui-emoji-picker-content strategy=\"fixed\" />\n</ui-emoji-picker>\n", dependencies: [{ kind: "component", type: EmojiPickerComponent, selector: "ui-emoji-picker", inputs: ["open", "closeOnSelect", "closeOnScroll"], outputs: ["openChange", "emojiSelect"] }, { kind: "component", type: EmojiPickerTriggerComponent, selector: "ui-emoji-picker-trigger" }, { kind: "component", type: EmojiPickerContentComponent, selector: "ui-emoji-picker-content", inputs: ["class", "strategy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
32817
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.22", type: RichTextEmojiButtonComponent, isStandalone: true, selector: "ui-rte-emoji-button", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-slot": "\"rte-emoji-host\"" }, classAttribute: "contents" }, viewQueries: [{ propertyName: "picker", first: true, predicate: EmojiPickerComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<ui-emoji-picker\n (openChange)=\"onOpenChange($event)\"\n [closeOnSelect]=\"false\"\n [closeOnScroll]=\"true\"\n (emojiSelect)=\"onEmoji($event)\"\n>\n <ui-emoji-picker-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-emoji-picker-trigger>\n <ui-emoji-picker-content strategy=\"fixed\" />\n</ui-emoji-picker>\n", dependencies: [{ kind: "component", type: EmojiPickerComponent, selector: "ui-emoji-picker", inputs: ["class", "open", "closeOnSelect", "closeOnScroll"], outputs: ["openChange", "emojiSelect"] }, { kind: "component", type: EmojiPickerTriggerComponent, selector: "ui-emoji-picker-trigger", inputs: ["class"] }, { kind: "component", type: EmojiPickerContentComponent, selector: "ui-emoji-picker-content", inputs: ["class", "strategy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
32666
32818
  }
32667
32819
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextEmojiButtonComponent, decorators: [{
32668
32820
  type: Component,
@@ -32670,8 +32822,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
32670
32822
  EmojiPickerComponent,
32671
32823
  EmojiPickerTriggerComponent,
32672
32824
  EmojiPickerContentComponent,
32673
- ], host: { class: 'contents' }, template: "<ui-emoji-picker\n (openChange)=\"onOpenChange($event)\"\n [closeOnSelect]=\"false\"\n [closeOnScroll]=\"true\"\n (emojiSelect)=\"onEmoji($event)\"\n>\n <ui-emoji-picker-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-emoji-picker-trigger>\n <ui-emoji-picker-content strategy=\"fixed\" />\n</ui-emoji-picker>\n" }]
32674
- }], ctorParameters: () => [], propDecorators: { picker: [{ type: i0.ViewChild, args: [i0.forwardRef(() => EmojiPickerComponent), { isSignal: true }] }] } });
32825
+ ], host: { class: 'contents', '[attr.data-slot]': '"rte-emoji-host"' }, template: "<ui-emoji-picker\n (openChange)=\"onOpenChange($event)\"\n [closeOnSelect]=\"false\"\n [closeOnScroll]=\"true\"\n (emojiSelect)=\"onEmoji($event)\"\n>\n <ui-emoji-picker-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-emoji-picker-trigger>\n <ui-emoji-picker-content strategy=\"fixed\" />\n</ui-emoji-picker>\n" }]
32826
+ }], ctorParameters: () => [], propDecorators: { picker: [{ type: i0.ViewChild, args: [i0.forwardRef(() => EmojiPickerComponent), { isSignal: true }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
32675
32827
 
32676
32828
  /**
32677
32829
  * Built-in locales for the emoji addon. Pass a key (`'en'`, `'he'`, …) or a
@@ -32868,27 +33020,29 @@ class RichTextFileImportButtonComponent {
32868
33020
  this.context = inject(RICH_TEXT_FILE_IMPORT_BUTTON_CONTEXT);
32869
33021
  this.icon = this.domSanitizer.bypassSecurityTrustHtml(IMPORT_ICON);
32870
33022
  this.interactionDisabled = computed(() => this.host.isDisabled() || this.host.readonly(), ...(ngDevMode ? [{ debugName: "interactionDisabled" }] : /* istanbul ignore next */ []));
33023
+ /** Extra classes merged onto the toolbar button, after the built-in icon-button styling. */
33024
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
32871
33025
  this.buttonClasses = computed(() => cn('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors', 'hover:bg-accent hover:text-accent-foreground', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', 'disabled:pointer-events-none disabled:opacity-50',
32872
33026
  // The global (pointer: coarse) floor targets `button:not([data-slot])`,
32873
33027
  // and these addon buttons carry a data-slot for testing — so they must
32874
33028
  // state the 44px touch minimum themselves rather than inherit it.
32875
- 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5'), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
33029
+ 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5', this.class()), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
32876
33030
  }
32877
33031
  onFileSelected(event) {
32878
- const input = event.target;
32879
- const file = input.files?.[0];
32880
- input.value = '';
33032
+ const fileInput = event.target;
33033
+ const file = fileInput.files?.[0];
33034
+ fileInput.value = '';
32881
33035
  if (this.interactionDisabled() || !file)
32882
33036
  return;
32883
33037
  this.context.onImport(file);
32884
33038
  }
32885
33039
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextFileImportButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
32886
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: RichTextFileImportButtonComponent, isStandalone: true, selector: "ui-rte-file-import-button", host: { classAttribute: "contents" }, ngImport: i0, template: "<button\n type=\"button\"\n data-slot=\"rte-file-import-button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n (click)=\"fileInput.click()\"\n>\n <span [innerHTML]=\"icon\"></span>\n</button>\n<!--\n Hidden by the HTML hidden attribute, not by a CSS class: the UA stylesheet\n hides it with no stylesheet of ours involved. Hiding it with a Tailwind\n class meant that, for as long as Tailwind had not been applied, the input\n was a visible, nameless file input \u2014 a critical label violation that\n surfaced at random whenever an axe scan won the race against the\n stylesheet. It is also named, so it stays correct even if a consumer\n unhides it.\n-->\n<input\n #fileInput\n type=\"file\"\n [attr.accept]=\"context.accept()\"\n hidden\n data-slot=\"rte-file-import-input\"\n [attr.aria-label]=\"context.locale().tooltip\"\n (change)=\"onFileSelected($event)\"\n/>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
33040
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: RichTextFileImportButtonComponent, isStandalone: true, selector: "ui-rte-file-import-button", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: "<button\n type=\"button\"\n data-slot=\"rte-file-import-button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n (click)=\"fileInput.click()\"\n>\n <span [innerHTML]=\"icon\"></span>\n</button>\n<!--\n Hidden by the HTML hidden attribute, not by a CSS class: the UA stylesheet\n hides it with no stylesheet of ours involved. Hiding it with a Tailwind\n class meant that, for as long as Tailwind had not been applied, the input\n was a visible, nameless file input \u2014 a critical label violation that\n surfaced at random whenever an axe scan won the race against the\n stylesheet. It is also named, so it stays correct even if a consumer\n unhides it.\n-->\n<input\n #fileInput\n type=\"file\"\n [attr.accept]=\"context.accept()\"\n hidden\n data-slot=\"rte-file-import-input\"\n [attr.aria-label]=\"context.locale().tooltip\"\n (change)=\"onFileSelected($event)\"\n/>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
32887
33041
  }
32888
33042
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextFileImportButtonComponent, decorators: [{
32889
33043
  type: Component,
32890
33044
  args: [{ selector: 'ui-rte-file-import-button', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'contents' }, template: "<button\n type=\"button\"\n data-slot=\"rte-file-import-button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n (click)=\"fileInput.click()\"\n>\n <span [innerHTML]=\"icon\"></span>\n</button>\n<!--\n Hidden by the HTML hidden attribute, not by a CSS class: the UA stylesheet\n hides it with no stylesheet of ours involved. Hiding it with a Tailwind\n class meant that, for as long as Tailwind had not been applied, the input\n was a visible, nameless file input \u2014 a critical label violation that\n surfaced at random whenever an axe scan won the race against the\n stylesheet. It is also named, so it stays correct even if a consumer\n unhides it.\n-->\n<input\n #fileInput\n type=\"file\"\n [attr.accept]=\"context.accept()\"\n hidden\n data-slot=\"rte-file-import-input\"\n [attr.aria-label]=\"context.locale().tooltip\"\n (change)=\"onFileSelected($event)\"\n/>\n" }]
32891
- }] });
33045
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
32892
33046
 
32893
33047
  /**
32894
33048
  * The file-import addon's editor-frame overlay: a full-editor busy layer while a
@@ -32899,6 +33053,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
32899
33053
  */
32900
33054
  class RichTextFileImportOverlayComponent {
32901
33055
  constructor() {
33056
+ /** Extra classes merged onto the busy and error layers, after the full-editor scrim styling. */
33057
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
33058
+ this.layerClasses = computed(() => cn('absolute inset-0 z-20 flex items-center justify-center bg-background/70 backdrop-blur-[1px]', this.class()), ...(ngDevMode ? [{ debugName: "layerClasses" }] : /* istanbul ignore next */ []));
32902
33059
  /**
32903
33060
  * Renders the full-editor busy layer (`data-slot="rte-file-import-busy"`)
32904
33061
  * showing {@link locale}`.importing`. The directive holds this true for the
@@ -32921,12 +33078,12 @@ class RichTextFileImportOverlayComponent {
32921
33078
  this.locale = input.required(...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
32922
33079
  }
32923
33080
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextFileImportOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
32924
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextFileImportOverlayComponent, isStandalone: true, selector: "ui-rte-file-import-overlay", inputs: { importing: { classPropertyName: "importing", publicName: "importing", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: "<!--\n The live region lives OUTSIDE the @if blocks and is always in the DOM.\n A region that is inserted already holding its text is not reliably announced\n by screen readers \u2014 the assistive tech has to be observing the node before\n the text arrives. Rendering it unconditionally and emptying it is what makes\n the busy and failure states audible at all.\n\n Busy uses polite/status (it is progress, not an interruption); failure uses\n assertive/alert, because the import silently did nothing and the user would\n otherwise wait for content that is never coming.\n-->\n<output class=\"sr-only\" aria-live=\"polite\" data-slot=\"rte-file-import-busy-status\">\n @if (importing()) {\n {{ locale().importing }}\n }\n</output>\n<div class=\"sr-only\" role=\"alert\" aria-live=\"assertive\" data-slot=\"rte-file-import-error-alert\">\n @if (errorMessage()) {\n {{ errorMessage() }}\n }\n</div>\n\n@if (importing()) {\n <div\n class=\"absolute inset-0 z-20 flex items-center justify-center bg-background/70 backdrop-blur-[1px]\"\n data-slot=\"rte-file-import-busy\"\n aria-hidden=\"true\"\n >\n <div class=\"text-sm text-muted-foreground\">{{ locale().importing }}</div>\n </div>\n}\n\n@if (errorMessage()) {\n <div\n class=\"absolute inset-0 z-20 flex items-center justify-center bg-background/70 backdrop-blur-[1px]\"\n data-slot=\"rte-file-import-error\"\n aria-hidden=\"true\"\n >\n <div class=\"text-sm text-destructive font-medium\">{{ errorMessage() }}</div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
33081
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextFileImportOverlayComponent, isStandalone: true, selector: "ui-rte-file-import-overlay", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, importing: { classPropertyName: "importing", publicName: "importing", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: "<!--\n The live region lives OUTSIDE the @if blocks and is always in the DOM.\n A region that is inserted already holding its text is not reliably announced\n by screen readers \u2014 the assistive tech has to be observing the node before\n the text arrives. Rendering it unconditionally and emptying it is what makes\n the busy and failure states audible at all.\n\n Busy uses polite/status (it is progress, not an interruption); failure uses\n assertive/alert, because the import silently did nothing and the user would\n otherwise wait for content that is never coming.\n-->\n<output class=\"sr-only\" aria-live=\"polite\" data-slot=\"rte-file-import-busy-status\">\n @if (importing()) {\n {{ locale().importing }}\n }\n</output>\n<div class=\"sr-only\" role=\"alert\" aria-live=\"assertive\" data-slot=\"rte-file-import-error-alert\">\n @if (errorMessage()) {\n {{ errorMessage() }}\n }\n</div>\n\n@if (importing()) {\n <div\n [class]=\"layerClasses()\"\n data-slot=\"rte-file-import-busy\"\n aria-hidden=\"true\"\n >\n <div class=\"text-sm text-muted-foreground\">{{ locale().importing }}</div>\n </div>\n}\n\n@if (errorMessage()) {\n <div\n [class]=\"layerClasses()\"\n data-slot=\"rte-file-import-error\"\n aria-hidden=\"true\"\n >\n <div class=\"text-sm text-destructive font-medium\">{{ errorMessage() }}</div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
32925
33082
  }
32926
33083
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextFileImportOverlayComponent, decorators: [{
32927
33084
  type: Component,
32928
- args: [{ selector: 'ui-rte-file-import-overlay', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'contents' }, template: "<!--\n The live region lives OUTSIDE the @if blocks and is always in the DOM.\n A region that is inserted already holding its text is not reliably announced\n by screen readers \u2014 the assistive tech has to be observing the node before\n the text arrives. Rendering it unconditionally and emptying it is what makes\n the busy and failure states audible at all.\n\n Busy uses polite/status (it is progress, not an interruption); failure uses\n assertive/alert, because the import silently did nothing and the user would\n otherwise wait for content that is never coming.\n-->\n<output class=\"sr-only\" aria-live=\"polite\" data-slot=\"rte-file-import-busy-status\">\n @if (importing()) {\n {{ locale().importing }}\n }\n</output>\n<div class=\"sr-only\" role=\"alert\" aria-live=\"assertive\" data-slot=\"rte-file-import-error-alert\">\n @if (errorMessage()) {\n {{ errorMessage() }}\n }\n</div>\n\n@if (importing()) {\n <div\n class=\"absolute inset-0 z-20 flex items-center justify-center bg-background/70 backdrop-blur-[1px]\"\n data-slot=\"rte-file-import-busy\"\n aria-hidden=\"true\"\n >\n <div class=\"text-sm text-muted-foreground\">{{ locale().importing }}</div>\n </div>\n}\n\n@if (errorMessage()) {\n <div\n class=\"absolute inset-0 z-20 flex items-center justify-center bg-background/70 backdrop-blur-[1px]\"\n data-slot=\"rte-file-import-error\"\n aria-hidden=\"true\"\n >\n <div class=\"text-sm text-destructive font-medium\">{{ errorMessage() }}</div>\n </div>\n}\n" }]
32929
- }], propDecorators: { importing: [{ type: i0.Input, args: [{ isSignal: true, alias: "importing", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: true }] }] } });
33085
+ args: [{ selector: 'ui-rte-file-import-overlay', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'contents' }, template: "<!--\n The live region lives OUTSIDE the @if blocks and is always in the DOM.\n A region that is inserted already holding its text is not reliably announced\n by screen readers \u2014 the assistive tech has to be observing the node before\n the text arrives. Rendering it unconditionally and emptying it is what makes\n the busy and failure states audible at all.\n\n Busy uses polite/status (it is progress, not an interruption); failure uses\n assertive/alert, because the import silently did nothing and the user would\n otherwise wait for content that is never coming.\n-->\n<output class=\"sr-only\" aria-live=\"polite\" data-slot=\"rte-file-import-busy-status\">\n @if (importing()) {\n {{ locale().importing }}\n }\n</output>\n<div class=\"sr-only\" role=\"alert\" aria-live=\"assertive\" data-slot=\"rte-file-import-error-alert\">\n @if (errorMessage()) {\n {{ errorMessage() }}\n }\n</div>\n\n@if (importing()) {\n <div\n [class]=\"layerClasses()\"\n data-slot=\"rte-file-import-busy\"\n aria-hidden=\"true\"\n >\n <div class=\"text-sm text-muted-foreground\">{{ locale().importing }}</div>\n </div>\n}\n\n@if (errorMessage()) {\n <div\n [class]=\"layerClasses()\"\n data-slot=\"rte-file-import-error\"\n aria-hidden=\"true\"\n >\n <div class=\"text-sm text-destructive font-medium\">{{ errorMessage() }}</div>\n </div>\n}\n" }]
33086
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], importing: [{ type: i0.Input, args: [{ isSignal: true, alias: "importing", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: true }] }] } });
32930
33087
 
32931
33088
  /**
32932
33089
  * The MIME types and extensions the file-import addon accepts. Kept in one place
@@ -33212,7 +33369,7 @@ class RichTextFileImportDirective {
33212
33369
  async importDocx(file) {
33213
33370
  this.assertImportableSize(file);
33214
33371
  const bytes = new Uint8Array(await file.arrayBuffer());
33215
- const { parseDocx } = await import('./gilav21-shadcn-angular-rte-docx-parser-DiBPweI4.mjs');
33372
+ const { parseDocx } = await import('./gilav21-shadcn-angular-rte-docx-parser-CAPT-WC9.mjs');
33216
33373
  const { renderDocxForEditor } = await import('./gilav21-shadcn-angular-rte-docx-to-editor-html-BreagmS_.mjs');
33217
33374
  const html = renderDocxForEditor(parseDocx(bytes));
33218
33375
  this.insertImported(html);
@@ -33530,6 +33687,9 @@ const RICH_TEXT_HISTORY_LOCALES = {
33530
33687
  */
33531
33688
  class RichTextHistoryPanelComponent {
33532
33689
  constructor() {
33690
+ /** Extra classes merged onto the corner wrapper that anchors the history button over the editor. */
33691
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
33692
+ this.classes = computed(() => cn('absolute top-2 z-30 ltr:right-2 rtl:left-2', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
33533
33693
  this.host = inject(RichTextEditorAddonHost);
33534
33694
  this.contentSanitizer = inject(RichTextSanitizerService);
33535
33695
  this.domSanitizer = inject(DomSanitizer);
@@ -33761,7 +33921,7 @@ class RichTextHistoryPanelComponent {
33761
33921
  }, 0);
33762
33922
  }
33763
33923
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextHistoryPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
33764
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextHistoryPanelComponent, isStandalone: true, selector: "ui-rich-text-history-panel", inputs: { locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, showButton: { classPropertyName: "showButton", publicName: "showButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { restore: "restore" }, host: { classAttribute: "contents" }, ngImport: i0, template: "@if (!readonly() && showButton()) {\n <div class=\"absolute top-2 z-30 ltr:right-2 rtl:left-2\">\n <ui-popover\n [open]=\"historyPanelOpen()\"\n (openChange)=\"onHistoryPanelOpenChange($event)\"\n >\n <ui-popover-trigger>\n <ui-button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n class=\"h-8 px-2.5 text-xs\"\n [disabled]=\"disabled()\"\n [attr.title]=\"'Ctrl/Cmd + Shift + H'\"\n [ariaLabel]=\"locale().ariaOpen\"\n >\n {{ interpolate(locale().button, { count: historyCount() }) }}\n </ui-button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-80 max-sm:w-[calc(100vw-2rem)] p-0\" align=\"end\" side=\"bottom\" [restoreFocus]=\"false\">\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <div class=\"text-sm font-medium\">{{ locale().title }}</div>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-7 w-7 p-0 pointer-coarse:size-11\"\n (click)=\"closePanel()\"\n (keydown.enter)=\"closePanel()\"\n (keydown.space)=\"closePanel()\"\n [ariaLabel]=\"locale().ariaClose\"\n >\n <svg class=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">{{ locale().close }}</span>\n </ui-button>\n </div>\n <ui-scroll-area [class]=\"'h-72 p-2'\">\n <div class=\"space-y-1 pr-2\" data-history-list=\"popover\">\n @for (entry of historyTimelineEntries(); track entry.index) {\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"w-full rounded-md border px-2 py-2 text-left transition-colors hover:bg-accent/60\"\n [class.bg-accent]=\"entry.active\"\n [class.border-primary/40]=\"entry.active\"\n [class.border-border]=\"!entry.active\"\n [attr.data-history-entry-action]=\"'true'\"\n [attr.data-history-entry-index]=\"entry.index\"\n [attr.aria-label]=\"interpolate(locale().ariaApply, { index: entry.index + 1 })\"\n (click)=\"onQuickApplyFromHistory(entry.index, $event)\"\n (keydown)=\"onHistoryEntryKeydown($event, entry.index)\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-xs font-medium\">{{ interpolate(locale().revision, { index: entry.index + 1 }) }}</span>\n <div class=\"flex items-center gap-2\">\n @if (lastAppliedHistoryIndex() === entry.index) {\n <span class=\"text-[11px] text-primary/90 font-medium\">{{ locale().applied }}</span>\n }\n <span class=\"text-[11px] text-muted-foreground\">{{ entry.timestamp | date:'HH:mm:ss' }}</span>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-6 px-2 text-[11px]\"\n (click)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.enter)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.space)=\"openHistoryPreview(entry.index, $event)\"\n >\n {{ locale().preview }}\n </ui-button>\n </div>\n </div>\n <div class=\"mt-1 space-y-0.5\">\n @for (line of entry.previewLines; track $index) {\n <p class=\"text-xs text-muted-foreground leading-4 truncate\">{{ line }}</p>\n }\n @if (entry.lineCount > entry.previewLines.length) {\n <p class=\"text-[11px] text-muted-foreground/80\">{{ interpolate(locale().moreLines, { count: entry.lineCount - entry.previewLines.length }) }}</p>\n }\n </div>\n </div>\n }\n </div>\n </ui-scroll-area>\n </ui-popover-content>\n </ui-popover>\n </div>\n}\n\n<ui-dialog [open]=\"historyPreviewOpen()\" (openChange)=\"historyPreviewOpen.set($event)\">\n <ui-dialog-content class=\"max-w-3xl p-0 overflow-hidden\">\n @if (selectedHistoryEntry(); as selected) {\n <ui-dialog-header class=\"px-5 pt-5 pb-3 border-b\">\n <ui-dialog-title>{{ interpolate(locale().revision, { index: selected.index + 1 }) }}</ui-dialog-title>\n <ui-dialog-description>\n {{ interpolate(locale().capturedAt, { time: (selected.timestamp | date:'MMM d, y, HH:mm:ss') ?? '' }) }}\n </ui-dialog-description>\n </ui-dialog-header>\n\n <ui-scroll-area [class]=\"'h-[70vh] px-5 py-4'\">\n <div class=\"space-y-4 pr-3\">\n <div class=\"rounded-md border bg-muted/20\">\n <div class=\"px-3 py-2 border-b text-xs font-medium text-muted-foreground\">{{ locale().renderedPreview }}</div>\n <div class=\"p-3 prose prose-sm dark:prose-invert max-w-none [&_*]:break-words\" [innerHTML]=\"previewHtml(selected.html)\"></div>\n </div>\n\n <div class=\"rounded-md border\">\n <div class=\"px-3 py-2 border-b text-xs font-medium text-muted-foreground\">{{ locale().markdownSnapshot }}</div>\n <pre class=\"p-3 text-xs whitespace-pre-wrap break-words\">{{ selected.markdown }}</pre>\n </div>\n </div>\n </ui-scroll-area>\n\n <ui-dialog-footer class=\"px-5 py-4 border-t\">\n <ui-button variant=\"outline\" (click)=\"closePreview()\" (keydown.enter)=\"closePreview()\" (keydown.space)=\"closePreview()\">{{ locale().cancel }}</ui-button>\n <ui-button (click)=\"restoreFromHistoryPreview()\" (keydown.enter)=\"restoreFromHistoryPreview()\" (keydown.space)=\"restoreFromHistoryPreview()\">{{ locale().restore }}</ui-button>\n </ui-dialog-footer>\n }\n </ui-dialog-content>\n</ui-dialog>\n\n<ui-dialog [open]=\"historyBrowserOpen()\" (openChange)=\"historyBrowserOpen.set($event)\">\n <ui-dialog-content class=\"max-w-xl p-0 overflow-hidden\">\n <ui-dialog-header class=\"px-5 pt-5 pb-3 border-b\">\n <ui-dialog-title>{{ locale().title }}</ui-dialog-title>\n <ui-dialog-description>{{ locale().browserDescription }}</ui-dialog-description>\n </ui-dialog-header>\n <ui-scroll-area [class]=\"'h-[60vh] px-4 py-3'\">\n <div class=\"space-y-2 pr-2\" data-history-list=\"dialog\">\n @for (entry of historyTimelineEntries(); track entry.index) {\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"w-full rounded-md border px-3 py-2 text-left transition-colors hover:bg-accent/60\"\n [class.bg-accent]=\"entry.active\"\n [class.border-primary/40]=\"entry.active\"\n [class.border-border]=\"!entry.active\"\n [attr.data-history-entry-action]=\"'true'\"\n [attr.data-history-entry-index]=\"entry.index\"\n [attr.aria-label]=\"interpolate(locale().ariaApply, { index: entry.index + 1 })\"\n (click)=\"onQuickApplyFromHistory(entry.index, $event)\"\n (keydown)=\"onHistoryEntryKeydown($event, entry.index)\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-xs font-medium\">{{ interpolate(locale().revision, { index: entry.index + 1 }) }}</span>\n <div class=\"flex items-center gap-2\">\n @if (lastAppliedHistoryIndex() === entry.index) {\n <span class=\"text-[11px] text-primary/90 font-medium\">{{ locale().applied }}</span>\n }\n <span class=\"text-[11px] text-muted-foreground\">{{ entry.timestamp | date:'HH:mm:ss' }}</span>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-6 px-2 text-[11px]\"\n (click)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.enter)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.space)=\"openHistoryPreview(entry.index, $event)\"\n >\n {{ locale().preview }}\n </ui-button>\n </div>\n </div>\n <div class=\"mt-1 space-y-0.5\">\n @for (line of entry.previewLines; track $index) {\n <p class=\"text-xs text-muted-foreground leading-4 truncate\">{{ line }}</p>\n }\n @if (entry.lineCount > entry.previewLines.length) {\n <p class=\"text-[11px] text-muted-foreground/80\">{{ interpolate(locale().moreLines, { count: entry.lineCount - entry.previewLines.length }) }}</p>\n }\n </div>\n </div>\n }\n </div>\n </ui-scroll-area>\n <ui-dialog-footer class=\"px-5 py-4 border-t\">\n <ui-button variant=\"outline\" (click)=\"closeBrowser()\" (keydown.enter)=\"closeBrowser()\" (keydown.space)=\"closeBrowser()\">{{ locale().close }}</ui-button>\n </ui-dialog-footer>\n </ui-dialog-content>\n</ui-dialog>\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }, { kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger" }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: DialogComponent, selector: "ui-dialog", inputs: ["open"], outputs: ["openChange"] }, { kind: "component", type: DialogContentComponent, selector: "ui-dialog-content", inputs: ["class", "title", "description", "locale"] }, { kind: "component", type: DialogHeaderComponent, selector: "ui-dialog-header" }, { kind: "component", type: DialogTitleComponent, selector: "ui-dialog-title" }, { kind: "component", type: DialogDescriptionComponent, selector: "ui-dialog-description" }, { kind: "component", type: DialogFooterComponent, selector: "ui-dialog-footer" }, { kind: "component", type: ScrollAreaComponent, selector: "ui-scroll-area", inputs: ["class", "orientation"] }, { kind: "pipe", type: DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
33924
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextHistoryPanelComponent, isStandalone: true, selector: "ui-rich-text-history-panel", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, showButton: { classPropertyName: "showButton", publicName: "showButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { restore: "restore" }, host: { classAttribute: "contents" }, ngImport: i0, template: "@if (!readonly() && showButton()) {\n <div [class]=\"classes()\" [attr.data-slot]=\"'rte-history-panel'\">\n <ui-popover\n [open]=\"historyPanelOpen()\"\n (openChange)=\"onHistoryPanelOpenChange($event)\"\n >\n <ui-popover-trigger>\n <ui-button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n class=\"h-8 px-2.5 text-xs\"\n [disabled]=\"disabled()\"\n [attr.title]=\"'Ctrl/Cmd + Shift + H'\"\n [ariaLabel]=\"locale().ariaOpen\"\n >\n {{ interpolate(locale().button, { count: historyCount() }) }}\n </ui-button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-80 max-sm:w-[calc(100vw-2rem)] p-0\" align=\"end\" side=\"bottom\" [restoreFocus]=\"false\">\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <div class=\"text-sm font-medium\">{{ locale().title }}</div>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-7 w-7 p-0 pointer-coarse:size-11\"\n (click)=\"closePanel()\"\n (keydown.enter)=\"closePanel()\"\n (keydown.space)=\"closePanel()\"\n [ariaLabel]=\"locale().ariaClose\"\n >\n <svg class=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">{{ locale().close }}</span>\n </ui-button>\n </div>\n <ui-scroll-area [class]=\"'h-72 p-2'\">\n <div class=\"space-y-1 pr-2\" data-history-list=\"popover\">\n @for (entry of historyTimelineEntries(); track entry.index) {\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"w-full rounded-md border px-2 py-2 text-left transition-colors hover:bg-accent/60\"\n [class.bg-accent]=\"entry.active\"\n [class.border-primary/40]=\"entry.active\"\n [class.border-border]=\"!entry.active\"\n [attr.data-history-entry-action]=\"'true'\"\n [attr.data-history-entry-index]=\"entry.index\"\n [attr.aria-label]=\"interpolate(locale().ariaApply, { index: entry.index + 1 })\"\n (click)=\"onQuickApplyFromHistory(entry.index, $event)\"\n (keydown)=\"onHistoryEntryKeydown($event, entry.index)\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-xs font-medium\">{{ interpolate(locale().revision, { index: entry.index + 1 }) }}</span>\n <div class=\"flex items-center gap-2\">\n @if (lastAppliedHistoryIndex() === entry.index) {\n <span class=\"text-[11px] text-primary/90 font-medium\">{{ locale().applied }}</span>\n }\n <span class=\"text-[11px] text-muted-foreground\">{{ entry.timestamp | date:'HH:mm:ss' }}</span>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-6 px-2 text-[11px]\"\n (click)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.enter)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.space)=\"openHistoryPreview(entry.index, $event)\"\n >\n {{ locale().preview }}\n </ui-button>\n </div>\n </div>\n <div class=\"mt-1 space-y-0.5\">\n @for (line of entry.previewLines; track $index) {\n <p class=\"text-xs text-muted-foreground leading-4 truncate\">{{ line }}</p>\n }\n @if (entry.lineCount > entry.previewLines.length) {\n <p class=\"text-[11px] text-muted-foreground/80\">{{ interpolate(locale().moreLines, { count: entry.lineCount - entry.previewLines.length }) }}</p>\n }\n </div>\n </div>\n }\n </div>\n </ui-scroll-area>\n </ui-popover-content>\n </ui-popover>\n </div>\n}\n\n<ui-dialog [open]=\"historyPreviewOpen()\" (openChange)=\"historyPreviewOpen.set($event)\">\n <ui-dialog-content class=\"max-w-3xl p-0 overflow-hidden\">\n @if (selectedHistoryEntry(); as selected) {\n <ui-dialog-header class=\"px-5 pt-5 pb-3 border-b\">\n <ui-dialog-title>{{ interpolate(locale().revision, { index: selected.index + 1 }) }}</ui-dialog-title>\n <ui-dialog-description>\n {{ interpolate(locale().capturedAt, { time: (selected.timestamp | date:'MMM d, y, HH:mm:ss') ?? '' }) }}\n </ui-dialog-description>\n </ui-dialog-header>\n\n <ui-scroll-area [class]=\"'h-[70vh] px-5 py-4'\">\n <div class=\"space-y-4 pr-3\">\n <div class=\"rounded-md border bg-muted/20\">\n <div class=\"px-3 py-2 border-b text-xs font-medium text-muted-foreground\">{{ locale().renderedPreview }}</div>\n <div class=\"p-3 prose prose-sm dark:prose-invert max-w-none [&_*]:break-words\" [innerHTML]=\"previewHtml(selected.html)\"></div>\n </div>\n\n <div class=\"rounded-md border\">\n <div class=\"px-3 py-2 border-b text-xs font-medium text-muted-foreground\">{{ locale().markdownSnapshot }}</div>\n <pre class=\"p-3 text-xs whitespace-pre-wrap break-words\">{{ selected.markdown }}</pre>\n </div>\n </div>\n </ui-scroll-area>\n\n <ui-dialog-footer class=\"px-5 py-4 border-t\">\n <ui-button variant=\"outline\" (click)=\"closePreview()\" (keydown.enter)=\"closePreview()\" (keydown.space)=\"closePreview()\">{{ locale().cancel }}</ui-button>\n <ui-button (click)=\"restoreFromHistoryPreview()\" (keydown.enter)=\"restoreFromHistoryPreview()\" (keydown.space)=\"restoreFromHistoryPreview()\">{{ locale().restore }}</ui-button>\n </ui-dialog-footer>\n }\n </ui-dialog-content>\n</ui-dialog>\n\n<ui-dialog [open]=\"historyBrowserOpen()\" (openChange)=\"historyBrowserOpen.set($event)\">\n <ui-dialog-content class=\"max-w-xl p-0 overflow-hidden\">\n <ui-dialog-header class=\"px-5 pt-5 pb-3 border-b\">\n <ui-dialog-title>{{ locale().title }}</ui-dialog-title>\n <ui-dialog-description>{{ locale().browserDescription }}</ui-dialog-description>\n </ui-dialog-header>\n <ui-scroll-area [class]=\"'h-[60vh] px-4 py-3'\">\n <div class=\"space-y-2 pr-2\" data-history-list=\"dialog\">\n @for (entry of historyTimelineEntries(); track entry.index) {\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"w-full rounded-md border px-3 py-2 text-left transition-colors hover:bg-accent/60\"\n [class.bg-accent]=\"entry.active\"\n [class.border-primary/40]=\"entry.active\"\n [class.border-border]=\"!entry.active\"\n [attr.data-history-entry-action]=\"'true'\"\n [attr.data-history-entry-index]=\"entry.index\"\n [attr.aria-label]=\"interpolate(locale().ariaApply, { index: entry.index + 1 })\"\n (click)=\"onQuickApplyFromHistory(entry.index, $event)\"\n (keydown)=\"onHistoryEntryKeydown($event, entry.index)\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-xs font-medium\">{{ interpolate(locale().revision, { index: entry.index + 1 }) }}</span>\n <div class=\"flex items-center gap-2\">\n @if (lastAppliedHistoryIndex() === entry.index) {\n <span class=\"text-[11px] text-primary/90 font-medium\">{{ locale().applied }}</span>\n }\n <span class=\"text-[11px] text-muted-foreground\">{{ entry.timestamp | date:'HH:mm:ss' }}</span>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-6 px-2 text-[11px]\"\n (click)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.enter)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.space)=\"openHistoryPreview(entry.index, $event)\"\n >\n {{ locale().preview }}\n </ui-button>\n </div>\n </div>\n <div class=\"mt-1 space-y-0.5\">\n @for (line of entry.previewLines; track $index) {\n <p class=\"text-xs text-muted-foreground leading-4 truncate\">{{ line }}</p>\n }\n @if (entry.lineCount > entry.previewLines.length) {\n <p class=\"text-[11px] text-muted-foreground/80\">{{ interpolate(locale().moreLines, { count: entry.lineCount - entry.previewLines.length }) }}</p>\n }\n </div>\n </div>\n }\n </div>\n </ui-scroll-area>\n <ui-dialog-footer class=\"px-5 py-4 border-t\">\n <ui-button variant=\"outline\" (click)=\"closeBrowser()\" (keydown.enter)=\"closeBrowser()\" (keydown.space)=\"closeBrowser()\">{{ locale().close }}</ui-button>\n </ui-dialog-footer>\n </ui-dialog-content>\n</ui-dialog>\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }, { kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["class", "open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger", inputs: ["class"] }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: DialogComponent, selector: "ui-dialog", inputs: ["open"], outputs: ["openChange"] }, { kind: "component", type: DialogContentComponent, selector: "ui-dialog-content", inputs: ["class", "title", "description", "locale"] }, { kind: "component", type: DialogHeaderComponent, selector: "ui-dialog-header", inputs: ["class"] }, { kind: "component", type: DialogTitleComponent, selector: "ui-dialog-title", inputs: ["class"] }, { kind: "component", type: DialogDescriptionComponent, selector: "ui-dialog-description", inputs: ["class"] }, { kind: "component", type: DialogFooterComponent, selector: "ui-dialog-footer", inputs: ["class"] }, { kind: "component", type: ScrollAreaComponent, selector: "ui-scroll-area", inputs: ["class", "orientation"] }, { kind: "pipe", type: DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
33765
33925
  }
33766
33926
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextHistoryPanelComponent, decorators: [{
33767
33927
  type: Component,
@@ -33778,8 +33938,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
33778
33938
  DialogDescriptionComponent,
33779
33939
  DialogFooterComponent,
33780
33940
  ScrollAreaComponent,
33781
- ], host: { class: 'contents' }, template: "@if (!readonly() && showButton()) {\n <div class=\"absolute top-2 z-30 ltr:right-2 rtl:left-2\">\n <ui-popover\n [open]=\"historyPanelOpen()\"\n (openChange)=\"onHistoryPanelOpenChange($event)\"\n >\n <ui-popover-trigger>\n <ui-button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n class=\"h-8 px-2.5 text-xs\"\n [disabled]=\"disabled()\"\n [attr.title]=\"'Ctrl/Cmd + Shift + H'\"\n [ariaLabel]=\"locale().ariaOpen\"\n >\n {{ interpolate(locale().button, { count: historyCount() }) }}\n </ui-button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-80 max-sm:w-[calc(100vw-2rem)] p-0\" align=\"end\" side=\"bottom\" [restoreFocus]=\"false\">\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <div class=\"text-sm font-medium\">{{ locale().title }}</div>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-7 w-7 p-0 pointer-coarse:size-11\"\n (click)=\"closePanel()\"\n (keydown.enter)=\"closePanel()\"\n (keydown.space)=\"closePanel()\"\n [ariaLabel]=\"locale().ariaClose\"\n >\n <svg class=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">{{ locale().close }}</span>\n </ui-button>\n </div>\n <ui-scroll-area [class]=\"'h-72 p-2'\">\n <div class=\"space-y-1 pr-2\" data-history-list=\"popover\">\n @for (entry of historyTimelineEntries(); track entry.index) {\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"w-full rounded-md border px-2 py-2 text-left transition-colors hover:bg-accent/60\"\n [class.bg-accent]=\"entry.active\"\n [class.border-primary/40]=\"entry.active\"\n [class.border-border]=\"!entry.active\"\n [attr.data-history-entry-action]=\"'true'\"\n [attr.data-history-entry-index]=\"entry.index\"\n [attr.aria-label]=\"interpolate(locale().ariaApply, { index: entry.index + 1 })\"\n (click)=\"onQuickApplyFromHistory(entry.index, $event)\"\n (keydown)=\"onHistoryEntryKeydown($event, entry.index)\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-xs font-medium\">{{ interpolate(locale().revision, { index: entry.index + 1 }) }}</span>\n <div class=\"flex items-center gap-2\">\n @if (lastAppliedHistoryIndex() === entry.index) {\n <span class=\"text-[11px] text-primary/90 font-medium\">{{ locale().applied }}</span>\n }\n <span class=\"text-[11px] text-muted-foreground\">{{ entry.timestamp | date:'HH:mm:ss' }}</span>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-6 px-2 text-[11px]\"\n (click)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.enter)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.space)=\"openHistoryPreview(entry.index, $event)\"\n >\n {{ locale().preview }}\n </ui-button>\n </div>\n </div>\n <div class=\"mt-1 space-y-0.5\">\n @for (line of entry.previewLines; track $index) {\n <p class=\"text-xs text-muted-foreground leading-4 truncate\">{{ line }}</p>\n }\n @if (entry.lineCount > entry.previewLines.length) {\n <p class=\"text-[11px] text-muted-foreground/80\">{{ interpolate(locale().moreLines, { count: entry.lineCount - entry.previewLines.length }) }}</p>\n }\n </div>\n </div>\n }\n </div>\n </ui-scroll-area>\n </ui-popover-content>\n </ui-popover>\n </div>\n}\n\n<ui-dialog [open]=\"historyPreviewOpen()\" (openChange)=\"historyPreviewOpen.set($event)\">\n <ui-dialog-content class=\"max-w-3xl p-0 overflow-hidden\">\n @if (selectedHistoryEntry(); as selected) {\n <ui-dialog-header class=\"px-5 pt-5 pb-3 border-b\">\n <ui-dialog-title>{{ interpolate(locale().revision, { index: selected.index + 1 }) }}</ui-dialog-title>\n <ui-dialog-description>\n {{ interpolate(locale().capturedAt, { time: (selected.timestamp | date:'MMM d, y, HH:mm:ss') ?? '' }) }}\n </ui-dialog-description>\n </ui-dialog-header>\n\n <ui-scroll-area [class]=\"'h-[70vh] px-5 py-4'\">\n <div class=\"space-y-4 pr-3\">\n <div class=\"rounded-md border bg-muted/20\">\n <div class=\"px-3 py-2 border-b text-xs font-medium text-muted-foreground\">{{ locale().renderedPreview }}</div>\n <div class=\"p-3 prose prose-sm dark:prose-invert max-w-none [&_*]:break-words\" [innerHTML]=\"previewHtml(selected.html)\"></div>\n </div>\n\n <div class=\"rounded-md border\">\n <div class=\"px-3 py-2 border-b text-xs font-medium text-muted-foreground\">{{ locale().markdownSnapshot }}</div>\n <pre class=\"p-3 text-xs whitespace-pre-wrap break-words\">{{ selected.markdown }}</pre>\n </div>\n </div>\n </ui-scroll-area>\n\n <ui-dialog-footer class=\"px-5 py-4 border-t\">\n <ui-button variant=\"outline\" (click)=\"closePreview()\" (keydown.enter)=\"closePreview()\" (keydown.space)=\"closePreview()\">{{ locale().cancel }}</ui-button>\n <ui-button (click)=\"restoreFromHistoryPreview()\" (keydown.enter)=\"restoreFromHistoryPreview()\" (keydown.space)=\"restoreFromHistoryPreview()\">{{ locale().restore }}</ui-button>\n </ui-dialog-footer>\n }\n </ui-dialog-content>\n</ui-dialog>\n\n<ui-dialog [open]=\"historyBrowserOpen()\" (openChange)=\"historyBrowserOpen.set($event)\">\n <ui-dialog-content class=\"max-w-xl p-0 overflow-hidden\">\n <ui-dialog-header class=\"px-5 pt-5 pb-3 border-b\">\n <ui-dialog-title>{{ locale().title }}</ui-dialog-title>\n <ui-dialog-description>{{ locale().browserDescription }}</ui-dialog-description>\n </ui-dialog-header>\n <ui-scroll-area [class]=\"'h-[60vh] px-4 py-3'\">\n <div class=\"space-y-2 pr-2\" data-history-list=\"dialog\">\n @for (entry of historyTimelineEntries(); track entry.index) {\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"w-full rounded-md border px-3 py-2 text-left transition-colors hover:bg-accent/60\"\n [class.bg-accent]=\"entry.active\"\n [class.border-primary/40]=\"entry.active\"\n [class.border-border]=\"!entry.active\"\n [attr.data-history-entry-action]=\"'true'\"\n [attr.data-history-entry-index]=\"entry.index\"\n [attr.aria-label]=\"interpolate(locale().ariaApply, { index: entry.index + 1 })\"\n (click)=\"onQuickApplyFromHistory(entry.index, $event)\"\n (keydown)=\"onHistoryEntryKeydown($event, entry.index)\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-xs font-medium\">{{ interpolate(locale().revision, { index: entry.index + 1 }) }}</span>\n <div class=\"flex items-center gap-2\">\n @if (lastAppliedHistoryIndex() === entry.index) {\n <span class=\"text-[11px] text-primary/90 font-medium\">{{ locale().applied }}</span>\n }\n <span class=\"text-[11px] text-muted-foreground\">{{ entry.timestamp | date:'HH:mm:ss' }}</span>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-6 px-2 text-[11px]\"\n (click)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.enter)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.space)=\"openHistoryPreview(entry.index, $event)\"\n >\n {{ locale().preview }}\n </ui-button>\n </div>\n </div>\n <div class=\"mt-1 space-y-0.5\">\n @for (line of entry.previewLines; track $index) {\n <p class=\"text-xs text-muted-foreground leading-4 truncate\">{{ line }}</p>\n }\n @if (entry.lineCount > entry.previewLines.length) {\n <p class=\"text-[11px] text-muted-foreground/80\">{{ interpolate(locale().moreLines, { count: entry.lineCount - entry.previewLines.length }) }}</p>\n }\n </div>\n </div>\n }\n </div>\n </ui-scroll-area>\n <ui-dialog-footer class=\"px-5 py-4 border-t\">\n <ui-button variant=\"outline\" (click)=\"closeBrowser()\" (keydown.enter)=\"closeBrowser()\" (keydown.space)=\"closeBrowser()\">{{ locale().close }}</ui-button>\n </ui-dialog-footer>\n </ui-dialog-content>\n</ui-dialog>\n" }]
33782
- }], propDecorators: { locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], showButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showButton", required: false }] }], restore: [{ type: i0.Output, args: ["restore"] }] } });
33941
+ ], host: { class: 'contents' }, template: "@if (!readonly() && showButton()) {\n <div [class]=\"classes()\" [attr.data-slot]=\"'rte-history-panel'\">\n <ui-popover\n [open]=\"historyPanelOpen()\"\n (openChange)=\"onHistoryPanelOpenChange($event)\"\n >\n <ui-popover-trigger>\n <ui-button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n class=\"h-8 px-2.5 text-xs\"\n [disabled]=\"disabled()\"\n [attr.title]=\"'Ctrl/Cmd + Shift + H'\"\n [ariaLabel]=\"locale().ariaOpen\"\n >\n {{ interpolate(locale().button, { count: historyCount() }) }}\n </ui-button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-80 max-sm:w-[calc(100vw-2rem)] p-0\" align=\"end\" side=\"bottom\" [restoreFocus]=\"false\">\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <div class=\"text-sm font-medium\">{{ locale().title }}</div>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-7 w-7 p-0 pointer-coarse:size-11\"\n (click)=\"closePanel()\"\n (keydown.enter)=\"closePanel()\"\n (keydown.space)=\"closePanel()\"\n [ariaLabel]=\"locale().ariaClose\"\n >\n <svg class=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">{{ locale().close }}</span>\n </ui-button>\n </div>\n <ui-scroll-area [class]=\"'h-72 p-2'\">\n <div class=\"space-y-1 pr-2\" data-history-list=\"popover\">\n @for (entry of historyTimelineEntries(); track entry.index) {\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"w-full rounded-md border px-2 py-2 text-left transition-colors hover:bg-accent/60\"\n [class.bg-accent]=\"entry.active\"\n [class.border-primary/40]=\"entry.active\"\n [class.border-border]=\"!entry.active\"\n [attr.data-history-entry-action]=\"'true'\"\n [attr.data-history-entry-index]=\"entry.index\"\n [attr.aria-label]=\"interpolate(locale().ariaApply, { index: entry.index + 1 })\"\n (click)=\"onQuickApplyFromHistory(entry.index, $event)\"\n (keydown)=\"onHistoryEntryKeydown($event, entry.index)\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-xs font-medium\">{{ interpolate(locale().revision, { index: entry.index + 1 }) }}</span>\n <div class=\"flex items-center gap-2\">\n @if (lastAppliedHistoryIndex() === entry.index) {\n <span class=\"text-[11px] text-primary/90 font-medium\">{{ locale().applied }}</span>\n }\n <span class=\"text-[11px] text-muted-foreground\">{{ entry.timestamp | date:'HH:mm:ss' }}</span>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-6 px-2 text-[11px]\"\n (click)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.enter)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.space)=\"openHistoryPreview(entry.index, $event)\"\n >\n {{ locale().preview }}\n </ui-button>\n </div>\n </div>\n <div class=\"mt-1 space-y-0.5\">\n @for (line of entry.previewLines; track $index) {\n <p class=\"text-xs text-muted-foreground leading-4 truncate\">{{ line }}</p>\n }\n @if (entry.lineCount > entry.previewLines.length) {\n <p class=\"text-[11px] text-muted-foreground/80\">{{ interpolate(locale().moreLines, { count: entry.lineCount - entry.previewLines.length }) }}</p>\n }\n </div>\n </div>\n }\n </div>\n </ui-scroll-area>\n </ui-popover-content>\n </ui-popover>\n </div>\n}\n\n<ui-dialog [open]=\"historyPreviewOpen()\" (openChange)=\"historyPreviewOpen.set($event)\">\n <ui-dialog-content class=\"max-w-3xl p-0 overflow-hidden\">\n @if (selectedHistoryEntry(); as selected) {\n <ui-dialog-header class=\"px-5 pt-5 pb-3 border-b\">\n <ui-dialog-title>{{ interpolate(locale().revision, { index: selected.index + 1 }) }}</ui-dialog-title>\n <ui-dialog-description>\n {{ interpolate(locale().capturedAt, { time: (selected.timestamp | date:'MMM d, y, HH:mm:ss') ?? '' }) }}\n </ui-dialog-description>\n </ui-dialog-header>\n\n <ui-scroll-area [class]=\"'h-[70vh] px-5 py-4'\">\n <div class=\"space-y-4 pr-3\">\n <div class=\"rounded-md border bg-muted/20\">\n <div class=\"px-3 py-2 border-b text-xs font-medium text-muted-foreground\">{{ locale().renderedPreview }}</div>\n <div class=\"p-3 prose prose-sm dark:prose-invert max-w-none [&_*]:break-words\" [innerHTML]=\"previewHtml(selected.html)\"></div>\n </div>\n\n <div class=\"rounded-md border\">\n <div class=\"px-3 py-2 border-b text-xs font-medium text-muted-foreground\">{{ locale().markdownSnapshot }}</div>\n <pre class=\"p-3 text-xs whitespace-pre-wrap break-words\">{{ selected.markdown }}</pre>\n </div>\n </div>\n </ui-scroll-area>\n\n <ui-dialog-footer class=\"px-5 py-4 border-t\">\n <ui-button variant=\"outline\" (click)=\"closePreview()\" (keydown.enter)=\"closePreview()\" (keydown.space)=\"closePreview()\">{{ locale().cancel }}</ui-button>\n <ui-button (click)=\"restoreFromHistoryPreview()\" (keydown.enter)=\"restoreFromHistoryPreview()\" (keydown.space)=\"restoreFromHistoryPreview()\">{{ locale().restore }}</ui-button>\n </ui-dialog-footer>\n }\n </ui-dialog-content>\n</ui-dialog>\n\n<ui-dialog [open]=\"historyBrowserOpen()\" (openChange)=\"historyBrowserOpen.set($event)\">\n <ui-dialog-content class=\"max-w-xl p-0 overflow-hidden\">\n <ui-dialog-header class=\"px-5 pt-5 pb-3 border-b\">\n <ui-dialog-title>{{ locale().title }}</ui-dialog-title>\n <ui-dialog-description>{{ locale().browserDescription }}</ui-dialog-description>\n </ui-dialog-header>\n <ui-scroll-area [class]=\"'h-[60vh] px-4 py-3'\">\n <div class=\"space-y-2 pr-2\" data-history-list=\"dialog\">\n @for (entry of historyTimelineEntries(); track entry.index) {\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"w-full rounded-md border px-3 py-2 text-left transition-colors hover:bg-accent/60\"\n [class.bg-accent]=\"entry.active\"\n [class.border-primary/40]=\"entry.active\"\n [class.border-border]=\"!entry.active\"\n [attr.data-history-entry-action]=\"'true'\"\n [attr.data-history-entry-index]=\"entry.index\"\n [attr.aria-label]=\"interpolate(locale().ariaApply, { index: entry.index + 1 })\"\n (click)=\"onQuickApplyFromHistory(entry.index, $event)\"\n (keydown)=\"onHistoryEntryKeydown($event, entry.index)\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-xs font-medium\">{{ interpolate(locale().revision, { index: entry.index + 1 }) }}</span>\n <div class=\"flex items-center gap-2\">\n @if (lastAppliedHistoryIndex() === entry.index) {\n <span class=\"text-[11px] text-primary/90 font-medium\">{{ locale().applied }}</span>\n }\n <span class=\"text-[11px] text-muted-foreground\">{{ entry.timestamp | date:'HH:mm:ss' }}</span>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-6 px-2 text-[11px]\"\n (click)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.enter)=\"openHistoryPreview(entry.index, $event)\"\n (keydown.space)=\"openHistoryPreview(entry.index, $event)\"\n >\n {{ locale().preview }}\n </ui-button>\n </div>\n </div>\n <div class=\"mt-1 space-y-0.5\">\n @for (line of entry.previewLines; track $index) {\n <p class=\"text-xs text-muted-foreground leading-4 truncate\">{{ line }}</p>\n }\n @if (entry.lineCount > entry.previewLines.length) {\n <p class=\"text-[11px] text-muted-foreground/80\">{{ interpolate(locale().moreLines, { count: entry.lineCount - entry.previewLines.length }) }}</p>\n }\n </div>\n </div>\n }\n </div>\n </ui-scroll-area>\n <ui-dialog-footer class=\"px-5 py-4 border-t\">\n <ui-button variant=\"outline\" (click)=\"closeBrowser()\" (keydown.enter)=\"closeBrowser()\" (keydown.space)=\"closeBrowser()\">{{ locale().close }}</ui-button>\n </ui-dialog-footer>\n </ui-dialog-content>\n</ui-dialog>\n" }]
33942
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], showButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showButton", required: false }] }], restore: [{ type: i0.Output, args: ["restore"] }] } });
33783
33943
 
33784
33944
  const HISTORY_SHORTCUT_ACTION = 'rich-text.history';
33785
33945
  /**
@@ -33904,11 +34064,13 @@ class RichTextImagesButtonComponent {
33904
34064
  this.showUrl = computed(() => this.context.sources() !== 'upload', ...(ngDevMode ? [{ debugName: "showUrl" }] : /* istanbul ignore next */ []));
33905
34065
  this.showUpload = computed(() => this.context.sources() !== 'url', ...(ngDevMode ? [{ debugName: "showUpload" }] : /* istanbul ignore next */ []));
33906
34066
  this.interactionDisabled = computed(() => this.host.isDisabled() || this.host.readonly(), ...(ngDevMode ? [{ debugName: "interactionDisabled" }] : /* istanbul ignore next */ []));
34067
+ /** Extra classes merged onto the toolbar button, after the built-in icon-button styling. */
34068
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
33907
34069
  this.buttonClasses = computed(() => cn('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors', 'hover:bg-accent hover:text-accent-foreground', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', 'disabled:pointer-events-none disabled:opacity-50',
33908
34070
  // The global (pointer: coarse) floor targets `button:not([data-slot])`,
33909
34071
  // and these addon buttons carry a data-slot for testing — so they must
33910
34072
  // state the 44px touch minimum themselves rather than inherit it.
33911
- 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5'), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
34073
+ 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5', this.class()), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
33912
34074
  inject(DestroyRef).onDestroy(() => this.exclusive.release());
33913
34075
  }
33914
34076
  onOpenChange(next) {
@@ -33936,16 +34098,16 @@ class RichTextImagesButtonComponent {
33936
34098
  this.open.set(false);
33937
34099
  }
33938
34100
  onFileSelected(event) {
33939
- const input = event.target;
33940
- const file = input.files?.[0];
33941
- input.value = '';
34101
+ const fileInput = event.target;
34102
+ const file = fileInput.files?.[0];
34103
+ fileInput.value = '';
33942
34104
  if (this.interactionDisabled() || !file)
33943
34105
  return;
33944
34106
  this.context.onUploadFile(file);
33945
34107
  this.open.set(false);
33946
34108
  }
33947
34109
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextImagesButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
33948
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextImagesButtonComponent, isStandalone: true, selector: "ui-rte-images-button", host: { classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n data-slot=\"rte-images-button\"\n [class]=\"buttonClasses()\"\n [title]=\"locale().tooltip\"\n [attr.aria-label]=\"locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-80 max-w-[calc(100vw-2rem)] p-4\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-3\">\n @if (showUrl()) {\n <div>\n <label for=\"rte-image-src\" class=\"text-sm font-medium mb-1 block\">{{ locale().url }}</label>\n <input\n #imageSrc\n id=\"rte-image-src\"\n type=\"url\"\n data-slot=\"rte-images-url\"\n [placeholder]=\"locale().urlPlaceholder\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n </div>\n <div>\n <label for=\"rte-image-alt\" class=\"text-sm font-medium mb-1 block\">{{ locale().altText }}</label>\n <input\n #imageAlt\n id=\"rte-image-alt\"\n type=\"text\"\n data-slot=\"rte-images-alt\"\n [placeholder]=\"locale().altTextPlaceholder\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n </div>\n <ui-button\n size=\"sm\"\n class=\"w-full\"\n data-slot=\"rte-images-insert\"\n [disabled]=\"interactionDisabled()\"\n (click)=\"onInsertUrl(imageSrc, imageAlt)\"\n (keydown.enter)=\"onInsertUrl(imageSrc, imageAlt)\"\n (keydown.space)=\"onInsertUrl(imageSrc, imageAlt)\"\n >\n {{ locale().insert }}\n </ui-button>\n }\n @if (showUpload()) {\n <label\n class=\"flex h-9 w-full cursor-pointer items-center justify-center rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors hover:bg-accent\"\n [class.pointer-events-none]=\"interactionDisabled()\"\n [class.opacity-50]=\"interactionDisabled()\"\n >\n <span>{{ locale().tooltip }}</span>\n <input\n type=\"file\"\n accept=\"image/*\"\n class=\"sr-only\"\n data-slot=\"rte-images-file\"\n [disabled]=\"interactionDisabled()\"\n (change)=\"onFileSelected($event)\"\n />\n </label>\n }\n </div>\n </ui-popover-content>\n</ui-popover>\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }, { kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger" }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
34110
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextImagesButtonComponent, isStandalone: true, selector: "ui-rte-images-button", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n data-slot=\"rte-images-button\"\n [class]=\"buttonClasses()\"\n [title]=\"locale().tooltip\"\n [attr.aria-label]=\"locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-80 max-w-[calc(100vw-2rem)] p-4\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-3\">\n @if (showUrl()) {\n <div>\n <label for=\"rte-image-src\" class=\"text-sm font-medium mb-1 block\">{{ locale().url }}</label>\n <input\n #imageSrc\n id=\"rte-image-src\"\n type=\"url\"\n data-slot=\"rte-images-url\"\n [placeholder]=\"locale().urlPlaceholder\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n </div>\n <div>\n <label for=\"rte-image-alt\" class=\"text-sm font-medium mb-1 block\">{{ locale().altText }}</label>\n <input\n #imageAlt\n id=\"rte-image-alt\"\n type=\"text\"\n data-slot=\"rte-images-alt\"\n [placeholder]=\"locale().altTextPlaceholder\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n </div>\n <ui-button\n size=\"sm\"\n class=\"w-full\"\n data-slot=\"rte-images-insert\"\n [disabled]=\"interactionDisabled()\"\n (click)=\"onInsertUrl(imageSrc, imageAlt)\"\n (keydown.enter)=\"onInsertUrl(imageSrc, imageAlt)\"\n (keydown.space)=\"onInsertUrl(imageSrc, imageAlt)\"\n >\n {{ locale().insert }}\n </ui-button>\n }\n @if (showUpload()) {\n <label\n class=\"flex h-9 w-full cursor-pointer items-center justify-center rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors hover:bg-accent\"\n [class.pointer-events-none]=\"interactionDisabled()\"\n [class.opacity-50]=\"interactionDisabled()\"\n >\n <span>{{ locale().tooltip }}</span>\n <input\n type=\"file\"\n accept=\"image/*\"\n class=\"sr-only\"\n data-slot=\"rte-images-file\"\n [disabled]=\"interactionDisabled()\"\n (change)=\"onFileSelected($event)\"\n />\n </label>\n }\n </div>\n </ui-popover-content>\n</ui-popover>\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }, { kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["class", "open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger", inputs: ["class"] }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
33949
34111
  }
33950
34112
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextImagesButtonComponent, decorators: [{
33951
34113
  type: Component,
@@ -33955,7 +34117,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
33955
34117
  PopoverTriggerComponent,
33956
34118
  PopoverContentComponent,
33957
34119
  ], host: { class: 'contents' }, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n data-slot=\"rte-images-button\"\n [class]=\"buttonClasses()\"\n [title]=\"locale().tooltip\"\n [attr.aria-label]=\"locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-80 max-w-[calc(100vw-2rem)] p-4\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-3\">\n @if (showUrl()) {\n <div>\n <label for=\"rte-image-src\" class=\"text-sm font-medium mb-1 block\">{{ locale().url }}</label>\n <input\n #imageSrc\n id=\"rte-image-src\"\n type=\"url\"\n data-slot=\"rte-images-url\"\n [placeholder]=\"locale().urlPlaceholder\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n </div>\n <div>\n <label for=\"rte-image-alt\" class=\"text-sm font-medium mb-1 block\">{{ locale().altText }}</label>\n <input\n #imageAlt\n id=\"rte-image-alt\"\n type=\"text\"\n data-slot=\"rte-images-alt\"\n [placeholder]=\"locale().altTextPlaceholder\"\n class=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n </div>\n <ui-button\n size=\"sm\"\n class=\"w-full\"\n data-slot=\"rte-images-insert\"\n [disabled]=\"interactionDisabled()\"\n (click)=\"onInsertUrl(imageSrc, imageAlt)\"\n (keydown.enter)=\"onInsertUrl(imageSrc, imageAlt)\"\n (keydown.space)=\"onInsertUrl(imageSrc, imageAlt)\"\n >\n {{ locale().insert }}\n </ui-button>\n }\n @if (showUpload()) {\n <label\n class=\"flex h-9 w-full cursor-pointer items-center justify-center rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors hover:bg-accent\"\n [class.pointer-events-none]=\"interactionDisabled()\"\n [class.opacity-50]=\"interactionDisabled()\"\n >\n <span>{{ locale().tooltip }}</span>\n <input\n type=\"file\"\n accept=\"image/*\"\n class=\"sr-only\"\n data-slot=\"rte-images-file\"\n [disabled]=\"interactionDisabled()\"\n (change)=\"onFileSelected($event)\"\n />\n </label>\n }\n </div>\n </ui-popover-content>\n</ui-popover>\n" }]
33958
- }], ctorParameters: () => [] });
34120
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
33959
34121
 
33960
34122
  /**
33961
34123
  * Apply the inline styles for a given alignment to an image element. Shared by
@@ -34128,6 +34290,9 @@ const KEYBOARD_RESIZE_COALESCE_MS = 400;
34128
34290
  const MAX_IMAGE_DIMENSION = 10000;
34129
34291
  class RichTextImageResizerComponent {
34130
34292
  constructor() {
34293
+ /** Extra classes merged onto the selection frame drawn over the image, after its primary-coloured border. */
34294
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
34295
+ this.classes = computed(() => cn('absolute border-2 border-primary pointer-events-none transition-none', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
34131
34296
  this.document = inject(DOCUMENT);
34132
34297
  this.sanitizer = inject(DomSanitizer);
34133
34298
  /**
@@ -34552,12 +34717,12 @@ class RichTextImageResizerComponent {
34552
34717
  }
34553
34718
  }
34554
34719
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextImageResizerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
34555
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextImageResizerComponent, isStandalone: true, selector: "ui-rich-text-image-resizer", inputs: { target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, showAlignment: { classPropertyName: "showAlignment", publicName: "showAlignment", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, lockAspectRatio: { classPropertyName: "lockAspectRatio", publicName: "lockAspectRatio", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { resizeEnd: "resizeEnd", alignmentChange: "alignmentChange", imageRemove: "imageRemove" }, ngImport: i0, template: "@if (target()) {\n <div class=\"absolute border-2 border-primary pointer-events-none transition-none\"\n [style.top.px]=\"rect().top\"\n [style.left.px]=\"rect().left\"\n [style.width.px]=\"rect().width\"\n [style.height.px]=\"rect().height\"\n [style.display]=\"visible() ? 'block' : 'none'\">\n\n @if (resizable()) {\n <button type=\"button\"\n class=\"absolute -top-1.5 -left-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-nw-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('nw')\"\n (keydown)=\"onResizeKeydown($event, 'nw')\"\n (mousedown)=\"startResize($event, 'nw')\" (touchstart)=\"startResize($event, 'nw')\"></button>\n <button type=\"button\"\n class=\"absolute -top-1.5 -right-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-ne-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('ne')\"\n (keydown)=\"onResizeKeydown($event, 'ne')\"\n (mousedown)=\"startResize($event, 'ne')\" (touchstart)=\"startResize($event, 'ne')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 -left-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-sw-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('sw')\"\n (keydown)=\"onResizeKeydown($event, 'sw')\"\n (mousedown)=\"startResize($event, 'sw')\" (touchstart)=\"startResize($event, 'sw')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 -right-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-se-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('se')\"\n (keydown)=\"onResizeKeydown($event, 'se')\"\n (mousedown)=\"startResize($event, 'se')\" (touchstart)=\"startResize($event, 'se')\"></button>\n }\n\n @if (resizable() && !lockAspectRatio()) {\n <button type=\"button\"\n class=\"absolute -top-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ns-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('n')\"\n (keydown)=\"onResizeKeydown($event, 'n')\"\n (mousedown)=\"startResize($event, 'n')\" (touchstart)=\"startResize($event, 'n')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ns-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('s')\"\n (keydown)=\"onResizeKeydown($event, 's')\"\n (mousedown)=\"startResize($event, 's')\" (touchstart)=\"startResize($event, 's')\"></button>\n <button type=\"button\"\n class=\"absolute -left-1.5 top-1/2 -translate-y-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ew-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('w')\"\n (keydown)=\"onResizeKeydown($event, 'w')\"\n (mousedown)=\"startResize($event, 'w')\" (touchstart)=\"startResize($event, 'w')\"></button>\n <button type=\"button\"\n class=\"absolute -right-1.5 top-1/2 -translate-y-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ew-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('e')\"\n (keydown)=\"onResizeKeydown($event, 'e')\"\n (mousedown)=\"startResize($event, 'e')\" (touchstart)=\"startResize($event, 'e')\"></button>\n }\n\n <div class=\"absolute -top-10 left-1/2 -translate-x-1/2 pointer-events-auto flex items-center gap-0.5 bg-popover border rounded-md shadow-md p-0.5\">\n @if (showAlignment()) {\n @for (align of alignments; track align) {\n <button\n type=\"button\"\n class=\"p-1.5 rounded-sm hover:bg-accent transition-colors\"\n [class.bg-accent]=\"currentAlignment() === align\"\n [class.text-accent-foreground]=\"currentAlignment() === align\"\n [title]=\"resolvedAlignmentLabels()[align]\"\n (mousedown)=\"onAlignClick($event, align)\"\n (click)=\"onAlignClick($event, align)\"\n [attr.aria-label]=\"resolvedAlignmentLabels()[align]\"\n [attr.aria-pressed]=\"currentAlignment() === align\">\n <span [innerHTML]=\"getAlignIcon(align)\"></span>\n </button>\n }\n <div class=\"w-px h-5 bg-border mx-0.5\"></div>\n }\n <button\n type=\"button\"\n class=\"p-1.5 rounded-sm hover:bg-destructive/10 hover:text-destructive transition-colors\"\n [title]=\"labels().deleteImage\"\n (mousedown)=\"onDeleteClick($event)\"\n (click)=\"onDeleteClick($event)\"\n [attr.aria-label]=\"labels().deleteImage\">\n <span [innerHTML]=\"deleteIconHtml\"></span>\n </button>\n </div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
34720
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextImageResizerComponent, isStandalone: true, selector: "ui-rich-text-image-resizer", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, showAlignment: { classPropertyName: "showAlignment", publicName: "showAlignment", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, lockAspectRatio: { classPropertyName: "lockAspectRatio", publicName: "lockAspectRatio", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { resizeEnd: "resizeEnd", alignmentChange: "alignmentChange", imageRemove: "imageRemove" }, ngImport: i0, template: "@if (target()) {\n <div [class]=\"classes()\" [attr.data-slot]=\"'rte-image-resizer'\"\n [style.top.px]=\"rect().top\"\n [style.left.px]=\"rect().left\"\n [style.width.px]=\"rect().width\"\n [style.height.px]=\"rect().height\"\n [style.display]=\"visible() ? 'block' : 'none'\">\n\n @if (resizable()) {\n <button type=\"button\"\n class=\"absolute -top-1.5 -left-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-nw-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('nw')\"\n (keydown)=\"onResizeKeydown($event, 'nw')\"\n (mousedown)=\"startResize($event, 'nw')\" (touchstart)=\"startResize($event, 'nw')\"></button>\n <button type=\"button\"\n class=\"absolute -top-1.5 -right-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-ne-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('ne')\"\n (keydown)=\"onResizeKeydown($event, 'ne')\"\n (mousedown)=\"startResize($event, 'ne')\" (touchstart)=\"startResize($event, 'ne')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 -left-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-sw-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('sw')\"\n (keydown)=\"onResizeKeydown($event, 'sw')\"\n (mousedown)=\"startResize($event, 'sw')\" (touchstart)=\"startResize($event, 'sw')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 -right-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-se-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('se')\"\n (keydown)=\"onResizeKeydown($event, 'se')\"\n (mousedown)=\"startResize($event, 'se')\" (touchstart)=\"startResize($event, 'se')\"></button>\n }\n\n @if (resizable() && !lockAspectRatio()) {\n <button type=\"button\"\n class=\"absolute -top-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ns-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('n')\"\n (keydown)=\"onResizeKeydown($event, 'n')\"\n (mousedown)=\"startResize($event, 'n')\" (touchstart)=\"startResize($event, 'n')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ns-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('s')\"\n (keydown)=\"onResizeKeydown($event, 's')\"\n (mousedown)=\"startResize($event, 's')\" (touchstart)=\"startResize($event, 's')\"></button>\n <button type=\"button\"\n class=\"absolute -left-1.5 top-1/2 -translate-y-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ew-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('w')\"\n (keydown)=\"onResizeKeydown($event, 'w')\"\n (mousedown)=\"startResize($event, 'w')\" (touchstart)=\"startResize($event, 'w')\"></button>\n <button type=\"button\"\n class=\"absolute -right-1.5 top-1/2 -translate-y-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ew-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('e')\"\n (keydown)=\"onResizeKeydown($event, 'e')\"\n (mousedown)=\"startResize($event, 'e')\" (touchstart)=\"startResize($event, 'e')\"></button>\n }\n\n <div class=\"absolute -top-10 left-1/2 -translate-x-1/2 pointer-events-auto flex items-center gap-0.5 bg-popover border rounded-md shadow-md p-0.5\">\n @if (showAlignment()) {\n @for (align of alignments; track align) {\n <button\n type=\"button\"\n class=\"p-1.5 rounded-sm hover:bg-accent transition-colors\"\n [class.bg-accent]=\"currentAlignment() === align\"\n [class.text-accent-foreground]=\"currentAlignment() === align\"\n [title]=\"resolvedAlignmentLabels()[align]\"\n (mousedown)=\"onAlignClick($event, align)\"\n (click)=\"onAlignClick($event, align)\"\n [attr.aria-label]=\"resolvedAlignmentLabels()[align]\"\n [attr.aria-pressed]=\"currentAlignment() === align\">\n <span [innerHTML]=\"getAlignIcon(align)\"></span>\n </button>\n }\n <div class=\"w-px h-5 bg-border mx-0.5\"></div>\n }\n <button\n type=\"button\"\n class=\"p-1.5 rounded-sm hover:bg-destructive/10 hover:text-destructive transition-colors\"\n [title]=\"labels().deleteImage\"\n (mousedown)=\"onDeleteClick($event)\"\n (click)=\"onDeleteClick($event)\"\n [attr.aria-label]=\"labels().deleteImage\">\n <span [innerHTML]=\"deleteIconHtml\"></span>\n </button>\n </div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
34556
34721
  }
34557
34722
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextImageResizerComponent, decorators: [{
34558
34723
  type: Component,
34559
- args: [{ selector: 'ui-rich-text-image-resizer', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (target()) {\n <div class=\"absolute border-2 border-primary pointer-events-none transition-none\"\n [style.top.px]=\"rect().top\"\n [style.left.px]=\"rect().left\"\n [style.width.px]=\"rect().width\"\n [style.height.px]=\"rect().height\"\n [style.display]=\"visible() ? 'block' : 'none'\">\n\n @if (resizable()) {\n <button type=\"button\"\n class=\"absolute -top-1.5 -left-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-nw-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('nw')\"\n (keydown)=\"onResizeKeydown($event, 'nw')\"\n (mousedown)=\"startResize($event, 'nw')\" (touchstart)=\"startResize($event, 'nw')\"></button>\n <button type=\"button\"\n class=\"absolute -top-1.5 -right-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-ne-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('ne')\"\n (keydown)=\"onResizeKeydown($event, 'ne')\"\n (mousedown)=\"startResize($event, 'ne')\" (touchstart)=\"startResize($event, 'ne')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 -left-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-sw-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('sw')\"\n (keydown)=\"onResizeKeydown($event, 'sw')\"\n (mousedown)=\"startResize($event, 'sw')\" (touchstart)=\"startResize($event, 'sw')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 -right-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-se-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('se')\"\n (keydown)=\"onResizeKeydown($event, 'se')\"\n (mousedown)=\"startResize($event, 'se')\" (touchstart)=\"startResize($event, 'se')\"></button>\n }\n\n @if (resizable() && !lockAspectRatio()) {\n <button type=\"button\"\n class=\"absolute -top-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ns-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('n')\"\n (keydown)=\"onResizeKeydown($event, 'n')\"\n (mousedown)=\"startResize($event, 'n')\" (touchstart)=\"startResize($event, 'n')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ns-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('s')\"\n (keydown)=\"onResizeKeydown($event, 's')\"\n (mousedown)=\"startResize($event, 's')\" (touchstart)=\"startResize($event, 's')\"></button>\n <button type=\"button\"\n class=\"absolute -left-1.5 top-1/2 -translate-y-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ew-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('w')\"\n (keydown)=\"onResizeKeydown($event, 'w')\"\n (mousedown)=\"startResize($event, 'w')\" (touchstart)=\"startResize($event, 'w')\"></button>\n <button type=\"button\"\n class=\"absolute -right-1.5 top-1/2 -translate-y-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ew-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('e')\"\n (keydown)=\"onResizeKeydown($event, 'e')\"\n (mousedown)=\"startResize($event, 'e')\" (touchstart)=\"startResize($event, 'e')\"></button>\n }\n\n <div class=\"absolute -top-10 left-1/2 -translate-x-1/2 pointer-events-auto flex items-center gap-0.5 bg-popover border rounded-md shadow-md p-0.5\">\n @if (showAlignment()) {\n @for (align of alignments; track align) {\n <button\n type=\"button\"\n class=\"p-1.5 rounded-sm hover:bg-accent transition-colors\"\n [class.bg-accent]=\"currentAlignment() === align\"\n [class.text-accent-foreground]=\"currentAlignment() === align\"\n [title]=\"resolvedAlignmentLabels()[align]\"\n (mousedown)=\"onAlignClick($event, align)\"\n (click)=\"onAlignClick($event, align)\"\n [attr.aria-label]=\"resolvedAlignmentLabels()[align]\"\n [attr.aria-pressed]=\"currentAlignment() === align\">\n <span [innerHTML]=\"getAlignIcon(align)\"></span>\n </button>\n }\n <div class=\"w-px h-5 bg-border mx-0.5\"></div>\n }\n <button\n type=\"button\"\n class=\"p-1.5 rounded-sm hover:bg-destructive/10 hover:text-destructive transition-colors\"\n [title]=\"labels().deleteImage\"\n (mousedown)=\"onDeleteClick($event)\"\n (click)=\"onDeleteClick($event)\"\n [attr.aria-label]=\"labels().deleteImage\">\n <span [innerHTML]=\"deleteIconHtml\"></span>\n </button>\n </div>\n </div>\n}\n" }]
34560
- }], ctorParameters: () => [], propDecorators: { target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], container: [{ type: i0.Input, args: [{ isSignal: true, alias: "container", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], showAlignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlignment", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], lockAspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockAspectRatio", required: false }] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], alignmentChange: [{ type: i0.Output, args: ["alignmentChange"] }], imageRemove: [{ type: i0.Output, args: ["imageRemove"] }] } });
34724
+ args: [{ selector: 'ui-rich-text-image-resizer', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (target()) {\n <div [class]=\"classes()\" [attr.data-slot]=\"'rte-image-resizer'\"\n [style.top.px]=\"rect().top\"\n [style.left.px]=\"rect().left\"\n [style.width.px]=\"rect().width\"\n [style.height.px]=\"rect().height\"\n [style.display]=\"visible() ? 'block' : 'none'\">\n\n @if (resizable()) {\n <button type=\"button\"\n class=\"absolute -top-1.5 -left-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-nw-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('nw')\"\n (keydown)=\"onResizeKeydown($event, 'nw')\"\n (mousedown)=\"startResize($event, 'nw')\" (touchstart)=\"startResize($event, 'nw')\"></button>\n <button type=\"button\"\n class=\"absolute -top-1.5 -right-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-ne-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('ne')\"\n (keydown)=\"onResizeKeydown($event, 'ne')\"\n (mousedown)=\"startResize($event, 'ne')\" (touchstart)=\"startResize($event, 'ne')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 -left-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-sw-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('sw')\"\n (keydown)=\"onResizeKeydown($event, 'sw')\"\n (mousedown)=\"startResize($event, 'sw')\" (touchstart)=\"startResize($event, 'sw')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 -right-1.5 w-3 h-3 bg-primary border border-white rounded-sm cursor-se-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('se')\"\n (keydown)=\"onResizeKeydown($event, 'se')\"\n (mousedown)=\"startResize($event, 'se')\" (touchstart)=\"startResize($event, 'se')\"></button>\n }\n\n @if (resizable() && !lockAspectRatio()) {\n <button type=\"button\"\n class=\"absolute -top-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ns-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('n')\"\n (keydown)=\"onResizeKeydown($event, 'n')\"\n (mousedown)=\"startResize($event, 'n')\" (touchstart)=\"startResize($event, 'n')\"></button>\n <button type=\"button\"\n class=\"absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ns-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('s')\"\n (keydown)=\"onResizeKeydown($event, 's')\"\n (mousedown)=\"startResize($event, 's')\" (touchstart)=\"startResize($event, 's')\"></button>\n <button type=\"button\"\n class=\"absolute -left-1.5 top-1/2 -translate-y-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ew-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('w')\"\n (keydown)=\"onResizeKeydown($event, 'w')\"\n (mousedown)=\"startResize($event, 'w')\" (touchstart)=\"startResize($event, 'w')\"></button>\n <button type=\"button\"\n class=\"absolute -right-1.5 top-1/2 -translate-y-1/2 w-3 h-3 bg-primary border border-white rounded-sm cursor-ew-resize pointer-events-auto shadow-sm touch-none before:absolute before:-inset-4 before:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\"\n [attr.aria-label]=\"handleLabel('e')\"\n (keydown)=\"onResizeKeydown($event, 'e')\"\n (mousedown)=\"startResize($event, 'e')\" (touchstart)=\"startResize($event, 'e')\"></button>\n }\n\n <div class=\"absolute -top-10 left-1/2 -translate-x-1/2 pointer-events-auto flex items-center gap-0.5 bg-popover border rounded-md shadow-md p-0.5\">\n @if (showAlignment()) {\n @for (align of alignments; track align) {\n <button\n type=\"button\"\n class=\"p-1.5 rounded-sm hover:bg-accent transition-colors\"\n [class.bg-accent]=\"currentAlignment() === align\"\n [class.text-accent-foreground]=\"currentAlignment() === align\"\n [title]=\"resolvedAlignmentLabels()[align]\"\n (mousedown)=\"onAlignClick($event, align)\"\n (click)=\"onAlignClick($event, align)\"\n [attr.aria-label]=\"resolvedAlignmentLabels()[align]\"\n [attr.aria-pressed]=\"currentAlignment() === align\">\n <span [innerHTML]=\"getAlignIcon(align)\"></span>\n </button>\n }\n <div class=\"w-px h-5 bg-border mx-0.5\"></div>\n }\n <button\n type=\"button\"\n class=\"p-1.5 rounded-sm hover:bg-destructive/10 hover:text-destructive transition-colors\"\n [title]=\"labels().deleteImage\"\n (mousedown)=\"onDeleteClick($event)\"\n (click)=\"onDeleteClick($event)\"\n [attr.aria-label]=\"labels().deleteImage\">\n <span [innerHTML]=\"deleteIconHtml\"></span>\n </button>\n </div>\n </div>\n}\n" }]
34725
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], container: [{ type: i0.Input, args: [{ isSignal: true, alias: "container", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], showAlignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlignment", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], lockAspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockAspectRatio", required: false }] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], alignmentChange: [{ type: i0.Output, args: ["alignmentChange"] }], imageRemove: [{ type: i0.Output, args: ["imageRemove"] }] } });
34561
34726
 
34562
34727
  /**
34563
34728
  * The images addon's editor-frame overlay layer: the resize/align handles for
@@ -34567,6 +34732,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
34567
34732
  */
34568
34733
  class RichTextImagesOverlayComponent {
34569
34734
  constructor() {
34735
+ /** Extra classes merged onto the full-editor uploading scrim, after its default blurred backdrop. */
34736
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
34737
+ this.uploadingClasses = computed(() => cn('absolute inset-0 z-20 flex items-center justify-center bg-background/70 backdrop-blur-[1px]', this.class()), ...(ngDevMode ? [{ debugName: "uploadingClasses" }] : /* istanbul ignore next */ []));
34570
34738
  /**
34571
34739
  * The currently selected image, forwarded to the resizer. `null` (the
34572
34740
  * default, and what the directive sends while the addon is disabled) hides
@@ -34634,12 +34802,12 @@ class RichTextImagesOverlayComponent {
34634
34802
  this.removeError = output();
34635
34803
  }
34636
34804
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextImagesOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
34637
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextImagesOverlayComponent, isStandalone: true, selector: "ui-rte-images-overlay", inputs: { target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: true, transformFunction: null }, resizerLabels: { classPropertyName: "resizerLabels", publicName: "resizerLabels", isSignal: true, isRequired: true, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, showAlignment: { classPropertyName: "showAlignment", publicName: "showAlignment", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, lockAspectRatio: { classPropertyName: "lockAspectRatio", publicName: "lockAspectRatio", isSignal: true, isRequired: false, transformFunction: null }, uploading: { classPropertyName: "uploading", publicName: "uploading", isSignal: true, isRequired: false, transformFunction: null }, errorEntries: { classPropertyName: "errorEntries", publicName: "errorEntries", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { resizeEnd: "resizeEnd", alignmentChange: "alignmentChange", imageRemove: "imageRemove", retryError: "retryError", removeError: "removeError" }, host: { classAttribute: "contents" }, ngImport: i0, template: "@if (uploading()) {\n <div class=\"absolute inset-0 z-20 flex items-center justify-center bg-background/70 backdrop-blur-[1px]\" data-slot=\"rte-images-uploading\">\n <div class=\"text-sm text-muted-foreground\">{{ locale().uploading }}</div>\n </div>\n}\n\n@for (entry of errorEntries(); track entry.id) {\n <div\n class=\"absolute z-20 flex flex-col items-center justify-center gap-1.5 rounded bg-destructive/10 border border-destructive/30 backdrop-blur-[1px]\"\n data-slot=\"rte-images-error\"\n [style.top.px]=\"entry.top\"\n [style.left.px]=\"entry.left\"\n [style.width.px]=\"entry.width\"\n [style.height.px]=\"entry.height\"\n contenteditable=\"false\"\n >\n <svg class=\"h-5 w-5 text-destructive\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z\" />\n </svg>\n <span class=\"text-xs text-destructive font-medium\">{{ locale().uploadFailed }}</span>\n <div class=\"flex gap-1\">\n <button\n type=\"button\"\n class=\"text-xs px-2 py-0.5 rounded bg-background border border-border text-foreground hover:bg-accent transition-colors\"\n (click)=\"retryError.emit(entry.id)\"\n >\n {{ locale().uploadRetry }}\n </button>\n <button\n type=\"button\"\n class=\"text-xs px-2 py-0.5 rounded bg-background border border-border text-foreground hover:bg-accent transition-colors\"\n (click)=\"removeError.emit(entry.id)\"\n >\n {{ locale().uploadRemove }}\n </button>\n </div>\n </div>\n}\n\n<ui-rich-text-image-resizer\n [target]=\"target()\"\n [container]=\"container()\"\n [labels]=\"resizerLabels()\"\n [resizable]=\"resizable()\"\n [showAlignment]=\"showAlignment()\"\n [minWidth]=\"minWidth()\"\n [maxWidth]=\"maxWidth()\"\n [lockAspectRatio]=\"lockAspectRatio()\"\n (resizeEnd)=\"resizeEnd.emit()\"\n (alignmentChange)=\"alignmentChange.emit($event)\"\n (imageRemove)=\"imageRemove.emit($event)\"\n/>\n", dependencies: [{ kind: "component", type: RichTextImageResizerComponent, selector: "ui-rich-text-image-resizer", inputs: ["target", "container", "labels", "resizable", "showAlignment", "minWidth", "maxWidth", "lockAspectRatio"], outputs: ["resizeEnd", "alignmentChange", "imageRemove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
34805
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextImagesOverlayComponent, isStandalone: true, selector: "ui-rte-images-overlay", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: true, transformFunction: null }, resizerLabels: { classPropertyName: "resizerLabels", publicName: "resizerLabels", isSignal: true, isRequired: true, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, showAlignment: { classPropertyName: "showAlignment", publicName: "showAlignment", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, lockAspectRatio: { classPropertyName: "lockAspectRatio", publicName: "lockAspectRatio", isSignal: true, isRequired: false, transformFunction: null }, uploading: { classPropertyName: "uploading", publicName: "uploading", isSignal: true, isRequired: false, transformFunction: null }, errorEntries: { classPropertyName: "errorEntries", publicName: "errorEntries", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { resizeEnd: "resizeEnd", alignmentChange: "alignmentChange", imageRemove: "imageRemove", retryError: "retryError", removeError: "removeError" }, host: { classAttribute: "contents" }, ngImport: i0, template: "@if (uploading()) {\n <div [class]=\"uploadingClasses()\" data-slot=\"rte-images-uploading\">\n <div class=\"text-sm text-muted-foreground\">{{ locale().uploading }}</div>\n </div>\n}\n\n@for (entry of errorEntries(); track entry.id) {\n <div\n class=\"absolute z-20 flex flex-col items-center justify-center gap-1.5 rounded bg-destructive/10 border border-destructive/30 backdrop-blur-[1px]\"\n data-slot=\"rte-images-error\"\n [style.top.px]=\"entry.top\"\n [style.left.px]=\"entry.left\"\n [style.width.px]=\"entry.width\"\n [style.height.px]=\"entry.height\"\n contenteditable=\"false\"\n >\n <svg class=\"h-5 w-5 text-destructive\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z\" />\n </svg>\n <span class=\"text-xs text-destructive font-medium\">{{ locale().uploadFailed }}</span>\n <div class=\"flex gap-1\">\n <button\n type=\"button\"\n class=\"text-xs px-2 py-0.5 rounded bg-background border border-border text-foreground hover:bg-accent transition-colors\"\n (click)=\"retryError.emit(entry.id)\"\n >\n {{ locale().uploadRetry }}\n </button>\n <button\n type=\"button\"\n class=\"text-xs px-2 py-0.5 rounded bg-background border border-border text-foreground hover:bg-accent transition-colors\"\n (click)=\"removeError.emit(entry.id)\"\n >\n {{ locale().uploadRemove }}\n </button>\n </div>\n </div>\n}\n\n<ui-rich-text-image-resizer\n [target]=\"target()\"\n [container]=\"container()\"\n [labels]=\"resizerLabels()\"\n [resizable]=\"resizable()\"\n [showAlignment]=\"showAlignment()\"\n [minWidth]=\"minWidth()\"\n [maxWidth]=\"maxWidth()\"\n [lockAspectRatio]=\"lockAspectRatio()\"\n (resizeEnd)=\"resizeEnd.emit()\"\n (alignmentChange)=\"alignmentChange.emit($event)\"\n (imageRemove)=\"imageRemove.emit($event)\"\n/>\n", dependencies: [{ kind: "component", type: RichTextImageResizerComponent, selector: "ui-rich-text-image-resizer", inputs: ["class", "target", "container", "labels", "resizable", "showAlignment", "minWidth", "maxWidth", "lockAspectRatio"], outputs: ["resizeEnd", "alignmentChange", "imageRemove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
34638
34806
  }
34639
34807
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextImagesOverlayComponent, decorators: [{
34640
34808
  type: Component,
34641
- args: [{ selector: 'ui-rte-images-overlay', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [RichTextImageResizerComponent], host: { class: 'contents' }, template: "@if (uploading()) {\n <div class=\"absolute inset-0 z-20 flex items-center justify-center bg-background/70 backdrop-blur-[1px]\" data-slot=\"rte-images-uploading\">\n <div class=\"text-sm text-muted-foreground\">{{ locale().uploading }}</div>\n </div>\n}\n\n@for (entry of errorEntries(); track entry.id) {\n <div\n class=\"absolute z-20 flex flex-col items-center justify-center gap-1.5 rounded bg-destructive/10 border border-destructive/30 backdrop-blur-[1px]\"\n data-slot=\"rte-images-error\"\n [style.top.px]=\"entry.top\"\n [style.left.px]=\"entry.left\"\n [style.width.px]=\"entry.width\"\n [style.height.px]=\"entry.height\"\n contenteditable=\"false\"\n >\n <svg class=\"h-5 w-5 text-destructive\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z\" />\n </svg>\n <span class=\"text-xs text-destructive font-medium\">{{ locale().uploadFailed }}</span>\n <div class=\"flex gap-1\">\n <button\n type=\"button\"\n class=\"text-xs px-2 py-0.5 rounded bg-background border border-border text-foreground hover:bg-accent transition-colors\"\n (click)=\"retryError.emit(entry.id)\"\n >\n {{ locale().uploadRetry }}\n </button>\n <button\n type=\"button\"\n class=\"text-xs px-2 py-0.5 rounded bg-background border border-border text-foreground hover:bg-accent transition-colors\"\n (click)=\"removeError.emit(entry.id)\"\n >\n {{ locale().uploadRemove }}\n </button>\n </div>\n </div>\n}\n\n<ui-rich-text-image-resizer\n [target]=\"target()\"\n [container]=\"container()\"\n [labels]=\"resizerLabels()\"\n [resizable]=\"resizable()\"\n [showAlignment]=\"showAlignment()\"\n [minWidth]=\"minWidth()\"\n [maxWidth]=\"maxWidth()\"\n [lockAspectRatio]=\"lockAspectRatio()\"\n (resizeEnd)=\"resizeEnd.emit()\"\n (alignmentChange)=\"alignmentChange.emit($event)\"\n (imageRemove)=\"imageRemove.emit($event)\"\n/>\n" }]
34642
- }], propDecorators: { target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], container: [{ type: i0.Input, args: [{ isSignal: true, alias: "container", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: true }] }], resizerLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizerLabels", required: true }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], showAlignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlignment", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], lockAspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockAspectRatio", required: false }] }], uploading: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploading", required: false }] }], errorEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorEntries", required: false }] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], alignmentChange: [{ type: i0.Output, args: ["alignmentChange"] }], imageRemove: [{ type: i0.Output, args: ["imageRemove"] }], retryError: [{ type: i0.Output, args: ["retryError"] }], removeError: [{ type: i0.Output, args: ["removeError"] }] } });
34809
+ args: [{ selector: 'ui-rte-images-overlay', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [RichTextImageResizerComponent], host: { class: 'contents' }, template: "@if (uploading()) {\n <div [class]=\"uploadingClasses()\" data-slot=\"rte-images-uploading\">\n <div class=\"text-sm text-muted-foreground\">{{ locale().uploading }}</div>\n </div>\n}\n\n@for (entry of errorEntries(); track entry.id) {\n <div\n class=\"absolute z-20 flex flex-col items-center justify-center gap-1.5 rounded bg-destructive/10 border border-destructive/30 backdrop-blur-[1px]\"\n data-slot=\"rte-images-error\"\n [style.top.px]=\"entry.top\"\n [style.left.px]=\"entry.left\"\n [style.width.px]=\"entry.width\"\n [style.height.px]=\"entry.height\"\n contenteditable=\"false\"\n >\n <svg class=\"h-5 w-5 text-destructive\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z\" />\n </svg>\n <span class=\"text-xs text-destructive font-medium\">{{ locale().uploadFailed }}</span>\n <div class=\"flex gap-1\">\n <button\n type=\"button\"\n class=\"text-xs px-2 py-0.5 rounded bg-background border border-border text-foreground hover:bg-accent transition-colors\"\n (click)=\"retryError.emit(entry.id)\"\n >\n {{ locale().uploadRetry }}\n </button>\n <button\n type=\"button\"\n class=\"text-xs px-2 py-0.5 rounded bg-background border border-border text-foreground hover:bg-accent transition-colors\"\n (click)=\"removeError.emit(entry.id)\"\n >\n {{ locale().uploadRemove }}\n </button>\n </div>\n </div>\n}\n\n<ui-rich-text-image-resizer\n [target]=\"target()\"\n [container]=\"container()\"\n [labels]=\"resizerLabels()\"\n [resizable]=\"resizable()\"\n [showAlignment]=\"showAlignment()\"\n [minWidth]=\"minWidth()\"\n [maxWidth]=\"maxWidth()\"\n [lockAspectRatio]=\"lockAspectRatio()\"\n (resizeEnd)=\"resizeEnd.emit()\"\n (alignmentChange)=\"alignmentChange.emit($event)\"\n (imageRemove)=\"imageRemove.emit($event)\"\n/>\n" }]
34810
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], container: [{ type: i0.Input, args: [{ isSignal: true, alias: "container", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: true }] }], resizerLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizerLabels", required: true }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], showAlignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlignment", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], lockAspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockAspectRatio", required: false }] }], uploading: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploading", required: false }] }], errorEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorEntries", required: false }] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], alignmentChange: [{ type: i0.Output, args: ["alignmentChange"] }], imageRemove: [{ type: i0.Output, args: ["imageRemove"] }], retryError: [{ type: i0.Output, args: ["retryError"] }], removeError: [{ type: i0.Output, args: ["removeError"] }] } });
34643
34811
 
34644
34812
  const IMAGE_SLOT_ID = 'images.insert';
34645
34813
  const AUTO_UPLOAD_STYLE_ID = 'ui-rte-auto-upload-styles';
@@ -35254,6 +35422,9 @@ const RICH_TEXT_LINKS_LOCALES = {
35254
35422
  */
35255
35423
  class RichTextLinksFormComponent {
35256
35424
  constructor() {
35425
+ /** Extra classes merged onto the form container, after its bounded `w-72` default. */
35426
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
35427
+ this.classes = computed(() => cn('w-72 max-w-[calc(100vw-2rem)] space-y-3', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
35257
35428
  /** Resolved locale strings. */
35258
35429
  this.locale = input(RICH_TEXT_LINKS_LOCALES['en'], ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
35259
35430
  /**
@@ -35285,12 +35456,12 @@ class RichTextLinksFormComponent {
35285
35456
  this.submitLink.emit({ text: text.trim(), url: trimmedUrl });
35286
35457
  }
35287
35458
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextLinksFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
35288
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextLinksFormComponent, isStandalone: true, selector: "ui-rich-text-links-form", inputs: { locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null }, showRemove: { classPropertyName: "showRemove", publicName: "showRemove", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitLink: "submitLink", cancelLink: "cancelLink", removeLink: "removeLink" }, host: { classAttribute: "contents" }, ngImport: i0, template: "<div\n class=\"w-72 max-w-[calc(100vw-2rem)] space-y-3\"\n [attr.dir]=\"dir()\"\n [attr.data-slot]=\"'rich-text-links-form'\"\n>\n <p class=\"text-sm font-medium m-0\">{{ locale().tooltip }}</p>\n\n <label class=\"block space-y-1\">\n <span class=\"text-xs text-muted-foreground\">{{ locale().text }}</span>\n <input\n #linkText\n type=\"text\"\n [value]=\"text()\"\n [placeholder]=\"locale().textPlaceholder\"\n class=\"border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n (keydown.enter)=\"onSubmit(linkText.value, linkUrl.value)\"\n />\n </label>\n\n <label class=\"block space-y-1\">\n <span class=\"text-xs text-muted-foreground\">{{ locale().url }}</span>\n <input\n #linkUrl\n type=\"url\"\n [value]=\"url()\"\n [placeholder]=\"locale().urlPlaceholder\"\n class=\"border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n [attr.aria-invalid]=\"errorMessage() ? 'true' : null\"\n [attr.aria-describedby]=\"errorMessage() ? 'rte-link-url-error' : null\"\n (keydown.enter)=\"onSubmit(linkText.value, linkUrl.value)\"\n />\n </label>\n\n @if (errorMessage()) {\n <p id=\"rte-link-url-error\" role=\"alert\" class=\"text-destructive m-0 text-xs\">\n {{ errorMessage() }}\n </p>\n }\n\n <div class=\"flex flex-wrap justify-end gap-2 pt-1\">\n @if (showRemove()) {\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"removeLink.emit()\">{{ locale().remove }}</ui-button>\n }\n <ui-button variant=\"outline\" size=\"sm\" (click)=\"cancelLink.emit()\">{{ locale().cancel }}</ui-button>\n <ui-button size=\"sm\" (click)=\"onSubmit(linkText.value, linkUrl.value)\">\n {{ showRemove() ? locale().update : locale().insert }}\n </ui-button>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
35459
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextLinksFormComponent, isStandalone: true, selector: "ui-rich-text-links-form", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null }, showRemove: { classPropertyName: "showRemove", publicName: "showRemove", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitLink: "submitLink", cancelLink: "cancelLink", removeLink: "removeLink" }, host: { classAttribute: "contents" }, ngImport: i0, template: "<div\n [class]=\"classes()\"\n [attr.dir]=\"dir()\"\n [attr.data-slot]=\"'rich-text-links-form'\"\n>\n <p class=\"text-sm font-medium m-0\">{{ locale().tooltip }}</p>\n\n <label class=\"block space-y-1\">\n <span class=\"text-xs text-muted-foreground\">{{ locale().text }}</span>\n <input\n #linkText\n type=\"text\"\n [value]=\"text()\"\n [placeholder]=\"locale().textPlaceholder\"\n class=\"border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n (keydown.enter)=\"onSubmit(linkText.value, linkUrl.value)\"\n />\n </label>\n\n <label class=\"block space-y-1\">\n <span class=\"text-xs text-muted-foreground\">{{ locale().url }}</span>\n <input\n #linkUrl\n type=\"url\"\n [value]=\"url()\"\n [placeholder]=\"locale().urlPlaceholder\"\n class=\"border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n [attr.aria-invalid]=\"errorMessage() ? 'true' : null\"\n [attr.aria-describedby]=\"errorMessage() ? 'rte-link-url-error' : null\"\n (keydown.enter)=\"onSubmit(linkText.value, linkUrl.value)\"\n />\n </label>\n\n @if (errorMessage()) {\n <p id=\"rte-link-url-error\" role=\"alert\" class=\"text-destructive m-0 text-xs\">\n {{ errorMessage() }}\n </p>\n }\n\n <div class=\"flex flex-wrap justify-end gap-2 pt-1\">\n @if (showRemove()) {\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"removeLink.emit()\">{{ locale().remove }}</ui-button>\n }\n <ui-button variant=\"outline\" size=\"sm\" (click)=\"cancelLink.emit()\">{{ locale().cancel }}</ui-button>\n <ui-button size=\"sm\" (click)=\"onSubmit(linkText.value, linkUrl.value)\">\n {{ showRemove() ? locale().update : locale().insert }}\n </ui-button>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
35289
35460
  }
35290
35461
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextLinksFormComponent, decorators: [{
35291
35462
  type: Component,
35292
- args: [{ selector: 'ui-rich-text-links-form', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ButtonComponent], host: { class: 'contents' }, template: "<div\n class=\"w-72 max-w-[calc(100vw-2rem)] space-y-3\"\n [attr.dir]=\"dir()\"\n [attr.data-slot]=\"'rich-text-links-form'\"\n>\n <p class=\"text-sm font-medium m-0\">{{ locale().tooltip }}</p>\n\n <label class=\"block space-y-1\">\n <span class=\"text-xs text-muted-foreground\">{{ locale().text }}</span>\n <input\n #linkText\n type=\"text\"\n [value]=\"text()\"\n [placeholder]=\"locale().textPlaceholder\"\n class=\"border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n (keydown.enter)=\"onSubmit(linkText.value, linkUrl.value)\"\n />\n </label>\n\n <label class=\"block space-y-1\">\n <span class=\"text-xs text-muted-foreground\">{{ locale().url }}</span>\n <input\n #linkUrl\n type=\"url\"\n [value]=\"url()\"\n [placeholder]=\"locale().urlPlaceholder\"\n class=\"border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n [attr.aria-invalid]=\"errorMessage() ? 'true' : null\"\n [attr.aria-describedby]=\"errorMessage() ? 'rte-link-url-error' : null\"\n (keydown.enter)=\"onSubmit(linkText.value, linkUrl.value)\"\n />\n </label>\n\n @if (errorMessage()) {\n <p id=\"rte-link-url-error\" role=\"alert\" class=\"text-destructive m-0 text-xs\">\n {{ errorMessage() }}\n </p>\n }\n\n <div class=\"flex flex-wrap justify-end gap-2 pt-1\">\n @if (showRemove()) {\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"removeLink.emit()\">{{ locale().remove }}</ui-button>\n }\n <ui-button variant=\"outline\" size=\"sm\" (click)=\"cancelLink.emit()\">{{ locale().cancel }}</ui-button>\n <ui-button size=\"sm\" (click)=\"onSubmit(linkText.value, linkUrl.value)\">\n {{ showRemove() ? locale().update : locale().insert }}\n </ui-button>\n </div>\n</div>\n" }]
35293
- }], propDecorators: { locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: false }] }], showRemove: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRemove", required: false }] }], submitLink: [{ type: i0.Output, args: ["submitLink"] }], cancelLink: [{ type: i0.Output, args: ["cancelLink"] }], removeLink: [{ type: i0.Output, args: ["removeLink"] }] } });
35463
+ args: [{ selector: 'ui-rich-text-links-form', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ButtonComponent], host: { class: 'contents' }, template: "<div\n [class]=\"classes()\"\n [attr.dir]=\"dir()\"\n [attr.data-slot]=\"'rich-text-links-form'\"\n>\n <p class=\"text-sm font-medium m-0\">{{ locale().tooltip }}</p>\n\n <label class=\"block space-y-1\">\n <span class=\"text-xs text-muted-foreground\">{{ locale().text }}</span>\n <input\n #linkText\n type=\"text\"\n [value]=\"text()\"\n [placeholder]=\"locale().textPlaceholder\"\n class=\"border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n (keydown.enter)=\"onSubmit(linkText.value, linkUrl.value)\"\n />\n </label>\n\n <label class=\"block space-y-1\">\n <span class=\"text-xs text-muted-foreground\">{{ locale().url }}</span>\n <input\n #linkUrl\n type=\"url\"\n [value]=\"url()\"\n [placeholder]=\"locale().urlPlaceholder\"\n class=\"border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n [attr.aria-invalid]=\"errorMessage() ? 'true' : null\"\n [attr.aria-describedby]=\"errorMessage() ? 'rte-link-url-error' : null\"\n (keydown.enter)=\"onSubmit(linkText.value, linkUrl.value)\"\n />\n </label>\n\n @if (errorMessage()) {\n <p id=\"rte-link-url-error\" role=\"alert\" class=\"text-destructive m-0 text-xs\">\n {{ errorMessage() }}\n </p>\n }\n\n <div class=\"flex flex-wrap justify-end gap-2 pt-1\">\n @if (showRemove()) {\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"removeLink.emit()\">{{ locale().remove }}</ui-button>\n }\n <ui-button variant=\"outline\" size=\"sm\" (click)=\"cancelLink.emit()\">{{ locale().cancel }}</ui-button>\n <ui-button size=\"sm\" (click)=\"onSubmit(linkText.value, linkUrl.value)\">\n {{ showRemove() ? locale().update : locale().insert }}\n </ui-button>\n </div>\n</div>\n" }]
35464
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: false }] }], showRemove: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRemove", required: false }] }], submitLink: [{ type: i0.Output, args: ["submitLink"] }], cancelLink: [{ type: i0.Output, args: ["cancelLink"] }], removeLink: [{ type: i0.Output, args: ["removeLink"] }] } });
35294
35465
 
35295
35466
  const RICH_TEXT_LINKS_BUTTON_CONTEXT = new InjectionToken('RICH_TEXT_LINKS_BUTTON_CONTEXT');
35296
35467
 
@@ -35315,11 +35486,13 @@ class RichTextLinksButtonComponent {
35315
35486
  this.exclusive = this.host.registerExclusivePopover(() => this.open.set(false));
35316
35487
  this.icon = this.domSanitizer.bypassSecurityTrustHtml(LINK_ICON);
35317
35488
  this.interactionDisabled = computed(() => this.host.isDisabled() || this.host.readonly(), ...(ngDevMode ? [{ debugName: "interactionDisabled" }] : /* istanbul ignore next */ []));
35489
+ /** Extra classes merged onto the toolbar button, after the built-in icon-button styling. */
35490
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
35318
35491
  this.buttonClasses = computed(() => cn('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors', 'hover:bg-accent hover:text-accent-foreground', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', 'disabled:pointer-events-none disabled:opacity-50',
35319
35492
  // The global (pointer: coarse) floor targets `button:not([data-slot])`,
35320
35493
  // and these addon buttons carry a data-slot for testing — so they must
35321
35494
  // state the 44px touch minimum themselves rather than inherit it.
35322
- 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5'), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
35495
+ 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5', this.class()), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
35323
35496
  inject(DestroyRef).onDestroy(() => this.exclusive.release());
35324
35497
  }
35325
35498
  onOpenChange(next) {
@@ -35343,7 +35516,7 @@ class RichTextLinksButtonComponent {
35343
35516
  this.open.set(false);
35344
35517
  }
35345
35518
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextLinksButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
35346
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: RichTextLinksButtonComponent, isStandalone: true, selector: "ui-rte-links-button", host: { classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-auto max-w-[calc(100vw-2rem)] p-3\" align=\"start\" strategy=\"fixed\">\n <ui-rich-text-links-form\n [locale]=\"context.locale()\"\n [text]=\"context.seededText()\"\n [url]=\"context.seededUrl()\"\n [showRemove]=\"context.editing()\"\n [errorMessage]=\"context.urlError()\"\n (submitLink)=\"onSubmit($event)\"\n (cancelLink)=\"open.set(false)\"\n (removeLink)=\"onRemove()\"\n />\n </ui-popover-content>\n</ui-popover>\n", dependencies: [{ kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger" }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: RichTextLinksFormComponent, selector: "ui-rich-text-links-form", inputs: ["locale", "errorMessage", "text", "url", "showRemove"], outputs: ["submitLink", "cancelLink", "removeLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
35519
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: RichTextLinksButtonComponent, isStandalone: true, selector: "ui-rte-links-button", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-slot": "\"rte-links-host\"" }, classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-auto max-w-[calc(100vw-2rem)] p-3\" align=\"start\" strategy=\"fixed\">\n <ui-rich-text-links-form\n [locale]=\"context.locale()\"\n [text]=\"context.seededText()\"\n [url]=\"context.seededUrl()\"\n [showRemove]=\"context.editing()\"\n [errorMessage]=\"context.urlError()\"\n (submitLink)=\"onSubmit($event)\"\n (cancelLink)=\"open.set(false)\"\n (removeLink)=\"onRemove()\"\n />\n </ui-popover-content>\n</ui-popover>\n", dependencies: [{ kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["class", "open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger", inputs: ["class"] }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: RichTextLinksFormComponent, selector: "ui-rich-text-links-form", inputs: ["class", "locale", "errorMessage", "text", "url", "showRemove"], outputs: ["submitLink", "cancelLink", "removeLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
35347
35520
  }
35348
35521
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextLinksButtonComponent, decorators: [{
35349
35522
  type: Component,
@@ -35352,8 +35525,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
35352
35525
  PopoverTriggerComponent,
35353
35526
  PopoverContentComponent,
35354
35527
  RichTextLinksFormComponent,
35355
- ], host: { class: 'contents' }, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-auto max-w-[calc(100vw-2rem)] p-3\" align=\"start\" strategy=\"fixed\">\n <ui-rich-text-links-form\n [locale]=\"context.locale()\"\n [text]=\"context.seededText()\"\n [url]=\"context.seededUrl()\"\n [showRemove]=\"context.editing()\"\n [errorMessage]=\"context.urlError()\"\n (submitLink)=\"onSubmit($event)\"\n (cancelLink)=\"open.set(false)\"\n (removeLink)=\"onRemove()\"\n />\n </ui-popover-content>\n</ui-popover>\n" }]
35356
- }], ctorParameters: () => [] });
35528
+ ], host: { class: 'contents', '[attr.data-slot]': '"rte-links-host"' }, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"w-auto max-w-[calc(100vw-2rem)] p-3\" align=\"start\" strategy=\"fixed\">\n <ui-rich-text-links-form\n [locale]=\"context.locale()\"\n [text]=\"context.seededText()\"\n [url]=\"context.seededUrl()\"\n [showRemove]=\"context.editing()\"\n [errorMessage]=\"context.urlError()\"\n (submitLink)=\"onSubmit($event)\"\n (cancelLink)=\"open.set(false)\"\n (removeLink)=\"onRemove()\"\n />\n </ui-popover-content>\n</ui-popover>\n" }]
35529
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
35357
35530
 
35358
35531
  const LINK_SLOT_ID = 'links.insert';
35359
35532
  const OVERLAY_WIDTH = 320;
@@ -35815,6 +35988,8 @@ class RichTextMentionPopoverComponent {
35815
35988
  * Also selects the empty-state and `aria-label` strings from {@link locale}.
35816
35989
  */
35817
35990
  this.type = input('mention', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
35991
+ /** Extra classes merged onto the floating list, after its bordered popover styling. */
35992
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
35818
35993
  /** Translated strings for the `aria-label` and the "no results" message. Defaults to English. */
35819
35994
  this.locale = input(RICH_TEXT_MENTIONS_LOCALES['en'], ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
35820
35995
  /**
@@ -35870,7 +36045,7 @@ class RichTextMentionPopoverComponent {
35870
36045
  this.closed.emit();
35871
36046
  }
35872
36047
  };
35873
- this.containerClasses = computed(() => cn('absolute z-50 w-64 max-w-[calc(100vw-2rem)] rounded-md border bg-popover text-popover-foreground shadow-md', 'animate-in fade-in-0 zoom-in-95'), ...(ngDevMode ? [{ debugName: "containerClasses" }] : /* istanbul ignore next */ []));
36048
+ this.containerClasses = computed(() => cn('absolute z-50 w-64 max-w-[calc(100vw-2rem)] rounded-md border bg-popover text-popover-foreground shadow-md', 'animate-in fade-in-0 zoom-in-95', this.class()), ...(ngDevMode ? [{ debugName: "containerClasses" }] : /* istanbul ignore next */ []));
35874
36049
  effect(() => {
35875
36050
  const length = this.items().length;
35876
36051
  const currentIndex = this.selectedIndex();
@@ -35968,17 +36143,17 @@ class RichTextMentionPopoverComponent {
35968
36143
  return item;
35969
36144
  }
35970
36145
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextMentionPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
35971
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextMentionPopoverComponent, isStandalone: true, selector: "ui-rich-text-mention-popover", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, query: { classPropertyName: "query", publicName: "query", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelect: "itemSelect", closed: "closed" }, host: { classAttribute: "contents" }, viewQueries: [{ propertyName: "itemButtons", predicate: ["itemButton"], descendants: true }], ngImport: i0, template: "<div\n [class]=\"containerClasses()\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\"\n role=\"listbox\"\n [id]=\"listboxId\"\n tabindex=\"-1\"\n [attr.aria-label]=\"type() === 'mention' ? locale().selectUser : locale().selectTag\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (items().length === 0) {\n <div class=\"p-3 text-sm text-muted-foreground text-center\">\n @if (type() === 'mention') {\n {{ locale().noUsersFound }}\n } @else {\n {{ locale().noTagsFound }}\n }\n </div>\n } @else {\n <ui-scroll-area class=\"max-h-48\">\n <div class=\"p-1\">\n @for (item of items(); track item.value; let i = $index) {\n <button\n #itemButton\n type=\"button\"\n [class]=\"itemClasses(i)\"\n [attr.data-index]=\"i\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"i === selectedIndex()\"\n role=\"option\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onItemClick(item)\"\n (mouseenter)=\"selectedIndex.set(i)\"\n >\n @if (type() === 'mention') {\n <!-- Mention item with avatar -->\n <div class=\"flex items-center gap-2\">\n @if (asMention(item).avatar) {\n <img \n [src]=\"asMention(item).avatar\" \n [alt]=\"item.label\"\n class=\"w-6 h-6 rounded-full object-cover\"\n />\n } @else {\n <div class=\"w-6 h-6 rounded-full bg-accent flex items-center justify-center text-xs font-medium\">\n {{ item.label.charAt(0).toUpperCase() }}\n </div>\n }\n <div class=\"flex flex-col items-start\">\n <span class=\"text-sm font-medium\">{{ item.label }}</span>\n @if (asMention(item).description) {\n <span class=\"text-xs text-muted-foreground\">{{ asMention(item).description }}</span>\n }\n </div>\n </div>\n } @else {\n <!-- Tag item with color -->\n <div class=\"flex items-center gap-2\">\n <div \n class=\"w-3 h-3 rounded-full\"\n [style.background-color]=\"asTag(item).color || 'var(--accent)'\"\n ></div>\n <span class=\"text-sm\">{{ item.label }}</span>\n </div>\n }\n </button>\n }\n </div>\n </ui-scroll-area>\n }\n</div>", dependencies: [{ kind: "component", type: ScrollAreaComponent, selector: "ui-scroll-area", inputs: ["class", "orientation"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
36146
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextMentionPopoverComponent, isStandalone: true, selector: "ui-rich-text-mention-popover", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, query: { classPropertyName: "query", publicName: "query", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelect: "itemSelect", closed: "closed" }, host: { classAttribute: "contents" }, viewQueries: [{ propertyName: "itemButtons", predicate: ["itemButton"], descendants: true }], ngImport: i0, template: "<div\n [class]=\"containerClasses()\"\n [attr.data-slot]=\"'rich-text-mention-popover'\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\"\n role=\"listbox\"\n [id]=\"listboxId\"\n tabindex=\"-1\"\n [attr.aria-label]=\"type() === 'mention' ? locale().selectUser : locale().selectTag\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (items().length === 0) {\n <div class=\"p-3 text-sm text-muted-foreground text-center\">\n @if (type() === 'mention') {\n {{ locale().noUsersFound }}\n } @else {\n {{ locale().noTagsFound }}\n }\n </div>\n } @else {\n <ui-scroll-area class=\"max-h-48\">\n <div class=\"p-1\">\n @for (item of items(); track item.value; let i = $index) {\n <button\n #itemButton\n type=\"button\"\n [class]=\"itemClasses(i)\"\n [attr.data-index]=\"i\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"i === selectedIndex()\"\n role=\"option\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onItemClick(item)\"\n (mouseenter)=\"selectedIndex.set(i)\"\n >\n @if (type() === 'mention') {\n <!-- Mention item with avatar -->\n <div class=\"flex items-center gap-2\">\n @if (asMention(item).avatar) {\n <img \n [src]=\"asMention(item).avatar\" \n [alt]=\"item.label\"\n class=\"w-6 h-6 rounded-full object-cover\"\n />\n } @else {\n <div class=\"w-6 h-6 rounded-full bg-accent flex items-center justify-center text-xs font-medium\">\n {{ item.label.charAt(0).toUpperCase() }}\n </div>\n }\n <div class=\"flex flex-col items-start\">\n <span class=\"text-sm font-medium\">{{ item.label }}</span>\n @if (asMention(item).description) {\n <span class=\"text-xs text-muted-foreground\">{{ asMention(item).description }}</span>\n }\n </div>\n </div>\n } @else {\n <!-- Tag item with color -->\n <div class=\"flex items-center gap-2\">\n <div \n class=\"w-3 h-3 rounded-full\"\n [style.background-color]=\"asTag(item).color || 'var(--accent)'\"\n ></div>\n <span class=\"text-sm\">{{ item.label }}</span>\n </div>\n }\n </button>\n }\n </div>\n </ui-scroll-area>\n }\n</div>", dependencies: [{ kind: "component", type: ScrollAreaComponent, selector: "ui-scroll-area", inputs: ["class", "orientation"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
35972
36147
  }
35973
36148
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextMentionPopoverComponent, decorators: [{
35974
36149
  type: Component,
35975
36150
  args: [{ selector: 'ui-rich-text-mention-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ScrollAreaComponent], host: {
35976
36151
  class: 'contents',
35977
- }, template: "<div\n [class]=\"containerClasses()\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\"\n role=\"listbox\"\n [id]=\"listboxId\"\n tabindex=\"-1\"\n [attr.aria-label]=\"type() === 'mention' ? locale().selectUser : locale().selectTag\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (items().length === 0) {\n <div class=\"p-3 text-sm text-muted-foreground text-center\">\n @if (type() === 'mention') {\n {{ locale().noUsersFound }}\n } @else {\n {{ locale().noTagsFound }}\n }\n </div>\n } @else {\n <ui-scroll-area class=\"max-h-48\">\n <div class=\"p-1\">\n @for (item of items(); track item.value; let i = $index) {\n <button\n #itemButton\n type=\"button\"\n [class]=\"itemClasses(i)\"\n [attr.data-index]=\"i\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"i === selectedIndex()\"\n role=\"option\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onItemClick(item)\"\n (mouseenter)=\"selectedIndex.set(i)\"\n >\n @if (type() === 'mention') {\n <!-- Mention item with avatar -->\n <div class=\"flex items-center gap-2\">\n @if (asMention(item).avatar) {\n <img \n [src]=\"asMention(item).avatar\" \n [alt]=\"item.label\"\n class=\"w-6 h-6 rounded-full object-cover\"\n />\n } @else {\n <div class=\"w-6 h-6 rounded-full bg-accent flex items-center justify-center text-xs font-medium\">\n {{ item.label.charAt(0).toUpperCase() }}\n </div>\n }\n <div class=\"flex flex-col items-start\">\n <span class=\"text-sm font-medium\">{{ item.label }}</span>\n @if (asMention(item).description) {\n <span class=\"text-xs text-muted-foreground\">{{ asMention(item).description }}</span>\n }\n </div>\n </div>\n } @else {\n <!-- Tag item with color -->\n <div class=\"flex items-center gap-2\">\n <div \n class=\"w-3 h-3 rounded-full\"\n [style.background-color]=\"asTag(item).color || 'var(--accent)'\"\n ></div>\n <span class=\"text-sm\">{{ item.label }}</span>\n </div>\n }\n </button>\n }\n </div>\n </ui-scroll-area>\n }\n</div>" }]
36152
+ }, template: "<div\n [class]=\"containerClasses()\"\n [attr.data-slot]=\"'rich-text-mention-popover'\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\"\n role=\"listbox\"\n [id]=\"listboxId\"\n tabindex=\"-1\"\n [attr.aria-label]=\"type() === 'mention' ? locale().selectUser : locale().selectTag\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (items().length === 0) {\n <div class=\"p-3 text-sm text-muted-foreground text-center\">\n @if (type() === 'mention') {\n {{ locale().noUsersFound }}\n } @else {\n {{ locale().noTagsFound }}\n }\n </div>\n } @else {\n <ui-scroll-area class=\"max-h-48\">\n <div class=\"p-1\">\n @for (item of items(); track item.value; let i = $index) {\n <button\n #itemButton\n type=\"button\"\n [class]=\"itemClasses(i)\"\n [attr.data-index]=\"i\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"i === selectedIndex()\"\n role=\"option\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onItemClick(item)\"\n (mouseenter)=\"selectedIndex.set(i)\"\n >\n @if (type() === 'mention') {\n <!-- Mention item with avatar -->\n <div class=\"flex items-center gap-2\">\n @if (asMention(item).avatar) {\n <img \n [src]=\"asMention(item).avatar\" \n [alt]=\"item.label\"\n class=\"w-6 h-6 rounded-full object-cover\"\n />\n } @else {\n <div class=\"w-6 h-6 rounded-full bg-accent flex items-center justify-center text-xs font-medium\">\n {{ item.label.charAt(0).toUpperCase() }}\n </div>\n }\n <div class=\"flex flex-col items-start\">\n <span class=\"text-sm font-medium\">{{ item.label }}</span>\n @if (asMention(item).description) {\n <span class=\"text-xs text-muted-foreground\">{{ asMention(item).description }}</span>\n }\n </div>\n </div>\n } @else {\n <!-- Tag item with color -->\n <div class=\"flex items-center gap-2\">\n <div \n class=\"w-3 h-3 rounded-full\"\n [style.background-color]=\"asTag(item).color || 'var(--accent)'\"\n ></div>\n <span class=\"text-sm\">{{ item.label }}</span>\n </div>\n }\n </button>\n }\n </div>\n </ui-scroll-area>\n }\n</div>" }]
35978
36153
  }], ctorParameters: () => [], propDecorators: { itemButtons: [{
35979
36154
  type: ViewChildren,
35980
36155
  args: ['itemButton']
35981
- }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], query: [{ type: i0.Input, args: [{ isSignal: true, alias: "query", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], itemSelect: [{ type: i0.Output, args: ["itemSelect"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
36156
+ }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], query: [{ type: i0.Input, args: [{ isSignal: true, alias: "query", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], itemSelect: [{ type: i0.Output, args: ["itemSelect"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
35982
36157
 
35983
36158
  /**
35984
36159
  * Where the caret is, for features that must stay quiet in some contexts.
@@ -36439,6 +36614,9 @@ let outlinePanelInstances = 0;
36439
36614
  class RichTextOutlinePanelComponent {
36440
36615
  constructor() {
36441
36616
  this.ctx = inject(RICH_TEXT_OUTLINE_CONTEXT);
36617
+ /** Extra classes merged onto the docked panel, after its start-edge positioning and width steps. */
36618
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
36619
+ this.classes = computed(() => cn('absolute top-0 bottom-0 z-20 w-full md:w-64 lg:w-80 max-w-full md:max-w-[calc(100vw-2rem)] overflow-y-auto bg-popover ltr:left-0 ltr:border-r rtl:right-0 rtl:border-l', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
36442
36620
  /**
36443
36621
  * Id wiring the panel's `aria-labelledby` to its visible heading. Counted
36444
36622
  * per instance so two editors on one page do not both claim the same id,
@@ -36448,12 +36626,12 @@ class RichTextOutlinePanelComponent {
36448
36626
  this.titleId = `rte-outline-title-${++outlinePanelInstances}`;
36449
36627
  }
36450
36628
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextOutlinePanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
36451
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextOutlinePanelComponent, isStandalone: true, selector: "ui-rte-outline-panel", host: { classAttribute: "contents" }, ngImport: i0, template: "@if (ctx.isOpen()) {\n <!--\n A <nav> with an accessible name, not a bare div: this is a jump-to-section\n landmark, so screen-reader users can reach it from the landmark rotor and\n hear what it is. The name comes from the visible title via aria-labelledby,\n which keeps the two from drifting apart across locales.\n -->\n <nav\n [attr.aria-labelledby]=\"titleId\"\n class=\"absolute top-0 bottom-0 z-20 w-full md:w-64 lg:w-80 max-w-full md:max-w-[calc(100vw-2rem)] overflow-y-auto bg-popover ltr:left-0 ltr:border-r rtl:right-0 rtl:border-l\"\n [attr.data-slot]=\"'rich-text-outline-panel'\"\n >\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <h2 [attr.id]=\"titleId\" class=\"text-sm font-medium\">{{ ctx.locale().title }}</h2>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-7 w-7 p-0 pointer-coarse:size-11\"\n (click)=\"ctx.close()\"\n (keydown.enter)=\"ctx.close()\"\n (keydown.space)=\"ctx.close()\"\n [ariaLabel]=\"ctx.locale().ariaClose\"\n >\n <svg class=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </ui-button>\n </div>\n <ui-scroll-area [class]=\"'max-h-72 p-3'\">\n @if (ctx.headings().length === 0) {\n <p class=\"px-2 py-3 text-xs text-muted-foreground\" data-slot=\"rich-text-outline-empty\">\n {{ ctx.locale().empty }}\n </p>\n } @else {\n <ol class=\"space-y-0.5 pr-2\" data-slot=\"rich-text-outline-list\">\n @for (heading of ctx.headings(); track heading.index) {\n <li>\n <button\n type=\"button\"\n class=\"block w-full cursor-pointer truncate rounded-md px-2 py-1.5 text-start text-sm transition-colors hover:bg-accent/60\"\n [attr.data-outline-entry]=\"'true'\"\n [attr.data-outline-level]=\"heading.level\"\n [style.padding-inline-start.rem]=\"0.5 + (heading.level - 1) * 0.75\"\n (click)=\"ctx.scrollTo(heading.index)\"\n (keydown)=\"ctx.onEntryKeydown($event, heading.index)\"\n >\n {{ heading.text }}\n </button>\n </li>\n }\n </ol>\n }\n </ui-scroll-area>\n </nav>\n}\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }, { kind: "component", type: ScrollAreaComponent, selector: "ui-scroll-area", inputs: ["class", "orientation"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
36629
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextOutlinePanelComponent, isStandalone: true, selector: "ui-rte-outline-panel", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: "@if (ctx.isOpen()) {\n <!--\n A <nav> with an accessible name, not a bare div: this is a jump-to-section\n landmark, so screen-reader users can reach it from the landmark rotor and\n hear what it is. The name comes from the visible title via aria-labelledby,\n which keeps the two from drifting apart across locales.\n -->\n <nav\n [attr.aria-labelledby]=\"titleId\"\n [class]=\"classes()\"\n [attr.data-slot]=\"'rich-text-outline-panel'\"\n >\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <h2 [attr.id]=\"titleId\" class=\"text-sm font-medium\">{{ ctx.locale().title }}</h2>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-7 w-7 p-0 pointer-coarse:size-11\"\n (click)=\"ctx.close()\"\n (keydown.enter)=\"ctx.close()\"\n (keydown.space)=\"ctx.close()\"\n [ariaLabel]=\"ctx.locale().ariaClose\"\n >\n <svg class=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </ui-button>\n </div>\n <ui-scroll-area [class]=\"'max-h-72 p-3'\">\n @if (ctx.headings().length === 0) {\n <p class=\"px-2 py-3 text-xs text-muted-foreground\" data-slot=\"rich-text-outline-empty\">\n {{ ctx.locale().empty }}\n </p>\n } @else {\n <ol class=\"space-y-0.5 pr-2\" data-slot=\"rich-text-outline-list\">\n @for (heading of ctx.headings(); track heading.index) {\n <li>\n <button\n type=\"button\"\n class=\"block w-full cursor-pointer truncate rounded-md px-2 py-1.5 text-start text-sm transition-colors hover:bg-accent/60\"\n [attr.data-outline-entry]=\"'true'\"\n [attr.data-outline-level]=\"heading.level\"\n [style.padding-inline-start.rem]=\"0.5 + (heading.level - 1) * 0.75\"\n (click)=\"ctx.scrollTo(heading.index)\"\n (keydown)=\"ctx.onEntryKeydown($event, heading.index)\"\n >\n {{ heading.text }}\n </button>\n </li>\n }\n </ol>\n }\n </ui-scroll-area>\n </nav>\n}\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "type", "class", "ariaLabel", "aria-expanded", "aria-pressed", "aria-haspopup", "aria-controls", "label", "ripple", "rippleColor", "loading", "skeleton"], outputs: ["clicked"] }, { kind: "component", type: ScrollAreaComponent, selector: "ui-scroll-area", inputs: ["class", "orientation"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
36452
36630
  }
36453
36631
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextOutlinePanelComponent, decorators: [{
36454
36632
  type: Component,
36455
- args: [{ selector: 'ui-rte-outline-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ButtonComponent, ScrollAreaComponent], host: { class: 'contents' }, template: "@if (ctx.isOpen()) {\n <!--\n A <nav> with an accessible name, not a bare div: this is a jump-to-section\n landmark, so screen-reader users can reach it from the landmark rotor and\n hear what it is. The name comes from the visible title via aria-labelledby,\n which keeps the two from drifting apart across locales.\n -->\n <nav\n [attr.aria-labelledby]=\"titleId\"\n class=\"absolute top-0 bottom-0 z-20 w-full md:w-64 lg:w-80 max-w-full md:max-w-[calc(100vw-2rem)] overflow-y-auto bg-popover ltr:left-0 ltr:border-r rtl:right-0 rtl:border-l\"\n [attr.data-slot]=\"'rich-text-outline-panel'\"\n >\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <h2 [attr.id]=\"titleId\" class=\"text-sm font-medium\">{{ ctx.locale().title }}</h2>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-7 w-7 p-0 pointer-coarse:size-11\"\n (click)=\"ctx.close()\"\n (keydown.enter)=\"ctx.close()\"\n (keydown.space)=\"ctx.close()\"\n [ariaLabel]=\"ctx.locale().ariaClose\"\n >\n <svg class=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </ui-button>\n </div>\n <ui-scroll-area [class]=\"'max-h-72 p-3'\">\n @if (ctx.headings().length === 0) {\n <p class=\"px-2 py-3 text-xs text-muted-foreground\" data-slot=\"rich-text-outline-empty\">\n {{ ctx.locale().empty }}\n </p>\n } @else {\n <ol class=\"space-y-0.5 pr-2\" data-slot=\"rich-text-outline-list\">\n @for (heading of ctx.headings(); track heading.index) {\n <li>\n <button\n type=\"button\"\n class=\"block w-full cursor-pointer truncate rounded-md px-2 py-1.5 text-start text-sm transition-colors hover:bg-accent/60\"\n [attr.data-outline-entry]=\"'true'\"\n [attr.data-outline-level]=\"heading.level\"\n [style.padding-inline-start.rem]=\"0.5 + (heading.level - 1) * 0.75\"\n (click)=\"ctx.scrollTo(heading.index)\"\n (keydown)=\"ctx.onEntryKeydown($event, heading.index)\"\n >\n {{ heading.text }}\n </button>\n </li>\n }\n </ol>\n }\n </ui-scroll-area>\n </nav>\n}\n" }]
36456
- }] });
36633
+ args: [{ selector: 'ui-rte-outline-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ButtonComponent, ScrollAreaComponent], host: { class: 'contents' }, template: "@if (ctx.isOpen()) {\n <!--\n A <nav> with an accessible name, not a bare div: this is a jump-to-section\n landmark, so screen-reader users can reach it from the landmark rotor and\n hear what it is. The name comes from the visible title via aria-labelledby,\n which keeps the two from drifting apart across locales.\n -->\n <nav\n [attr.aria-labelledby]=\"titleId\"\n [class]=\"classes()\"\n [attr.data-slot]=\"'rich-text-outline-panel'\"\n >\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <h2 [attr.id]=\"titleId\" class=\"text-sm font-medium\">{{ ctx.locale().title }}</h2>\n <ui-button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"h-7 w-7 p-0 pointer-coarse:size-11\"\n (click)=\"ctx.close()\"\n (keydown.enter)=\"ctx.close()\"\n (keydown.space)=\"ctx.close()\"\n [ariaLabel]=\"ctx.locale().ariaClose\"\n >\n <svg class=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </ui-button>\n </div>\n <ui-scroll-area [class]=\"'max-h-72 p-3'\">\n @if (ctx.headings().length === 0) {\n <p class=\"px-2 py-3 text-xs text-muted-foreground\" data-slot=\"rich-text-outline-empty\">\n {{ ctx.locale().empty }}\n </p>\n } @else {\n <ol class=\"space-y-0.5 pr-2\" data-slot=\"rich-text-outline-list\">\n @for (heading of ctx.headings(); track heading.index) {\n <li>\n <button\n type=\"button\"\n class=\"block w-full cursor-pointer truncate rounded-md px-2 py-1.5 text-start text-sm transition-colors hover:bg-accent/60\"\n [attr.data-outline-entry]=\"'true'\"\n [attr.data-outline-level]=\"heading.level\"\n [style.padding-inline-start.rem]=\"0.5 + (heading.level - 1) * 0.75\"\n (click)=\"ctx.scrollTo(heading.index)\"\n (keydown)=\"ctx.onEntryKeydown($event, heading.index)\"\n >\n {{ heading.text }}\n </button>\n </li>\n }\n </ol>\n }\n </ui-scroll-area>\n </nav>\n}\n" }]
36634
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
36457
36635
 
36458
36636
  /** Built-in locales for the document-outline addon. */
36459
36637
  const RICH_TEXT_OUTLINE_LOCALES = {
@@ -36781,6 +36959,9 @@ class RichTextSlashCommandsMenuComponent {
36781
36959
  return `${this.listboxId}-option-${index}`;
36782
36960
  }
36783
36961
  constructor() {
36962
+ /** Extra classes merged onto the menu host, after its bordered popover styling. */
36963
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
36964
+ this.classes = computed(() => cn('block w-72 max-w-[calc(100vw-2rem)] rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
36784
36965
  /**
36785
36966
  * Stable ids so the editable can point `aria-controls` and
36786
36967
  * `aria-activedescendant` here. Focus stays in the editable while the menu is
@@ -36830,7 +37011,7 @@ class RichTextSlashCommandsMenuComponent {
36830
37011
  }
36831
37012
  }
36832
37013
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextSlashCommandsMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
36833
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextSlashCommandsMenuComponent, isStandalone: true, selector: "ui-rich-text-slash-commands-menu", inputs: { commands: { classPropertyName: "commands", publicName: "commands", isSignal: true, isRequired: false, transformFunction: null }, selectedIndex: { classPropertyName: "selectedIndex", publicName: "selectedIndex", isSignal: true, isRequired: false, transformFunction: null }, noResultsLabel: { classPropertyName: "noResultsLabel", publicName: "noResultsLabel", isSignal: true, isRequired: false, transformFunction: null }, menuAriaLabel: { classPropertyName: "menuAriaLabel", publicName: "menuAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { commandSelect: "commandSelect", hoverIndex: "hoverIndex" }, host: { attributes: { "role": "listbox" }, properties: { "attr.aria-label": "menuAriaLabel()", "attr.data-slot": "'rich-text-slash-commands-menu'" }, classAttribute: "block w-72 max-w-[calc(100vw-2rem)] rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95" }, viewQueries: [{ propertyName: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (commands().length === 0) {\n <div class=\"px-3 py-2 text-sm text-muted-foreground\">{{ noResultsLabel() }}</div>\n} @else {\n <div #list class=\"max-h-56 overflow-y-auto p-1\">\n @for (command of commands(); track command.id; let i = $index) {\n <button\n type=\"button\"\n class=\"w-full rounded-sm px-2 py-1.5 text-left transition-colors hover:bg-accent hover:text-accent-foreground\"\n [class.bg-accent]=\"i === selectedIndex()\"\n [class.text-accent-foreground]=\"i === selectedIndex()\"\n [attr.aria-selected]=\"i === selectedIndex()\"\n [attr.data-slash-index]=\"i\"\n [id]=\"optionId(i)\"\n role=\"option\"\n (mousedown)=\"onPointerDown($event)\"\n (mouseenter)=\"hoverIndex.emit(i)\"\n (click)=\"commandSelect.emit(command)\"\n >\n <div class=\"text-sm font-medium\">{{ command.label }}</div>\n @if (command.description) {\n <div class=\"text-xs text-muted-foreground\">{{ command.description }}</div>\n }\n </button>\n }\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
37014
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextSlashCommandsMenuComponent, isStandalone: true, selector: "ui-rich-text-slash-commands-menu", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, commands: { classPropertyName: "commands", publicName: "commands", isSignal: true, isRequired: false, transformFunction: null }, selectedIndex: { classPropertyName: "selectedIndex", publicName: "selectedIndex", isSignal: true, isRequired: false, transformFunction: null }, noResultsLabel: { classPropertyName: "noResultsLabel", publicName: "noResultsLabel", isSignal: true, isRequired: false, transformFunction: null }, menuAriaLabel: { classPropertyName: "menuAriaLabel", publicName: "menuAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { commandSelect: "commandSelect", hoverIndex: "hoverIndex" }, host: { attributes: { "role": "listbox" }, properties: { "attr.aria-label": "menuAriaLabel()", "attr.data-slot": "'rich-text-slash-commands-menu'", "class": "classes()" } }, viewQueries: [{ propertyName: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (commands().length === 0) {\n <div class=\"px-3 py-2 text-sm text-muted-foreground\">{{ noResultsLabel() }}</div>\n} @else {\n <div #list class=\"max-h-56 overflow-y-auto p-1\">\n @for (command of commands(); track command.id; let i = $index) {\n <button\n type=\"button\"\n class=\"w-full rounded-sm px-2 py-1.5 text-left transition-colors hover:bg-accent hover:text-accent-foreground\"\n [class.bg-accent]=\"i === selectedIndex()\"\n [class.text-accent-foreground]=\"i === selectedIndex()\"\n [attr.aria-selected]=\"i === selectedIndex()\"\n [attr.data-slash-index]=\"i\"\n [id]=\"optionId(i)\"\n role=\"option\"\n (mousedown)=\"onPointerDown($event)\"\n (mouseenter)=\"hoverIndex.emit(i)\"\n (click)=\"commandSelect.emit(command)\"\n >\n <div class=\"text-sm font-medium\">{{ command.label }}</div>\n @if (command.description) {\n <div class=\"text-xs text-muted-foreground\">{{ command.description }}</div>\n }\n </button>\n }\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
36834
37015
  }
36835
37016
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextSlashCommandsMenuComponent, decorators: [{
36836
37017
  type: Component,
@@ -36838,9 +37019,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
36838
37019
  role: 'listbox',
36839
37020
  '[attr.aria-label]': 'menuAriaLabel()',
36840
37021
  '[attr.data-slot]': "'rich-text-slash-commands-menu'",
36841
- class: 'block w-72 max-w-[calc(100vw-2rem)] rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95',
37022
+ '[class]': 'classes()',
36842
37023
  }, template: "@if (commands().length === 0) {\n <div class=\"px-3 py-2 text-sm text-muted-foreground\">{{ noResultsLabel() }}</div>\n} @else {\n <div #list class=\"max-h-56 overflow-y-auto p-1\">\n @for (command of commands(); track command.id; let i = $index) {\n <button\n type=\"button\"\n class=\"w-full rounded-sm px-2 py-1.5 text-left transition-colors hover:bg-accent hover:text-accent-foreground\"\n [class.bg-accent]=\"i === selectedIndex()\"\n [class.text-accent-foreground]=\"i === selectedIndex()\"\n [attr.aria-selected]=\"i === selectedIndex()\"\n [attr.data-slash-index]=\"i\"\n [id]=\"optionId(i)\"\n role=\"option\"\n (mousedown)=\"onPointerDown($event)\"\n (mouseenter)=\"hoverIndex.emit(i)\"\n (click)=\"commandSelect.emit(command)\"\n >\n <div class=\"text-sm font-medium\">{{ command.label }}</div>\n @if (command.description) {\n <div class=\"text-xs text-muted-foreground\">{{ command.description }}</div>\n }\n </button>\n }\n </div>\n}\n" }]
36843
- }], ctorParameters: () => [], propDecorators: { commands: [{ type: i0.Input, args: [{ isSignal: true, alias: "commands", required: false }] }], selectedIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIndex", required: false }] }], noResultsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsLabel", required: false }] }], menuAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuAriaLabel", required: false }] }], commandSelect: [{ type: i0.Output, args: ["commandSelect"] }], hoverIndex: [{ type: i0.Output, args: ["hoverIndex"] }], list: [{ type: i0.ViewChild, args: ['list', { isSignal: true }] }] } });
37024
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], commands: [{ type: i0.Input, args: [{ isSignal: true, alias: "commands", required: false }] }], selectedIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIndex", required: false }] }], noResultsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsLabel", required: false }] }], menuAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuAriaLabel", required: false }] }], commandSelect: [{ type: i0.Output, args: ["commandSelect"] }], hoverIndex: [{ type: i0.Output, args: ["hoverIndex"] }], list: [{ type: i0.ViewChild, args: ['list', { isSignal: true }] }] } });
36844
37025
 
36845
37026
  /**
36846
37027
  * Builds the addon's built-in slash commands (paragraph, headings, lists,
@@ -38133,11 +38314,13 @@ class RichTextTablesButtonComponent {
38133
38314
  this.hoverCols = signal(0, ...(ngDevMode ? [{ debugName: "hoverCols" }] : /* istanbul ignore next */ []));
38134
38315
  this.icon = this.domSanitizer.bypassSecurityTrustHtml(TABLE_ICON);
38135
38316
  this.interactionDisabled = computed(() => this.host.isDisabled() || this.host.readonly(), ...(ngDevMode ? [{ debugName: "interactionDisabled" }] : /* istanbul ignore next */ []));
38317
+ /** Extra classes merged onto the toolbar button, after the built-in icon-button styling. */
38318
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
38136
38319
  this.buttonClasses = computed(() => cn('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors', 'hover:bg-accent hover:text-accent-foreground', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', 'disabled:pointer-events-none disabled:opacity-50',
38137
38320
  // The global (pointer: coarse) floor targets `button:not([data-slot])`,
38138
38321
  // and these addon buttons carry a data-slot for testing — so they must
38139
38322
  // state the 44px touch minimum themselves rather than inherit it.
38140
- 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5'), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
38323
+ 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5', this.class()), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
38141
38324
  inject(DestroyRef).onDestroy(() => this.exclusive.release());
38142
38325
  }
38143
38326
  onOpenChange(next) {
@@ -38166,7 +38349,7 @@ class RichTextTablesButtonComponent {
38166
38349
  this.hoverCols.set(0);
38167
38350
  }
38168
38351
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextTablesButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
38169
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextTablesButtonComponent, isStandalone: true, selector: "ui-rte-tables-button", host: { classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"p-3 max-sm:max-w-[calc(100vw-1rem)]\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <div class=\"grid gap-0.5\" style=\"grid-template-columns: repeat(8, 1fr)\">\n @for (row of gridRange; track row) {\n @for (col of gridRange; track col) {\n <button\n type=\"button\"\n data-grid-cell\n class=\"aspect-square w-5 border rounded-sm transition-colors\"\n [class.bg-primary]=\"row <= hoverRows() && col <= hoverCols()\"\n [class.border-primary]=\"row <= hoverRows() && col <= hoverCols()\"\n [class.border-border]=\"row > hoverRows() || col > hoverCols()\"\n [class.bg-background]=\"row > hoverRows() || col > hoverCols()\"\n [attr.aria-label]=\"row + 'x' + col\"\n (mouseenter)=\"onHover(row, col)\"\n (click)=\"onSelect(row, col)\"\n ></button>\n }\n }\n </div>\n <div class=\"text-xs text-center text-muted-foreground\">\n @if (hoverRows() > 0 && hoverCols() > 0) {\n {{ hoverRows() }} x {{ hoverCols() }}\n } @else {\n {{ context.locale().insertTable }}\n }\n </div>\n </div>\n </ui-popover-content>\n</ui-popover>\n", dependencies: [{ kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger" }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38352
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextTablesButtonComponent, isStandalone: true, selector: "ui-rte-tables-button", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-slot": "\"rte-tables-host\"" }, classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"p-3 max-sm:max-w-[calc(100vw-1rem)]\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <div class=\"grid gap-0.5\" style=\"grid-template-columns: repeat(8, 1fr)\">\n @for (row of gridRange; track row) {\n @for (col of gridRange; track col) {\n <button\n type=\"button\"\n data-grid-cell\n class=\"aspect-square w-5 border rounded-sm transition-colors\"\n [class.bg-primary]=\"row <= hoverRows() && col <= hoverCols()\"\n [class.border-primary]=\"row <= hoverRows() && col <= hoverCols()\"\n [class.border-border]=\"row > hoverRows() || col > hoverCols()\"\n [class.bg-background]=\"row > hoverRows() || col > hoverCols()\"\n [attr.aria-label]=\"row + 'x' + col\"\n (mouseenter)=\"onHover(row, col)\"\n (click)=\"onSelect(row, col)\"\n ></button>\n }\n }\n </div>\n <div class=\"text-xs text-center text-muted-foreground\">\n @if (hoverRows() > 0 && hoverCols() > 0) {\n {{ hoverRows() }} x {{ hoverCols() }}\n } @else {\n {{ context.locale().insertTable }}\n }\n </div>\n </div>\n </ui-popover-content>\n</ui-popover>\n", dependencies: [{ kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["class", "open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger", inputs: ["class"] }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38170
38353
  }
38171
38354
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextTablesButtonComponent, decorators: [{
38172
38355
  type: Component,
@@ -38174,8 +38357,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
38174
38357
  PopoverComponent,
38175
38358
  PopoverTriggerComponent,
38176
38359
  PopoverContentComponent,
38177
- ], host: { class: 'contents' }, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"p-3 max-sm:max-w-[calc(100vw-1rem)]\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <div class=\"grid gap-0.5\" style=\"grid-template-columns: repeat(8, 1fr)\">\n @for (row of gridRange; track row) {\n @for (col of gridRange; track col) {\n <button\n type=\"button\"\n data-grid-cell\n class=\"aspect-square w-5 border rounded-sm transition-colors\"\n [class.bg-primary]=\"row <= hoverRows() && col <= hoverCols()\"\n [class.border-primary]=\"row <= hoverRows() && col <= hoverCols()\"\n [class.border-border]=\"row > hoverRows() || col > hoverCols()\"\n [class.bg-background]=\"row > hoverRows() || col > hoverCols()\"\n [attr.aria-label]=\"row + 'x' + col\"\n (mouseenter)=\"onHover(row, col)\"\n (click)=\"onSelect(row, col)\"\n ></button>\n }\n }\n </div>\n <div class=\"text-xs text-center text-muted-foreground\">\n @if (hoverRows() > 0 && hoverCols() > 0) {\n {{ hoverRows() }} x {{ hoverCols() }}\n } @else {\n {{ context.locale().insertTable }}\n }\n </div>\n </div>\n </ui-popover-content>\n</ui-popover>\n" }]
38178
- }], ctorParameters: () => [] });
38360
+ ], host: { class: 'contents', '[attr.data-slot]': '"rte-tables-host"' }, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.locale().tooltip\"\n [attr.aria-label]=\"context.locale().tooltip\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content class=\"p-3 max-sm:max-w-[calc(100vw-1rem)]\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <div class=\"grid gap-0.5\" style=\"grid-template-columns: repeat(8, 1fr)\">\n @for (row of gridRange; track row) {\n @for (col of gridRange; track col) {\n <button\n type=\"button\"\n data-grid-cell\n class=\"aspect-square w-5 border rounded-sm transition-colors\"\n [class.bg-primary]=\"row <= hoverRows() && col <= hoverCols()\"\n [class.border-primary]=\"row <= hoverRows() && col <= hoverCols()\"\n [class.border-border]=\"row > hoverRows() || col > hoverCols()\"\n [class.bg-background]=\"row > hoverRows() || col > hoverCols()\"\n [attr.aria-label]=\"row + 'x' + col\"\n (mouseenter)=\"onHover(row, col)\"\n (click)=\"onSelect(row, col)\"\n ></button>\n }\n }\n </div>\n <div class=\"text-xs text-center text-muted-foreground\">\n @if (hoverRows() > 0 && hoverCols() > 0) {\n {{ hoverRows() }} x {{ hoverCols() }}\n } @else {\n {{ context.locale().insertTable }}\n }\n </div>\n </div>\n </ui-popover-content>\n</ui-popover>\n" }]
38361
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
38179
38362
 
38180
38363
  /** Built-in locales for the tables addon. */
38181
38364
  const RICH_TEXT_TABLES_LOCALES = {
@@ -38739,6 +38922,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
38739
38922
  class CommandInputComponent {
38740
38923
  constructor() {
38741
38924
  this.cmdService = inject(CommandService);
38925
+ /** Extra classes merged onto the search row (icon + field), after the bordered default — the `<input>` itself is not reachable from here. */
38926
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
38927
+ this.classes = computed(() => cn('flex items-center border-b px-3', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
38742
38928
  /** Override for the placeholder. Falls back to the locale's `searchPlaceholder`. */
38743
38929
  this.placeholder = input(...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
38744
38930
  /** Override for the aria-label. Falls back to the locale's `search`. */
@@ -38821,8 +39007,8 @@ class CommandInputComponent {
38821
39007
  this.inputEl?.nativeElement?.focus();
38822
39008
  }
38823
39009
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: CommandInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
38824
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: CommandInputComponent, isStandalone: true, selector: "ui-command-input", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true }], ngImport: i0, template: `
38825
- <div class="flex items-center border-b px-3" [attr.data-slot]="'command-input'" [attr.dir]="dir()">
39010
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: CommandInputComponent, isStandalone: true, selector: "ui-command-input", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true }], ngImport: i0, template: `
39011
+ <div [class]="classes()" [attr.data-slot]="'command-input'" [attr.dir]="dir()">
38826
39012
  <svg class="h-4 w-4 shrink-0 opacity-50 ltr:mr-2 rtl:ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
38827
39013
  <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
38828
39014
  </svg>
@@ -38844,7 +39030,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
38844
39030
  selector: 'ui-command-input',
38845
39031
  changeDetection: ChangeDetectionStrategy.OnPush,
38846
39032
  template: `
38847
- <div class="flex items-center border-b px-3" [attr.data-slot]="'command-input'" [attr.dir]="dir()">
39033
+ <div [class]="classes()" [attr.data-slot]="'command-input'" [attr.dir]="dir()">
38848
39034
  <svg class="h-4 w-4 shrink-0 opacity-50 ltr:mr-2 rtl:ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
38849
39035
  <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
38850
39036
  </svg>
@@ -38864,7 +39050,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
38864
39050
  }], propDecorators: { inputEl: [{
38865
39051
  type: ViewChild,
38866
39052
  args: ['inputEl']
38867
- }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }] } });
39053
+ }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }] } });
38868
39054
 
38869
39055
  class CommandListComponent {
38870
39056
  constructor() {
@@ -38909,14 +39095,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
38909
39095
  class CommandEmptyComponent {
38910
39096
  constructor() {
38911
39097
  this.cmdService = inject(CommandService);
39098
+ /** Extra classes merged onto the empty-state message, after the centred muted default. */
39099
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
39100
+ this.classes = computed(() => cn('py-6 text-center text-sm text-muted-foreground', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
38912
39101
  this.isVisible = computed(() => {
38913
39102
  return this.cmdService.filteredItemIds().size === 0;
38914
39103
  }, ...(ngDevMode ? [{ debugName: "isVisible" }] : /* istanbul ignore next */ []));
38915
39104
  }
38916
39105
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: CommandEmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
38917
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: CommandEmptyComponent, isStandalone: true, selector: "ui-command-empty", host: { classAttribute: "contents" }, ngImport: i0, template: `
39106
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: CommandEmptyComponent, isStandalone: true, selector: "ui-command-empty", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
38918
39107
  @if (isVisible()) {
38919
- <div class="py-6 text-center text-sm text-muted-foreground" [attr.data-slot]="'command-empty'">
39108
+ <div [class]="classes()" [attr.data-slot]="'command-empty'">
38920
39109
  <ng-content />
38921
39110
  </div>
38922
39111
  }
@@ -38929,14 +39118,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
38929
39118
  changeDetection: ChangeDetectionStrategy.OnPush,
38930
39119
  template: `
38931
39120
  @if (isVisible()) {
38932
- <div class="py-6 text-center text-sm text-muted-foreground" [attr.data-slot]="'command-empty'">
39121
+ <div [class]="classes()" [attr.data-slot]="'command-empty'">
38933
39122
  <ng-content />
38934
39123
  </div>
38935
39124
  }
38936
39125
  `,
38937
39126
  host: { class: 'contents' },
38938
39127
  }]
38939
- }] });
39128
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
38940
39129
 
38941
39130
  const COMMAND_GROUP = new InjectionToken('COMMAND_GROUP');
38942
39131
  class CommandGroupComponent {
@@ -39120,9 +39309,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
39120
39309
  }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], shortcut: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcut", required: false }] }], selectItem: [{ type: i0.Output, args: ["selectItem"] }], row: [{ type: i0.ViewChild, args: ['row', { isSignal: true }] }] } });
39121
39310
 
39122
39311
  class CommandSeparatorComponent {
39312
+ constructor() {
39313
+ /** Extra classes merged onto the rule, after `-mx-1 h-px bg-border`. */
39314
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
39315
+ this.classes = computed(() => cn('-mx-1 h-px bg-border', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
39316
+ }
39123
39317
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: CommandSeparatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
39124
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: CommandSeparatorComponent, isStandalone: true, selector: "ui-command-separator", host: { classAttribute: "contents" }, ngImport: i0, template: `
39125
- <div class="-mx-1 h-px bg-border" [attr.data-slot]="'command-separator'"></div>
39318
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: CommandSeparatorComponent, isStandalone: true, selector: "ui-command-separator", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
39319
+ <div [class]="classes()" [attr.data-slot]="'command-separator'"></div>
39126
39320
  `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
39127
39321
  }
39128
39322
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: CommandSeparatorComponent, decorators: [{
@@ -39131,16 +39325,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
39131
39325
  selector: 'ui-command-separator',
39132
39326
  changeDetection: ChangeDetectionStrategy.OnPush,
39133
39327
  template: `
39134
- <div class="-mx-1 h-px bg-border" [attr.data-slot]="'command-separator'"></div>
39328
+ <div [class]="classes()" [attr.data-slot]="'command-separator'"></div>
39135
39329
  `,
39136
39330
  host: { class: 'contents' },
39137
39331
  }]
39138
- }] });
39332
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
39139
39333
 
39140
39334
  class CommandShortcutComponent {
39335
+ constructor() {
39336
+ /** Extra classes merged onto the hint, after the muted `text-xs` default — so a `text-*` here wins. */
39337
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
39338
+ this.classes = computed(() => cn('text-xs tracking-widest text-muted-foreground ltr:ml-auto rtl:mr-auto', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
39339
+ }
39141
39340
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: CommandShortcutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
39142
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: CommandShortcutComponent, isStandalone: true, selector: "ui-command-shortcut", host: { classAttribute: "contents" }, ngImport: i0, template: `
39143
- <span class="text-xs tracking-widest text-muted-foreground ltr:ml-auto rtl:mr-auto" [attr.data-slot]="'command-shortcut'">
39341
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: CommandShortcutComponent, isStandalone: true, selector: "ui-command-shortcut", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
39342
+ <span [class]="classes()" [attr.data-slot]="'command-shortcut'">
39144
39343
  <ng-content />
39145
39344
  </span>
39146
39345
  `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
@@ -39151,16 +39350,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
39151
39350
  selector: 'ui-command-shortcut',
39152
39351
  changeDetection: ChangeDetectionStrategy.OnPush,
39153
39352
  template: `
39154
- <span class="text-xs tracking-widest text-muted-foreground ltr:ml-auto rtl:mr-auto" [attr.data-slot]="'command-shortcut'">
39353
+ <span [class]="classes()" [attr.data-slot]="'command-shortcut'">
39155
39354
  <ng-content />
39156
39355
  </span>
39157
39356
  `,
39158
39357
  host: { class: 'contents' },
39159
39358
  }]
39160
- }] });
39359
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
39161
39360
 
39162
39361
  class CommandDialogComponent {
39163
39362
  constructor() {
39363
+ /** Extra classes merged onto the dialog panel, after `overflow-hidden p-0 shadow-lg` — e.g. a width utility. */
39364
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
39365
+ this.classes = computed(() => cn('overflow-hidden p-0 shadow-lg', this.class()), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
39164
39366
  /**
39165
39367
  * Two-way open state of the underlying `ui-dialog`. Toggled by the global
39166
39368
  * {@link shortcut}, and each transition to open focuses the projected
@@ -39230,9 +39432,9 @@ class CommandDialogComponent {
39230
39432
  this.shortcutHandle = null;
39231
39433
  }
39232
39434
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: CommandDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
39233
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.22", type: CommandDialogComponent, isStandalone: true, selector: "ui-command-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, shortcutEnabled: { classPropertyName: "shortcutEnabled", publicName: "shortcutEnabled", isSignal: true, isRequired: false, transformFunction: null }, shortcut: { classPropertyName: "shortcut", publicName: "shortcut", isSignal: true, isRequired: false, transformFunction: null }, shortcutActionId: { classPropertyName: "shortcutActionId", publicName: "shortcutActionId", isSignal: true, isRequired: false, transformFunction: null }, shortcutCategory: { classPropertyName: "shortcutCategory", publicName: "shortcutCategory", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { classAttribute: "contents" }, queries: [{ propertyName: "commandInput", first: true, predicate: CommandInputComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
39435
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.22", type: CommandDialogComponent, isStandalone: true, selector: "ui-command-dialog", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, shortcutEnabled: { classPropertyName: "shortcutEnabled", publicName: "shortcutEnabled", isSignal: true, isRequired: false, transformFunction: null }, shortcut: { classPropertyName: "shortcut", publicName: "shortcut", isSignal: true, isRequired: false, transformFunction: null }, shortcutActionId: { classPropertyName: "shortcutActionId", publicName: "shortcutActionId", isSignal: true, isRequired: false, transformFunction: null }, shortcutCategory: { classPropertyName: "shortcutCategory", publicName: "shortcutCategory", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { properties: { "attr.data-slot": "\"command-dialog\"" }, classAttribute: "contents" }, queries: [{ propertyName: "commandInput", first: true, predicate: CommandInputComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
39234
39436
  <ui-dialog [(open)]="open">
39235
- <ui-dialog-content class="overflow-hidden p-0 shadow-lg">
39437
+ <ui-dialog-content [class]="classes()">
39236
39438
  <ui-command class="**:data-[slot=command-group]:px-2 **:data-[slot=command-group]:font-medium **:data-[slot=command-group]:text-muted-foreground **:data-[slot=command-item]:px-2 **:data-[slot=command-item]:py-3 [&_[data-slot=command-item]_svg]:h-5 [&_[data-slot=command-item]_svg]:w-5">
39237
39439
  <ng-content />
39238
39440
  </ui-command>
@@ -39248,16 +39450,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
39248
39450
  imports: [DialogComponent, DialogContentComponent, CommandComponent],
39249
39451
  template: `
39250
39452
  <ui-dialog [(open)]="open">
39251
- <ui-dialog-content class="overflow-hidden p-0 shadow-lg">
39453
+ <ui-dialog-content [class]="classes()">
39252
39454
  <ui-command class="**:data-[slot=command-group]:px-2 **:data-[slot=command-group]:font-medium **:data-[slot=command-group]:text-muted-foreground **:data-[slot=command-item]:px-2 **:data-[slot=command-item]:py-3 [&_[data-slot=command-item]_svg]:h-5 [&_[data-slot=command-item]_svg]:w-5">
39253
39455
  <ng-content />
39254
39456
  </ui-command>
39255
39457
  </ui-dialog-content>
39256
39458
  </ui-dialog>
39257
39459
  `,
39258
- host: { class: 'contents' },
39460
+ host: { class: 'contents', '[attr.data-slot]': '"command-dialog"' },
39259
39461
  }]
39260
- }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], shortcutEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcutEnabled", required: false }] }], shortcut: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcut", required: false }] }], shortcutActionId: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcutActionId", required: false }] }], shortcutCategory: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcutCategory", required: false }] }], commandInput: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CommandInputComponent), { isSignal: true }] }] } });
39462
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], shortcutEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcutEnabled", required: false }] }], shortcut: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcut", required: false }] }], shortcutActionId: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcutActionId", required: false }] }], shortcutCategory: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcutCategory", required: false }] }], commandInput: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CommandInputComponent), { isSignal: true }] }] } });
39261
39463
 
39262
39464
  class HighlightPipe {
39263
39465
  /**
@@ -39909,7 +40111,7 @@ class AutocompleteComponent {
39909
40111
  useExisting: forwardRef(() => AutocompleteComponent),
39910
40112
  multi: true,
39911
40113
  },
39912
- ], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }, { propertyName: "command", first: true, predicate: CommandComponent, descendants: true, isSignal: true }, { propertyName: "commandService", first: true, predicate: CommandComponent, descendants: true, read: CommandService, isSignal: true }], ngImport: i0, template: "<ui-popover [open]=\"open()\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger class=\"w-full\">\n <div\n [class]=\"containerClasses()\"\n [attr.data-state]=\"open() ? 'open' : 'closed'\"\n [attr.data-disabled]=\"isDisabled() || null\"\n [attr.data-slot]=\"'autocomplete-container'\"\n [attr.dir]=\"dir()\"\n tabindex=\"-1\"\n (click)=\"onContainerClick($event)\"\n (keydown.enter)=\"onContainerClick($event)\"\n (keydown.space)=\"onContainerClick($event)\"\n >\n @if (multiple()) {\n <div class=\"flex flex-wrap items-center gap-1 w-full\">\n @for (item of selectedItems(); track item; let i = $index) {\n <ui-badge variant=\"secondary\" class=\"gap-1 pe-0.5\">\n {{ getDisplayValue(item) }}\n <button\n type=\"button\"\n class=\"cursor-pointer rounded-full p-0.5 pointer-coarse:size-11 hover:bg-secondary-foreground/20 inline-flex items-center justify-center bg-transparent border-0\"\n data-slot=\"chip-remove\"\n (click)=\"removeItem(item, $event)\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-3 w-3\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>\n </button>\n </ui-badge>\n }\n <input\n #inputEl\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"listId\"\n [attr.aria-activedescendant]=\"activeItemId()\"\n [class]=\"multiInputClasses()\"\n [placeholder]=\"selectedItems().length === 0 ? (placeholder() ?? t().selectPlaceholder) : ''\"\n [disabled]=\"isDisabled()\"\n [(ngModel)]=\"searchTerm\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onTouched()\"\n />\n </div>\n } @else {\n <div class=\"flex items-center w-full gap-2\">\n <input\n #inputEl\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"listId\"\n [attr.aria-activedescendant]=\"activeItemId()\"\n [class]=\"singleInputClasses()\"\n [placeholder]=\"placeholder() ?? t().selectPlaceholder\"\n [disabled]=\"isDisabled()\"\n [value]=\"inputValue()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n />\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-4 w-4 opacity-50 shrink-0\"><path d=\"m6 9 6 6 6-6\"/></svg>\n </div>\n }\n </div>\n </ui-popover-trigger>\n <ui-popover-content [side]=\"dropdownSide()\" class=\"w-[--radix-popover-trigger-width] p-0\" align=\"start\" [restoreFocus]=\"false\" [avoidCollisions]=\"avoidPopoverCollisions()\">\n <ui-command [shouldFilter]=\"filter()\" [search]=\"searchTerm()\" [attr.dir]=\"dir()\">\n <ui-command-list [attr.id]=\"listId\" role=\"listbox\">\n <ui-command-empty>{{ t().noResults }}</ui-command-empty>\n\n @for (option of options(); track getTrackBy(option)) {\n <ui-command-item\n [value]=\"getSearchValue(option)\"\n [selected]=\"isSelected(option)\"\n (selectItem)=\"onSelect(option)\"\n >\n <span class=\"truncate\" [innerHTML]=\"getDisplayValue(option) | highlight: searchTerm()\"></span>\n <span class=\"ms-auto flex h-3.5 w-3.5 shrink-0 items-center justify-center opacity-0\" [class.opacity-100]=\"isSelected(option)\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-4 w-4\"><polyline points=\"20 6 9 17 4 12\"/></svg>\n </span>\n </ui-command-item>\n }\n </ui-command-list>\n </ui-command>\n </ui-popover-content>\n</ui-popover>\n", styles: [":host{--_d: var(--density-select, var(--density, 1))}@layer components{[data-slot=autocomplete-container]{min-height:calc(2.5rem * var(--_d));padding-inline:calc(.75rem * var(--_d));padding-block:calc(.5rem * var(--_d))}}\n"], dependencies: [{ kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger" }, { kind: "component", type: CommandComponent, selector: "ui-command", inputs: ["class", "shouldFilter", "search", "source", "debounce", "recentKey", "recentLimit"] }, { kind: "component", type: CommandListComponent, selector: "ui-command-list", inputs: ["class", "ariaLabel"] }, { kind: "component", type: CommandItemComponent, selector: "ui-command-item", inputs: ["class", "disabled", "selected", "value", "shortcut"], outputs: ["selectItem"] }, { kind: "component", type: CommandEmptyComponent, selector: "ui-command-empty" }, { kind: "component", type: BadgeComponent, selector: "ui-badge", inputs: ["variant", "label", "class", "skeleton"] }, { 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: "pipe", type: HighlightPipe, name: "highlight" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
40114
+ ], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }, { propertyName: "command", first: true, predicate: CommandComponent, descendants: true, isSignal: true }, { propertyName: "commandService", first: true, predicate: CommandComponent, descendants: true, read: CommandService, isSignal: true }], ngImport: i0, template: "<ui-popover [open]=\"open()\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger class=\"w-full\">\n <div\n [class]=\"containerClasses()\"\n [attr.data-state]=\"open() ? 'open' : 'closed'\"\n [attr.data-disabled]=\"isDisabled() || null\"\n [attr.data-slot]=\"'autocomplete-container'\"\n [attr.dir]=\"dir()\"\n tabindex=\"-1\"\n (click)=\"onContainerClick($event)\"\n (keydown.enter)=\"onContainerClick($event)\"\n (keydown.space)=\"onContainerClick($event)\"\n >\n @if (multiple()) {\n <div class=\"flex flex-wrap items-center gap-1 w-full\">\n @for (item of selectedItems(); track item; let i = $index) {\n <ui-badge variant=\"secondary\" class=\"gap-1 pe-0.5\">\n {{ getDisplayValue(item) }}\n <button\n type=\"button\"\n class=\"cursor-pointer rounded-full p-0.5 pointer-coarse:size-11 hover:bg-secondary-foreground/20 inline-flex items-center justify-center bg-transparent border-0\"\n data-slot=\"chip-remove\"\n (click)=\"removeItem(item, $event)\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-3 w-3\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>\n </button>\n </ui-badge>\n }\n <input\n #inputEl\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"listId\"\n [attr.aria-activedescendant]=\"activeItemId()\"\n [class]=\"multiInputClasses()\"\n [placeholder]=\"selectedItems().length === 0 ? (placeholder() ?? t().selectPlaceholder) : ''\"\n [disabled]=\"isDisabled()\"\n [(ngModel)]=\"searchTerm\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onTouched()\"\n />\n </div>\n } @else {\n <div class=\"flex items-center w-full gap-2\">\n <input\n #inputEl\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"listId\"\n [attr.aria-activedescendant]=\"activeItemId()\"\n [class]=\"singleInputClasses()\"\n [placeholder]=\"placeholder() ?? t().selectPlaceholder\"\n [disabled]=\"isDisabled()\"\n [value]=\"inputValue()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n />\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-4 w-4 opacity-50 shrink-0\"><path d=\"m6 9 6 6 6-6\"/></svg>\n </div>\n }\n </div>\n </ui-popover-trigger>\n <ui-popover-content [side]=\"dropdownSide()\" class=\"w-[--radix-popover-trigger-width] p-0\" align=\"start\" [restoreFocus]=\"false\" [avoidCollisions]=\"avoidPopoverCollisions()\">\n <ui-command [shouldFilter]=\"filter()\" [search]=\"searchTerm()\" [attr.dir]=\"dir()\">\n <ui-command-list [attr.id]=\"listId\" role=\"listbox\">\n <ui-command-empty>{{ t().noResults }}</ui-command-empty>\n\n @for (option of options(); track getTrackBy(option)) {\n <ui-command-item\n [value]=\"getSearchValue(option)\"\n [selected]=\"isSelected(option)\"\n (selectItem)=\"onSelect(option)\"\n >\n <span class=\"truncate\" [innerHTML]=\"getDisplayValue(option) | highlight: searchTerm()\"></span>\n <span class=\"ms-auto flex h-3.5 w-3.5 shrink-0 items-center justify-center opacity-0\" [class.opacity-100]=\"isSelected(option)\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-4 w-4\"><polyline points=\"20 6 9 17 4 12\"/></svg>\n </span>\n </ui-command-item>\n }\n </ui-command-list>\n </ui-command>\n </ui-popover-content>\n</ui-popover>\n", styles: [":host{--_d: var(--density-select, var(--density, 1))}@layer components{[data-slot=autocomplete-container]{min-height:calc(2.5rem * var(--_d));padding-inline:calc(.75rem * var(--_d));padding-block:calc(.5rem * var(--_d))}}\n"], dependencies: [{ kind: "component", type: PopoverComponent, selector: "ui-popover", inputs: ["class", "open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger", inputs: ["class"] }, { kind: "component", type: CommandComponent, selector: "ui-command", inputs: ["class", "shouldFilter", "search", "source", "debounce", "recentKey", "recentLimit"] }, { kind: "component", type: CommandListComponent, selector: "ui-command-list", inputs: ["class", "ariaLabel"] }, { kind: "component", type: CommandItemComponent, selector: "ui-command-item", inputs: ["class", "disabled", "selected", "value", "shortcut"], outputs: ["selectItem"] }, { kind: "component", type: CommandEmptyComponent, selector: "ui-command-empty", inputs: ["class"] }, { kind: "component", type: BadgeComponent, selector: "ui-badge", inputs: ["variant", "label", "class", "skeleton"] }, { 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: "pipe", type: HighlightPipe, name: "highlight" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
39913
40115
  }
39914
40116
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: AutocompleteComponent, decorators: [{
39915
40117
  type: Component,
@@ -39962,11 +40164,13 @@ class RichTextTypographyButtonComponent {
39962
40164
  this.icon = this.domSanitizer.bypassSecurityTrustHtml(this.context.kind === 'size' ? SIZE_ICON : FAMILY_ICON);
39963
40165
  this.panelClasses = this.context.kind === 'size' ? 'w-48' : 'w-56';
39964
40166
  this.interactionDisabled = computed(() => this.host.isDisabled() || this.host.readonly(), ...(ngDevMode ? [{ debugName: "interactionDisabled" }] : /* istanbul ignore next */ []));
40167
+ /** Extra classes merged onto the toolbar button, after the built-in icon-button styling. */
40168
+ this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
39965
40169
  this.buttonClasses = computed(() => cn('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors', 'hover:bg-accent hover:text-accent-foreground', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', 'disabled:pointer-events-none disabled:opacity-50',
39966
40170
  // The global (pointer: coarse) floor targets `button:not([data-slot])`,
39967
40171
  // and these addon buttons carry a data-slot for testing — so they must
39968
40172
  // state the 44px touch minimum themselves rather than inherit it.
39969
- 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5'), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
40173
+ 'pointer-coarse:min-h-11 pointer-coarse:min-w-11', this.toolbarView?.compact() ? 'p-1' : 'p-1.5', this.class()), ...(ngDevMode ? [{ debugName: "buttonClasses" }] : /* istanbul ignore next */ []));
39970
40174
  inject(DestroyRef).onDestroy(() => this.exclusive.release());
39971
40175
  }
39972
40176
  onOpenChange(next) {
@@ -39986,7 +40190,7 @@ class RichTextTypographyButtonComponent {
39986
40190
  this.context.onSelect(value);
39987
40191
  }
39988
40192
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextTypographyButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
39989
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: RichTextTypographyButtonComponent, isStandalone: true, selector: "ui-rte-typography-button", host: { classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content [class]=\"panelClasses + ' max-w-[calc(100vw-2rem)] p-3'\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium block m-0\">{{ context.heading() }}</p>\n <ui-autocomplete\n [ngModel]=\"context.seededValue()\"\n [options]=\"context.options()\"\n [placeholder]=\"context.placeholder()\"\n [disabled]=\"interactionDisabled()\"\n [filter]=\"context.filter\"\n (ngModelChange)=\"onValueChange($event)\"\n class=\"w-full\"\n />\n </div>\n </ui-popover-content>\n</ui-popover>\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: PopoverComponent, selector: "ui-popover", inputs: ["open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger" }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: AutocompleteComponent, selector: "ui-autocomplete", inputs: ["options", "displayWith", "valueAttribute", "filter", "multiple", "placeholder", "disabled", "class", "debounceTime", "value", "locale", "searchTerm"], outputs: ["valueChange", "searchChange", "searchTermChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
40193
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: RichTextTypographyButtonComponent, isStandalone: true, selector: "ui-rte-typography-button", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-slot": "\"rte-typography-host\"" }, classAttribute: "contents" }, ngImport: i0, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content [class]=\"panelClasses + ' max-w-[calc(100vw-2rem)] p-3'\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium block m-0\">{{ context.heading() }}</p>\n <ui-autocomplete\n [ngModel]=\"context.seededValue()\"\n [options]=\"context.options()\"\n [placeholder]=\"context.placeholder()\"\n [disabled]=\"interactionDisabled()\"\n [filter]=\"context.filter\"\n (ngModelChange)=\"onValueChange($event)\"\n class=\"w-full\"\n />\n </div>\n </ui-popover-content>\n</ui-popover>\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: PopoverComponent, selector: "ui-popover", inputs: ["class", "open", "closeOnScroll"], outputs: ["openChange"] }, { kind: "component", type: PopoverTriggerComponent, selector: "ui-popover-trigger", inputs: ["class"] }, { kind: "component", type: PopoverContentComponent, selector: "ui-popover-content", inputs: ["class", "align", "side", "sideOffset", "avoidCollisions", "restoreFocus", "strategy"] }, { kind: "component", type: AutocompleteComponent, selector: "ui-autocomplete", inputs: ["options", "displayWith", "valueAttribute", "filter", "multiple", "placeholder", "disabled", "class", "debounceTime", "value", "locale", "searchTerm"], outputs: ["valueChange", "searchChange", "searchTermChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
39990
40194
  }
39991
40195
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextTypographyButtonComponent, decorators: [{
39992
40196
  type: Component,
@@ -39996,8 +40200,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
39996
40200
  PopoverTriggerComponent,
39997
40201
  PopoverContentComponent,
39998
40202
  AutocompleteComponent,
39999
- ], host: { class: 'contents' }, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content [class]=\"panelClasses + ' max-w-[calc(100vw-2rem)] p-3'\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium block m-0\">{{ context.heading() }}</p>\n <ui-autocomplete\n [ngModel]=\"context.seededValue()\"\n [options]=\"context.options()\"\n [placeholder]=\"context.placeholder()\"\n [disabled]=\"interactionDisabled()\"\n [filter]=\"context.filter\"\n (ngModelChange)=\"onValueChange($event)\"\n class=\"w-full\"\n />\n </div>\n </ui-popover-content>\n</ui-popover>\n" }]
40000
- }], ctorParameters: () => [] });
40203
+ ], host: { class: 'contents', '[attr.data-slot]': '"rte-typography-host"' }, template: "<ui-popover [open]=\"open()\" [closeOnScroll]=\"true\" (openChange)=\"onOpenChange($event)\">\n <ui-popover-trigger>\n <button\n type=\"button\"\n [class]=\"buttonClasses()\"\n [title]=\"context.tooltip()\"\n [attr.aria-label]=\"context.tooltip()\"\n [disabled]=\"interactionDisabled()\"\n >\n <span [innerHTML]=\"icon\"></span>\n </button>\n </ui-popover-trigger>\n <ui-popover-content [class]=\"panelClasses + ' max-w-[calc(100vw-2rem)] p-3'\" align=\"start\" strategy=\"fixed\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium block m-0\">{{ context.heading() }}</p>\n <ui-autocomplete\n [ngModel]=\"context.seededValue()\"\n [options]=\"context.options()\"\n [placeholder]=\"context.placeholder()\"\n [disabled]=\"interactionDisabled()\"\n [filter]=\"context.filter\"\n (ngModelChange)=\"onValueChange($event)\"\n class=\"w-full\"\n />\n </div>\n </ui-popover-content>\n</ui-popover>\n" }]
40204
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
40001
40205
 
40002
40206
  /** Built-in locales for the typography addon. */
40003
40207
  const RICH_TEXT_TYPOGRAPHY_LOCALES = {
@@ -40205,4 +40409,4 @@ const RTE_FULL = [
40205
40409
  */
40206
40410
 
40207
40411
  export { RichTextAllowHost as $, ACTION_ATTRS as A, RICH_TEXT_LOCALES as B, RICH_TEXT_MENTIONS_LOCALES as C, DEFAULT_COLOR_PALETTE as D, EMPTINESS_FIXTURES as E, FIND_MAX_PAINTED_RECTS as F, RICH_TEXT_OUTLINE_CONTEXT as G, HEADER_BYTES as H, IMAGE_IMPORT_ACCEPT as I, RICH_TEXT_OUTLINE_LOCALES as J, RICH_TEXT_PROSE_CLASSES as K, RICH_TEXT_SHORTCUT_DEFINITIONS as L, MAX_NESTING_DEPTH as M, RICH_TEXT_SLASH_COMMANDS_LOCALES as N, RICH_TEXT_TABLES_BUTTON_CONTEXT as O, PDF_MIME as P, RICH_TEXT_TABLES_LOCALES as Q, RICH_TEXT_ACTIONS_SANITIZER_RULES as R, RICH_TEXT_TYPOGRAPHY_BUTTON_CONTEXT as S, RICH_TEXT_TYPOGRAPHY_LOCALES as T, RTE_FULL as U, RichTextActionsBindDirective as V, RichTextActionsDirective as W, RichTextAiChipComponent as X, RichTextAiDirective as Y, RichTextAiPanelComponent as Z, RichTextAllowDirective as _, ACTION_PARAMS as a, flattenIntoRowText as a$, RichTextColorsButtonComponent as a0, RichTextColorsDirective as a1, RichTextCommandRegistry as a2, RichTextEditorAddonHost as a3, RichTextEditorComponent as a4, RichTextEmojiButtonComponent as a5, RichTextEmojiDirective as a6, RichTextFileImportButtonComponent as a7, RichTextFileImportDirective as a8, RichTextFileImportOverlayComponent as a9, TRANSPARENT_PIXEL as aA, addonSetting as aB, anchorOverlay as aC, applyImageAlignment as aD, applyStarterStyle as aE, assertFlatParams as aF, bindRichTextActions as aG, blockquoteDepthOf as aH, buildDefaultSlashCommands as aI, buildEntityInsertNode as aJ, buildEntityRenderContext as aK, buildFindIndex as aL, buildLineIndex as aM, caretPosition as aN, childList as aO, classifyImport as aP, compileFindRegex as aQ, computeSeedStyleString as aR, containsCssUrl as aS, createImageElement as aT, cssFunctionCalls as aU, dataUrlToFile as aV, decodeCssEscapes as aW, detectTrigger as aX, directionOf as aY, dragHasSupportedDocument as aZ, extractCssUrls as a_, RichTextHistoryDirective as aa, RichTextHistoryPanelComponent as ab, RichTextImageResizerComponent as ac, RichTextImagesButtonComponent as ad, RichTextImagesDirective as ae, RichTextImagesOverlayComponent as af, RichTextLinksButtonComponent as ag, RichTextLinksDirective as ah, RichTextLinksFormComponent as ai, RichTextMarkdownService as aj, RichTextMentionPopoverComponent as ak, RichTextMentionsDirective as al, RichTextOutlineDirective as am, RichTextOutlinePanelComponent as an, RichTextPasteNormalizerService as ao, RichTextSanitizerService as ap, RichTextSlashCommandsDirective as aq, RichTextSlashCommandsMenuComponent as ar, RichTextTablesButtonComponent as as, RichTextTablesDirective as at, RichTextToolbarComponent as au, RichTextToolbarViewContext as av, RichTextTypographyButtonComponent as aw, RichTextTypographyDirective as ax, TEXT_STYLE_OPTIONS as ay, TOOLBAR_BUTTONS as az, AddonSlotRegistry as b, validateActionParams as b$, hasUnsafeCssFunction as b0, holdsNothing as b1, hostOf as b2, hoverCardAction as b3, hoverCardHandlers as b4, inlineElementsHoldingBlocks as b5, isCombinedOnElement as b6, isHostAllowed as b7, isHostBearingUrl as b8, isLineOwner as b9, offsetToPosition as bA, openDialogAction as bB, openDialogHandlers as bC, parseImageSize as bD, placeCaretIn as bE, placeImageAtSelection as bF, positionAfterLine as bG, rangeShowsNothing as bH, readActions as bI, readFileAsDataUrl as bJ, remoteHostOf as bK, removeAction as bL, reportResourceDecisions as bM, resolveFromPage as bN, richTextHasMedia as bO, richTextMaxLength as bP, richTextMinWords as bQ, richTextRequired as bR, richTextVisibleText as bS, rowRunsOf as bT, selectTriggerRange as bU, separateListKinds as bV, simpleHash as bW, stripCssComments as bX, stripStyleIfMatches as bY, structureAround as bZ, validateActionId as b_, isNestedList as ba, isPdfHeader as bb, isPhrasing as bc, isRichTextEmpty as bd, isSupportedDocumentFile as be, isZipHeader as bf, labelBlockedImages as bg, lastOwnInlineNode as bh, lineAbove as bi, lineBelow as bj, lineIsEmpty as bk, lineIsTextOnly as bl, lineKeepsItsElement as bm, lineOf as bn, lineOwnNodes as bo, lineTagIsFixed as bp, lineText as bq, linesBetween as br, linesMayJoin as bs, linkedPreviewDialogAction as bt, linkedPreviewDialogHandlers as bu, matchBlockInputRule as bv, matchInlineInputRule as bw, mountTopLayer as bx, nodeShowsNothing as by, normalizeHostEntry as bz, DEFAULT_FONT_FAMILIES as c, writeAction as c0, writeCombined as c1, DEFAULT_HIGHLIGHT_PALETTE as d, DEFAULT_LINK_SCHEMES as e, DEFAULT_TOOLBAR_ITEMS as f, DOCUMENT_IMPORT_ACCEPT as g, DOCX_MIME as h, isValidImageMagicBytes as i, FIND_MAX_QUERY_LENGTH as j, INLINE_RULE_LOOKBEHIND as k, PresetDialogComponent as l, PresetHoverCardComponent as m, RICH_TEXT_AI_CONTEXT as n, RICH_TEXT_AI_LOCALES as o, RICH_TEXT_COLORS_LOCALES as p, RICH_TEXT_COLOR_BUTTON_CONTEXT as q, RICH_TEXT_EMOJI_CONTEXT as r, RICH_TEXT_EMOJI_LOCALES as s, RICH_TEXT_FILE_IMPORT_BUTTON_CONTEXT as t, RICH_TEXT_FILE_IMPORT_LOCALES as u, RICH_TEXT_HISTORY_LOCALES as v, RICH_TEXT_IMAGES_BUTTON_CONTEXT as w, RICH_TEXT_IMAGES_LOCALES as x, RICH_TEXT_LINKS_BUTTON_CONTEXT as y, RICH_TEXT_LINKS_LOCALES as z };
40208
- //# sourceMappingURL=gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BnEAQOuU.mjs.map
40412
+ //# sourceMappingURL=gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-CjHrbpSa.mjs.map