@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.
- package/README.md +43 -27
- package/fesm2022/{gilav21-shadcn-angular-rte-docx-parser-B8BeJWtY.mjs → gilav21-shadcn-angular-rte-docx-parser-CdxuIlVT.mjs} +2 -2
- package/fesm2022/{gilav21-shadcn-angular-rte-docx-parser-B8BeJWtY.mjs.map → gilav21-shadcn-angular-rte-docx-parser-CdxuIlVT.mjs.map} +1 -1
- package/fesm2022/{gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-CfjU_y-y.mjs → gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BFcfCqW4.mjs} +73 -6
- package/fesm2022/gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BFcfCqW4.mjs.map +1 -0
- package/fesm2022/gilav21-shadcn-angular-rte.mjs +1 -1
- package/package.json +6 -2
- package/schematics/collection.json +10 -0
- package/schematics/ng-add/index.cjs +169 -0
- package/schematics/ng-add/schema.json +13 -0
- package/styles.css +2 -0
- package/types/gilav21-shadcn-angular-rte.d.ts +6 -1
- package/types/gilav21-shadcn-angular-rte.d.ts.map +1 -1
- package/fesm2022/gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-CfjU_y-y.mjs.map +0 -1
- package/theme.css +0 -159
|
@@ -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()\">▲</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()\">▼</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()\">✕</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()\">▲</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()\">▼</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()\">✕</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()\">▲</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()\">▼</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()\">✕</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()\">▲</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()\">▼</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()\">✕</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-
|
|
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-
|
|
38615
|
+
//# sourceMappingURL=gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BFcfCqW4.mjs.map
|