@gilav21/shadcn-angular-rte 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10833,6 +10833,11 @@ class RichTextEditorComponent extends RichTextEditorAddonHost {
10833
10833
  this.rootCommandRegistry = inject(RichTextCommandRegistry, { skipSelf: true });
10834
10834
  /** Output format: `'markdown'` converts to/from Markdown; `'html'` works with raw HTML. */
10835
10835
  this.mode = input('markdown', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
10836
+ /**
10837
+ * Colour preset for this editor and its overlays — the names `change-theme`
10838
+ * accepts. Unset, the editor follows the app's global tokens.
10839
+ */
10840
+ this.theme = input(...(ngDevMode ? [undefined, { debugName: "theme" }] : /* istanbul ignore next */ []));
10836
10841
  /** Visual border/focus style. See {@link EditorVariant}. */
10837
10842
  this.variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
10838
10843
  /** Text size preset for the editor content. See {@link EditorSize}. */
@@ -18657,7 +18662,7 @@ class RichTextEditorComponent extends RichTextEditorAddonHost {
18657
18662
  this.removeFloatingScrollListener();
18658
18663
  }
18659
18664
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18660
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextEditorComponent, isStandalone: true, selector: "ui-rich-text-editor", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, toolbarItems: { classPropertyName: "toolbarItems", publicName: "toolbarItems", isSignal: true, isRequired: false, transformFunction: null }, customToolbarItems: { classPropertyName: "customToolbarItems", publicName: "customToolbarItems", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, markdownShortcuts: { classPropertyName: "markdownShortcuts", publicName: "markdownShortcuts", isSignal: true, isRequired: false, transformFunction: null }, counter: { classPropertyName: "counter", publicName: "counter", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, history: { classPropertyName: "history", publicName: "history", isSignal: true, isRequired: false, transformFunction: null }, findDebounceMs: { classPropertyName: "findDebounceMs", publicName: "findDebounceMs", isSignal: true, isRequired: false, transformFunction: null }, codeHighlightDebounceMs: { classPropertyName: "codeHighlightDebounceMs", publicName: "codeHighlightDebounceMs", isSignal: true, isRequired: false, transformFunction: null }, allowedImageHosts: { classPropertyName: "allowedImageHosts", publicName: "allowedImageHosts", isSignal: true, isRequired: false, transformFunction: null }, allowedLinkSchemes: { classPropertyName: "allowedLinkSchemes", publicName: "allowedLinkSchemes", isSignal: true, isRequired: false, transformFunction: null }, blockedImageMessage: { classPropertyName: "blockedImageMessage", publicName: "blockedImageMessage", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { customToolbarAction: "customToolbarAction", htmlChange: "htmlChange", markdownChange: "markdownChange", wordCountChange: "wordCountChange", historyChange: "historyChange", imageBlocked: "imageBlocked", focused: "focused", blurred: "blurred" }, host: { classAttribute: "block" }, providers: [
18665
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: RichTextEditorComponent, isStandalone: true, selector: "ui-rich-text-editor", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, toolbarItems: { classPropertyName: "toolbarItems", publicName: "toolbarItems", isSignal: true, isRequired: false, transformFunction: null }, customToolbarItems: { classPropertyName: "customToolbarItems", publicName: "customToolbarItems", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, markdownShortcuts: { classPropertyName: "markdownShortcuts", publicName: "markdownShortcuts", isSignal: true, isRequired: false, transformFunction: null }, counter: { classPropertyName: "counter", publicName: "counter", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, history: { classPropertyName: "history", publicName: "history", isSignal: true, isRequired: false, transformFunction: null }, findDebounceMs: { classPropertyName: "findDebounceMs", publicName: "findDebounceMs", isSignal: true, isRequired: false, transformFunction: null }, codeHighlightDebounceMs: { classPropertyName: "codeHighlightDebounceMs", publicName: "codeHighlightDebounceMs", isSignal: true, isRequired: false, transformFunction: null }, allowedImageHosts: { classPropertyName: "allowedImageHosts", publicName: "allowedImageHosts", isSignal: true, isRequired: false, transformFunction: null }, allowedLinkSchemes: { classPropertyName: "allowedLinkSchemes", publicName: "allowedLinkSchemes", isSignal: true, isRequired: false, transformFunction: null }, blockedImageMessage: { classPropertyName: "blockedImageMessage", publicName: "blockedImageMessage", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { customToolbarAction: "customToolbarAction", htmlChange: "htmlChange", markdownChange: "markdownChange", wordCountChange: "wordCountChange", historyChange: "historyChange", imageBlocked: "imageBlocked", focused: "focused", blurred: "blurred" }, host: { properties: { "attr.data-ui-theme": "theme()" }, classAttribute: "block" }, providers: [
18661
18666
  {
18662
18667
  provide: NG_VALUE_ACCESSOR,
18663
18668
  useExisting: forwardRef(() => RichTextEditorComponent),
@@ -18679,7 +18684,7 @@ class RichTextEditorComponent extends RichTextEditorAddonHost {
18679
18684
  RichTextSanitizerService,
18680
18685
  RichTextMarkdownService,
18681
18686
  provideComponentLocale(() => RichTextEditorComponent),
18682
- ], viewQueries: [{ propertyName: "editorDiv", first: true, predicate: ["editorDiv"], descendants: true }, { propertyName: "editorContainer", first: true, predicate: ["editorContainer"], descendants: true }, { propertyName: "tableContextMenuRef", first: true, predicate: ["tableContextMenuRef"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (toolbar() === 'top' && !readonly()) {\n <ui-rich-text-toolbar\n [items]=\"toolbarItems()\"\n [activeFormats]=\"activeFormats()\"\n [textStyleAvailable]=\"textStyleAvailable()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [locale]=\"resolvedLocale()\"\n (formatCommand)=\"onFormatCommand($event)\"\n [addonSlots]=\"toolbarSlots.slots()\"\n (addonSlotClick)=\"onAddonSlotClick($event)\"\n />\n}\n\n<div #editorContainer [class]=\"editorContainerClasses()\" [dir]=\"resolvedDir()\">\n <!--\n Three of the attributes below exist for assistive tech specifically:\n\n The tab index drops to -1 when disabled. A native disabled control leaves the\n tab order entirely; a static 0 left a keyboard user stopping on an editor\n that takes focus and then does nothing.\n\n The readonly state is announced explicitly, because contenteditable false is\n a browser editing hint rather than a state screen readers reliably report on\n a textbox \u2014 without it a reader discovers the field is read-only by typing\n and seeing nothing happen.\n\n The placeholder is announced explicitly too, because the visible one is CSS\n generated content. Chromium exposes that as a plain text child, so a reader\n announces the hint as though it were the document's own text.\n -->\n <div\n #editorDiv\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n [attr.contenteditable]=\"!isDisabled() && !readonly()\"\n [attr.aria-disabled]=\"isDisabled()\"\n [attr.aria-readonly]=\"readonly() ? 'true' : null\"\n [class]=\"editableClasses()\"\n [attr.placeholder]=\"placeholder() || resolvedLocale().editor.placeholder\"\n [attr.aria-placeholder]=\"placeholder() || resolvedLocale().editor.placeholder\"\n [attr.aria-label]=\"ariaLabel() || resolvedLocale().editor.ariaLabel\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.data-slot]=\"'rich-text-editor'\"\n [style.min-height]=\"minHeight()\"\n [style.max-height]=\"maxHeight()\"\n role=\"textbox\"\n aria-multiline=\"true\"\n [attr.aria-expanded]=\"activeSuggestionPopup() ? 'true' : null\"\n [attr.aria-controls]=\"activeSuggestionPopup()?.controlsId ?? null\"\n [attr.aria-activedescendant]=\"activeSuggestionPopup()?.activeOptionId ?? null\"\n (input)=\"onInput($event)\"\n (beforeinput)=\"onBeforeInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (paste)=\"onPaste($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur($event)\"\n (mouseup)=\"onSelectionChange()\"\n (keyup)=\"onSelectionChange()\"\n (click)=\"onEditorClick($event)\"\n (mousemove)=\"onEditorMouseMove($event)\"\n (mousedown)=\"onEditorMouseDown($event)\"\n (touchstart)=\"onEditorTouchStart($event)\"\n (contextmenu)=\"onEditorContextMenu($event)\"\n (dragover)=\"onEditorDragOver($event)\"\n (dragleave)=\"onEditorDragLeave($event)\"\n (drop)=\"onEditorDrop($event)\"\n ></div>\n\n @if (findReplaceVisible()) {\n <div data-slot=\"rich-text-find-panel\"\n class=\"absolute top-2 end-2 z-50 bg-popover border rounded-lg shadow-lg p-3 w-80 max-w-[calc(100vw-2rem)] max-sm:w-[calc(100%-1rem)] max-sm:start-2 animate-in slide-in-from-top-2 fade-in-0\"\n tabindex=\"-1\"\n (keydown.escape)=\"closeFindReplace()\"\n (keydown)=\"onFindReplaceKeydown($event)\">\n <div class=\"flex flex-wrap items-center gap-1.5 mb-2\">\n <input\n #findInput\n data-slot=\"rich-text-find-query\"\n type=\"text\"\n [placeholder]=\"resolvedLocale().findReplace.findPlaceholder\"\n [attr.aria-label]=\"resolvedLocale().findReplace.find\"\n [attr.aria-invalid]=\"findRegexError() ? 'true' : null\"\n [value]=\"findQuery()\"\n (input)=\"onFindQueryChange($any($event.target).value)\"\n class=\"flex h-7 min-w-0 flex-1 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findCaseSensitive()\"\n [attr.aria-pressed]=\"findCaseSensitive()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.caseSensitive\"\n [title]=\"resolvedLocale().findReplace.caseSensitive\"\n (click)=\"toggleFindCaseSensitive()\">Aa</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findWholeWord()\"\n [attr.aria-pressed]=\"findWholeWord()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.wholeWord\"\n [title]=\"resolvedLocale().findReplace.wholeWord\"\n (click)=\"toggleFindWholeWord()\">ab</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findUseRegex()\"\n [attr.aria-pressed]=\"findUseRegex()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.useRegex\"\n [title]=\"resolvedLocale().findReplace.useRegex\"\n (click)=\"toggleFindUseRegex()\">.*</button>\n </div>\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\n <span data-slot=\"rich-text-find-counter\"\n aria-live=\"polite\"\n class=\"text-xs text-muted-foreground\">{{ findCounterText() }}</span>\n <div class=\"flex gap-1\">\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent disabled:opacity-50\"\n [attr.aria-label]=\"resolvedLocale().findReplace.previous\"\n [title]=\"resolvedLocale().findReplace.previous\"\n [disabled]=\"findMatchCount() === 0\"\n (click)=\"findPrevious()\">&#x25B2;</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent disabled:opacity-50\"\n [attr.aria-label]=\"resolvedLocale().findReplace.next\"\n [title]=\"resolvedLocale().findReplace.next\"\n [disabled]=\"findMatchCount() === 0\"\n (click)=\"findNext()\">&#x25BC;</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent\"\n [attr.aria-label]=\"resolvedLocale().findReplace.close\"\n [title]=\"resolvedLocale().findReplace.close\"\n (click)=\"closeFindReplace()\">&#x2715;</button>\n </div>\n </div>\n @if (showReplaceRow()) {\n <div class=\"flex flex-wrap items-center gap-1.5\">\n <input\n data-slot=\"rich-text-find-replace\"\n type=\"text\"\n [placeholder]=\"resolvedLocale().findReplace.replacePlaceholder\"\n [attr.aria-label]=\"resolvedLocale().findReplace.replace\"\n [value]=\"replaceText()\"\n (input)=\"replaceText.set($any($event.target).value)\"\n class=\"flex h-7 min-w-0 flex-1 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n <button type=\"button\" class=\"inline-flex min-h-7 items-center justify-center rounded-md px-2 py-1 text-xs hover:bg-accent whitespace-nowrap disabled:opacity-50\" [disabled]=\"findMatchCount() === 0\" (click)=\"replaceSingle()\">{{ resolvedLocale().findReplace.replace }}</button>\n <button type=\"button\" class=\"inline-flex min-h-7 items-center justify-center rounded-md px-2 py-1 text-xs hover:bg-accent whitespace-nowrap disabled:opacity-50\" [disabled]=\"findMatchCount() === 0\" (click)=\"replaceAll()\">{{ resolvedLocale().findReplace.replaceAll }}</button>\n </div>\n }\n </div>\n }\n\n @if (dragOver()) {\n <div class=\"absolute inset-0 pointer-events-none border-2 border-dashed border-primary/60 rounded-md bg-primary/5\"></div>\n }\n\n @if (toolbar() === 'floating' && !readonly() && showFloatingToolbar()) {\n <div \n class=\"fixed z-[9999] bg-popover border rounded-lg shadow-lg p-1\"\n [style.left.px]=\"floatingToolbarPosition().x\"\n [style.top.px]=\"floatingToolbarPosition().y\"\n >\n <ui-rich-text-toolbar\n [items]=\"['bold', 'italic', 'underline', 'separator', 'clear']\"\n [activeFormats]=\"emptyFormats\"\n [compact]=\"true\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [locale]=\"resolvedLocale()\"\n (formatCommand)=\"onFloatingFormatCommand($event)\"\n [addonSlots]=\"toolbarSlots.slots()\"\n (addonSlotClick)=\"onAddonSlotClick($event)\"\n />\n </div>\n }\n\n @if (tableContextMenuOpen()) {\n <div\n #tableContextMenuRef\n class=\"fixed z-50 min-w-[180px] max-w-[calc(100vw-2rem)] max-h-[calc(100vh-1rem)] overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95\"\n [style.left.px]=\"tableContextMenuPosition().x\"\n [style.top.px]=\"tableContextMenuPosition().y\"\n (mousedown)=\"$event.preventDefault()\"\n (contextmenu)=\"onContextMenuOverlayContextMenu($event)\"\n >\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableRowAbove()\">\n {{ resolvedLocale().table.addRowAbove }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableRowBelow()\">\n {{ resolvedLocale().table.addRowBelow }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableColumnLeft()\">\n {{ resolvedLocale().table.addColumnLeft }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableColumnRight()\">\n {{ resolvedLocale().table.addColumnRight }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"toggleTableHeaderRow()\">\n {{ resolvedLocale().table.toggleHeaderRow }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n @if (tableCellSelected().length >= 2) {\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"mergeCells()\">\n {{ resolvedLocale().table.mergeCells }}\n </button>\n }\n @if (canSplitCell()) {\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"splitCell()\">\n {{ resolvedLocale().table.splitCell }}\n </button>\n }\n @if (tableCellSelected().length >= 2 || canSplitCell()) {\n <div class=\"my-1 h-px bg-border\"></div>\n }\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.borders }}</div>\n <div class=\"flex items-center gap-1\">\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersAll\" (click)=\"setTableBorders('all')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersNone\" (click)=\"setTableBorders('none')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\" opacity=\"0.35\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" stroke-dasharray=\"2 2\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" stroke-dasharray=\"2 2\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersOuter\" (click)=\"setTableBorders('outer')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" stroke-width=\"1.5\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" stroke-width=\"1\" opacity=\"0.25\" stroke-dasharray=\"2 2\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-width=\"1\" opacity=\"0.25\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersHorizontal\" (click)=\"setTableBorders('horizontal')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\">\n <line x1=\"1\" y1=\"1\" x2=\"19\" y2=\"1\" stroke-width=\"1.5\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-width=\"1.5\" /><line x1=\"1\" y1=\"19\" x2=\"19\" y2=\"19\" stroke-width=\"1.5\" />\n </svg>\n </button>\n </div>\n </div>\n <div class=\"my-1 h-px bg-border\"></div>\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.cellAlignLeft }}</div>\n <div class=\"flex items-center gap-1\" dir=\"ltr\">\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignLeft\" (click)=\"setCellAlignment('left')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"15\" x2=\"3\" y1=\"12\" y2=\"12\"/><line x1=\"17\" x2=\"3\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignCenter\" (click)=\"setCellAlignment('center')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"17\" x2=\"7\" y1=\"12\" y2=\"12\"/><line x1=\"19\" x2=\"5\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignRight\" (click)=\"setCellAlignment('right')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\"/><line x1=\"21\" x2=\"7\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n </div>\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.cellColor }}</div>\n <div class=\"grid grid-cols-8 gap-0.5\">\n @for (color of tableCellColors; track color) {\n <button type=\"button\" class=\"w-4 h-4 rounded border border-border hover:scale-110 transition-transform\" [style.background-color]=\"color\" [attr.aria-label]=\"color\" (click)=\"setCellColor(color)\"></button>\n }\n </div>\n </div>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTableRow()\">\n {{ resolvedLocale().table.deleteRow }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTableColumn()\">\n {{ resolvedLocale().table.deleteColumn }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTable()\">\n {{ resolvedLocale().table.deleteTable }}\n </button>\n </div>\n }\n</div>\n\n@if (showCount() || showWordCount()) {\n <!--\n A polite status region, so a screen reader hears the count change, and the\n limit is shown once one is set: enforcement used to be entirely silent,\n so hitting maxLength read as a dead keyboard with the counter still showing\n a bare number and no indication a limit existed at all. The colour change\n at the limit gives sighted users the same signal.\n -->\n <output [attr.id]=\"counterId\" class=\"flex justify-end text-xs text-muted-foreground mt-1 px-1\" aria-live=\"polite\">\n @if (showCount()) {\n <!--\n The localized phrase keeps its own {count}, and the limit follows as a\n separate parenthetical. Interpolating \"0 / 120\" INTO the slot produced\n \"0 / 120 characters\", which is wrong in English and cannot be localized\n at all -- a locale ordering it differently had no way to express it,\n because the separator was hardcoded in the template expression.\n -->\n <span [class.text-destructive]=\"atCharacterLimit()\" [class.font-medium]=\"atCharacterLimit()\">\n {{ interpolateLocale(resolvedLocale().editor.characters, { count: characterCount() }) }}@if (maxLength()) {<span class=\"ms-1\">({{ maxLength() }} max)</span>}\n </span>\n }\n @if (showWordCount()) {\n <span [class.ms-3]=\"showCount()\">{{ interpolateLocale(resolvedLocale().editor.words, { count: wordCount() }) }}</span>\n }\n </output>\n}\n", styles: ["@media print{:host{display:block;overflow:visible}:host [data-slot=rich-text-editor]{max-height:none!important;height:auto!important;overflow:visible!important;border:none}:host [role=toolbar],:host [data-slot=rich-text-floating-toolbar],:host [data-slot=rich-text-find-overlay],:host [data-slot=rich-text-outline-panel],:host [data-slot=rich-text-history-badge]{display:none!important}:host tr,:host img{break-inside:avoid}:host h1,:host h2,:host h3{break-after:avoid}}:host img[data-blocked-src]{display:inline-flex;align-items:center;justify-content:center;min-width:8rem;min-height:4.5rem;padding:calc(.75rem * var(--_d));border:1px dashed var(--border);border-radius:var(--radius);background-color:color-mix(in oklab,var(--muted) 60%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);color:var(--muted-foreground);font-size:.75rem;line-height:1.4;text-align:center;font-style:italic}:host img[data-blocked-src]:after{content:attr(data-blocked-label)}\n"], dependencies: [{ kind: "component", type: RichTextToolbarComponent, selector: "ui-rich-text-toolbar", inputs: ["items", "activeFormats", "compact", "class", "disabled", "readonly", "textStyleAvailable", "locale", "addonSlots"], outputs: ["formatCommand", "addonSlotClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
18687
+ ], viewQueries: [{ propertyName: "editorDiv", first: true, predicate: ["editorDiv"], descendants: true }, { propertyName: "editorContainer", first: true, predicate: ["editorContainer"], descendants: true }, { propertyName: "tableContextMenuRef", first: true, predicate: ["tableContextMenuRef"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (toolbar() === 'top' && !readonly()) {\n <ui-rich-text-toolbar\n [items]=\"toolbarItems()\"\n [activeFormats]=\"activeFormats()\"\n [textStyleAvailable]=\"textStyleAvailable()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [locale]=\"resolvedLocale()\"\n (formatCommand)=\"onFormatCommand($event)\"\n [addonSlots]=\"toolbarSlots.slots()\"\n (addonSlotClick)=\"onAddonSlotClick($event)\"\n />\n}\n\n<div #editorContainer [class]=\"editorContainerClasses()\" [dir]=\"resolvedDir()\">\n <!--\n Three of the attributes below exist for assistive tech specifically:\n\n The tab index drops to -1 when disabled. A native disabled control leaves the\n tab order entirely; a static 0 left a keyboard user stopping on an editor\n that takes focus and then does nothing.\n\n The readonly state is announced explicitly, because contenteditable false is\n a browser editing hint rather than a state screen readers reliably report on\n a textbox \u2014 without it a reader discovers the field is read-only by typing\n and seeing nothing happen.\n\n The placeholder is announced explicitly too, because the visible one is CSS\n generated content. Chromium exposes that as a plain text child, so a reader\n announces the hint as though it were the document's own text.\n -->\n <div\n #editorDiv\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n [attr.contenteditable]=\"!isDisabled() && !readonly()\"\n [attr.aria-disabled]=\"isDisabled()\"\n [attr.aria-readonly]=\"readonly() ? 'true' : null\"\n [class]=\"editableClasses()\"\n [attr.placeholder]=\"placeholder() || resolvedLocale().editor.placeholder\"\n [attr.aria-placeholder]=\"placeholder() || resolvedLocale().editor.placeholder\"\n [attr.aria-label]=\"ariaLabel() || resolvedLocale().editor.ariaLabel\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.data-slot]=\"'rich-text-editor'\"\n [style.min-height]=\"minHeight()\"\n [style.max-height]=\"maxHeight()\"\n role=\"textbox\"\n aria-multiline=\"true\"\n [attr.aria-expanded]=\"activeSuggestionPopup() ? 'true' : null\"\n [attr.aria-controls]=\"activeSuggestionPopup()?.controlsId ?? null\"\n [attr.aria-activedescendant]=\"activeSuggestionPopup()?.activeOptionId ?? null\"\n (input)=\"onInput($event)\"\n (beforeinput)=\"onBeforeInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (paste)=\"onPaste($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur($event)\"\n (mouseup)=\"onSelectionChange()\"\n (keyup)=\"onSelectionChange()\"\n (click)=\"onEditorClick($event)\"\n (mousemove)=\"onEditorMouseMove($event)\"\n (mousedown)=\"onEditorMouseDown($event)\"\n (touchstart)=\"onEditorTouchStart($event)\"\n (contextmenu)=\"onEditorContextMenu($event)\"\n (dragover)=\"onEditorDragOver($event)\"\n (dragleave)=\"onEditorDragLeave($event)\"\n (drop)=\"onEditorDrop($event)\"\n ></div>\n\n @if (findReplaceVisible()) {\n <div data-slot=\"rich-text-find-panel\"\n class=\"absolute top-2 end-2 z-50 bg-popover border rounded-lg shadow-lg p-3 w-80 max-w-[calc(100vw-2rem)] max-sm:w-[calc(100%-1rem)] max-sm:start-2 animate-in slide-in-from-top-2 fade-in-0\"\n tabindex=\"-1\"\n (keydown.escape)=\"closeFindReplace()\"\n (keydown)=\"onFindReplaceKeydown($event)\">\n <div class=\"flex flex-wrap items-center gap-1.5 mb-2\">\n <input\n #findInput\n data-slot=\"rich-text-find-query\"\n type=\"text\"\n [placeholder]=\"resolvedLocale().findReplace.findPlaceholder\"\n [attr.aria-label]=\"resolvedLocale().findReplace.find\"\n [attr.aria-invalid]=\"findRegexError() ? 'true' : null\"\n [value]=\"findQuery()\"\n (input)=\"onFindQueryChange($any($event.target).value)\"\n class=\"flex h-7 min-w-0 flex-1 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findCaseSensitive()\"\n [attr.aria-pressed]=\"findCaseSensitive()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.caseSensitive\"\n [title]=\"resolvedLocale().findReplace.caseSensitive\"\n (click)=\"toggleFindCaseSensitive()\">Aa</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findWholeWord()\"\n [attr.aria-pressed]=\"findWholeWord()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.wholeWord\"\n [title]=\"resolvedLocale().findReplace.wholeWord\"\n (click)=\"toggleFindWholeWord()\">ab</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findUseRegex()\"\n [attr.aria-pressed]=\"findUseRegex()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.useRegex\"\n [title]=\"resolvedLocale().findReplace.useRegex\"\n (click)=\"toggleFindUseRegex()\">.*</button>\n </div>\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\n <span data-slot=\"rich-text-find-counter\"\n aria-live=\"polite\"\n class=\"text-xs text-muted-foreground\">{{ findCounterText() }}</span>\n <div class=\"flex gap-1\">\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent disabled:opacity-50\"\n [attr.aria-label]=\"resolvedLocale().findReplace.previous\"\n [title]=\"resolvedLocale().findReplace.previous\"\n [disabled]=\"findMatchCount() === 0\"\n (click)=\"findPrevious()\">&#x25B2;</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent disabled:opacity-50\"\n [attr.aria-label]=\"resolvedLocale().findReplace.next\"\n [title]=\"resolvedLocale().findReplace.next\"\n [disabled]=\"findMatchCount() === 0\"\n (click)=\"findNext()\">&#x25BC;</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent\"\n [attr.aria-label]=\"resolvedLocale().findReplace.close\"\n [title]=\"resolvedLocale().findReplace.close\"\n (click)=\"closeFindReplace()\">&#x2715;</button>\n </div>\n </div>\n @if (showReplaceRow()) {\n <div class=\"flex flex-wrap items-center gap-1.5\">\n <input\n data-slot=\"rich-text-find-replace\"\n type=\"text\"\n [placeholder]=\"resolvedLocale().findReplace.replacePlaceholder\"\n [attr.aria-label]=\"resolvedLocale().findReplace.replace\"\n [value]=\"replaceText()\"\n (input)=\"replaceText.set($any($event.target).value)\"\n class=\"flex h-7 min-w-0 flex-1 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n <button type=\"button\" class=\"inline-flex min-h-7 items-center justify-center rounded-md px-2 py-1 text-xs hover:bg-accent whitespace-nowrap disabled:opacity-50\" [disabled]=\"findMatchCount() === 0\" (click)=\"replaceSingle()\">{{ resolvedLocale().findReplace.replace }}</button>\n <button type=\"button\" class=\"inline-flex min-h-7 items-center justify-center rounded-md px-2 py-1 text-xs hover:bg-accent whitespace-nowrap disabled:opacity-50\" [disabled]=\"findMatchCount() === 0\" (click)=\"replaceAll()\">{{ resolvedLocale().findReplace.replaceAll }}</button>\n </div>\n }\n </div>\n }\n\n @if (dragOver()) {\n <div class=\"absolute inset-0 pointer-events-none border-2 border-dashed border-primary/60 rounded-md bg-primary/5\"></div>\n }\n\n @if (toolbar() === 'floating' && !readonly() && showFloatingToolbar()) {\n <div \n class=\"fixed z-[9999] bg-popover border rounded-lg shadow-lg p-1\"\n [style.left.px]=\"floatingToolbarPosition().x\"\n [style.top.px]=\"floatingToolbarPosition().y\"\n >\n <ui-rich-text-toolbar\n [items]=\"['bold', 'italic', 'underline', 'separator', 'clear']\"\n [activeFormats]=\"emptyFormats\"\n [compact]=\"true\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [locale]=\"resolvedLocale()\"\n (formatCommand)=\"onFloatingFormatCommand($event)\"\n [addonSlots]=\"toolbarSlots.slots()\"\n (addonSlotClick)=\"onAddonSlotClick($event)\"\n />\n </div>\n }\n\n @if (tableContextMenuOpen()) {\n <div\n #tableContextMenuRef\n class=\"fixed z-50 min-w-[180px] max-w-[calc(100vw-2rem)] max-h-[calc(100vh-1rem)] overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95\"\n [style.left.px]=\"tableContextMenuPosition().x\"\n [style.top.px]=\"tableContextMenuPosition().y\"\n (mousedown)=\"$event.preventDefault()\"\n (contextmenu)=\"onContextMenuOverlayContextMenu($event)\"\n >\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableRowAbove()\">\n {{ resolvedLocale().table.addRowAbove }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableRowBelow()\">\n {{ resolvedLocale().table.addRowBelow }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableColumnLeft()\">\n {{ resolvedLocale().table.addColumnLeft }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableColumnRight()\">\n {{ resolvedLocale().table.addColumnRight }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"toggleTableHeaderRow()\">\n {{ resolvedLocale().table.toggleHeaderRow }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n @if (tableCellSelected().length >= 2) {\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"mergeCells()\">\n {{ resolvedLocale().table.mergeCells }}\n </button>\n }\n @if (canSplitCell()) {\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"splitCell()\">\n {{ resolvedLocale().table.splitCell }}\n </button>\n }\n @if (tableCellSelected().length >= 2 || canSplitCell()) {\n <div class=\"my-1 h-px bg-border\"></div>\n }\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.borders }}</div>\n <div class=\"flex items-center gap-1\">\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersAll\" (click)=\"setTableBorders('all')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersNone\" (click)=\"setTableBorders('none')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\" opacity=\"0.35\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" stroke-dasharray=\"2 2\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" stroke-dasharray=\"2 2\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersOuter\" (click)=\"setTableBorders('outer')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" stroke-width=\"1.5\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" stroke-width=\"1\" opacity=\"0.25\" stroke-dasharray=\"2 2\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-width=\"1\" opacity=\"0.25\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersHorizontal\" (click)=\"setTableBorders('horizontal')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\">\n <line x1=\"1\" y1=\"1\" x2=\"19\" y2=\"1\" stroke-width=\"1.5\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-width=\"1.5\" /><line x1=\"1\" y1=\"19\" x2=\"19\" y2=\"19\" stroke-width=\"1.5\" />\n </svg>\n </button>\n </div>\n </div>\n <div class=\"my-1 h-px bg-border\"></div>\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.cellAlignLeft }}</div>\n <div class=\"flex items-center gap-1\" dir=\"ltr\">\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignLeft\" (click)=\"setCellAlignment('left')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"15\" x2=\"3\" y1=\"12\" y2=\"12\"/><line x1=\"17\" x2=\"3\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignCenter\" (click)=\"setCellAlignment('center')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"17\" x2=\"7\" y1=\"12\" y2=\"12\"/><line x1=\"19\" x2=\"5\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignRight\" (click)=\"setCellAlignment('right')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\"/><line x1=\"21\" x2=\"7\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n </div>\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.cellColor }}</div>\n <div class=\"grid grid-cols-8 gap-0.5\">\n @for (color of tableCellColors; track color) {\n <button type=\"button\" class=\"w-4 h-4 rounded border border-border hover:scale-110 transition-transform\" [style.background-color]=\"color\" [attr.aria-label]=\"color\" (click)=\"setCellColor(color)\"></button>\n }\n </div>\n </div>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTableRow()\">\n {{ resolvedLocale().table.deleteRow }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTableColumn()\">\n {{ resolvedLocale().table.deleteColumn }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTable()\">\n {{ resolvedLocale().table.deleteTable }}\n </button>\n </div>\n }\n</div>\n\n@if (showCount() || showWordCount()) {\n <!--\n A polite status region, so a screen reader hears the count change, and the\n limit is shown once one is set: enforcement used to be entirely silent,\n so hitting maxLength read as a dead keyboard with the counter still showing\n a bare number and no indication a limit existed at all. The colour change\n at the limit gives sighted users the same signal.\n -->\n <output [attr.id]=\"counterId\" class=\"flex justify-end text-xs text-muted-foreground mt-1 px-1\" aria-live=\"polite\">\n @if (showCount()) {\n <!--\n The localized phrase keeps its own {count}, and the limit follows as a\n separate parenthetical. Interpolating \"0 / 120\" INTO the slot produced\n \"0 / 120 characters\", which is wrong in English and cannot be localized\n at all -- a locale ordering it differently had no way to express it,\n because the separator was hardcoded in the template expression.\n -->\n <span [class.text-destructive]=\"atCharacterLimit()\" [class.font-medium]=\"atCharacterLimit()\">\n {{ interpolateLocale(resolvedLocale().editor.characters, { count: characterCount() }) }}@if (maxLength()) {<span class=\"ms-1\">({{ maxLength() }} max)</span>}\n </span>\n }\n @if (showWordCount()) {\n <span [class.ms-3]=\"showCount()\">{{ interpolateLocale(resolvedLocale().editor.words, { count: wordCount() }) }}</span>\n }\n </output>\n}\n", styles: ["@media print{:host{display:block;overflow:visible}:host [data-slot=rich-text-editor]{max-height:none!important;height:auto!important;overflow:visible!important;border:none}:host [role=toolbar],:host [data-slot=rich-text-floating-toolbar],:host [data-slot=rich-text-find-overlay],:host [data-slot=rich-text-outline-panel],:host [data-slot=rich-text-history-badge]{display:none!important}:host tr,:host img{break-inside:avoid}:host h1,:host h2,:host h3{break-after:avoid}}:host img[data-blocked-src]{display:inline-flex;align-items:center;justify-content:center;min-width:8rem;min-height:4.5rem;padding:calc(.75rem * var(--_d));border:1px dashed var(--border);border-radius:var(--radius);background-color:color-mix(in oklab,var(--muted) 60%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);color:var(--muted-foreground);font-size:.75rem;line-height:1.4;text-align:center;font-style:italic}:host img[data-blocked-src]:after{content:attr(data-blocked-label)}:host([data-ui-theme=\"neutral\"]){--primary: oklch(.205 0 0);--primary-foreground: oklch(.985 0 0);--ring: oklch(.708 0 0)}:host-context(.dark)[data-ui-theme=neutral]{--primary: oklch(.985 0 0);--primary-foreground: oklch(.205 0 0);--ring: oklch(.708 0 0)}:host([data-ui-theme=\"zinc\"]){--primary: oklch(.205 0 0);--primary-foreground: oklch(.985 0 0);--ring: oklch(.708 0 0)}:host-context(.dark)[data-ui-theme=zinc]{--primary: oklch(.985 0 0);--primary-foreground: oklch(.205 0 0);--ring: oklch(.708 0 0)}:host([data-ui-theme=\"slate\"]){--primary: oklch(.208 .042 265.755);--primary-foreground: oklch(.984 .003 247.858);--ring: oklch(.704 .04 256.788)}:host-context(.dark)[data-ui-theme=slate]{--primary: oklch(.929 .013 255.508);--primary-foreground: oklch(.208 .042 265.755);--ring: oklch(.704 .04 256.788)}:host([data-ui-theme=\"stone\"]){--primary: oklch(.216 .006 56.043);--primary-foreground: oklch(.985 .001 106.423);--ring: oklch(.709 .01 56.259)}:host-context(.dark)[data-ui-theme=stone]{--primary: oklch(.923 .003 48.717);--primary-foreground: oklch(.216 .006 56.043);--ring: oklch(.553 .013 58.071)}:host([data-ui-theme=\"gray\"]){--primary: oklch(.21 .028 264.532);--primary-foreground: oklch(.985 .002 247.839);--ring: oklch(.707 .022 264.436)}:host-context(.dark)[data-ui-theme=gray]{--primary: oklch(.928 .006 264.531);--primary-foreground: oklch(.21 .028 264.532);--ring: oklch(.551 .027 264.364)}:host([data-ui-theme=\"red\"]){--primary: oklch(.577 .245 27.325);--primary-foreground: oklch(.985 0 0);--ring: oklch(.577 .245 27.325)}:host-context(.dark)[data-ui-theme=red]{--primary: oklch(.577 .245 27.325);--primary-foreground: oklch(.985 0 0);--ring: oklch(.577 .245 27.325)}:host([data-ui-theme=\"rose\"]){--primary: oklch(.645 .246 16.439);--primary-foreground: oklch(.985 0 0);--ring: oklch(.645 .246 16.439)}:host-context(.dark)[data-ui-theme=rose]{--primary: oklch(.645 .246 16.439);--primary-foreground: oklch(.985 0 0);--ring: oklch(.645 .246 16.439)}:host([data-ui-theme=\"orange\"]){--primary: oklch(.646 .222 41.116);--primary-foreground: oklch(.985 0 0);--ring: oklch(.646 .222 41.116)}:host-context(.dark)[data-ui-theme=orange]{--primary: oklch(.646 .222 41.116);--primary-foreground: oklch(.985 0 0);--ring: oklch(.646 .222 41.116)}:host([data-ui-theme=\"green\"]){--primary: oklch(.623 .214 131.655);--primary-foreground: oklch(.985 0 0);--ring: oklch(.623 .214 131.655)}:host-context(.dark)[data-ui-theme=green]{--primary: oklch(.623 .214 131.655);--primary-foreground: oklch(.985 0 0);--ring: oklch(.623 .214 131.655)}:host([data-ui-theme=\"blue\"]){--primary: oklch(.546 .245 262.881);--primary-foreground: oklch(.985 0 0);--ring: oklch(.546 .245 262.881)}:host-context(.dark)[data-ui-theme=blue]{--primary: oklch(.546 .245 262.881);--primary-foreground: oklch(.985 0 0);--ring: oklch(.546 .245 262.881)}:host([data-ui-theme=\"yellow\"]){--primary: oklch(.82 .185 84.67);--primary-foreground: oklch(.205 0 0);--ring: oklch(.82 .185 84.67)}:host-context(.dark)[data-ui-theme=yellow]{--primary: oklch(.82 .185 84.67);--primary-foreground: oklch(.205 0 0);--ring: oklch(.82 .185 84.67)}:host([data-ui-theme=\"violet\"]){--primary: oklch(.558 .288 302.321);--primary-foreground: oklch(.985 0 0);--ring: oklch(.558 .288 302.321)}:host-context(.dark)[data-ui-theme=violet]{--primary: oklch(.558 .288 302.321);--primary-foreground: oklch(.985 0 0);--ring: oklch(.558 .288 302.321)}:host([data-ui-theme=\"amber\"]){--primary: oklch(.77 .16 70);--primary-foreground: oklch(.145 0 0);--ring: oklch(.77 .16 70)}:host-context(.dark)[data-ui-theme=amber]{--primary: oklch(.77 .16 70);--primary-foreground: oklch(.145 0 0);--ring: oklch(.77 .16 70)}\n"], dependencies: [{ kind: "component", type: RichTextToolbarComponent, selector: "ui-rich-text-toolbar", inputs: ["items", "activeFormats", "compact", "class", "disabled", "readonly", "textStyleAvailable", "locale", "addonSlots"], outputs: ["formatCommand", "addonSlotClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
18683
18688
  }
18684
18689
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: RichTextEditorComponent, decorators: [{
18685
18690
  type: Component,
@@ -18709,7 +18714,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
18709
18714
  provideComponentLocale(() => RichTextEditorComponent),
18710
18715
  ], host: {
18711
18716
  class: 'block',
18712
- }, template: "@if (toolbar() === 'top' && !readonly()) {\n <ui-rich-text-toolbar\n [items]=\"toolbarItems()\"\n [activeFormats]=\"activeFormats()\"\n [textStyleAvailable]=\"textStyleAvailable()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [locale]=\"resolvedLocale()\"\n (formatCommand)=\"onFormatCommand($event)\"\n [addonSlots]=\"toolbarSlots.slots()\"\n (addonSlotClick)=\"onAddonSlotClick($event)\"\n />\n}\n\n<div #editorContainer [class]=\"editorContainerClasses()\" [dir]=\"resolvedDir()\">\n <!--\n Three of the attributes below exist for assistive tech specifically:\n\n The tab index drops to -1 when disabled. A native disabled control leaves the\n tab order entirely; a static 0 left a keyboard user stopping on an editor\n that takes focus and then does nothing.\n\n The readonly state is announced explicitly, because contenteditable false is\n a browser editing hint rather than a state screen readers reliably report on\n a textbox \u2014 without it a reader discovers the field is read-only by typing\n and seeing nothing happen.\n\n The placeholder is announced explicitly too, because the visible one is CSS\n generated content. Chromium exposes that as a plain text child, so a reader\n announces the hint as though it were the document's own text.\n -->\n <div\n #editorDiv\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n [attr.contenteditable]=\"!isDisabled() && !readonly()\"\n [attr.aria-disabled]=\"isDisabled()\"\n [attr.aria-readonly]=\"readonly() ? 'true' : null\"\n [class]=\"editableClasses()\"\n [attr.placeholder]=\"placeholder() || resolvedLocale().editor.placeholder\"\n [attr.aria-placeholder]=\"placeholder() || resolvedLocale().editor.placeholder\"\n [attr.aria-label]=\"ariaLabel() || resolvedLocale().editor.ariaLabel\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.data-slot]=\"'rich-text-editor'\"\n [style.min-height]=\"minHeight()\"\n [style.max-height]=\"maxHeight()\"\n role=\"textbox\"\n aria-multiline=\"true\"\n [attr.aria-expanded]=\"activeSuggestionPopup() ? 'true' : null\"\n [attr.aria-controls]=\"activeSuggestionPopup()?.controlsId ?? null\"\n [attr.aria-activedescendant]=\"activeSuggestionPopup()?.activeOptionId ?? null\"\n (input)=\"onInput($event)\"\n (beforeinput)=\"onBeforeInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (paste)=\"onPaste($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur($event)\"\n (mouseup)=\"onSelectionChange()\"\n (keyup)=\"onSelectionChange()\"\n (click)=\"onEditorClick($event)\"\n (mousemove)=\"onEditorMouseMove($event)\"\n (mousedown)=\"onEditorMouseDown($event)\"\n (touchstart)=\"onEditorTouchStart($event)\"\n (contextmenu)=\"onEditorContextMenu($event)\"\n (dragover)=\"onEditorDragOver($event)\"\n (dragleave)=\"onEditorDragLeave($event)\"\n (drop)=\"onEditorDrop($event)\"\n ></div>\n\n @if (findReplaceVisible()) {\n <div data-slot=\"rich-text-find-panel\"\n class=\"absolute top-2 end-2 z-50 bg-popover border rounded-lg shadow-lg p-3 w-80 max-w-[calc(100vw-2rem)] max-sm:w-[calc(100%-1rem)] max-sm:start-2 animate-in slide-in-from-top-2 fade-in-0\"\n tabindex=\"-1\"\n (keydown.escape)=\"closeFindReplace()\"\n (keydown)=\"onFindReplaceKeydown($event)\">\n <div class=\"flex flex-wrap items-center gap-1.5 mb-2\">\n <input\n #findInput\n data-slot=\"rich-text-find-query\"\n type=\"text\"\n [placeholder]=\"resolvedLocale().findReplace.findPlaceholder\"\n [attr.aria-label]=\"resolvedLocale().findReplace.find\"\n [attr.aria-invalid]=\"findRegexError() ? 'true' : null\"\n [value]=\"findQuery()\"\n (input)=\"onFindQueryChange($any($event.target).value)\"\n class=\"flex h-7 min-w-0 flex-1 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findCaseSensitive()\"\n [attr.aria-pressed]=\"findCaseSensitive()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.caseSensitive\"\n [title]=\"resolvedLocale().findReplace.caseSensitive\"\n (click)=\"toggleFindCaseSensitive()\">Aa</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findWholeWord()\"\n [attr.aria-pressed]=\"findWholeWord()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.wholeWord\"\n [title]=\"resolvedLocale().findReplace.wholeWord\"\n (click)=\"toggleFindWholeWord()\">ab</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findUseRegex()\"\n [attr.aria-pressed]=\"findUseRegex()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.useRegex\"\n [title]=\"resolvedLocale().findReplace.useRegex\"\n (click)=\"toggleFindUseRegex()\">.*</button>\n </div>\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\n <span data-slot=\"rich-text-find-counter\"\n aria-live=\"polite\"\n class=\"text-xs text-muted-foreground\">{{ findCounterText() }}</span>\n <div class=\"flex gap-1\">\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent disabled:opacity-50\"\n [attr.aria-label]=\"resolvedLocale().findReplace.previous\"\n [title]=\"resolvedLocale().findReplace.previous\"\n [disabled]=\"findMatchCount() === 0\"\n (click)=\"findPrevious()\">&#x25B2;</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent disabled:opacity-50\"\n [attr.aria-label]=\"resolvedLocale().findReplace.next\"\n [title]=\"resolvedLocale().findReplace.next\"\n [disabled]=\"findMatchCount() === 0\"\n (click)=\"findNext()\">&#x25BC;</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent\"\n [attr.aria-label]=\"resolvedLocale().findReplace.close\"\n [title]=\"resolvedLocale().findReplace.close\"\n (click)=\"closeFindReplace()\">&#x2715;</button>\n </div>\n </div>\n @if (showReplaceRow()) {\n <div class=\"flex flex-wrap items-center gap-1.5\">\n <input\n data-slot=\"rich-text-find-replace\"\n type=\"text\"\n [placeholder]=\"resolvedLocale().findReplace.replacePlaceholder\"\n [attr.aria-label]=\"resolvedLocale().findReplace.replace\"\n [value]=\"replaceText()\"\n (input)=\"replaceText.set($any($event.target).value)\"\n class=\"flex h-7 min-w-0 flex-1 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n <button type=\"button\" class=\"inline-flex min-h-7 items-center justify-center rounded-md px-2 py-1 text-xs hover:bg-accent whitespace-nowrap disabled:opacity-50\" [disabled]=\"findMatchCount() === 0\" (click)=\"replaceSingle()\">{{ resolvedLocale().findReplace.replace }}</button>\n <button type=\"button\" class=\"inline-flex min-h-7 items-center justify-center rounded-md px-2 py-1 text-xs hover:bg-accent whitespace-nowrap disabled:opacity-50\" [disabled]=\"findMatchCount() === 0\" (click)=\"replaceAll()\">{{ resolvedLocale().findReplace.replaceAll }}</button>\n </div>\n }\n </div>\n }\n\n @if (dragOver()) {\n <div class=\"absolute inset-0 pointer-events-none border-2 border-dashed border-primary/60 rounded-md bg-primary/5\"></div>\n }\n\n @if (toolbar() === 'floating' && !readonly() && showFloatingToolbar()) {\n <div \n class=\"fixed z-[9999] bg-popover border rounded-lg shadow-lg p-1\"\n [style.left.px]=\"floatingToolbarPosition().x\"\n [style.top.px]=\"floatingToolbarPosition().y\"\n >\n <ui-rich-text-toolbar\n [items]=\"['bold', 'italic', 'underline', 'separator', 'clear']\"\n [activeFormats]=\"emptyFormats\"\n [compact]=\"true\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [locale]=\"resolvedLocale()\"\n (formatCommand)=\"onFloatingFormatCommand($event)\"\n [addonSlots]=\"toolbarSlots.slots()\"\n (addonSlotClick)=\"onAddonSlotClick($event)\"\n />\n </div>\n }\n\n @if (tableContextMenuOpen()) {\n <div\n #tableContextMenuRef\n class=\"fixed z-50 min-w-[180px] max-w-[calc(100vw-2rem)] max-h-[calc(100vh-1rem)] overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95\"\n [style.left.px]=\"tableContextMenuPosition().x\"\n [style.top.px]=\"tableContextMenuPosition().y\"\n (mousedown)=\"$event.preventDefault()\"\n (contextmenu)=\"onContextMenuOverlayContextMenu($event)\"\n >\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableRowAbove()\">\n {{ resolvedLocale().table.addRowAbove }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableRowBelow()\">\n {{ resolvedLocale().table.addRowBelow }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableColumnLeft()\">\n {{ resolvedLocale().table.addColumnLeft }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableColumnRight()\">\n {{ resolvedLocale().table.addColumnRight }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"toggleTableHeaderRow()\">\n {{ resolvedLocale().table.toggleHeaderRow }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n @if (tableCellSelected().length >= 2) {\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"mergeCells()\">\n {{ resolvedLocale().table.mergeCells }}\n </button>\n }\n @if (canSplitCell()) {\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"splitCell()\">\n {{ resolvedLocale().table.splitCell }}\n </button>\n }\n @if (tableCellSelected().length >= 2 || canSplitCell()) {\n <div class=\"my-1 h-px bg-border\"></div>\n }\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.borders }}</div>\n <div class=\"flex items-center gap-1\">\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersAll\" (click)=\"setTableBorders('all')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersNone\" (click)=\"setTableBorders('none')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\" opacity=\"0.35\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" stroke-dasharray=\"2 2\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" stroke-dasharray=\"2 2\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersOuter\" (click)=\"setTableBorders('outer')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" stroke-width=\"1.5\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" stroke-width=\"1\" opacity=\"0.25\" stroke-dasharray=\"2 2\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-width=\"1\" opacity=\"0.25\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersHorizontal\" (click)=\"setTableBorders('horizontal')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\">\n <line x1=\"1\" y1=\"1\" x2=\"19\" y2=\"1\" stroke-width=\"1.5\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-width=\"1.5\" /><line x1=\"1\" y1=\"19\" x2=\"19\" y2=\"19\" stroke-width=\"1.5\" />\n </svg>\n </button>\n </div>\n </div>\n <div class=\"my-1 h-px bg-border\"></div>\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.cellAlignLeft }}</div>\n <div class=\"flex items-center gap-1\" dir=\"ltr\">\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignLeft\" (click)=\"setCellAlignment('left')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"15\" x2=\"3\" y1=\"12\" y2=\"12\"/><line x1=\"17\" x2=\"3\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignCenter\" (click)=\"setCellAlignment('center')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"17\" x2=\"7\" y1=\"12\" y2=\"12\"/><line x1=\"19\" x2=\"5\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignRight\" (click)=\"setCellAlignment('right')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\"/><line x1=\"21\" x2=\"7\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n </div>\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.cellColor }}</div>\n <div class=\"grid grid-cols-8 gap-0.5\">\n @for (color of tableCellColors; track color) {\n <button type=\"button\" class=\"w-4 h-4 rounded border border-border hover:scale-110 transition-transform\" [style.background-color]=\"color\" [attr.aria-label]=\"color\" (click)=\"setCellColor(color)\"></button>\n }\n </div>\n </div>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTableRow()\">\n {{ resolvedLocale().table.deleteRow }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTableColumn()\">\n {{ resolvedLocale().table.deleteColumn }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTable()\">\n {{ resolvedLocale().table.deleteTable }}\n </button>\n </div>\n }\n</div>\n\n@if (showCount() || showWordCount()) {\n <!--\n A polite status region, so a screen reader hears the count change, and the\n limit is shown once one is set: enforcement used to be entirely silent,\n so hitting maxLength read as a dead keyboard with the counter still showing\n a bare number and no indication a limit existed at all. The colour change\n at the limit gives sighted users the same signal.\n -->\n <output [attr.id]=\"counterId\" class=\"flex justify-end text-xs text-muted-foreground mt-1 px-1\" aria-live=\"polite\">\n @if (showCount()) {\n <!--\n The localized phrase keeps its own {count}, and the limit follows as a\n separate parenthetical. Interpolating \"0 / 120\" INTO the slot produced\n \"0 / 120 characters\", which is wrong in English and cannot be localized\n at all -- a locale ordering it differently had no way to express it,\n because the separator was hardcoded in the template expression.\n -->\n <span [class.text-destructive]=\"atCharacterLimit()\" [class.font-medium]=\"atCharacterLimit()\">\n {{ interpolateLocale(resolvedLocale().editor.characters, { count: characterCount() }) }}@if (maxLength()) {<span class=\"ms-1\">({{ maxLength() }} max)</span>}\n </span>\n }\n @if (showWordCount()) {\n <span [class.ms-3]=\"showCount()\">{{ interpolateLocale(resolvedLocale().editor.words, { count: wordCount() }) }}</span>\n }\n </output>\n}\n", styles: ["@media print{:host{display:block;overflow:visible}:host [data-slot=rich-text-editor]{max-height:none!important;height:auto!important;overflow:visible!important;border:none}:host [role=toolbar],:host [data-slot=rich-text-floating-toolbar],:host [data-slot=rich-text-find-overlay],:host [data-slot=rich-text-outline-panel],:host [data-slot=rich-text-history-badge]{display:none!important}:host tr,:host img{break-inside:avoid}:host h1,:host h2,:host h3{break-after:avoid}}:host img[data-blocked-src]{display:inline-flex;align-items:center;justify-content:center;min-width:8rem;min-height:4.5rem;padding:calc(.75rem * var(--_d));border:1px dashed var(--border);border-radius:var(--radius);background-color:color-mix(in oklab,var(--muted) 60%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);color:var(--muted-foreground);font-size:.75rem;line-height:1.4;text-align:center;font-style:italic}:host img[data-blocked-src]:after{content:attr(data-blocked-label)}\n"] }]
18717
+ '[attr.data-ui-theme]': 'theme()',
18718
+ }, template: "@if (toolbar() === 'top' && !readonly()) {\n <ui-rich-text-toolbar\n [items]=\"toolbarItems()\"\n [activeFormats]=\"activeFormats()\"\n [textStyleAvailable]=\"textStyleAvailable()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [locale]=\"resolvedLocale()\"\n (formatCommand)=\"onFormatCommand($event)\"\n [addonSlots]=\"toolbarSlots.slots()\"\n (addonSlotClick)=\"onAddonSlotClick($event)\"\n />\n}\n\n<div #editorContainer [class]=\"editorContainerClasses()\" [dir]=\"resolvedDir()\">\n <!--\n Three of the attributes below exist for assistive tech specifically:\n\n The tab index drops to -1 when disabled. A native disabled control leaves the\n tab order entirely; a static 0 left a keyboard user stopping on an editor\n that takes focus and then does nothing.\n\n The readonly state is announced explicitly, because contenteditable false is\n a browser editing hint rather than a state screen readers reliably report on\n a textbox \u2014 without it a reader discovers the field is read-only by typing\n and seeing nothing happen.\n\n The placeholder is announced explicitly too, because the visible one is CSS\n generated content. Chromium exposes that as a plain text child, so a reader\n announces the hint as though it were the document's own text.\n -->\n <div\n #editorDiv\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n [attr.contenteditable]=\"!isDisabled() && !readonly()\"\n [attr.aria-disabled]=\"isDisabled()\"\n [attr.aria-readonly]=\"readonly() ? 'true' : null\"\n [class]=\"editableClasses()\"\n [attr.placeholder]=\"placeholder() || resolvedLocale().editor.placeholder\"\n [attr.aria-placeholder]=\"placeholder() || resolvedLocale().editor.placeholder\"\n [attr.aria-label]=\"ariaLabel() || resolvedLocale().editor.ariaLabel\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.data-slot]=\"'rich-text-editor'\"\n [style.min-height]=\"minHeight()\"\n [style.max-height]=\"maxHeight()\"\n role=\"textbox\"\n aria-multiline=\"true\"\n [attr.aria-expanded]=\"activeSuggestionPopup() ? 'true' : null\"\n [attr.aria-controls]=\"activeSuggestionPopup()?.controlsId ?? null\"\n [attr.aria-activedescendant]=\"activeSuggestionPopup()?.activeOptionId ?? null\"\n (input)=\"onInput($event)\"\n (beforeinput)=\"onBeforeInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (paste)=\"onPaste($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur($event)\"\n (mouseup)=\"onSelectionChange()\"\n (keyup)=\"onSelectionChange()\"\n (click)=\"onEditorClick($event)\"\n (mousemove)=\"onEditorMouseMove($event)\"\n (mousedown)=\"onEditorMouseDown($event)\"\n (touchstart)=\"onEditorTouchStart($event)\"\n (contextmenu)=\"onEditorContextMenu($event)\"\n (dragover)=\"onEditorDragOver($event)\"\n (dragleave)=\"onEditorDragLeave($event)\"\n (drop)=\"onEditorDrop($event)\"\n ></div>\n\n @if (findReplaceVisible()) {\n <div data-slot=\"rich-text-find-panel\"\n class=\"absolute top-2 end-2 z-50 bg-popover border rounded-lg shadow-lg p-3 w-80 max-w-[calc(100vw-2rem)] max-sm:w-[calc(100%-1rem)] max-sm:start-2 animate-in slide-in-from-top-2 fade-in-0\"\n tabindex=\"-1\"\n (keydown.escape)=\"closeFindReplace()\"\n (keydown)=\"onFindReplaceKeydown($event)\">\n <div class=\"flex flex-wrap items-center gap-1.5 mb-2\">\n <input\n #findInput\n data-slot=\"rich-text-find-query\"\n type=\"text\"\n [placeholder]=\"resolvedLocale().findReplace.findPlaceholder\"\n [attr.aria-label]=\"resolvedLocale().findReplace.find\"\n [attr.aria-invalid]=\"findRegexError() ? 'true' : null\"\n [value]=\"findQuery()\"\n (input)=\"onFindQueryChange($any($event.target).value)\"\n class=\"flex h-7 min-w-0 flex-1 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findCaseSensitive()\"\n [attr.aria-pressed]=\"findCaseSensitive()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.caseSensitive\"\n [title]=\"resolvedLocale().findReplace.caseSensitive\"\n (click)=\"toggleFindCaseSensitive()\">Aa</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findWholeWord()\"\n [attr.aria-pressed]=\"findWholeWord()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.wholeWord\"\n [title]=\"resolvedLocale().findReplace.wholeWord\"\n (click)=\"toggleFindWholeWord()\">ab</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs font-medium transition-colors hover:bg-accent\"\n [class.bg-accent]=\"findUseRegex()\"\n [attr.aria-pressed]=\"findUseRegex()\"\n [attr.aria-label]=\"resolvedLocale().findReplace.useRegex\"\n [title]=\"resolvedLocale().findReplace.useRegex\"\n (click)=\"toggleFindUseRegex()\">.*</button>\n </div>\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\n <span data-slot=\"rich-text-find-counter\"\n aria-live=\"polite\"\n class=\"text-xs text-muted-foreground\">{{ findCounterText() }}</span>\n <div class=\"flex gap-1\">\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent disabled:opacity-50\"\n [attr.aria-label]=\"resolvedLocale().findReplace.previous\"\n [title]=\"resolvedLocale().findReplace.previous\"\n [disabled]=\"findMatchCount() === 0\"\n (click)=\"findPrevious()\">&#x25B2;</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent disabled:opacity-50\"\n [attr.aria-label]=\"resolvedLocale().findReplace.next\"\n [title]=\"resolvedLocale().findReplace.next\"\n [disabled]=\"findMatchCount() === 0\"\n (click)=\"findNext()\">&#x25BC;</button>\n <button type=\"button\"\n class=\"inline-flex min-h-7 min-w-7 items-center justify-center rounded-md p-1 text-xs hover:bg-accent\"\n [attr.aria-label]=\"resolvedLocale().findReplace.close\"\n [title]=\"resolvedLocale().findReplace.close\"\n (click)=\"closeFindReplace()\">&#x2715;</button>\n </div>\n </div>\n @if (showReplaceRow()) {\n <div class=\"flex flex-wrap items-center gap-1.5\">\n <input\n data-slot=\"rich-text-find-replace\"\n type=\"text\"\n [placeholder]=\"resolvedLocale().findReplace.replacePlaceholder\"\n [attr.aria-label]=\"resolvedLocale().findReplace.replace\"\n [value]=\"replaceText()\"\n (input)=\"replaceText.set($any($event.target).value)\"\n class=\"flex h-7 min-w-0 flex-1 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n />\n <button type=\"button\" class=\"inline-flex min-h-7 items-center justify-center rounded-md px-2 py-1 text-xs hover:bg-accent whitespace-nowrap disabled:opacity-50\" [disabled]=\"findMatchCount() === 0\" (click)=\"replaceSingle()\">{{ resolvedLocale().findReplace.replace }}</button>\n <button type=\"button\" class=\"inline-flex min-h-7 items-center justify-center rounded-md px-2 py-1 text-xs hover:bg-accent whitespace-nowrap disabled:opacity-50\" [disabled]=\"findMatchCount() === 0\" (click)=\"replaceAll()\">{{ resolvedLocale().findReplace.replaceAll }}</button>\n </div>\n }\n </div>\n }\n\n @if (dragOver()) {\n <div class=\"absolute inset-0 pointer-events-none border-2 border-dashed border-primary/60 rounded-md bg-primary/5\"></div>\n }\n\n @if (toolbar() === 'floating' && !readonly() && showFloatingToolbar()) {\n <div \n class=\"fixed z-[9999] bg-popover border rounded-lg shadow-lg p-1\"\n [style.left.px]=\"floatingToolbarPosition().x\"\n [style.top.px]=\"floatingToolbarPosition().y\"\n >\n <ui-rich-text-toolbar\n [items]=\"['bold', 'italic', 'underline', 'separator', 'clear']\"\n [activeFormats]=\"emptyFormats\"\n [compact]=\"true\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [locale]=\"resolvedLocale()\"\n (formatCommand)=\"onFloatingFormatCommand($event)\"\n [addonSlots]=\"toolbarSlots.slots()\"\n (addonSlotClick)=\"onAddonSlotClick($event)\"\n />\n </div>\n }\n\n @if (tableContextMenuOpen()) {\n <div\n #tableContextMenuRef\n class=\"fixed z-50 min-w-[180px] max-w-[calc(100vw-2rem)] max-h-[calc(100vh-1rem)] overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95\"\n [style.left.px]=\"tableContextMenuPosition().x\"\n [style.top.px]=\"tableContextMenuPosition().y\"\n (mousedown)=\"$event.preventDefault()\"\n (contextmenu)=\"onContextMenuOverlayContextMenu($event)\"\n >\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableRowAbove()\">\n {{ resolvedLocale().table.addRowAbove }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableRowBelow()\">\n {{ resolvedLocale().table.addRowBelow }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableColumnLeft()\">\n {{ resolvedLocale().table.addColumnLeft }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"addTableColumnRight()\">\n {{ resolvedLocale().table.addColumnRight }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"toggleTableHeaderRow()\">\n {{ resolvedLocale().table.toggleHeaderRow }}\n </button>\n <div class=\"my-1 h-px bg-border\"></div>\n @if (tableCellSelected().length >= 2) {\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"mergeCells()\">\n {{ resolvedLocale().table.mergeCells }}\n </button>\n }\n @if (canSplitCell()) {\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground\" (click)=\"splitCell()\">\n {{ resolvedLocale().table.splitCell }}\n </button>\n }\n @if (tableCellSelected().length >= 2 || canSplitCell()) {\n <div class=\"my-1 h-px bg-border\"></div>\n }\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.borders }}</div>\n <div class=\"flex items-center gap-1\">\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersAll\" (click)=\"setTableBorders('all')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersNone\" (click)=\"setTableBorders('none')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\" opacity=\"0.35\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" stroke-dasharray=\"2 2\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" stroke-dasharray=\"2 2\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersOuter\" (click)=\"setTableBorders('outer')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\">\n <rect x=\"1\" y=\"1\" width=\"18\" height=\"18\" stroke-width=\"1.5\" /><line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"19\" stroke-width=\"1\" opacity=\"0.25\" stroke-dasharray=\"2 2\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-width=\"1\" opacity=\"0.25\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.bordersHorizontal\" (click)=\"setTableBorders('horizontal')\">\n <svg viewBox=\"0 0 20 20\" class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\">\n <line x1=\"1\" y1=\"1\" x2=\"19\" y2=\"1\" stroke-width=\"1.5\" /><line x1=\"1\" y1=\"10\" x2=\"19\" y2=\"10\" stroke-width=\"1.5\" /><line x1=\"1\" y1=\"19\" x2=\"19\" y2=\"19\" stroke-width=\"1.5\" />\n </svg>\n </button>\n </div>\n </div>\n <div class=\"my-1 h-px bg-border\"></div>\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.cellAlignLeft }}</div>\n <div class=\"flex items-center gap-1\" dir=\"ltr\">\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignLeft\" (click)=\"setCellAlignment('left')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"15\" x2=\"3\" y1=\"12\" y2=\"12\"/><line x1=\"17\" x2=\"3\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignCenter\" (click)=\"setCellAlignment('center')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"17\" x2=\"7\" y1=\"12\" y2=\"12\"/><line x1=\"19\" x2=\"5\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n <button type=\"button\" class=\"flex items-center justify-center w-7 h-7 rounded border border-transparent hover:border-border hover:bg-accent\" [title]=\"resolvedLocale().table.cellAlignRight\" (click)=\"setCellAlignment('right')\">\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\"><line x1=\"21\" x2=\"3\" y1=\"6\" y2=\"6\"/><line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\"/><line x1=\"21\" x2=\"7\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n </div>\n <div class=\"px-2 py-1.5\">\n <div class=\"text-xs text-muted-foreground mb-1.5\">{{ resolvedLocale().table.cellColor }}</div>\n <div class=\"grid grid-cols-8 gap-0.5\">\n @for (color of tableCellColors; track color) {\n <button type=\"button\" class=\"w-4 h-4 rounded border border-border hover:scale-110 transition-transform\" [style.background-color]=\"color\" [attr.aria-label]=\"color\" (click)=\"setCellColor(color)\"></button>\n }\n </div>\n </div>\n <div class=\"my-1 h-px bg-border\"></div>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTableRow()\">\n {{ resolvedLocale().table.deleteRow }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTableColumn()\">\n {{ resolvedLocale().table.deleteColumn }}\n </button>\n <button type=\"button\" class=\"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground text-destructive\" (click)=\"deleteTable()\">\n {{ resolvedLocale().table.deleteTable }}\n </button>\n </div>\n }\n</div>\n\n@if (showCount() || showWordCount()) {\n <!--\n A polite status region, so a screen reader hears the count change, and the\n limit is shown once one is set: enforcement used to be entirely silent,\n so hitting maxLength read as a dead keyboard with the counter still showing\n a bare number and no indication a limit existed at all. The colour change\n at the limit gives sighted users the same signal.\n -->\n <output [attr.id]=\"counterId\" class=\"flex justify-end text-xs text-muted-foreground mt-1 px-1\" aria-live=\"polite\">\n @if (showCount()) {\n <!--\n The localized phrase keeps its own {count}, and the limit follows as a\n separate parenthetical. Interpolating \"0 / 120\" INTO the slot produced\n \"0 / 120 characters\", which is wrong in English and cannot be localized\n at all -- a locale ordering it differently had no way to express it,\n because the separator was hardcoded in the template expression.\n -->\n <span [class.text-destructive]=\"atCharacterLimit()\" [class.font-medium]=\"atCharacterLimit()\">\n {{ interpolateLocale(resolvedLocale().editor.characters, { count: characterCount() }) }}@if (maxLength()) {<span class=\"ms-1\">({{ maxLength() }} max)</span>}\n </span>\n }\n @if (showWordCount()) {\n <span [class.ms-3]=\"showCount()\">{{ interpolateLocale(resolvedLocale().editor.words, { count: wordCount() }) }}</span>\n }\n </output>\n}\n", styles: ["@media print{:host{display:block;overflow:visible}:host [data-slot=rich-text-editor]{max-height:none!important;height:auto!important;overflow:visible!important;border:none}:host [role=toolbar],:host [data-slot=rich-text-floating-toolbar],:host [data-slot=rich-text-find-overlay],:host [data-slot=rich-text-outline-panel],:host [data-slot=rich-text-history-badge]{display:none!important}:host tr,:host img{break-inside:avoid}:host h1,:host h2,:host h3{break-after:avoid}}:host img[data-blocked-src]{display:inline-flex;align-items:center;justify-content:center;min-width:8rem;min-height:4.5rem;padding:calc(.75rem * var(--_d));border:1px dashed var(--border);border-radius:var(--radius);background-color:color-mix(in oklab,var(--muted) 60%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);color:var(--muted-foreground);font-size:.75rem;line-height:1.4;text-align:center;font-style:italic}:host img[data-blocked-src]:after{content:attr(data-blocked-label)}:host([data-ui-theme=\"neutral\"]){--primary: oklch(.205 0 0);--primary-foreground: oklch(.985 0 0);--ring: oklch(.708 0 0)}:host-context(.dark)[data-ui-theme=neutral]{--primary: oklch(.985 0 0);--primary-foreground: oklch(.205 0 0);--ring: oklch(.708 0 0)}:host([data-ui-theme=\"zinc\"]){--primary: oklch(.205 0 0);--primary-foreground: oklch(.985 0 0);--ring: oklch(.708 0 0)}:host-context(.dark)[data-ui-theme=zinc]{--primary: oklch(.985 0 0);--primary-foreground: oklch(.205 0 0);--ring: oklch(.708 0 0)}:host([data-ui-theme=\"slate\"]){--primary: oklch(.208 .042 265.755);--primary-foreground: oklch(.984 .003 247.858);--ring: oklch(.704 .04 256.788)}:host-context(.dark)[data-ui-theme=slate]{--primary: oklch(.929 .013 255.508);--primary-foreground: oklch(.208 .042 265.755);--ring: oklch(.704 .04 256.788)}:host([data-ui-theme=\"stone\"]){--primary: oklch(.216 .006 56.043);--primary-foreground: oklch(.985 .001 106.423);--ring: oklch(.709 .01 56.259)}:host-context(.dark)[data-ui-theme=stone]{--primary: oklch(.923 .003 48.717);--primary-foreground: oklch(.216 .006 56.043);--ring: oklch(.553 .013 58.071)}:host([data-ui-theme=\"gray\"]){--primary: oklch(.21 .028 264.532);--primary-foreground: oklch(.985 .002 247.839);--ring: oklch(.707 .022 264.436)}:host-context(.dark)[data-ui-theme=gray]{--primary: oklch(.928 .006 264.531);--primary-foreground: oklch(.21 .028 264.532);--ring: oklch(.551 .027 264.364)}:host([data-ui-theme=\"red\"]){--primary: oklch(.577 .245 27.325);--primary-foreground: oklch(.985 0 0);--ring: oklch(.577 .245 27.325)}:host-context(.dark)[data-ui-theme=red]{--primary: oklch(.577 .245 27.325);--primary-foreground: oklch(.985 0 0);--ring: oklch(.577 .245 27.325)}:host([data-ui-theme=\"rose\"]){--primary: oklch(.645 .246 16.439);--primary-foreground: oklch(.985 0 0);--ring: oklch(.645 .246 16.439)}:host-context(.dark)[data-ui-theme=rose]{--primary: oklch(.645 .246 16.439);--primary-foreground: oklch(.985 0 0);--ring: oklch(.645 .246 16.439)}:host([data-ui-theme=\"orange\"]){--primary: oklch(.646 .222 41.116);--primary-foreground: oklch(.985 0 0);--ring: oklch(.646 .222 41.116)}:host-context(.dark)[data-ui-theme=orange]{--primary: oklch(.646 .222 41.116);--primary-foreground: oklch(.985 0 0);--ring: oklch(.646 .222 41.116)}:host([data-ui-theme=\"green\"]){--primary: oklch(.623 .214 131.655);--primary-foreground: oklch(.985 0 0);--ring: oklch(.623 .214 131.655)}:host-context(.dark)[data-ui-theme=green]{--primary: oklch(.623 .214 131.655);--primary-foreground: oklch(.985 0 0);--ring: oklch(.623 .214 131.655)}:host([data-ui-theme=\"blue\"]){--primary: oklch(.546 .245 262.881);--primary-foreground: oklch(.985 0 0);--ring: oklch(.546 .245 262.881)}:host-context(.dark)[data-ui-theme=blue]{--primary: oklch(.546 .245 262.881);--primary-foreground: oklch(.985 0 0);--ring: oklch(.546 .245 262.881)}:host([data-ui-theme=\"yellow\"]){--primary: oklch(.82 .185 84.67);--primary-foreground: oklch(.205 0 0);--ring: oklch(.82 .185 84.67)}:host-context(.dark)[data-ui-theme=yellow]{--primary: oklch(.82 .185 84.67);--primary-foreground: oklch(.205 0 0);--ring: oklch(.82 .185 84.67)}:host([data-ui-theme=\"violet\"]){--primary: oklch(.558 .288 302.321);--primary-foreground: oklch(.985 0 0);--ring: oklch(.558 .288 302.321)}:host-context(.dark)[data-ui-theme=violet]{--primary: oklch(.558 .288 302.321);--primary-foreground: oklch(.985 0 0);--ring: oklch(.558 .288 302.321)}:host([data-ui-theme=\"amber\"]){--primary: oklch(.77 .16 70);--primary-foreground: oklch(.145 0 0);--ring: oklch(.77 .16 70)}:host-context(.dark)[data-ui-theme=amber]{--primary: oklch(.77 .16 70);--primary-foreground: oklch(.145 0 0);--ring: oklch(.77 .16 70)}\n"] }]
18713
18719
  }], ctorParameters: () => [], propDecorators: { editorDiv: [{
18714
18720
  type: ViewChild,
18715
18721
  args: ['editorDiv']
@@ -18719,7 +18725,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
18719
18725
  }], tableContextMenuRef: [{
18720
18726
  type: ViewChild,
18721
18727
  args: ['tableContextMenuRef']
18722
- }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], toolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbar", required: false }] }], toolbarItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarItems", required: false }] }], customToolbarItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "customToolbarItems", required: false }] }], customToolbarAction: [{ type: i0.Output, args: ["customToolbarAction"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], minHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "minHeight", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], markdownShortcuts: [{ type: i0.Input, args: [{ isSignal: true, alias: "markdownShortcuts", required: false }] }], counter: [{ type: i0.Input, args: [{ isSignal: true, alias: "counter", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], history: [{ type: i0.Input, args: [{ isSignal: true, alias: "history", required: false }] }], findDebounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "findDebounceMs", required: false }] }], codeHighlightDebounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "codeHighlightDebounceMs", required: false }] }], allowedImageHosts: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowedImageHosts", required: false }] }], allowedLinkSchemes: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowedLinkSchemes", required: false }] }], blockedImageMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "blockedImageMessage", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], htmlChange: [{ type: i0.Output, args: ["htmlChange"] }], markdownChange: [{ type: i0.Output, args: ["markdownChange"] }], wordCountChange: [{ type: i0.Output, args: ["wordCountChange"] }], historyChange: [{ type: i0.Output, args: ["historyChange"] }], imageBlocked: [{ type: i0.Output, args: ["imageBlocked"] }], focused: [{ type: i0.Output, args: ["focused"] }], blurred: [{ type: i0.Output, args: ["blurred"] }] } });
18728
+ }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], toolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbar", required: false }] }], toolbarItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarItems", required: false }] }], customToolbarItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "customToolbarItems", required: false }] }], customToolbarAction: [{ type: i0.Output, args: ["customToolbarAction"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], minHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "minHeight", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], markdownShortcuts: [{ type: i0.Input, args: [{ isSignal: true, alias: "markdownShortcuts", required: false }] }], counter: [{ type: i0.Input, args: [{ isSignal: true, alias: "counter", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], history: [{ type: i0.Input, args: [{ isSignal: true, alias: "history", required: false }] }], findDebounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "findDebounceMs", required: false }] }], codeHighlightDebounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "codeHighlightDebounceMs", required: false }] }], allowedImageHosts: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowedImageHosts", required: false }] }], allowedLinkSchemes: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowedLinkSchemes", required: false }] }], blockedImageMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "blockedImageMessage", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], htmlChange: [{ type: i0.Output, args: ["htmlChange"] }], markdownChange: [{ type: i0.Output, args: ["markdownChange"] }], wordCountChange: [{ type: i0.Output, args: ["wordCountChange"] }], historyChange: [{ type: i0.Output, args: ["historyChange"] }], imageBlocked: [{ type: i0.Output, args: ["imageBlocked"] }], focused: [{ type: i0.Output, args: ["focused"] }], blurred: [{ type: i0.Output, args: ["blurred"] }] } });
18723
18729
  /** The last child element of `parent` whose tag is `tagName`, or null. */
18724
18730
  function lastChildTagged(parent, tagName) {
18725
18731
  for (let child = parent.lastElementChild; child; child = child.previousElementSibling) {
@@ -19862,6 +19868,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
19862
19868
  }, template: "@if (skeleton()) {\n <ui-skeleton class=\"h-9 w-24 rounded-md\" />\n} @else {\n <button\n uiRipple\n [uiRippleDisabled]=\"!ripple()\"\n [uiRippleColor]=\"rippleColor()\"\n [class]=\"classes()\"\n [disabled]=\"disabled() || loading()\"\n [type]=\"type()\"\n [attr.data-slot]=\"'button'\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n (click)=\"clicked.emit($event)\"\n >\n @if (loading()) {\n <div class=\"absolute inset-0 flex items-center justify-center\" aria-hidden=\"true\">\n <ui-spinner size=\"xs\" />\n </div>\n }\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content />\n }\n </button>\n}\n", styles: [":host{--_d: var(--density-button, var(--density, 1))}@layer components{[data-slot=button]{height:calc(2.25rem * var(--_d));padding-inline:calc(1rem * var(--_d))}:host([data-size=\"sm\"]) [data-slot=button]{height:calc(2rem * var(--_d));padding-inline:calc(.75rem * var(--_d))}:host([data-size=\"lg\"]) [data-slot=button]{height:calc(2.5rem * var(--_d));padding-inline:calc(2rem * var(--_d))}:host([data-size=\"icon\"]) [data-slot=button]{height:calc(2.25rem * var(--_d));width:calc(2.25rem * var(--_d));padding:0}:host([data-size=\"icon-sm\"]) [data-slot=button]{height:calc(2rem * var(--_d));width:calc(2rem * var(--_d));padding:0}:host([data-size=\"icon-lg\"]) [data-slot=button]{height:calc(2.5rem * var(--_d));width:calc(2.5rem * var(--_d));padding:0}}\n"] }]
19863
19869
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], ripple: [{ type: i0.Input, args: [{ isSignal: true, alias: "ripple", required: false }] }], rippleColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "rippleColor", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], skeleton: [{ type: i0.Input, args: [{ isSignal: true, alias: "skeleton", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
19864
19870
 
19871
+ /**
19872
+ * Per-instance colour presets — the same names `npx shadcn-angular change-theme`
19873
+ * accepts. A component that exposes a `theme` input reflects it as the
19874
+ * `data-ui-theme` attribute, and its own stylesheet maps each name to the
19875
+ * preset's tokens, so nothing global is involved.
19876
+ */
19877
+ const THEME_NAMES = [
19878
+ 'zinc', 'slate', 'stone', 'gray', 'neutral',
19879
+ 'red', 'rose', 'orange', 'green', 'blue', 'yellow', 'violet', 'amber',
19880
+ ];
19881
+ /** The attribute a themed host carries; overlays look it up to inherit the preset. */
19882
+ const THEME_ATTRIBUTE = 'data-ui-theme';
19883
+ /** The tokens a preset overrides — everything else stays the app's global tokens. */
19884
+ const THEME_TOKENS = ['--primary', '--primary-foreground', '--ring'];
19885
+ /**
19886
+ * Carries a themed component's preset onto an overlay rendered outside it.
19887
+ * Call it when the overlay is shown — including every re-show of a reused one.
19888
+ *
19889
+ * Custom properties inherit through the DOM tree, so anything a themed component
19890
+ * renders inside itself is themed for free, live. Two kinds of overlay are NOT
19891
+ * descendants and would silently fall back to the global tokens: one appended
19892
+ * to `document.body`, and one an addon directive creates through its
19893
+ * `ViewContainerRef`, which Angular inserts as a SIBLING of the host. Those get
19894
+ * the resolved tokens copied at show time (so a dark-mode toggle while one is
19895
+ * open is not reflected until it re-opens).
19896
+ *
19897
+ * A real descendant is left alone so it keeps inheriting live, and an overlay
19898
+ * whose origin is not themed (any more) has earlier copies cleared, so it
19899
+ * follows the global tokens.
19900
+ */
19901
+ function inheritThemeTokens(origin, overlay) {
19902
+ const themed = origin.closest(`[${THEME_ATTRIBUTE}]`);
19903
+ if (themed?.contains(overlay))
19904
+ return;
19905
+ if (!themed) {
19906
+ for (const token of THEME_TOKENS)
19907
+ overlay.style.removeProperty(token);
19908
+ delete overlay.dataset['uiTheme'];
19909
+ return;
19910
+ }
19911
+ const computed = getComputedStyle(themed);
19912
+ for (const token of THEME_TOKENS) {
19913
+ overlay.style.setProperty(token, computed.getPropertyValue(token));
19914
+ }
19915
+ // The attribute travels too, so an overlay opened FROM this overlay (a
19916
+ // context submenu, a tooltip inside a popover) still finds a themed origin.
19917
+ overlay.dataset['uiTheme'] = themed.dataset['uiTheme'];
19918
+ }
19919
+
19865
19920
  const ALERT_DIALOG = new InjectionToken('ALERT_DIALOG');
19866
19921
  class AlertDialogComponent {
19867
19922
  constructor() {
@@ -20445,6 +20500,7 @@ class ConfirmDirective {
20445
20500
  this.appRef = inject(ApplicationRef);
20446
20501
  this.injector = inject(EnvironmentInjector);
20447
20502
  this.elementInjector = inject(Injector);
20503
+ this.hostEl = inject(ElementRef);
20448
20504
  }
20449
20505
  /**
20450
20506
  * Intercept the host click and open the confirmation dialog instead.
@@ -20463,6 +20519,7 @@ class ConfirmDirective {
20463
20519
  ref.instance.cancelLabel.set(this.resolvedCancelLabel());
20464
20520
  this.appRef.attachView(ref.hostView);
20465
20521
  document.body.appendChild(ref.location.nativeElement);
20522
+ inheritThemeTokens(this.hostEl.nativeElement, ref.location.nativeElement);
20466
20523
  ref.instance.show();
20467
20524
  const confirmSub = ref.instance.confirmed.subscribe(() => {
20468
20525
  this.confirmed.emit();
@@ -21154,6 +21211,7 @@ class RichTextActionsDirective {
21154
21211
  };
21155
21212
  const occupied = target.existing ? readActions(target.existing).map((a) => a.trigger) : [];
21156
21213
  const ref = this.vcr.createComponent(RichTextActionsDialogComponent);
21214
+ inheritThemeTokens(this.vcr.element.nativeElement, ref.location.nativeElement);
21157
21215
  ref.setInput('definitions', this.uiRteActions());
21158
21216
  ref.setInput('locale', this.i18n.t());
21159
21217
  ref.setInput('context', {
@@ -21249,6 +21307,7 @@ class RichTextActionsDirective {
21249
21307
  this.popoverTarget = el;
21250
21308
  const rows = this.buildPopoverRows(el);
21251
21309
  const ref = this.vcr.createComponent(RichTextActionsPopoverComponent);
21310
+ inheritThemeTokens(this.vcr.element.nativeElement, ref.location.nativeElement);
21252
21311
  ref.setInput('actions', rows);
21253
21312
  ref.setInput('locale', this.i18n.t());
21254
21313
  ref.setInput('canAdd', rows.length < 2);
@@ -21320,6 +21379,7 @@ class RichTextActionsDirective {
21320
21379
  this.hidePopover();
21321
21380
  const target = { kind: 'text', existing: el, image: null };
21322
21381
  const ref = this.vcr.createComponent(RichTextActionsDialogComponent);
21382
+ inheritThemeTokens(this.vcr.element.nativeElement, ref.location.nativeElement);
21323
21383
  ref.setInput('definitions', this.uiRteActions());
21324
21384
  ref.setInput('locale', this.i18n.t());
21325
21385
  ref.setInput('context', {
@@ -21904,6 +21964,7 @@ function hoverCardHandlers(injector, o = {}) {
21904
21964
  body: String(event.params['body'] ?? ''),
21905
21965
  dir: directionOf(event.element),
21906
21966
  });
21967
+ inheritThemeTokens(event.element, open.host);
21907
21968
  anchorOverlay(open.host, event.element);
21908
21969
  // Grace area: keep the card open while the pointer is over it.
21909
21970
  open.host.addEventListener('mouseenter', cancelClose);
@@ -22048,6 +22109,7 @@ function openDialogHandlers(injector, o = {}) {
22048
22109
  dir: directionOf(event.element),
22049
22110
  });
22050
22111
  overlay.host.style.inset = '0';
22112
+ inheritThemeTokens(event.element, overlay.host);
22051
22113
  const onKeydown = (e) => { if (e.key === 'Escape')
22052
22114
  dismiss(); };
22053
22115
  const dismiss = () => {
@@ -23508,6 +23570,7 @@ class PopoverContentComponent {
23508
23570
  constructor() {
23509
23571
  this.popover = inject(POPOVER, { optional: true });
23510
23572
  this.document = inject(DOCUMENT);
23573
+ this.hostEl = inject(ElementRef);
23511
23574
  /** Extra classes merged onto the panel. Keep a width constraint viewport-aware (`max-w-[calc(100vw-2rem)]`), since the panel is positioned, not laid out by its parent. */
23512
23575
  this.class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
23513
23576
  /** Alignment along the chosen {@link side}'s edge: `'start'`, `'center'` or `'end'`. May be flipped at runtime when {@link avoidCollisions} is on. */
@@ -23741,6 +23804,7 @@ class PopoverContentComponent {
23741
23804
  this.portalHost.dataset['popoverPortal'] = 'true';
23742
23805
  this.portalHost.style.cssText = 'display:contents';
23743
23806
  this.document.body.appendChild(this.portalHost);
23807
+ inheritThemeTokens(this.hostEl.nativeElement, this.portalHost);
23744
23808
  this.popover?.registerPortal(this.portalHost);
23745
23809
  }
23746
23810
  this.portalHost.appendChild(el);
@@ -26984,6 +27048,7 @@ class TooltipDirective {
26984
27048
  this.renderer.appendChild(tooltipEl, text);
26985
27049
  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');
26986
27050
  this.renderer.appendChild(document.body, tooltipEl);
27051
+ inheritThemeTokens(this.el.nativeElement, tooltipEl);
26987
27052
  return tooltipEl;
26988
27053
  }
26989
27054
  resolveTargetElement() {
@@ -31582,7 +31647,7 @@ class RichTextFileImportDirective {
31582
31647
  async importDocx(file) {
31583
31648
  this.assertImportableSize(file);
31584
31649
  const bytes = new Uint8Array(await file.arrayBuffer());
31585
- const { parseDocx } = await import('./gilav21-shadcn-angular-rte-docx-parser-B8BeJWtY.mjs');
31650
+ const { parseDocx } = await import('./gilav21-shadcn-angular-rte-docx-parser-CdxuIlVT.mjs');
31586
31651
  const { renderDocxForEditor } = await import('./gilav21-shadcn-angular-rte-docx-to-editor-html-Cl9eIhkC.mjs');
31587
31652
  const html = renderDocxForEditor(parseDocx(bytes));
31588
31653
  this.insertImported(html);
@@ -33937,6 +34002,7 @@ class RichTextLinksDirective {
33937
34002
  createOverlay(text, url, showRemove, rect) {
33938
34003
  this.closeOverlay();
33939
34004
  const ref = this.vcr.createComponent(RichTextLinksFormComponent);
34005
+ inheritThemeTokens(this.vcr.element.nativeElement, ref.location.nativeElement);
33940
34006
  ref.setInput('locale', this.i18n.t());
33941
34007
  ref.setInput('text', text);
33942
34008
  ref.setInput('url', url);
@@ -36297,6 +36363,7 @@ class RichTextSlashCommandsDirective {
36297
36363
  }
36298
36364
  createMenu() {
36299
36365
  const ref = this.vcr.createComponent(RichTextSlashCommandsMenuComponent);
36366
+ inheritThemeTokens(this.vcr.element.nativeElement, ref.location.nativeElement);
36300
36367
  // Set here rather than as a host binding on the component: the id never
36301
36368
  // changes, and a host binding costs a change-detection pass per cycle
36302
36369
  // that re-fires the menu's scroll-into-view effect.
@@ -38545,4 +38612,4 @@ const RTE_FULL = [
38545
38612
  */
38546
38613
 
38547
38614
  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, hasUnsafeCssFunction 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, classifyImport as aO, compileFindRegex as aP, computeSeedStyleString as aQ, containsCssUrl as aR, createImageElement as aS, cssFunctionCalls as aT, dataUrlToFile as aU, decodeCssEscapes as aV, detectTrigger as aW, directionOf as aX, dragHasSupportedDocument as aY, extractCssUrls as aZ, flattenIntoRowText 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, writeAction as b$, holdsNothing as b0, hostOf as b1, hoverCardAction as b2, hoverCardHandlers as b3, isCombinedOnElement as b4, isHostAllowed as b5, isHostBearingUrl as b6, isInlineHoldingBlock as b7, isLineOwner as b8, isNestedList as b9, openDialogAction as bA, openDialogHandlers as bB, parseImageSize as bC, placeCaretIn as bD, placeImageAtSelection as bE, positionAfterLine as bF, rangeShowsNothing as bG, readActions as bH, readFileAsDataUrl as bI, remoteHostOf as bJ, removeAction as bK, reportResourceDecisions as bL, resolveFromPage as bM, richTextHasMedia as bN, richTextMaxLength as bO, richTextMinWords as bP, richTextRequired as bQ, richTextVisibleText as bR, rowRunsOf as bS, selectTriggerRange as bT, separateListKinds as bU, simpleHash as bV, stripCssComments as bW, stripStyleIfMatches as bX, structureAround as bY, validateActionId as bZ, validateActionParams as b_, isPdfHeader as ba, isPhrasing as bb, isRichTextEmpty as bc, isSupportedDocumentFile as bd, isZipHeader as be, labelBlockedImages as bf, lastOwnInlineNode as bg, lineAbove as bh, lineBelow as bi, lineIsEmpty as bj, lineIsTextOnly as bk, lineKeepsItsElement as bl, lineOf as bm, lineOwnNodes as bn, lineTagIsFixed as bo, lineText as bp, linesBetween as bq, linesMayJoin as br, linkedPreviewDialogAction as bs, linkedPreviewDialogHandlers as bt, matchBlockInputRule as bu, matchInlineInputRule as bv, mountTopLayer as bw, nodeShowsNothing as bx, normalizeHostEntry as by, offsetToPosition as bz, DEFAULT_FONT_FAMILIES as c, writeCombined as c0, 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 };
38548
- //# sourceMappingURL=gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-CfjU_y-y.mjs.map
38615
+ //# sourceMappingURL=gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BFcfCqW4.mjs.map