@3ddv/software-division-components 1.4.12 → 1.5.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.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { input, computed, signal, Component, InjectionToken, inject, Directive, NgModule, booleanAttribute, model, numberAttribute, viewChild, ChangeDetectionStrategy, Renderer2, ElementRef, effect, forwardRef, output, ViewEncapsulation, Injectable, ChangeDetectorRef, EventEmitter, Output, ViewChild, ApplicationRef, EnvironmentInjector, createEnvironmentInjector, createComponent, TemplateRef, Input, Inject, DestroyRef, untracked, contentChildren, contentChild } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
- import { FormSubmittedEvent, ReactiveFormsModule, NG_VALUE_ACCESSOR, TouchedChangeEvent, PristineChangeEvent, FormsModule, FormControl } from '@angular/forms';
4
+ import { FormSubmittedEvent, ReactiveFormsModule, NG_VALUE_ACCESSOR, TouchedChangeEvent, PristineChangeEvent, FormsModule, FormControl, FormBuilder, Validators } from '@angular/forms';
5
5
  import { injectDateAdapter, provideDateAdapter, BrnNativeDateAdapter } from '@spartan-ng/brain/date-time';
6
6
  import { provideIcons, NgIcon } from '@ng-icons/core';
7
7
  import { lucideChevronRight, lucideChevronLeft, lucideCalendar, lucideArrowDown, lucideArrowUp, lucideArrowUpDown, lucideChevronDown, lucideChevronUp, lucideEye, lucideMapPin, lucideArrowRight, lucideArrowLeft, lucideX, lucideCheck } from '@ng-icons/lucide';
@@ -24,6 +24,11 @@ import * as i1$2 from '@spartan-ng/brain/dialog';
24
24
  import { BrnDialog, BrnDialogOverlay, provideBrnDialogDefaultOptions, BrnDialogRef, injectBrnDialogContext, BrnDialogClose, BrnDialogDescription, BrnDialogTitle, BrnDialogService, cssClassesToArray, DEFAULT_BRN_DIALOG_OPTIONS } from '@spartan-ng/brain/dialog';
25
25
  import { HttpClient } from '@angular/common/http';
26
26
  import { DomSanitizer } from '@angular/platform-browser';
27
+ import { Editor } from '@tiptap/core';
28
+ import StarterKit from '@tiptap/starter-kit';
29
+ import Underline from '@tiptap/extension-underline';
30
+ import Link from '@tiptap/extension-link';
31
+ import Placeholder from '@tiptap/extension-placeholder';
27
32
  import * as i1$3 from '@spartan-ng/brain/select';
28
33
  import { BrnSelectGroup, BrnSelectLabel, BrnSelectOption, BrnSelect, BrnSelectTrigger, BrnSelectImports } from '@spartan-ng/brain/select';
29
34
  import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
@@ -5575,6 +5580,602 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
5575
5580
  * Public API Surface of software-division-components
5576
5581
  */
5577
5582
 
5583
+ /**
5584
+ * Predefined toolbar presets
5585
+ */
5586
+ const TOOLBAR_PRESETS = {
5587
+ minimal: {
5588
+ bold: true,
5589
+ italic: true,
5590
+ link: true,
5591
+ },
5592
+ standard: {
5593
+ bold: true,
5594
+ italic: true,
5595
+ underline: true,
5596
+ bulletList: true,
5597
+ orderedList: true,
5598
+ headings: [1, 2, 3],
5599
+ link: true,
5600
+ },
5601
+ full: {
5602
+ bold: true,
5603
+ italic: true,
5604
+ underline: true,
5605
+ strike: true,
5606
+ bulletList: true,
5607
+ orderedList: true,
5608
+ headings: [1, 2, 3, 4, 5, 6],
5609
+ horizontalRule: true,
5610
+ link: true,
5611
+ blockquote: true,
5612
+ code: true,
5613
+ codeBlock: true,
5614
+ undo: true,
5615
+ redo: true,
5616
+ },
5617
+ };
5618
+ /**
5619
+ * Default toolbar configuration (standard preset)
5620
+ */
5621
+ const DEFAULT_TOOLBAR_CONFIG = TOOLBAR_PRESETS.standard;
5622
+
5623
+ /**
5624
+ * Default link configuration
5625
+ */
5626
+ const DEFAULT_LINK_CONFIG = {
5627
+ openOnClick: false,
5628
+ linkClass: 'text-blue-500 underline',
5629
+ addNoopener: true,
5630
+ openInNewTab: true,
5631
+ };
5632
+ /**
5633
+ * Default editor configuration
5634
+ */
5635
+ const DEFAULT_EDITOR_CONFIG = {
5636
+ placeholder: '',
5637
+ minHeight: '180px',
5638
+ autoFocus: false,
5639
+ linkConfig: DEFAULT_LINK_CONFIG,
5640
+ spellcheck: true,
5641
+ };
5642
+
5643
+ /**
5644
+ * Toolbar component for the rich text editor
5645
+ * Provides formatting buttons with responsive design and active state tracking
5646
+ */
5647
+ class EditorToolbarComponent {
5648
+ /** The TipTap editor instance */
5649
+ editor = input.required();
5650
+ /** Toolbar configuration */
5651
+ config = input(DEFAULT_TOOLBAR_CONFIG);
5652
+ /** Event emitted when link button is clicked */
5653
+ linkRequested = output();
5654
+ /** Mobile menu visibility state */
5655
+ showMobileMenu = signal(false);
5656
+ /** Computed config with defaults applied */
5657
+ mergedConfig = computed(() => {
5658
+ return { ...DEFAULT_TOOLBAR_CONFIG, ...this.config() };
5659
+ });
5660
+ /** Check if any formatting option is enabled */
5661
+ hasFormattingOptions = computed(() => {
5662
+ const cfg = this.mergedConfig();
5663
+ return cfg.bold || cfg.italic || cfg.underline || cfg.strike;
5664
+ });
5665
+ /** Check if any list option is enabled */
5666
+ hasListOptions = computed(() => {
5667
+ const cfg = this.mergedConfig();
5668
+ return cfg.bulletList || cfg.orderedList;
5669
+ });
5670
+ /** Check if any heading is enabled */
5671
+ hasHeadings = computed(() => {
5672
+ const cfg = this.mergedConfig();
5673
+ return cfg.headings && cfg.headings.length > 0;
5674
+ });
5675
+ /** Check if history buttons are enabled */
5676
+ hasHistory = computed(() => {
5677
+ const cfg = this.mergedConfig();
5678
+ return cfg.undo || cfg.redo;
5679
+ });
5680
+ /** Check if code options are enabled */
5681
+ hasCodeOptions = computed(() => {
5682
+ const cfg = this.mergedConfig();
5683
+ return cfg.code || cfg.codeBlock;
5684
+ });
5685
+ /** Toggle mobile menu visibility */
5686
+ toggleMobileMenu() {
5687
+ this.showMobileMenu.update(v => !v);
5688
+ }
5689
+ /** Toggle heading with smart selection handling */
5690
+ toggleHeading(level) {
5691
+ const editor = this.editor();
5692
+ const { from, to } = editor.state.selection;
5693
+ const selectedText = editor.state.doc.textBetween(from, to);
5694
+ if (selectedText) {
5695
+ // Delete selected text and insert heading with the text
5696
+ editor
5697
+ .chain()
5698
+ .focus()
5699
+ .deleteRange({ from, to })
5700
+ .insertContent(`<h${level}>${selectedText}</h${level}>`)
5701
+ .run();
5702
+ }
5703
+ else {
5704
+ // Toggle heading on current line
5705
+ editor.chain().focus().toggleHeading({ level }).run();
5706
+ }
5707
+ }
5708
+ /** Request link insertion/editing */
5709
+ setLink() {
5710
+ this.linkRequested.emit();
5711
+ }
5712
+ /** Toggle bold formatting */
5713
+ toggleBold() {
5714
+ this.editor().chain().focus().toggleBold().run();
5715
+ }
5716
+ /** Toggle italic formatting */
5717
+ toggleItalic() {
5718
+ this.editor().chain().focus().toggleItalic().run();
5719
+ }
5720
+ /** Toggle underline formatting */
5721
+ toggleUnderline() {
5722
+ this.editor().chain().focus().toggleUnderline().run();
5723
+ }
5724
+ /** Toggle strikethrough formatting */
5725
+ toggleStrike() {
5726
+ this.editor().chain().focus().toggleStrike().run();
5727
+ }
5728
+ /** Toggle bullet list */
5729
+ toggleBulletList() {
5730
+ this.editor().chain().focus().toggleBulletList().run();
5731
+ }
5732
+ /** Toggle ordered list */
5733
+ toggleOrderedList() {
5734
+ this.editor().chain().focus().toggleOrderedList().run();
5735
+ }
5736
+ /** Insert horizontal rule */
5737
+ insertHorizontalRule() {
5738
+ this.editor().chain().focus().setHorizontalRule().run();
5739
+ }
5740
+ /** Toggle blockquote */
5741
+ toggleBlockquote() {
5742
+ this.editor().chain().focus().toggleBlockquote().run();
5743
+ }
5744
+ /** Toggle inline code */
5745
+ toggleCode() {
5746
+ this.editor().chain().focus().toggleCode().run();
5747
+ }
5748
+ /** Toggle code block */
5749
+ toggleCodeBlock() {
5750
+ this.editor().chain().focus().toggleCodeBlock().run();
5751
+ }
5752
+ /** Undo last action */
5753
+ undo() {
5754
+ this.editor().chain().focus().undo().run();
5755
+ }
5756
+ /** Redo last undone action */
5757
+ redo() {
5758
+ this.editor().chain().focus().redo().run();
5759
+ }
5760
+ /** Remove link from selection */
5761
+ unsetLink() {
5762
+ this.editor().chain().focus().unsetLink().run();
5763
+ }
5764
+ /** Check if a formatting type is active */
5765
+ isActive(type, options) {
5766
+ return this.editor().isActive(type, options);
5767
+ }
5768
+ /** Track function for heading levels */
5769
+ trackByLevel(index, level) {
5770
+ return level;
5771
+ }
5772
+ /** Track function for custom buttons */
5773
+ trackByButtonId(index, btn) {
5774
+ return btn.id;
5775
+ }
5776
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EditorToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5777
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: EditorToolbarComponent, isStandalone: true, selector: "sdc-editor-toolbar", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { linkRequested: "linkRequested" }, ngImport: i0, template: "<div class=\"sdc-editor-toolbar\">\n <!-- Mobile: Expandable toolbar -->\n <div class=\"sdc-editor-toolbar__mobile\">\n <div class=\"sdc-editor-toolbar__mobile-container\">\n <!-- Primary actions row -->\n <div class=\"sdc-editor-toolbar__mobile-primary\">\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().bold) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('bold')\"\n (click)=\"toggleBold()\"\n title=\"Bold\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 4h5a3 3 0 0 1 0 6H6zm0 6h6a3 3 0 0 1 0 6H6z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().italic) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('italic')\"\n (click)=\"toggleItalic()\"\n title=\"Italic\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M10 4h6M4 16h6m2-12l-6 16\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().link) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('link')\"\n (click)=\"setLink()\"\n title=\"Link\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M8 12a3 3 0 0 0 4.24 0l3.5-3.5a3 3 0 0 0-4.24-4.24l-.88.87M12 8a3 3 0 0 0-4.24 0l-3.5 3.5a3 3 0 0 0 4.24 4.24l.88-.87\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n\n <!-- Toggle button -->\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button sdc-editor-toolbar__toggle\"\n [class.sdc-editor-toolbar__toggle--open]=\"showMobileMenu()\"\n (click)=\"toggleMobileMenu()\"\n title=\"More options\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 8l4 4 4-4\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <!-- Expanded toolbar -->\n @if (showMobileMenu()) {\n <div class=\"sdc-editor-toolbar__mobile-expanded\">\n <!-- Text formatting -->\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().underline) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('underline')\"\n (click)=\"toggleUnderline()\"\n title=\"Underline\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 4v5a4 4 0 0 0 8 0V4M4 17h12\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().strike) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('strike')\"\n (click)=\"toggleStrike()\"\n title=\"Strikethrough\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 10h12M7 4c-1.5 0-3 1-3 3s1.5 3 3 3h6c1.5 0 3 1 3 3s-1.5 3-3 3\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().bulletList) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('bulletList')\"\n (click)=\"toggleBulletList()\"\n title=\"Bullet List\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <circle cx=\"5\" cy=\"5\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"5\" cy=\"10\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"5\" cy=\"15\" r=\"1.5\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"4\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"9\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"14\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().orderedList) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('orderedList')\"\n (click)=\"toggleOrderedList()\"\n title=\"Ordered List\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <text x=\"3\" y=\"7\" font-size=\"6\" fill=\"currentColor\">1.</text>\n <text x=\"3\" y=\"12\" font-size=\"6\" fill=\"currentColor\">2.</text>\n <text x=\"3\" y=\"17\" font-size=\"6\" fill=\"currentColor\">3.</text>\n <rect x=\"9\" y=\"4\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"9\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"14\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n }\n </div>\n\n <!-- Headings -->\n @if (hasHeadings()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @for (level of mergedConfig().headings; track level) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button sdc-editor-toolbar__button--text\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('heading', { level })\"\n (click)=\"toggleHeading(level)\"\n [title]=\"'Heading ' + level\">\n H{{ level }}\n </button>\n }\n </div>\n }\n\n <!-- Extra options -->\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().blockquote) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('blockquote')\"\n (click)=\"toggleBlockquote()\"\n title=\"Blockquote\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 8h4v4H4zM12 8h4v4h-4zM4 12v2a2 2 0 0 0 2 2M12 12v2a2 2 0 0 0 2 2\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().horizontalRule) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"insertHorizontalRule()\"\n title=\"Horizontal Rule\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M2 10h16\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n\n @if (isActive('link')) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"unsetLink()\"\n title=\"Remove Link\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M8 12a3 3 0 0 0 4.24 0l3.5-3.5a3 3 0 0 0-4.24-4.24M12 8a3 3 0 0 0-4.24 0l-3.5 3.5a3 3 0 0 0 4.24 4.24M3 17l14-14\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Desktop: Full toolbar -->\n <div class=\"sdc-editor-toolbar__desktop\">\n <!-- Text formatting group -->\n @if (hasFormattingOptions()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().bold) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('bold')\"\n (click)=\"toggleBold()\"\n title=\"Bold\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 4h5a3 3 0 0 1 0 6H6zm0 6h6a3 3 0 0 1 0 6H6z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().italic) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('italic')\"\n (click)=\"toggleItalic()\"\n title=\"Italic\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M10 4h6M4 16h6m2-12l-6 16\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().underline) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('underline')\"\n (click)=\"toggleUnderline()\"\n title=\"Underline\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 4v5a4 4 0 0 0 8 0V4M4 17h12\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().strike) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('strike')\"\n (click)=\"toggleStrike()\"\n title=\"Strikethrough\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 10h12M7 4c-1.5 0-3 1-3 3s1.5 3 3 3h6c1.5 0 3 1 3 3s-1.5 3-3 3\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n\n <div class=\"sdc-editor-toolbar__separator\"></div>\n }\n\n <!-- List group -->\n @if (hasListOptions()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().bulletList) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('bulletList')\"\n (click)=\"toggleBulletList()\"\n title=\"Bullet List\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <circle cx=\"5\" cy=\"5\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"5\" cy=\"10\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"5\" cy=\"15\" r=\"1.5\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"4\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"9\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"14\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().orderedList) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('orderedList')\"\n (click)=\"toggleOrderedList()\"\n title=\"Ordered List\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <text x=\"3\" y=\"7\" font-size=\"6\" fill=\"currentColor\">1.</text>\n <text x=\"3\" y=\"12\" font-size=\"6\" fill=\"currentColor\">2.</text>\n <text x=\"3\" y=\"17\" font-size=\"6\" fill=\"currentColor\">3.</text>\n <rect x=\"9\" y=\"4\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"9\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"14\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n }\n </div>\n\n <div class=\"sdc-editor-toolbar__separator\"></div>\n }\n\n <!-- Headings group -->\n @if (hasHeadings()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @for (level of mergedConfig().headings; track level) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button sdc-editor-toolbar__button--text\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('heading', { level })\"\n (click)=\"toggleHeading(level)\"\n [title]=\"'Heading ' + level\">\n H{{ level }}\n </button>\n }\n </div>\n\n <div class=\"sdc-editor-toolbar__separator\"></div>\n }\n\n <!-- Block formatting group -->\n @if (mergedConfig().blockquote || mergedConfig().horizontalRule || hasCodeOptions()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().blockquote) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('blockquote')\"\n (click)=\"toggleBlockquote()\"\n title=\"Blockquote\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 8h4v4H4zM12 8h4v4h-4zM4 12v2a2 2 0 0 0 2 2M12 12v2a2 2 0 0 0 2 2\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().code) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('code')\"\n (click)=\"toggleCode()\"\n title=\"Inline Code\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M7 5l-4 5 4 5M13 5l4 5-4 5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().codeBlock) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('codeBlock')\"\n (click)=\"toggleCodeBlock()\"\n title=\"Code Block\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <rect x=\"2\" y=\"2\" width=\"16\" height=\"16\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"2\" />\n <path d=\"M6 7l-2 3 2 3M10 7l2 3-2 3\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().horizontalRule) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"insertHorizontalRule()\"\n title=\"Horizontal Rule\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M2 10h16\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n </div>\n\n <div class=\"sdc-editor-toolbar__separator\"></div>\n }\n\n <!-- Link group -->\n @if (mergedConfig().link) {\n <div class=\"sdc-editor-toolbar__button-group\">\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('link')\"\n (click)=\"setLink()\"\n title=\"Insert Link\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M8 12a3 3 0 0 0 4.24 0l3.5-3.5a3 3 0 0 0-4.24-4.24l-.88.87M12 8a3 3 0 0 0-4.24 0l-3.5 3.5a3 3 0 0 0 4.24 4.24l.88-.87\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n @if (isActive('link')) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"unsetLink()\"\n title=\"Remove Link\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M8 12a3 3 0 0 0 4.24 0l3.5-3.5a3 3 0 0 0-4.24-4.24M12 8a3 3 0 0 0-4.24 0l-3.5 3.5a3 3 0 0 0 4.24 4.24M3 17l14-14\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n }\n\n <!-- History group -->\n @if (hasHistory()) {\n <div class=\"sdc-editor-toolbar__separator\"></div>\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().undo) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"undo()\"\n title=\"Undo\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 8h10a4 4 0 0 1 0 8H10M4 8l4-4M4 8l4 4\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().redo) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"redo()\"\n title=\"Redo\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M16 8H6a4 4 0 0 0 0 8h4M16 8l-4-4M16 8l-4 4\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n }\n\n <!-- Custom buttons -->\n @if (mergedConfig().customButtons && mergedConfig().customButtons!.length > 0) {\n <div class=\"sdc-editor-toolbar__separator\"></div>\n <div class=\"sdc-editor-toolbar__button-group\">\n @for (btn of mergedConfig().customButtons; track btn.id) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"btn.isActive ? btn.isActive() : false\"\n (click)=\"btn.action()\"\n [title]=\"btn.title\"\n [innerHTML]=\"btn.icon\">\n </button>\n }\n </div>\n }\n </div>\n</div>\n", styles: [".sdc-editor-toolbar{width:100%}.sdc-editor-toolbar__mobile{display:block}@media (min-width: 768px){.sdc-editor-toolbar__mobile{display:none}}.sdc-editor-toolbar__mobile-container{background-color:var(--sdc-toolbar-bg, #ffffff);border:1px solid var(--sdc-toolbar-border, #e5e7eb);border-radius:.5rem;overflow:hidden}.sdc-editor-toolbar__mobile-primary{display:flex;align-items:center;justify-content:space-between;padding:.5rem}.sdc-editor-toolbar__mobile-expanded{border-top:1px solid var(--sdc-toolbar-border, #e5e7eb);padding:.5rem;background-color:var(--sdc-toolbar-expanded-bg, #f9fafb);display:flex;flex-wrap:wrap;gap:.5rem}.sdc-editor-toolbar__desktop{display:none}@media (min-width: 768px){.sdc-editor-toolbar__desktop{display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;background-color:var(--sdc-toolbar-bg, #ffffff);border:1px solid var(--sdc-toolbar-border, #e5e7eb);border-radius:.5rem;padding:.25rem}}.sdc-editor-toolbar__button-group{display:flex;gap:.125rem}.sdc-editor-toolbar__separator{width:1px;height:1.5rem;background-color:var(--sdc-toolbar-separator, #d1d5db);margin:0 .25rem}.sdc-editor-toolbar__button{display:inline-flex;align-items:center;justify-content:center;padding:.5rem;border-radius:.375rem;border:none;background:transparent;color:var(--sdc-toolbar-button-color, #4b5563);cursor:pointer;transition:background-color .15s ease,color .15s ease;min-width:2rem;min-height:2rem}.sdc-editor-toolbar__button:hover{background-color:var(--sdc-toolbar-button-hover-bg, #f3f4f6)}.sdc-editor-toolbar__button--active{background-color:var(--sdc-toolbar-button-active-bg, #dbeafe);color:var(--sdc-toolbar-button-active-color, #2563eb)}.sdc-editor-toolbar__button--active:hover{background-color:var(--sdc-toolbar-button-active-hover-bg, #bfdbfe)}.sdc-editor-toolbar__button--text{font-weight:600;font-size:.875rem;padding:.375rem .5rem}.sdc-editor-toolbar__toggle svg{transition:transform .2s ease}.sdc-editor-toolbar__toggle--open svg{transform:rotate(180deg)}:host-context(.theme-sdc) .sdc-editor-toolbar__button--active{background-color:#e0f2fe;color:#0369a1}:host-context(.theme-sdc) .sdc-editor-toolbar__button--active:hover{background-color:#bae6fd}:host-context(.theme-backoffice) .sdc-editor-toolbar{--sdc-toolbar-bg: #ffffff;--sdc-toolbar-border: #d1d5db;--sdc-toolbar-button-color: #374151}:host-context(.theme-backoffice) .sdc-editor-toolbar__button--active{background-color:#fed7aa;color:#c2410c}:host-context(.theme-backoffice) .sdc-editor-toolbar__button--active:hover{background-color:#fdba74}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5778
+ }
5779
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EditorToolbarComponent, decorators: [{
5780
+ type: Component,
5781
+ args: [{ selector: 'sdc-editor-toolbar', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"sdc-editor-toolbar\">\n <!-- Mobile: Expandable toolbar -->\n <div class=\"sdc-editor-toolbar__mobile\">\n <div class=\"sdc-editor-toolbar__mobile-container\">\n <!-- Primary actions row -->\n <div class=\"sdc-editor-toolbar__mobile-primary\">\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().bold) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('bold')\"\n (click)=\"toggleBold()\"\n title=\"Bold\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 4h5a3 3 0 0 1 0 6H6zm0 6h6a3 3 0 0 1 0 6H6z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().italic) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('italic')\"\n (click)=\"toggleItalic()\"\n title=\"Italic\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M10 4h6M4 16h6m2-12l-6 16\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().link) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('link')\"\n (click)=\"setLink()\"\n title=\"Link\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M8 12a3 3 0 0 0 4.24 0l3.5-3.5a3 3 0 0 0-4.24-4.24l-.88.87M12 8a3 3 0 0 0-4.24 0l-3.5 3.5a3 3 0 0 0 4.24 4.24l.88-.87\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n\n <!-- Toggle button -->\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button sdc-editor-toolbar__toggle\"\n [class.sdc-editor-toolbar__toggle--open]=\"showMobileMenu()\"\n (click)=\"toggleMobileMenu()\"\n title=\"More options\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 8l4 4 4-4\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <!-- Expanded toolbar -->\n @if (showMobileMenu()) {\n <div class=\"sdc-editor-toolbar__mobile-expanded\">\n <!-- Text formatting -->\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().underline) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('underline')\"\n (click)=\"toggleUnderline()\"\n title=\"Underline\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 4v5a4 4 0 0 0 8 0V4M4 17h12\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().strike) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('strike')\"\n (click)=\"toggleStrike()\"\n title=\"Strikethrough\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 10h12M7 4c-1.5 0-3 1-3 3s1.5 3 3 3h6c1.5 0 3 1 3 3s-1.5 3-3 3\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().bulletList) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('bulletList')\"\n (click)=\"toggleBulletList()\"\n title=\"Bullet List\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <circle cx=\"5\" cy=\"5\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"5\" cy=\"10\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"5\" cy=\"15\" r=\"1.5\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"4\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"9\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"14\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().orderedList) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('orderedList')\"\n (click)=\"toggleOrderedList()\"\n title=\"Ordered List\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <text x=\"3\" y=\"7\" font-size=\"6\" fill=\"currentColor\">1.</text>\n <text x=\"3\" y=\"12\" font-size=\"6\" fill=\"currentColor\">2.</text>\n <text x=\"3\" y=\"17\" font-size=\"6\" fill=\"currentColor\">3.</text>\n <rect x=\"9\" y=\"4\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"9\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"14\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n }\n </div>\n\n <!-- Headings -->\n @if (hasHeadings()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @for (level of mergedConfig().headings; track level) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button sdc-editor-toolbar__button--text\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('heading', { level })\"\n (click)=\"toggleHeading(level)\"\n [title]=\"'Heading ' + level\">\n H{{ level }}\n </button>\n }\n </div>\n }\n\n <!-- Extra options -->\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().blockquote) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('blockquote')\"\n (click)=\"toggleBlockquote()\"\n title=\"Blockquote\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 8h4v4H4zM12 8h4v4h-4zM4 12v2a2 2 0 0 0 2 2M12 12v2a2 2 0 0 0 2 2\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().horizontalRule) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"insertHorizontalRule()\"\n title=\"Horizontal Rule\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M2 10h16\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n\n @if (isActive('link')) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"unsetLink()\"\n title=\"Remove Link\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M8 12a3 3 0 0 0 4.24 0l3.5-3.5a3 3 0 0 0-4.24-4.24M12 8a3 3 0 0 0-4.24 0l-3.5 3.5a3 3 0 0 0 4.24 4.24M3 17l14-14\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Desktop: Full toolbar -->\n <div class=\"sdc-editor-toolbar__desktop\">\n <!-- Text formatting group -->\n @if (hasFormattingOptions()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().bold) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('bold')\"\n (click)=\"toggleBold()\"\n title=\"Bold\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 4h5a3 3 0 0 1 0 6H6zm0 6h6a3 3 0 0 1 0 6H6z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().italic) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('italic')\"\n (click)=\"toggleItalic()\"\n title=\"Italic\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M10 4h6M4 16h6m2-12l-6 16\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().underline) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('underline')\"\n (click)=\"toggleUnderline()\"\n title=\"Underline\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M6 4v5a4 4 0 0 0 8 0V4M4 17h12\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().strike) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('strike')\"\n (click)=\"toggleStrike()\"\n title=\"Strikethrough\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 10h12M7 4c-1.5 0-3 1-3 3s1.5 3 3 3h6c1.5 0 3 1 3 3s-1.5 3-3 3\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n\n <div class=\"sdc-editor-toolbar__separator\"></div>\n }\n\n <!-- List group -->\n @if (hasListOptions()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().bulletList) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('bulletList')\"\n (click)=\"toggleBulletList()\"\n title=\"Bullet List\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <circle cx=\"5\" cy=\"5\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"5\" cy=\"10\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"5\" cy=\"15\" r=\"1.5\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"4\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"9\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"14\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().orderedList) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('orderedList')\"\n (click)=\"toggleOrderedList()\"\n title=\"Ordered List\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <text x=\"3\" y=\"7\" font-size=\"6\" fill=\"currentColor\">1.</text>\n <text x=\"3\" y=\"12\" font-size=\"6\" fill=\"currentColor\">2.</text>\n <text x=\"3\" y=\"17\" font-size=\"6\" fill=\"currentColor\">3.</text>\n <rect x=\"9\" y=\"4\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"9\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"9\" y=\"14\" width=\"8\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n }\n </div>\n\n <div class=\"sdc-editor-toolbar__separator\"></div>\n }\n\n <!-- Headings group -->\n @if (hasHeadings()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @for (level of mergedConfig().headings; track level) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button sdc-editor-toolbar__button--text\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('heading', { level })\"\n (click)=\"toggleHeading(level)\"\n [title]=\"'Heading ' + level\">\n H{{ level }}\n </button>\n }\n </div>\n\n <div class=\"sdc-editor-toolbar__separator\"></div>\n }\n\n <!-- Block formatting group -->\n @if (mergedConfig().blockquote || mergedConfig().horizontalRule || hasCodeOptions()) {\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().blockquote) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('blockquote')\"\n (click)=\"toggleBlockquote()\"\n title=\"Blockquote\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 8h4v4H4zM12 8h4v4h-4zM4 12v2a2 2 0 0 0 2 2M12 12v2a2 2 0 0 0 2 2\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().code) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('code')\"\n (click)=\"toggleCode()\"\n title=\"Inline Code\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M7 5l-4 5 4 5M13 5l4 5-4 5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().codeBlock) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('codeBlock')\"\n (click)=\"toggleCodeBlock()\"\n title=\"Code Block\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <rect x=\"2\" y=\"2\" width=\"16\" height=\"16\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"2\" />\n <path d=\"M6 7l-2 3 2 3M10 7l2 3-2 3\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().horizontalRule) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"insertHorizontalRule()\"\n title=\"Horizontal Rule\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M2 10h16\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n </div>\n\n <div class=\"sdc-editor-toolbar__separator\"></div>\n }\n\n <!-- Link group -->\n @if (mergedConfig().link) {\n <div class=\"sdc-editor-toolbar__button-group\">\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"isActive('link')\"\n (click)=\"setLink()\"\n title=\"Insert Link\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M8 12a3 3 0 0 0 4.24 0l3.5-3.5a3 3 0 0 0-4.24-4.24l-.88.87M12 8a3 3 0 0 0-4.24 0l-3.5 3.5a3 3 0 0 0 4.24 4.24l.88-.87\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n @if (isActive('link')) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"unsetLink()\"\n title=\"Remove Link\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M8 12a3 3 0 0 0 4.24 0l3.5-3.5a3 3 0 0 0-4.24-4.24M12 8a3 3 0 0 0-4.24 0l-3.5 3.5a3 3 0 0 0 4.24 4.24M3 17l14-14\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n }\n\n <!-- History group -->\n @if (hasHistory()) {\n <div class=\"sdc-editor-toolbar__separator\"></div>\n <div class=\"sdc-editor-toolbar__button-group\">\n @if (mergedConfig().undo) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"undo()\"\n title=\"Undo\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M4 8h10a4 4 0 0 1 0 8H10M4 8l4-4M4 8l4 4\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n\n @if (mergedConfig().redo) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n (click)=\"redo()\"\n title=\"Redo\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M16 8H6a4 4 0 0 0 0 8h4M16 8l-4-4M16 8l-4 4\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n }\n </div>\n }\n\n <!-- Custom buttons -->\n @if (mergedConfig().customButtons && mergedConfig().customButtons!.length > 0) {\n <div class=\"sdc-editor-toolbar__separator\"></div>\n <div class=\"sdc-editor-toolbar__button-group\">\n @for (btn of mergedConfig().customButtons; track btn.id) {\n <button\n type=\"button\"\n class=\"sdc-editor-toolbar__button\"\n [class.sdc-editor-toolbar__button--active]=\"btn.isActive ? btn.isActive() : false\"\n (click)=\"btn.action()\"\n [title]=\"btn.title\"\n [innerHTML]=\"btn.icon\">\n </button>\n }\n </div>\n }\n </div>\n</div>\n", styles: [".sdc-editor-toolbar{width:100%}.sdc-editor-toolbar__mobile{display:block}@media (min-width: 768px){.sdc-editor-toolbar__mobile{display:none}}.sdc-editor-toolbar__mobile-container{background-color:var(--sdc-toolbar-bg, #ffffff);border:1px solid var(--sdc-toolbar-border, #e5e7eb);border-radius:.5rem;overflow:hidden}.sdc-editor-toolbar__mobile-primary{display:flex;align-items:center;justify-content:space-between;padding:.5rem}.sdc-editor-toolbar__mobile-expanded{border-top:1px solid var(--sdc-toolbar-border, #e5e7eb);padding:.5rem;background-color:var(--sdc-toolbar-expanded-bg, #f9fafb);display:flex;flex-wrap:wrap;gap:.5rem}.sdc-editor-toolbar__desktop{display:none}@media (min-width: 768px){.sdc-editor-toolbar__desktop{display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;background-color:var(--sdc-toolbar-bg, #ffffff);border:1px solid var(--sdc-toolbar-border, #e5e7eb);border-radius:.5rem;padding:.25rem}}.sdc-editor-toolbar__button-group{display:flex;gap:.125rem}.sdc-editor-toolbar__separator{width:1px;height:1.5rem;background-color:var(--sdc-toolbar-separator, #d1d5db);margin:0 .25rem}.sdc-editor-toolbar__button{display:inline-flex;align-items:center;justify-content:center;padding:.5rem;border-radius:.375rem;border:none;background:transparent;color:var(--sdc-toolbar-button-color, #4b5563);cursor:pointer;transition:background-color .15s ease,color .15s ease;min-width:2rem;min-height:2rem}.sdc-editor-toolbar__button:hover{background-color:var(--sdc-toolbar-button-hover-bg, #f3f4f6)}.sdc-editor-toolbar__button--active{background-color:var(--sdc-toolbar-button-active-bg, #dbeafe);color:var(--sdc-toolbar-button-active-color, #2563eb)}.sdc-editor-toolbar__button--active:hover{background-color:var(--sdc-toolbar-button-active-hover-bg, #bfdbfe)}.sdc-editor-toolbar__button--text{font-weight:600;font-size:.875rem;padding:.375rem .5rem}.sdc-editor-toolbar__toggle svg{transition:transform .2s ease}.sdc-editor-toolbar__toggle--open svg{transform:rotate(180deg)}:host-context(.theme-sdc) .sdc-editor-toolbar__button--active{background-color:#e0f2fe;color:#0369a1}:host-context(.theme-sdc) .sdc-editor-toolbar__button--active:hover{background-color:#bae6fd}:host-context(.theme-backoffice) .sdc-editor-toolbar{--sdc-toolbar-bg: #ffffff;--sdc-toolbar-border: #d1d5db;--sdc-toolbar-button-color: #374151}:host-context(.theme-backoffice) .sdc-editor-toolbar__button--active{background-color:#fed7aa;color:#c2410c}:host-context(.theme-backoffice) .sdc-editor-toolbar__button--active:hover{background-color:#fdba74}\n"] }]
5782
+ }] });
5783
+
5784
+ /**
5785
+ * Modal component for inserting/editing links in the rich text editor
5786
+ */
5787
+ class LinkModalComponent {
5788
+ fb = inject(FormBuilder);
5789
+ /** Whether the modal is visible */
5790
+ visible = input(false);
5791
+ /** Pre-selected text to use as link text */
5792
+ selectedText = input('');
5793
+ /** Existing URL when editing a link */
5794
+ existingUrl = input('');
5795
+ /** Event emitted when a link is added/updated */
5796
+ linkAdded = output();
5797
+ /** Event emitted when the modal is closed */
5798
+ closed = output();
5799
+ /** Form group for link data */
5800
+ linkForm;
5801
+ /** Track if form was submitted to show validation errors */
5802
+ submitted = signal(false);
5803
+ /** Computed title based on whether we're editing or adding */
5804
+ modalTitle = computed(() => {
5805
+ return this.existingUrl() ? 'Edit Link' : 'Add Link';
5806
+ });
5807
+ constructor() {
5808
+ this.linkForm = this.fb.group({
5809
+ url: ['', [Validators.required, Validators.pattern('https?://.+')]],
5810
+ text: ['', Validators.required],
5811
+ });
5812
+ // Effect to update form when inputs change
5813
+ effect(() => {
5814
+ const text = this.selectedText();
5815
+ const url = this.existingUrl();
5816
+ const isVisible = this.visible();
5817
+ if (isVisible) {
5818
+ this.linkForm.patchValue({
5819
+ text: text || '',
5820
+ url: url || '',
5821
+ });
5822
+ this.submitted.set(false);
5823
+ }
5824
+ });
5825
+ }
5826
+ /** Submit the form and emit link data */
5827
+ addLink() {
5828
+ this.submitted.set(true);
5829
+ if (this.linkForm.valid) {
5830
+ const { url, text } = this.linkForm.value;
5831
+ this.linkAdded.emit({ url, text });
5832
+ this.closeModal();
5833
+ }
5834
+ else {
5835
+ this.linkForm.markAllAsTouched();
5836
+ }
5837
+ }
5838
+ /** Close the modal and reset form */
5839
+ closeModal() {
5840
+ this.closed.emit();
5841
+ this.linkForm.reset();
5842
+ this.submitted.set(false);
5843
+ }
5844
+ /** Check if a field has errors and should show them */
5845
+ hasError(fieldName) {
5846
+ const field = this.linkForm.get(fieldName);
5847
+ return !!(field?.invalid && (field?.touched || this.submitted()));
5848
+ }
5849
+ /** Get specific error for a field */
5850
+ getError(fieldName, errorType) {
5851
+ const field = this.linkForm.get(fieldName);
5852
+ return !!field?.errors?.[errorType];
5853
+ }
5854
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LinkModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5855
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: LinkModalComponent, isStandalone: true, selector: "sdc-link-modal", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, selectedText: { classPropertyName: "selectedText", publicName: "selectedText", isSignal: true, isRequired: false, transformFunction: null }, existingUrl: { classPropertyName: "existingUrl", publicName: "existingUrl", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { linkAdded: "linkAdded", closed: "closed" }, ngImport: i0, template: "@if (visible()) {\n <div class=\"sdc-link-modal__overlay\" (click)=\"closeModal()\">\n <div class=\"sdc-link-modal__container\" (click)=\"$event.stopPropagation()\">\n <!-- Header -->\n <div class=\"sdc-link-modal__header\">\n <h3 class=\"sdc-link-modal__title\">{{ modalTitle() }}</h3>\n <button\n type=\"button\"\n class=\"sdc-link-modal__close\"\n (click)=\"closeModal()\"\n aria-label=\"Close\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M15 5L5 15M5 5l10 10\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"sdc-link-modal__content\">\n <form [formGroup]=\"linkForm\" class=\"sdc-link-modal__form\">\n <!-- Link Text Field -->\n <div class=\"sdc-link-modal__field\">\n <label for=\"linkText\" class=\"sdc-link-modal__label\">\n Link Text\n </label>\n <input\n id=\"linkText\"\n type=\"text\"\n formControlName=\"text\"\n placeholder=\"Enter link text\"\n class=\"sdc-link-modal__input\"\n [class.sdc-link-modal__input--error]=\"hasError('text')\" />\n @if (hasError('text')) {\n <span class=\"sdc-link-modal__error\">\n Link text is required\n </span>\n }\n </div>\n\n <!-- URL Field -->\n <div class=\"sdc-link-modal__field\">\n <label for=\"linkUrl\" class=\"sdc-link-modal__label\">\n URL\n </label>\n <input\n id=\"linkUrl\"\n type=\"url\"\n formControlName=\"url\"\n placeholder=\"https://example.com\"\n class=\"sdc-link-modal__input\"\n [class.sdc-link-modal__input--error]=\"hasError('url')\" />\n @if (hasError('url')) {\n <span class=\"sdc-link-modal__error\">\n @if (getError('url', 'required')) {\n URL is required\n } @else if (getError('url', 'pattern')) {\n URL must start with http:// or https://\n }\n </span>\n }\n <span class=\"sdc-link-modal__hint\">\n Must start with http:// or https://\n </span>\n </div>\n </form>\n </div>\n\n <!-- Footer -->\n <div class=\"sdc-link-modal__footer\">\n <button\n type=\"button\"\n class=\"sdc-link-modal__button sdc-link-modal__button--secondary\"\n (click)=\"closeModal()\">\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"sdc-link-modal__button sdc-link-modal__button--primary\"\n [disabled]=\"linkForm.invalid\"\n (click)=\"addLink()\">\n {{ existingUrl() ? 'Update' : 'Add' }} Link\n </button>\n </div>\n </div>\n </div>\n}\n", styles: [".sdc-link-modal__overlay{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;padding:1rem}.sdc-link-modal__container{background-color:var(--sdc-modal-bg, #ffffff);border-radius:1rem;box-shadow:0 25px 50px -12px #00000040;max-width:28rem;width:100%;overflow:hidden;animation:sdc-modal-enter .2s ease-out}@keyframes sdc-modal-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.sdc-link-modal__header{display:flex;align-items:center;justify-content:space-between;padding:1.25rem 1.5rem;border-bottom:1px solid var(--sdc-modal-border, #e5e7eb)}.sdc-link-modal__title{margin:0;font-size:1.125rem;font-weight:600;color:var(--sdc-modal-title-color, #111827)}.sdc-link-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;color:var(--sdc-modal-close-color, #6b7280);border-radius:.375rem;cursor:pointer;transition:background-color .15s ease,color .15s ease}.sdc-link-modal__close:hover{background-color:var(--sdc-modal-close-hover-bg, #f3f4f6);color:var(--sdc-modal-close-hover-color, #111827)}.sdc-link-modal__content{padding:1.5rem}.sdc-link-modal__form{display:flex;flex-direction:column;gap:1.25rem}.sdc-link-modal__field{display:flex;flex-direction:column;gap:.5rem}.sdc-link-modal__label{font-size:.875rem;font-weight:500;color:var(--sdc-modal-label-color, #374151)}.sdc-link-modal__input{width:100%;padding:.75rem 1rem;border:1px solid var(--sdc-modal-input-border, #d1d5db);border-radius:.5rem;font-size:1rem;color:var(--sdc-modal-input-color, #111827);background-color:var(--sdc-modal-input-bg, #ffffff);transition:border-color .15s ease,box-shadow .15s ease}.sdc-link-modal__input:focus{outline:none;border-color:var(--sdc-modal-input-focus-border, #3b82f6);box-shadow:0 0 0 3px var(--sdc-modal-input-focus-ring, rgba(59, 130, 246, .1))}.sdc-link-modal__input::placeholder{color:var(--sdc-modal-input-placeholder, #9ca3af)}.sdc-link-modal__input--error{border-color:var(--sdc-modal-input-error-border, #ef4444)}.sdc-link-modal__input--error:focus{border-color:var(--sdc-modal-input-error-border, #ef4444);box-shadow:0 0 0 3px var(--sdc-modal-input-error-ring, rgba(239, 68, 68, .1))}.sdc-link-modal__error{font-size:.75rem;color:var(--sdc-modal-error-color, #ef4444)}.sdc-link-modal__hint{font-size:.75rem;color:var(--sdc-modal-hint-color, #6b7280)}.sdc-link-modal__footer{display:flex;justify-content:flex-end;gap:.75rem;padding:1rem 1.5rem;border-top:1px solid var(--sdc-modal-border, #e5e7eb);background-color:var(--sdc-modal-footer-bg, #f9fafb)}.sdc-link-modal__button{display:inline-flex;align-items:center;justify-content:center;padding:.625rem 1.25rem;font-size:.875rem;font-weight:500;border-radius:.5rem;cursor:pointer;transition:background-color .15s ease,color .15s ease,opacity .15s ease}.sdc-link-modal__button--secondary{background-color:var(--sdc-modal-btn-secondary-bg, #ffffff);border:1px solid var(--sdc-modal-btn-secondary-border, #d1d5db);color:var(--sdc-modal-btn-secondary-color, #374151)}.sdc-link-modal__button--secondary:hover{background-color:var(--sdc-modal-btn-secondary-hover-bg, #f3f4f6)}.sdc-link-modal__button--primary{background-color:var(--sdc-modal-btn-primary-bg, #3b82f6);border:1px solid transparent;color:var(--sdc-modal-btn-primary-color, #ffffff)}.sdc-link-modal__button--primary:hover{background-color:var(--sdc-modal-btn-primary-hover-bg, #2563eb)}.sdc-link-modal__button--primary:disabled{opacity:.5;cursor:not-allowed}:host-context(.theme-sdc) .sdc-link-modal__button--primary{background-color:#0ea5e9}:host-context(.theme-sdc) .sdc-link-modal__button--primary:hover{background-color:#0284c7}:host-context(.theme-backoffice) .sdc-link-modal__button--primary{background-color:#f97316}:host-context(.theme-backoffice) .sdc-link-modal__button--primary:hover{background-color:#ea580c}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5856
+ }
5857
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LinkModalComponent, decorators: [{
5858
+ type: Component,
5859
+ args: [{ selector: 'sdc-link-modal', standalone: true, imports: [ReactiveFormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible()) {\n <div class=\"sdc-link-modal__overlay\" (click)=\"closeModal()\">\n <div class=\"sdc-link-modal__container\" (click)=\"$event.stopPropagation()\">\n <!-- Header -->\n <div class=\"sdc-link-modal__header\">\n <h3 class=\"sdc-link-modal__title\">{{ modalTitle() }}</h3>\n <button\n type=\"button\"\n class=\"sdc-link-modal__close\"\n (click)=\"closeModal()\"\n aria-label=\"Close\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M15 5L5 15M5 5l10 10\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"sdc-link-modal__content\">\n <form [formGroup]=\"linkForm\" class=\"sdc-link-modal__form\">\n <!-- Link Text Field -->\n <div class=\"sdc-link-modal__field\">\n <label for=\"linkText\" class=\"sdc-link-modal__label\">\n Link Text\n </label>\n <input\n id=\"linkText\"\n type=\"text\"\n formControlName=\"text\"\n placeholder=\"Enter link text\"\n class=\"sdc-link-modal__input\"\n [class.sdc-link-modal__input--error]=\"hasError('text')\" />\n @if (hasError('text')) {\n <span class=\"sdc-link-modal__error\">\n Link text is required\n </span>\n }\n </div>\n\n <!-- URL Field -->\n <div class=\"sdc-link-modal__field\">\n <label for=\"linkUrl\" class=\"sdc-link-modal__label\">\n URL\n </label>\n <input\n id=\"linkUrl\"\n type=\"url\"\n formControlName=\"url\"\n placeholder=\"https://example.com\"\n class=\"sdc-link-modal__input\"\n [class.sdc-link-modal__input--error]=\"hasError('url')\" />\n @if (hasError('url')) {\n <span class=\"sdc-link-modal__error\">\n @if (getError('url', 'required')) {\n URL is required\n } @else if (getError('url', 'pattern')) {\n URL must start with http:// or https://\n }\n </span>\n }\n <span class=\"sdc-link-modal__hint\">\n Must start with http:// or https://\n </span>\n </div>\n </form>\n </div>\n\n <!-- Footer -->\n <div class=\"sdc-link-modal__footer\">\n <button\n type=\"button\"\n class=\"sdc-link-modal__button sdc-link-modal__button--secondary\"\n (click)=\"closeModal()\">\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"sdc-link-modal__button sdc-link-modal__button--primary\"\n [disabled]=\"linkForm.invalid\"\n (click)=\"addLink()\">\n {{ existingUrl() ? 'Update' : 'Add' }} Link\n </button>\n </div>\n </div>\n </div>\n}\n", styles: [".sdc-link-modal__overlay{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;padding:1rem}.sdc-link-modal__container{background-color:var(--sdc-modal-bg, #ffffff);border-radius:1rem;box-shadow:0 25px 50px -12px #00000040;max-width:28rem;width:100%;overflow:hidden;animation:sdc-modal-enter .2s ease-out}@keyframes sdc-modal-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.sdc-link-modal__header{display:flex;align-items:center;justify-content:space-between;padding:1.25rem 1.5rem;border-bottom:1px solid var(--sdc-modal-border, #e5e7eb)}.sdc-link-modal__title{margin:0;font-size:1.125rem;font-weight:600;color:var(--sdc-modal-title-color, #111827)}.sdc-link-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;color:var(--sdc-modal-close-color, #6b7280);border-radius:.375rem;cursor:pointer;transition:background-color .15s ease,color .15s ease}.sdc-link-modal__close:hover{background-color:var(--sdc-modal-close-hover-bg, #f3f4f6);color:var(--sdc-modal-close-hover-color, #111827)}.sdc-link-modal__content{padding:1.5rem}.sdc-link-modal__form{display:flex;flex-direction:column;gap:1.25rem}.sdc-link-modal__field{display:flex;flex-direction:column;gap:.5rem}.sdc-link-modal__label{font-size:.875rem;font-weight:500;color:var(--sdc-modal-label-color, #374151)}.sdc-link-modal__input{width:100%;padding:.75rem 1rem;border:1px solid var(--sdc-modal-input-border, #d1d5db);border-radius:.5rem;font-size:1rem;color:var(--sdc-modal-input-color, #111827);background-color:var(--sdc-modal-input-bg, #ffffff);transition:border-color .15s ease,box-shadow .15s ease}.sdc-link-modal__input:focus{outline:none;border-color:var(--sdc-modal-input-focus-border, #3b82f6);box-shadow:0 0 0 3px var(--sdc-modal-input-focus-ring, rgba(59, 130, 246, .1))}.sdc-link-modal__input::placeholder{color:var(--sdc-modal-input-placeholder, #9ca3af)}.sdc-link-modal__input--error{border-color:var(--sdc-modal-input-error-border, #ef4444)}.sdc-link-modal__input--error:focus{border-color:var(--sdc-modal-input-error-border, #ef4444);box-shadow:0 0 0 3px var(--sdc-modal-input-error-ring, rgba(239, 68, 68, .1))}.sdc-link-modal__error{font-size:.75rem;color:var(--sdc-modal-error-color, #ef4444)}.sdc-link-modal__hint{font-size:.75rem;color:var(--sdc-modal-hint-color, #6b7280)}.sdc-link-modal__footer{display:flex;justify-content:flex-end;gap:.75rem;padding:1rem 1.5rem;border-top:1px solid var(--sdc-modal-border, #e5e7eb);background-color:var(--sdc-modal-footer-bg, #f9fafb)}.sdc-link-modal__button{display:inline-flex;align-items:center;justify-content:center;padding:.625rem 1.25rem;font-size:.875rem;font-weight:500;border-radius:.5rem;cursor:pointer;transition:background-color .15s ease,color .15s ease,opacity .15s ease}.sdc-link-modal__button--secondary{background-color:var(--sdc-modal-btn-secondary-bg, #ffffff);border:1px solid var(--sdc-modal-btn-secondary-border, #d1d5db);color:var(--sdc-modal-btn-secondary-color, #374151)}.sdc-link-modal__button--secondary:hover{background-color:var(--sdc-modal-btn-secondary-hover-bg, #f3f4f6)}.sdc-link-modal__button--primary{background-color:var(--sdc-modal-btn-primary-bg, #3b82f6);border:1px solid transparent;color:var(--sdc-modal-btn-primary-color, #ffffff)}.sdc-link-modal__button--primary:hover{background-color:var(--sdc-modal-btn-primary-hover-bg, #2563eb)}.sdc-link-modal__button--primary:disabled{opacity:.5;cursor:not-allowed}:host-context(.theme-sdc) .sdc-link-modal__button--primary{background-color:#0ea5e9}:host-context(.theme-sdc) .sdc-link-modal__button--primary:hover{background-color:#0284c7}:host-context(.theme-backoffice) .sdc-link-modal__button--primary{background-color:#f97316}:host-context(.theme-backoffice) .sdc-link-modal__button--primary:hover{background-color:#ea580c}\n"] }]
5860
+ }], ctorParameters: () => [] });
5861
+
5862
+ /**
5863
+ * A rich text editor component built on TipTap
5864
+ *
5865
+ * This component provides a WYSIWYG editor with configurable toolbar,
5866
+ * form integration, and theme support.
5867
+ *
5868
+ * @since 1.5.0
5869
+ */
5870
+ class RichTextEditorComponent {
5871
+ /** Editor content container element */
5872
+ editorContent = viewChild('editorContent');
5873
+ /** TipTap editor instance (signal for change detection) */
5874
+ editorSignal = signal(null);
5875
+ /** Getter for backward compatibility */
5876
+ get editor() {
5877
+ return this.editorSignal();
5878
+ }
5879
+ // ============================================
5880
+ // Input signals
5881
+ // ============================================
5882
+ /** Theme class to apply */
5883
+ theme = input('theme-sdc');
5884
+ /** Form control for two-way binding */
5885
+ control = input(null);
5886
+ /** Placeholder text when editor is empty */
5887
+ placeholder = input('');
5888
+ /** Whether the editor is disabled */
5889
+ disabled = input(false);
5890
+ /** Minimum height of the editor */
5891
+ minHeight = input('180px');
5892
+ /** Maximum height of the editor (enables scrolling) */
5893
+ maxHeight = input(null);
5894
+ /** Toolbar configuration object */
5895
+ toolbarConfig = input(DEFAULT_TOOLBAR_CONFIG);
5896
+ /** Toolbar preset name (overrides toolbarConfig) */
5897
+ toolbarPreset = input(null);
5898
+ /** Link behavior configuration */
5899
+ linkConfig = input(DEFAULT_LINK_CONFIG);
5900
+ /** Error display mode */
5901
+ errorDisplayMode = input('after-submit');
5902
+ /** Custom error message */
5903
+ errorMessage = input('');
5904
+ /** Label text */
5905
+ label = input('');
5906
+ /** Label position */
5907
+ labelPosition = input('top');
5908
+ /** Name attribute for form control */
5909
+ name = input('');
5910
+ /** Whether to autofocus the editor on init */
5911
+ autoFocus = input(false);
5912
+ // ============================================
5913
+ // Output signals
5914
+ // ============================================
5915
+ /** Emits when the editor is ready */
5916
+ editorReady = output();
5917
+ /** Emits HTML content on change */
5918
+ contentChange = output();
5919
+ /** Emits on focus */
5920
+ onFocus = output();
5921
+ /** Emits on blur */
5922
+ onBlur = output();
5923
+ // ============================================
5924
+ // Internal state
5925
+ // ============================================
5926
+ /** Form control state for validation display */
5927
+ controlState = signal({ invalid: false, touched: false, dirty: false, errors: null, isFormSubmitted: false });
5928
+ /** Link modal visibility state */
5929
+ showLinkModal = signal(false);
5930
+ /** Selected text for link modal */
5931
+ selectedText = signal('');
5932
+ /** Existing URL when editing a link */
5933
+ existingLinkUrl = signal('');
5934
+ /** Subscriptions for cleanup */
5935
+ subscriptions = [];
5936
+ /** Flag to prevent update loops */
5937
+ isUpdatingFromEditor = false;
5938
+ /** Cached form control reference (to avoid calling signals in callbacks) */
5939
+ formControlRef = null;
5940
+ // ============================================
5941
+ // Computed values
5942
+ // ============================================
5943
+ /** Computed toolbar config using preset or custom config */
5944
+ computedToolbarConfig = computed(() => {
5945
+ const preset = this.toolbarPreset();
5946
+ if (preset) {
5947
+ return TOOLBAR_PRESETS[preset];
5948
+ }
5949
+ return this.toolbarConfig();
5950
+ });
5951
+ /** Computed class string for the component */
5952
+ computedClass = computed(() => {
5953
+ const themeClass = this.theme();
5954
+ const errorClass = this.showError() ? 'has-error' : '';
5955
+ const disabledClass = this.disabled() ? 'sdc-rich-text-editor--disabled' : '';
5956
+ return ['sdc-rich-text-editor', themeClass, errorClass, disabledClass].filter(Boolean).join(' ');
5957
+ });
5958
+ /** Computed label class */
5959
+ labelClass = computed(() => {
5960
+ const position = this.labelPosition();
5961
+ return position === 'left' ? 'sdc-rich-text-editor__label left' : 'sdc-rich-text-editor__label top';
5962
+ });
5963
+ /** Whether to show the label */
5964
+ showLabel = computed(() => {
5965
+ return this.label() && this.label().trim().length > 0;
5966
+ });
5967
+ /** Current error message to display */
5968
+ currentErrorMessage = computed(() => {
5969
+ const customMessage = this.errorMessage();
5970
+ const hasErrors = Object.keys(this.controlState()?.errors ?? {}).length > 0;
5971
+ if (hasErrors && customMessage && customMessage.trim().length > 0) {
5972
+ return customMessage;
5973
+ }
5974
+ if (hasErrors) {
5975
+ const firstErrorKey = Object.keys(this.controlState()?.errors ?? {})[0];
5976
+ return this.getValidatorErrorMessage(firstErrorKey);
5977
+ }
5978
+ return '';
5979
+ });
5980
+ /** Whether to show error */
5981
+ showError = computed(() => {
5982
+ const errorMode = this.errorDisplayMode();
5983
+ if (this.controlState()?.invalid) {
5984
+ if (errorMode === 'always') {
5985
+ return this.controlState()?.touched || this.controlState()?.dirty || this.controlState()?.isFormSubmitted;
5986
+ }
5987
+ else if (errorMode === 'after-submit') {
5988
+ return this.controlState()?.isFormSubmitted;
5989
+ }
5990
+ }
5991
+ return false;
5992
+ });
5993
+ /** Computed editor styles */
5994
+ editorStyles = computed(() => {
5995
+ const styles = {
5996
+ minHeight: this.minHeight(),
5997
+ };
5998
+ const maxH = this.maxHeight();
5999
+ if (maxH) {
6000
+ styles['maxHeight'] = maxH;
6001
+ styles['overflowY'] = 'auto';
6002
+ }
6003
+ return styles;
6004
+ });
6005
+ constructor() {
6006
+ // No effects needed - disabled state is set during initialization
6007
+ // and can be updated via setDisabled() method if needed dynamically
6008
+ }
6009
+ ngOnInit() {
6010
+ // Validate required inputs
6011
+ if ((this.control() || this.showLabel()) && !this.name()) {
6012
+ console.warn('RichTextEditorComponent: name is recommended when control or label inputs are present');
6013
+ }
6014
+ // Cache the control reference to avoid calling signals in callbacks
6015
+ const ctrl = this.control();
6016
+ this.formControlRef = ctrl;
6017
+ // Subscribe to form events for validation
6018
+ const formEventsSubscription = ctrl?.parent?.events.subscribe(event => {
6019
+ if (event instanceof FormSubmittedEvent) {
6020
+ this.controlState.set({ ...this.controlState(), isFormSubmitted: true });
6021
+ if (event.source.status === 'INVALID') {
6022
+ this.controlState.set({ ...this.controlState(), invalid: true });
6023
+ }
6024
+ }
6025
+ this.updateErrors();
6026
+ });
6027
+ const statusChangesSubscription = ctrl?.statusChanges.subscribe(status => {
6028
+ if (status === 'INVALID') {
6029
+ this.controlState.set({ ...this.controlState(), invalid: true });
6030
+ }
6031
+ this.updateErrors();
6032
+ });
6033
+ if (formEventsSubscription) {
6034
+ this.subscriptions.push(formEventsSubscription);
6035
+ }
6036
+ if (statusChangesSubscription) {
6037
+ this.subscriptions.push(statusChangesSubscription);
6038
+ }
6039
+ }
6040
+ ngAfterViewInit() {
6041
+ this.initializeEditor();
6042
+ }
6043
+ ngOnDestroy() {
6044
+ this.editorSignal()?.destroy();
6045
+ this.subscriptions.forEach(sub => sub.unsubscribe());
6046
+ }
6047
+ /** Initialize the TipTap editor */
6048
+ initializeEditor() {
6049
+ const element = this.editorContent()?.nativeElement;
6050
+ if (!element)
6051
+ return;
6052
+ const linkCfg = { ...DEFAULT_LINK_CONFIG, ...this.linkConfig() };
6053
+ const newEditor = new Editor({
6054
+ element,
6055
+ extensions: [
6056
+ StarterKit.configure({
6057
+ heading: {
6058
+ levels: this.computedToolbarConfig().headings || [1, 2, 3],
6059
+ },
6060
+ }),
6061
+ Underline,
6062
+ Link.configure({
6063
+ openOnClick: linkCfg.openOnClick,
6064
+ HTMLAttributes: {
6065
+ class: linkCfg.linkClass,
6066
+ ...(linkCfg.openInNewTab ? { target: '_blank' } : {}),
6067
+ ...(linkCfg.addNoopener ? { rel: 'noopener noreferrer' } : {}),
6068
+ },
6069
+ }),
6070
+ Placeholder.configure({
6071
+ placeholder: this.placeholder(),
6072
+ }),
6073
+ ],
6074
+ content: this.formControlRef?.value || '',
6075
+ editable: !this.disabled(),
6076
+ autofocus: this.autoFocus(),
6077
+ onUpdate: ({ editor }) => {
6078
+ this.isUpdatingFromEditor = true;
6079
+ const html = editor.getHTML();
6080
+ // Update form control - cache the control reference
6081
+ const ctrl = this.formControlRef;
6082
+ if (ctrl) {
6083
+ ctrl.setValue(html, { emitEvent: false });
6084
+ ctrl.markAsDirty();
6085
+ }
6086
+ // Emit content change
6087
+ this.contentChange.emit(html);
6088
+ this.isUpdatingFromEditor = false;
6089
+ },
6090
+ onFocus: ({ event }) => {
6091
+ this.controlState.set({ ...this.controlState(), touched: true });
6092
+ this.onFocus.emit(event);
6093
+ },
6094
+ onBlur: ({ event }) => {
6095
+ this.controlState.set({ ...this.controlState(), touched: true });
6096
+ // Update errors on blur to ensure validation shows after touch
6097
+ this.updateErrors();
6098
+ this.onBlur.emit(event);
6099
+ },
6100
+ });
6101
+ // Set the signal to trigger change detection
6102
+ this.editorSignal.set(newEditor);
6103
+ this.editorReady.emit(newEditor);
6104
+ }
6105
+ /** Update error state from form control */
6106
+ updateErrors() {
6107
+ const ctrl = this.formControlRef;
6108
+ const newErrors = ctrl?.errors || null;
6109
+ this.controlState.set({
6110
+ ...this.controlState(),
6111
+ errors: newErrors,
6112
+ invalid: !!newErrors,
6113
+ });
6114
+ }
6115
+ /** Get error message for validator */
6116
+ getValidatorErrorMessage(errorKey) {
6117
+ switch (errorKey) {
6118
+ case 'required':
6119
+ return 'This field is required.';
6120
+ case 'minlength':
6121
+ return 'Content is too short.';
6122
+ case 'maxlength':
6123
+ return 'Content is too long.';
6124
+ default:
6125
+ return 'Please enter a valid value.';
6126
+ }
6127
+ }
6128
+ /** Handle link button click from toolbar */
6129
+ handleLinkRequested() {
6130
+ const editor = this.editorSignal();
6131
+ if (!editor)
6132
+ return;
6133
+ const { from, to } = editor.state.selection;
6134
+ const selectedText = editor.state.doc.textBetween(from, to);
6135
+ // Check if we're on an existing link
6136
+ const linkMark = editor.getAttributes('link');
6137
+ const existingUrl = linkMark?.href || '';
6138
+ this.selectedText.set(selectedText);
6139
+ this.existingLinkUrl.set(existingUrl);
6140
+ this.showLinkModal.set(true);
6141
+ }
6142
+ /** Handle link added from modal */
6143
+ handleLinkAdded(data) {
6144
+ const editor = this.editorSignal();
6145
+ if (!editor)
6146
+ return;
6147
+ const { url, text } = data;
6148
+ const { from, to } = editor.state.selection;
6149
+ const hasSelection = from !== to;
6150
+ if (hasSelection) {
6151
+ // Update selected text with link
6152
+ editor.chain().focus().setLink({ href: url }).run();
6153
+ }
6154
+ else {
6155
+ // Insert new link at cursor position
6156
+ editor
6157
+ .chain()
6158
+ .focus()
6159
+ .insertContent(`<a href="${url}">${text}</a>`)
6160
+ .run();
6161
+ }
6162
+ }
6163
+ /** Handle link modal close */
6164
+ handleLinkModalClose() {
6165
+ this.showLinkModal.set(false);
6166
+ this.selectedText.set('');
6167
+ this.existingLinkUrl.set('');
6168
+ }
6169
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RichTextEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6170
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: RichTextEditorComponent, isStandalone: true, selector: "sdc-rich-text-editor", inputs: { theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", 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 }, toolbarConfig: { classPropertyName: "toolbarConfig", publicName: "toolbarConfig", isSignal: true, isRequired: false, transformFunction: null }, toolbarPreset: { classPropertyName: "toolbarPreset", publicName: "toolbarPreset", isSignal: true, isRequired: false, transformFunction: null }, linkConfig: { classPropertyName: "linkConfig", publicName: "linkConfig", isSignal: true, isRequired: false, transformFunction: null }, errorDisplayMode: { classPropertyName: "errorDisplayMode", publicName: "errorDisplayMode", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelPosition: { classPropertyName: "labelPosition", publicName: "labelPosition", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { editorReady: "editorReady", contentChange: "contentChange", onFocus: "onFocus", onBlur: "onBlur" }, viewQueries: [{ propertyName: "editorContent", first: true, predicate: ["editorContent"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"computedClass()\">\n <!-- Label -->\n @if (showLabel()) {\n <label [for]=\"name()\" [class]=\"labelClass()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"sdc-rich-text-editor__wrapper\" [class.sdc-rich-text-editor__wrapper--left-label]=\"labelPosition() === 'left'\">\n <!-- Toolbar -->\n @if (editorSignal()) {\n <sdc-editor-toolbar\n [editor]=\"editorSignal()!\"\n [config]=\"computedToolbarConfig()\"\n (linkRequested)=\"handleLinkRequested()\"\n />\n }\n\n <!-- Editor content area -->\n <div\n class=\"sdc-rich-text-editor__content\"\n [class.sdc-rich-text-editor__content--error]=\"showError()\"\n [class.sdc-rich-text-editor__content--disabled]=\"disabled()\"\n [style]=\"editorStyles()\">\n <div #editorContent class=\"sdc-rich-text-editor__prosemirror\"></div>\n </div>\n\n <!-- Error message -->\n @if (showError() && currentErrorMessage()) {\n <div class=\"sdc-rich-text-editor__error\">\n {{ currentErrorMessage() }}\n </div>\n }\n </div>\n</div>\n\n<!-- Link Modal -->\n<sdc-link-modal\n [visible]=\"showLinkModal()\"\n [selectedText]=\"selectedText()\"\n [existingUrl]=\"existingLinkUrl()\"\n (linkAdded)=\"handleLinkAdded($event)\"\n (closed)=\"handleLinkModalClose()\"\n/>\n", styles: [".sdc-rich-text-editor{display:flex;flex-direction:column;gap:.5rem;width:100%;font-family:var(--sdc-font-family, system-ui, -apple-system, sans-serif)}.sdc-rich-text-editor__label{font-size:.875rem;font-weight:500;color:var(--sdc-label-color, #374151)}.sdc-rich-text-editor__label.left{min-width:8rem;padding-top:.5rem}.sdc-rich-text-editor__label.top{margin-bottom:.25rem}.sdc-rich-text-editor__wrapper{display:flex;flex-direction:column;gap:.5rem;flex:1}.sdc-rich-text-editor__wrapper--left-label{flex-direction:row;align-items:flex-start}.sdc-rich-text-editor__content{border:2px solid var(--sdc-editor-border, #e5e7eb);border-radius:.5rem;background-color:var(--sdc-editor-bg, #ffffff);transition:border-color .15s ease,box-shadow .15s ease;overflow:hidden}.sdc-rich-text-editor__content:focus-within{border-color:var(--sdc-editor-focus-border, #3b82f6);box-shadow:0 0 0 3px var(--sdc-editor-focus-ring, rgba(59, 130, 246, .1))}.sdc-rich-text-editor__content--error{border-color:var(--sdc-editor-error-border, #ef4444)}.sdc-rich-text-editor__content--error:focus-within{border-color:var(--sdc-editor-error-border, #ef4444);box-shadow:0 0 0 3px var(--sdc-editor-error-ring, rgba(239, 68, 68, .1))}.sdc-rich-text-editor__content--disabled{opacity:.6;cursor:not-allowed;background-color:var(--sdc-editor-disabled-bg, #f9fafb)}.sdc-rich-text-editor__prosemirror{padding:1rem 1.25rem}:host ::ng-deep .ProseMirror{outline:none;min-height:inherit;font-size:1rem;line-height:1.625;color:var(--sdc-editor-text-color, #111827)}:host ::ng-deep .ProseMirror:focus{outline:none}:host ::ng-deep .ProseMirror h1{font-size:2rem;font-weight:700;margin:1.5rem 0 1rem;line-height:1.25;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h2{font-size:1.5rem;font-weight:600;margin:1.25rem 0 .75rem;line-height:1.3;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h3{font-size:1.25rem;font-weight:600;margin:1rem 0 .5rem;line-height:1.4;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h4{font-size:1.125rem;font-weight:600;margin:1rem 0 .5rem;line-height:1.4;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h5,:host ::ng-deep .ProseMirror h6{font-size:1rem;font-weight:600;margin:.75rem 0 .5rem;line-height:1.5;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h1:first-child,:host ::ng-deep .ProseMirror h2:first-child,:host ::ng-deep .ProseMirror h3:first-child,:host ::ng-deep .ProseMirror h4:first-child,:host ::ng-deep .ProseMirror h5:first-child,:host ::ng-deep .ProseMirror h6:first-child{margin-top:0}:host ::ng-deep .ProseMirror p{margin:0 0 1rem}:host ::ng-deep .ProseMirror p:last-child{margin-bottom:0}:host ::ng-deep .ProseMirror a{color:var(--sdc-editor-link-color, #3b82f6);text-decoration:underline;cursor:pointer}:host ::ng-deep .ProseMirror a:hover{color:var(--sdc-editor-link-hover-color, #2563eb)}:host ::ng-deep .ProseMirror ul,:host ::ng-deep .ProseMirror ol{padding-left:1.5rem;margin:0 0 1rem}:host ::ng-deep .ProseMirror ul{list-style-type:disc}:host ::ng-deep .ProseMirror ol{list-style-type:decimal}:host ::ng-deep .ProseMirror li{margin-bottom:.25rem}:host ::ng-deep .ProseMirror li p{margin:0}:host ::ng-deep .ProseMirror ul ul,:host ::ng-deep .ProseMirror ol ol,:host ::ng-deep .ProseMirror ul ol,:host ::ng-deep .ProseMirror ol ul{margin-top:.25rem;margin-bottom:0}:host ::ng-deep .ProseMirror blockquote{border-left:4px solid var(--sdc-editor-blockquote-border, #e5e7eb);padding-left:1rem;margin:1rem 0;color:var(--sdc-editor-blockquote-color, #6b7280);font-style:italic}:host ::ng-deep .ProseMirror code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.875em;background-color:var(--sdc-editor-code-bg, #f3f4f6);padding:.125rem .375rem;border-radius:.25rem;color:var(--sdc-editor-code-color, #dc2626)}:host ::ng-deep .ProseMirror pre{background-color:var(--sdc-editor-code-block-bg, #1f2937);color:var(--sdc-editor-code-block-color, #f3f4f6);font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.875rem;padding:1rem;border-radius:.5rem;overflow-x:auto;margin:1rem 0}:host ::ng-deep .ProseMirror pre code{background:none;padding:0;color:inherit;font-size:inherit}:host ::ng-deep .ProseMirror hr{border:none;border-top:2px solid var(--sdc-editor-hr-color, #e5e7eb);margin:1.5rem 0}:host ::ng-deep .ProseMirror s{text-decoration:line-through}:host ::ng-deep .ProseMirror strong{font-weight:700}:host ::ng-deep .ProseMirror em{font-style:italic}:host ::ng-deep .ProseMirror u{text-decoration:underline}:host ::ng-deep .ProseMirror p.is-editor-empty:first-child:before{content:attr(data-placeholder);color:var(--sdc-editor-placeholder-color, #9ca3af);pointer-events:none;float:left;height:0}:host ::ng-deep .ProseMirror ::selection{background-color:var(--sdc-editor-selection-bg, rgba(59, 130, 246, .2))}.sdc-rich-text-editor__error{font-size:.75rem;color:var(--sdc-editor-error-color, #ef4444);margin-top:.25rem}.sdc-rich-text-editor--disabled .sdc-rich-text-editor__prosemirror{pointer-events:none}:host-context(.theme-sdc) .sdc-rich-text-editor__content:focus-within{border-color:#0ea5e9;box-shadow:0 0 0 3px #0ea5e91a}:host-context(.theme-sdc) ::ng-deep .ProseMirror a{color:#0ea5e9}:host-context(.theme-sdc) ::ng-deep .ProseMirror a:hover{color:#0284c7}:host-context(.theme-backoffice) .sdc-rich-text-editor__content:focus-within{border-color:#f97316;box-shadow:0 0 0 3px #f973161a}:host-context(.theme-backoffice) .sdc-rich-text-editor__content--error:focus-within{border-color:#ef4444;box-shadow:0 0 0 3px #ef44441a}:host-context(.theme-backoffice) ::ng-deep .ProseMirror a{color:#f97316}:host-context(.theme-backoffice) ::ng-deep .ProseMirror a:hover{color:#ea580c}:host-context(.theme-backoffice) ::ng-deep .ProseMirror blockquote{border-left-color:#fed7aa}@media (max-width: 640px){:host ::ng-deep .ProseMirror h1{font-size:1.5rem}:host ::ng-deep .ProseMirror h2{font-size:1.25rem}:host ::ng-deep .ProseMirror h3{font-size:1.125rem}.sdc-rich-text-editor__prosemirror{padding:.75rem 1rem}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: EditorToolbarComponent, selector: "sdc-editor-toolbar", inputs: ["editor", "config"], outputs: ["linkRequested"] }, { kind: "component", type: LinkModalComponent, selector: "sdc-link-modal", inputs: ["visible", "selectedText", "existingUrl"], outputs: ["linkAdded", "closed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6171
+ }
6172
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RichTextEditorComponent, decorators: [{
6173
+ type: Component,
6174
+ args: [{ selector: 'sdc-rich-text-editor', standalone: true, imports: [ReactiveFormsModule, EditorToolbarComponent, LinkModalComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"computedClass()\">\n <!-- Label -->\n @if (showLabel()) {\n <label [for]=\"name()\" [class]=\"labelClass()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"sdc-rich-text-editor__wrapper\" [class.sdc-rich-text-editor__wrapper--left-label]=\"labelPosition() === 'left'\">\n <!-- Toolbar -->\n @if (editorSignal()) {\n <sdc-editor-toolbar\n [editor]=\"editorSignal()!\"\n [config]=\"computedToolbarConfig()\"\n (linkRequested)=\"handleLinkRequested()\"\n />\n }\n\n <!-- Editor content area -->\n <div\n class=\"sdc-rich-text-editor__content\"\n [class.sdc-rich-text-editor__content--error]=\"showError()\"\n [class.sdc-rich-text-editor__content--disabled]=\"disabled()\"\n [style]=\"editorStyles()\">\n <div #editorContent class=\"sdc-rich-text-editor__prosemirror\"></div>\n </div>\n\n <!-- Error message -->\n @if (showError() && currentErrorMessage()) {\n <div class=\"sdc-rich-text-editor__error\">\n {{ currentErrorMessage() }}\n </div>\n }\n </div>\n</div>\n\n<!-- Link Modal -->\n<sdc-link-modal\n [visible]=\"showLinkModal()\"\n [selectedText]=\"selectedText()\"\n [existingUrl]=\"existingLinkUrl()\"\n (linkAdded)=\"handleLinkAdded($event)\"\n (closed)=\"handleLinkModalClose()\"\n/>\n", styles: [".sdc-rich-text-editor{display:flex;flex-direction:column;gap:.5rem;width:100%;font-family:var(--sdc-font-family, system-ui, -apple-system, sans-serif)}.sdc-rich-text-editor__label{font-size:.875rem;font-weight:500;color:var(--sdc-label-color, #374151)}.sdc-rich-text-editor__label.left{min-width:8rem;padding-top:.5rem}.sdc-rich-text-editor__label.top{margin-bottom:.25rem}.sdc-rich-text-editor__wrapper{display:flex;flex-direction:column;gap:.5rem;flex:1}.sdc-rich-text-editor__wrapper--left-label{flex-direction:row;align-items:flex-start}.sdc-rich-text-editor__content{border:2px solid var(--sdc-editor-border, #e5e7eb);border-radius:.5rem;background-color:var(--sdc-editor-bg, #ffffff);transition:border-color .15s ease,box-shadow .15s ease;overflow:hidden}.sdc-rich-text-editor__content:focus-within{border-color:var(--sdc-editor-focus-border, #3b82f6);box-shadow:0 0 0 3px var(--sdc-editor-focus-ring, rgba(59, 130, 246, .1))}.sdc-rich-text-editor__content--error{border-color:var(--sdc-editor-error-border, #ef4444)}.sdc-rich-text-editor__content--error:focus-within{border-color:var(--sdc-editor-error-border, #ef4444);box-shadow:0 0 0 3px var(--sdc-editor-error-ring, rgba(239, 68, 68, .1))}.sdc-rich-text-editor__content--disabled{opacity:.6;cursor:not-allowed;background-color:var(--sdc-editor-disabled-bg, #f9fafb)}.sdc-rich-text-editor__prosemirror{padding:1rem 1.25rem}:host ::ng-deep .ProseMirror{outline:none;min-height:inherit;font-size:1rem;line-height:1.625;color:var(--sdc-editor-text-color, #111827)}:host ::ng-deep .ProseMirror:focus{outline:none}:host ::ng-deep .ProseMirror h1{font-size:2rem;font-weight:700;margin:1.5rem 0 1rem;line-height:1.25;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h2{font-size:1.5rem;font-weight:600;margin:1.25rem 0 .75rem;line-height:1.3;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h3{font-size:1.25rem;font-weight:600;margin:1rem 0 .5rem;line-height:1.4;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h4{font-size:1.125rem;font-weight:600;margin:1rem 0 .5rem;line-height:1.4;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h5,:host ::ng-deep .ProseMirror h6{font-size:1rem;font-weight:600;margin:.75rem 0 .5rem;line-height:1.5;color:var(--sdc-editor-heading-color, #111827)}:host ::ng-deep .ProseMirror h1:first-child,:host ::ng-deep .ProseMirror h2:first-child,:host ::ng-deep .ProseMirror h3:first-child,:host ::ng-deep .ProseMirror h4:first-child,:host ::ng-deep .ProseMirror h5:first-child,:host ::ng-deep .ProseMirror h6:first-child{margin-top:0}:host ::ng-deep .ProseMirror p{margin:0 0 1rem}:host ::ng-deep .ProseMirror p:last-child{margin-bottom:0}:host ::ng-deep .ProseMirror a{color:var(--sdc-editor-link-color, #3b82f6);text-decoration:underline;cursor:pointer}:host ::ng-deep .ProseMirror a:hover{color:var(--sdc-editor-link-hover-color, #2563eb)}:host ::ng-deep .ProseMirror ul,:host ::ng-deep .ProseMirror ol{padding-left:1.5rem;margin:0 0 1rem}:host ::ng-deep .ProseMirror ul{list-style-type:disc}:host ::ng-deep .ProseMirror ol{list-style-type:decimal}:host ::ng-deep .ProseMirror li{margin-bottom:.25rem}:host ::ng-deep .ProseMirror li p{margin:0}:host ::ng-deep .ProseMirror ul ul,:host ::ng-deep .ProseMirror ol ol,:host ::ng-deep .ProseMirror ul ol,:host ::ng-deep .ProseMirror ol ul{margin-top:.25rem;margin-bottom:0}:host ::ng-deep .ProseMirror blockquote{border-left:4px solid var(--sdc-editor-blockquote-border, #e5e7eb);padding-left:1rem;margin:1rem 0;color:var(--sdc-editor-blockquote-color, #6b7280);font-style:italic}:host ::ng-deep .ProseMirror code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.875em;background-color:var(--sdc-editor-code-bg, #f3f4f6);padding:.125rem .375rem;border-radius:.25rem;color:var(--sdc-editor-code-color, #dc2626)}:host ::ng-deep .ProseMirror pre{background-color:var(--sdc-editor-code-block-bg, #1f2937);color:var(--sdc-editor-code-block-color, #f3f4f6);font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.875rem;padding:1rem;border-radius:.5rem;overflow-x:auto;margin:1rem 0}:host ::ng-deep .ProseMirror pre code{background:none;padding:0;color:inherit;font-size:inherit}:host ::ng-deep .ProseMirror hr{border:none;border-top:2px solid var(--sdc-editor-hr-color, #e5e7eb);margin:1.5rem 0}:host ::ng-deep .ProseMirror s{text-decoration:line-through}:host ::ng-deep .ProseMirror strong{font-weight:700}:host ::ng-deep .ProseMirror em{font-style:italic}:host ::ng-deep .ProseMirror u{text-decoration:underline}:host ::ng-deep .ProseMirror p.is-editor-empty:first-child:before{content:attr(data-placeholder);color:var(--sdc-editor-placeholder-color, #9ca3af);pointer-events:none;float:left;height:0}:host ::ng-deep .ProseMirror ::selection{background-color:var(--sdc-editor-selection-bg, rgba(59, 130, 246, .2))}.sdc-rich-text-editor__error{font-size:.75rem;color:var(--sdc-editor-error-color, #ef4444);margin-top:.25rem}.sdc-rich-text-editor--disabled .sdc-rich-text-editor__prosemirror{pointer-events:none}:host-context(.theme-sdc) .sdc-rich-text-editor__content:focus-within{border-color:#0ea5e9;box-shadow:0 0 0 3px #0ea5e91a}:host-context(.theme-sdc) ::ng-deep .ProseMirror a{color:#0ea5e9}:host-context(.theme-sdc) ::ng-deep .ProseMirror a:hover{color:#0284c7}:host-context(.theme-backoffice) .sdc-rich-text-editor__content:focus-within{border-color:#f97316;box-shadow:0 0 0 3px #f973161a}:host-context(.theme-backoffice) .sdc-rich-text-editor__content--error:focus-within{border-color:#ef4444;box-shadow:0 0 0 3px #ef44441a}:host-context(.theme-backoffice) ::ng-deep .ProseMirror a{color:#f97316}:host-context(.theme-backoffice) ::ng-deep .ProseMirror a:hover{color:#ea580c}:host-context(.theme-backoffice) ::ng-deep .ProseMirror blockquote{border-left-color:#fed7aa}@media (max-width: 640px){:host ::ng-deep .ProseMirror h1{font-size:1.5rem}:host ::ng-deep .ProseMirror h2{font-size:1.25rem}:host ::ng-deep .ProseMirror h3{font-size:1.125rem}.sdc-rich-text-editor__prosemirror{padding:.75rem 1rem}}\n"] }]
6175
+ }], ctorParameters: () => [] });
6176
+
6177
+ // Main component
6178
+
5578
6179
  class HlmSelect {
5579
6180
  userClass = input('', { alias: 'class' });
5580
6181
  _computedClass = computed(() => hlm(this.userClass()));
@@ -5963,5 +6564,5 @@ function provideScreenObserver(screens) {
5963
6564
  * Generated bundle index. Do not edit.
5964
6565
  */
5965
6566
 
5966
- export { AddDigitalWalletComponent, BasePopoverComponent, BasePopoverDataTransformer, BaseSeatDataTransformer, BaseSectionDataTransformer, BraintreeComponent, ButtonComponent, CONFIGURATION_SERVICE, CarouselComponent, CarouselItemComponent, CartComponent, CartItemComponent, CartItemService, CheckboxComponent, DVM_FORMATTER, DVM_SERVICE, DatePickerComponent, DialogComponent, HlmDialogService as DialogService, DrawerComponent, DrawerService, DvmPopoverPositionerService, InputComponent, LegendComponent, LegendElementsComponent, LoaderComponent, LoaderService, MapLoaderComponent, NeighborsComponent, POPOVER_MANAGER, POPOVER_POSITIONER, PopoverComponent, PopoverManagerService, PopoverService, RadioComponent, ScreenObserver, SeatListComponent, SeatPopoverComponent, SectionPopoverComponent, SelectComponent, StepperComponent, SvgIconComponent, THUMBNAIL_PROVIDER, TableComponent, TicketInfoItemComponent, TicketInfoItemService, applyGlobalCssVariables, provideScreenObserver, provideSdc };
6567
+ export { AddDigitalWalletComponent, BasePopoverComponent, BasePopoverDataTransformer, BaseSeatDataTransformer, BaseSectionDataTransformer, BraintreeComponent, ButtonComponent, CONFIGURATION_SERVICE, CarouselComponent, CarouselItemComponent, CartComponent, CartItemComponent, CartItemService, CheckboxComponent, DEFAULT_EDITOR_CONFIG, DEFAULT_LINK_CONFIG, DEFAULT_TOOLBAR_CONFIG, DVM_FORMATTER, DVM_SERVICE, DatePickerComponent, DialogComponent, HlmDialogService as DialogService, DrawerComponent, DrawerService, DvmPopoverPositionerService, EditorToolbarComponent, InputComponent, LegendComponent, LegendElementsComponent, LinkModalComponent, LoaderComponent, LoaderService, MapLoaderComponent, NeighborsComponent, POPOVER_MANAGER, POPOVER_POSITIONER, PopoverComponent, PopoverManagerService, PopoverService, RadioComponent, RichTextEditorComponent, ScreenObserver, SeatListComponent, SeatPopoverComponent, SectionPopoverComponent, SelectComponent, StepperComponent, SvgIconComponent, THUMBNAIL_PROVIDER, TOOLBAR_PRESETS, TableComponent, TicketInfoItemComponent, TicketInfoItemService, applyGlobalCssVariables, provideScreenObserver, provideSdc };
5967
6568
  //# sourceMappingURL=3ddv-software-division-components.mjs.map