@flogeez/angular-tiptap-editor 3.5.4 → 3.6.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +2 -2
  3. package/esm2022/lib/components/bubble-menus/color/ate-color-bubble-menu.component.mjs +12 -2
  4. package/esm2022/lib/components/editor/angular-tiptap-editor.component.mjs +99 -24
  5. package/esm2022/lib/config/ate-editor.config.mjs +3 -1
  6. package/esm2022/lib/config/ate-slash-commands.config.mjs +2 -1
  7. package/esm2022/lib/extensions/ate-block-shortcuts.extension.mjs +100 -0
  8. package/esm2022/lib/extensions/ate-pasted-image.extension.mjs +7 -3
  9. package/esm2022/lib/i18n/ateTranslationsModel.mjs +1 -1
  10. package/esm2022/lib/i18n/es_ateTranslations.mjs +230 -0
  11. package/esm2022/lib/i18n/pt_ateTranslations.mjs +220 -0
  12. package/esm2022/lib/models/ate-editor-config.model.mjs +1 -1
  13. package/esm2022/lib/models/ate-editor-ref.mjs +3 -3
  14. package/esm2022/lib/models/ate-image.model.mjs +12 -2
  15. package/esm2022/lib/services/ate-editor-commands.service.mjs +6 -3
  16. package/esm2022/lib/services/ate-i18n.service.mjs +19 -9
  17. package/esm2022/lib/services/ate-image.service.mjs +18 -11
  18. package/esm2022/lib/utils/ate-equality.utils.mjs +14 -0
  19. package/esm2022/lib/utils/ate-extensions.utils.mjs +79 -0
  20. package/esm2022/public-api.mjs +2 -1
  21. package/fesm2022/flogeez-angular-tiptap-editor.mjs +808 -50
  22. package/fesm2022/flogeez-angular-tiptap-editor.mjs.map +1 -1
  23. package/lib/components/bubble-menus/color/ate-color-bubble-menu.component.d.ts +1 -0
  24. package/lib/components/editor/angular-tiptap-editor.component.d.ts +12 -2
  25. package/lib/config/ate-slash-commands.config.d.ts +2 -0
  26. package/lib/extensions/ate-block-shortcuts.extension.d.ts +32 -0
  27. package/lib/i18n/ateTranslationsModel.d.ts +1 -1
  28. package/lib/i18n/es_ateTranslations.d.ts +2 -0
  29. package/lib/i18n/pt_ateTranslations.d.ts +2 -0
  30. package/lib/models/ate-editor-config.model.d.ts +8 -0
  31. package/lib/models/ate-image.model.d.ts +30 -2
  32. package/lib/services/ate-editor-commands.service.d.ts +2 -1
  33. package/lib/services/ate-i18n.service.d.ts +3 -1
  34. package/lib/services/ate-image.service.d.ts +5 -3
  35. package/lib/utils/ate-equality.utils.d.ts +2 -0
  36. package/lib/utils/ate-extensions.utils.d.ts +13 -0
  37. package/package.json +1 -1
  38. package/public-api.d.ts +1 -0
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, signal, inject, Injectable, computed, Directive, ApplicationRef, EnvironmentInjector, createComponent, input, booleanAttribute, effect, untracked, Component, ChangeDetectionStrategy, HostListener, ElementRef, ViewEncapsulation, output, viewChild, DestroyRef, Injector, makeEnvironmentProviders, APP_INITIALIZER } from '@angular/core';
2
+ import { InjectionToken, signal, inject, Injectable, computed, Directive, ApplicationRef, EnvironmentInjector, createComponent, input, booleanAttribute, effect, untracked, Component, ChangeDetectionStrategy, HostListener, ElementRef, ViewEncapsulation, output, viewChild, DestroyRef, Injector, isDevMode, makeEnvironmentProviders, APP_INITIALIZER } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
4
  import { Node as Node$1, mergeAttributes, nodeInputRule, Extension, getAttributes, Editor } from '@tiptap/core';
5
5
  import StarterKit from '@tiptap/starter-kit';
@@ -11,7 +11,7 @@ import { Highlight } from '@tiptap/extension-highlight';
11
11
  import { TextStyle } from '@tiptap/extension-text-style';
12
12
  import { Color } from '@tiptap/extension-color';
13
13
  import OfficePaste from '@intevation/tiptap-extension-office-paste';
14
- import { Plugin, PluginKey, TextSelection, NodeSelection } from '@tiptap/pm/state';
14
+ import { Plugin, PluginKey, NodeSelection, TextSelection } from '@tiptap/pm/state';
15
15
  import { DecorationSet, Decoration } from '@tiptap/pm/view';
16
16
  import { Fragment, Slice } from '@tiptap/pm/model';
17
17
  import { Table, TableRow, TableHeader, TableCell } from '@tiptap/extension-table';
@@ -682,6 +682,18 @@ const AteUploadProgress = Extension.create({
682
682
  },
683
683
  });
684
684
 
685
+ /**
686
+ * Thrown when an image fails validation, before compression and before `imageUploadHandler` runs.
687
+ * `message` is the translated, user-facing text.
688
+ */
689
+ class AteImageValidationError extends Error {
690
+ constructor(reason, message) {
691
+ super(message);
692
+ this.reason = reason;
693
+ this.name = "AteImageValidationError";
694
+ }
695
+ }
696
+
685
697
  const IMAGE_NODE_NAMES = new Set(["resizableImage", "image"]);
686
698
  const REMOTE_SRC = /^(https?:)?\/\//i;
687
699
  const INLINE_SRC = /^data:(image\/[\w.+-]+);base64,(.*)$/is;
@@ -812,9 +824,12 @@ const AtePastedImage = Extension.create({
812
824
  options
813
825
  .rehost(file)
814
826
  .then(url => replaceImageSrc(editor, src, url))
815
- .catch(() => {
827
+ .catch((error) => {
816
828
  replaceImageSrc(editor, src, null);
817
- options.onRejected({ reason: "upload-failed", src });
829
+ options.onRejected({
830
+ reason: error instanceof AteImageValidationError ? error.reason : "upload-failed",
831
+ src,
832
+ });
818
833
  });
819
834
  };
820
835
  return [
@@ -883,6 +898,104 @@ const AteLinkShortcut = Extension.create({
883
898
  },
884
899
  });
885
900
 
901
+ const LIST_ITEM_NODE_NAMES = new Set(["listItem", "taskItem"]);
902
+ /**
903
+ * Resolves the block the shortcuts act on: a selected block node, the list or task item
904
+ * holding the cursor, or else the top-level block holding the cursor.
905
+ */
906
+ function findBlockAtSelection(selection) {
907
+ const { $from } = selection;
908
+ if (selection instanceof NodeSelection && selection.node.isBlock) {
909
+ return {
910
+ node: selection.node,
911
+ pos: selection.from,
912
+ parent: $from.parent,
913
+ index: $from.index(),
914
+ };
915
+ }
916
+ if ($from.depth < 1) {
917
+ return null;
918
+ }
919
+ let depth = 1;
920
+ for (let current = $from.depth; current > 0; current--) {
921
+ if (LIST_ITEM_NODE_NAMES.has($from.node(current).type.name)) {
922
+ depth = current;
923
+ break;
924
+ }
925
+ }
926
+ return {
927
+ node: $from.node(depth),
928
+ pos: $from.before(depth),
929
+ parent: $from.node(depth - 1),
930
+ index: $from.index(depth - 1),
931
+ };
932
+ }
933
+ /** Inserts a copy of the current block right after it */
934
+ function duplicateBlock(state) {
935
+ const block = findBlockAtSelection(state.selection);
936
+ if (!block) {
937
+ return null;
938
+ }
939
+ return state.tr.insert(block.pos, block.node).scrollIntoView();
940
+ }
941
+ /** Swaps the current block with its previous sibling, or returns `null` at the first position */
942
+ function moveBlockUp(state) {
943
+ const block = findBlockAtSelection(state.selection);
944
+ if (!block || block.index === 0) {
945
+ return null;
946
+ }
947
+ const previous = block.parent.child(block.index - 1);
948
+ const end = block.pos + block.node.nodeSize;
949
+ return state.tr
950
+ .insert(end, previous)
951
+ .delete(block.pos - previous.nodeSize, block.pos)
952
+ .scrollIntoView();
953
+ }
954
+ /** Swaps the current block with its next sibling, or returns `null` at the last position */
955
+ function moveBlockDown(state) {
956
+ const block = findBlockAtSelection(state.selection);
957
+ if (!block || block.index >= block.parent.childCount - 1) {
958
+ return null;
959
+ }
960
+ const next = block.parent.child(block.index + 1);
961
+ const end = block.pos + block.node.nodeSize;
962
+ return state.tr
963
+ .delete(end, end + next.nodeSize)
964
+ .insert(block.pos, next)
965
+ .scrollIntoView();
966
+ }
967
+ /**
968
+ * Notion-style block shortcuts: `Mod+D` duplicates the current block, `Mod+Shift+ArrowUp` and
969
+ * `Mod+Shift+ArrowDown` move it one sibling up or down. Inside a list the block is the list
970
+ * or task item, which moves within its list. At the edges the key event is left alone.
971
+ */
972
+ const AteBlockShortcuts = Extension.create({
973
+ name: "ateBlockShortcuts",
974
+ addOptions() {
975
+ return {
976
+ enabled: () => true,
977
+ };
978
+ },
979
+ addKeyboardShortcuts() {
980
+ const run = (build) => () => {
981
+ if (!this.options.enabled() || !this.editor.isEditable) {
982
+ return false;
983
+ }
984
+ const transaction = build(this.editor.state);
985
+ if (!transaction) {
986
+ return false;
987
+ }
988
+ this.editor.view.dispatch(transaction);
989
+ return true;
990
+ };
991
+ return {
992
+ "Mod-d": run(duplicateBlock),
993
+ "Mod-Shift-ArrowUp": run(moveBlockUp),
994
+ "Mod-Shift-ArrowDown": run(moveBlockDown),
995
+ };
996
+ },
997
+ });
998
+
886
999
  const AteTableExtension = Extension.create({
887
1000
  name: "tableExtension",
888
1001
  addExtensions() {
@@ -1471,13 +1584,13 @@ class AteEditorRef {
1471
1584
  insertImage(options) {
1472
1585
  const editor = this.editor;
1473
1586
  if (editor) {
1474
- this.commandsService.insertImage(editor, options);
1587
+ this.commandsService.insertImage(editor, options).catch(() => undefined);
1475
1588
  }
1476
1589
  }
1477
1590
  uploadImage(file, options) {
1478
1591
  const editor = this.editor;
1479
1592
  if (editor) {
1480
- this.commandsService.uploadImage(editor, file, options);
1593
+ this.commandsService.uploadImage(editor, file, options).catch(() => undefined);
1481
1594
  }
1482
1595
  }
1483
1596
  toggleHighlight(color) {
@@ -2348,6 +2461,456 @@ const GERMAN_TRANSLATIONS = {
2348
2461
  },
2349
2462
  };
2350
2463
 
2464
+ const PORTUGUESE_TRANSLATIONS = {
2465
+ toolbar: {
2466
+ bold: "Negrito\nCtrl+B",
2467
+ italic: "Itálico\nCtrl+I",
2468
+ underline: "Sublinhado\nCtrl+U",
2469
+ strike: "Tachado\nCtrl+Shift+X",
2470
+ code: "Código em linha\nCtrl+E",
2471
+ codeBlock: "Bloco de código",
2472
+ superscript: "Sobrescrito",
2473
+ subscript: "Subscrito",
2474
+ highlight: "Destacar",
2475
+ highlightPicker: "Cor de destaque",
2476
+ heading1: "Título 1",
2477
+ heading2: "Título 2",
2478
+ heading3: "Título 3",
2479
+ bulletList: "Lista com marcadores",
2480
+ orderedList: "Lista numerada",
2481
+ blockquote: "Citação",
2482
+ alignLeft: "Alinhar à esquerda",
2483
+ alignCenter: "Centralizar",
2484
+ alignRight: "Alinhar à direita",
2485
+ alignJustify: "Justificar",
2486
+ link: "Inserir link",
2487
+ image: "Inserir imagem",
2488
+ horizontalRule: "Linha horizontal",
2489
+ table: "Inserir tabela",
2490
+ undo: "Desfazer\nCtrl+Z",
2491
+ redo: "Refazer\nCtrl+Shift+Z",
2492
+ clear: "Limpar",
2493
+ textColor: "Cor do texto",
2494
+ customColor: "Cor personalizada",
2495
+ presets: "Predefinições",
2496
+ },
2497
+ bubbleMenu: {
2498
+ bold: "Negrito\nCtrl+B",
2499
+ italic: "Itálico\nCtrl+I",
2500
+ underline: "Sublinhado\nCtrl+U",
2501
+ strike: "Tachado\nCtrl+Shift+X",
2502
+ code: "Código\nCtrl+E",
2503
+ superscript: "Sobrescrito",
2504
+ subscript: "Subscrito",
2505
+ highlight: "Destacar",
2506
+ highlightPicker: "Cor de destaque",
2507
+ textColor: "Cor do texto",
2508
+ link: "Link",
2509
+ addLink: "Inserir link",
2510
+ editLink: "Editar link",
2511
+ removeLink: "Remover link",
2512
+ linkUrl: "URL do link",
2513
+ linkText: "Texto do link",
2514
+ openLink: "Abrir link",
2515
+ customColor: "Cor personalizada",
2516
+ presets: "Predefinições",
2517
+ },
2518
+ slashCommands: {
2519
+ heading1: {
2520
+ title: "Título 1",
2521
+ description: "Título de seção grande",
2522
+ keywords: ["heading", "h1", "title", "1", "header", "título", "titulo", "cabeçalho"],
2523
+ },
2524
+ heading2: {
2525
+ title: "Título 2",
2526
+ description: "Título de seção médio",
2527
+ keywords: ["heading", "h2", "title", "2", "header", "título", "titulo", "subtítulo"],
2528
+ },
2529
+ heading3: {
2530
+ title: "Título 3",
2531
+ description: "Título de seção pequeno",
2532
+ keywords: ["heading", "h3", "title", "3", "header", "título", "titulo", "subtítulo"],
2533
+ },
2534
+ bulletList: {
2535
+ title: "Lista com marcadores",
2536
+ description: "Criar uma lista com marcadores",
2537
+ keywords: ["bullet", "list", "ul", "unordered", "lista", "marcadores", "tópicos"],
2538
+ },
2539
+ orderedList: {
2540
+ title: "Lista numerada",
2541
+ description: "Criar uma lista numerada",
2542
+ keywords: ["ordered", "list", "ol", "numbered", "lista", "numerada", "ordenada"],
2543
+ },
2544
+ blockquote: {
2545
+ title: "Citação",
2546
+ description: "Adicionar uma citação",
2547
+ keywords: ["quote", "blockquote", "citation", "citação", "citacao", "aspas"],
2548
+ },
2549
+ code: {
2550
+ title: "Bloco de código",
2551
+ description: "Adicionar um bloco de código",
2552
+ keywords: ["code", "codeblock", "pre", "programming", "código", "codigo", "programação"],
2553
+ },
2554
+ image: {
2555
+ title: "Imagem",
2556
+ description: "Inserir uma imagem",
2557
+ keywords: ["image", "photo", "picture", "img", "imagem", "foto"],
2558
+ },
2559
+ horizontalRule: {
2560
+ title: "Linha horizontal",
2561
+ description: "Adicionar uma linha divisória",
2562
+ keywords: ["hr", "horizontal", "rule", "line", "separator", "linha", "divisor", "separador"],
2563
+ },
2564
+ table: {
2565
+ title: "Tabela",
2566
+ description: "Inserir uma tabela",
2567
+ keywords: [
2568
+ "table",
2569
+ "grid",
2570
+ "data",
2571
+ "rows",
2572
+ "columns",
2573
+ "tabela",
2574
+ "grade",
2575
+ "dados",
2576
+ "linhas",
2577
+ "colunas",
2578
+ ],
2579
+ },
2580
+ tableOfContents: {
2581
+ title: "Sumário",
2582
+ description: "Inserir um sumário",
2583
+ keywords: [
2584
+ "toc",
2585
+ "table",
2586
+ "contents",
2587
+ "summary",
2588
+ "index",
2589
+ "headings",
2590
+ "outline",
2591
+ "sumário",
2592
+ "sumario",
2593
+ "índice",
2594
+ "indice",
2595
+ "títulos",
2596
+ ],
2597
+ },
2598
+ filterPlaceholder: "Filtrar...",
2599
+ },
2600
+ table: {
2601
+ addRowBefore: "Inserir linha acima",
2602
+ addRowAfter: "Inserir linha abaixo",
2603
+ deleteRow: "Excluir linha",
2604
+ addColumnBefore: "Inserir coluna à esquerda",
2605
+ addColumnAfter: "Inserir coluna à direita",
2606
+ deleteColumn: "Excluir coluna",
2607
+ deleteTable: "Excluir tabela",
2608
+ toggleHeaderRow: "Alternar linha de cabeçalho",
2609
+ toggleHeaderColumn: "Alternar coluna de cabeçalho",
2610
+ mergeCells: "Mesclar células",
2611
+ splitCell: "Dividir célula",
2612
+ },
2613
+ imageUpload: {
2614
+ selectImage: "Selecionar imagem",
2615
+ loadError: "Erro ao carregar a imagem",
2616
+ uploadingImage: "Enviando imagem...",
2617
+ uploadProgress: "Progresso do envio",
2618
+ uploadError: "Erro no envio",
2619
+ uploadSuccess: "Envio concluído",
2620
+ imageTooLarge: "Imagem muito grande",
2621
+ invalidFileType: "Tipo de arquivo inválido",
2622
+ dragDropText: "Arraste e solte imagens aqui",
2623
+ changeImage: "Trocar imagem",
2624
+ downloadImage: "Baixar imagem",
2625
+ deleteImage: "Excluir imagem",
2626
+ resizeSmall: "Pequena",
2627
+ resizeMedium: "Média",
2628
+ resizeLarge: "Grande",
2629
+ resizeOriginal: "Original",
2630
+ alignLeft: "Alinhar à esquerda",
2631
+ alignCenter: "Centralizar",
2632
+ alignRight: "Alinhar à direita",
2633
+ resizing: "Redimensionando...",
2634
+ compressing: "Comprimindo...",
2635
+ compressionError: "Erro ao comprimir a imagem",
2636
+ validating: "Validando arquivo...",
2637
+ uploadingToServer: "Enviando para o servidor...",
2638
+ replacingImage: "Substituindo imagem...",
2639
+ insertingImage: "Inserindo no editor...",
2640
+ noFileSelected: "Nenhum arquivo de imagem selecionado",
2641
+ selectionCancelled: "Seleção cancelada",
2642
+ },
2643
+ editor: {
2644
+ placeholder: "Comece a escrever...",
2645
+ character: "caractere",
2646
+ characterPlural: "caracteres",
2647
+ word: "palavra",
2648
+ wordPlural: "palavras",
2649
+ linkPrompt: "Digite a URL do link",
2650
+ linkUrlPrompt: "Digite a URL",
2651
+ confirmDelete: "Tem certeza de que deseja excluir?",
2652
+ toggleEdit: "Mudar para o modo de edição",
2653
+ viewMode: "Mudar para o modo de leitura",
2654
+ blockAdd: "Clique para adicionar um bloco",
2655
+ blockDrag: "Arraste para mover este bloco",
2656
+ tableOfContents: "Sumário",
2657
+ },
2658
+ common: {
2659
+ cancel: "Cancelar",
2660
+ confirm: "Confirmar",
2661
+ apply: "Aplicar",
2662
+ delete: "Excluir",
2663
+ save: "Salvar",
2664
+ close: "Fechar",
2665
+ loading: "Carregando",
2666
+ error: "Erro",
2667
+ success: "Sucesso",
2668
+ },
2669
+ export: {
2670
+ export: "Exportar",
2671
+ html: "HTML",
2672
+ markdown: "Markdown",
2673
+ text: "Texto simples",
2674
+ copyHtml: "Copiar como HTML",
2675
+ copyMarkdown: "Copiar como Markdown",
2676
+ copyText: "Copiar como texto simples",
2677
+ downloadHtml: "Baixar .html",
2678
+ downloadMarkdown: "Baixar .md",
2679
+ downloadText: "Baixar .txt",
2680
+ copiedSuccess: "Copiado para a área de transferência!",
2681
+ },
2682
+ };
2683
+
2684
+ const SPANISH_TRANSLATIONS = {
2685
+ toolbar: {
2686
+ bold: "Negrita\nCtrl+B",
2687
+ italic: "Cursiva\nCtrl+I",
2688
+ underline: "Subrayado\nCtrl+U",
2689
+ strike: "Tachado\nCtrl+Shift+X",
2690
+ code: "Código en línea\nCtrl+E",
2691
+ codeBlock: "Bloque de código",
2692
+ superscript: "Superíndice",
2693
+ subscript: "Subíndice",
2694
+ highlight: "Resaltar",
2695
+ highlightPicker: "Color de resaltado",
2696
+ heading1: "Título 1",
2697
+ heading2: "Título 2",
2698
+ heading3: "Título 3",
2699
+ bulletList: "Lista con viñetas",
2700
+ orderedList: "Lista numerada",
2701
+ blockquote: "Cita",
2702
+ alignLeft: "Alinear a la izquierda",
2703
+ alignCenter: "Centrar",
2704
+ alignRight: "Alinear a la derecha",
2705
+ alignJustify: "Justificar",
2706
+ link: "Insertar enlace",
2707
+ image: "Insertar imagen",
2708
+ horizontalRule: "Línea horizontal",
2709
+ table: "Insertar tabla",
2710
+ undo: "Deshacer\nCtrl+Z",
2711
+ redo: "Rehacer\nCtrl+Shift+Z",
2712
+ clear: "Limpiar",
2713
+ textColor: "Color del texto",
2714
+ customColor: "Color personalizado",
2715
+ presets: "Predefinidos",
2716
+ },
2717
+ bubbleMenu: {
2718
+ bold: "Negrita\nCtrl+B",
2719
+ italic: "Cursiva\nCtrl+I",
2720
+ underline: "Subrayado\nCtrl+U",
2721
+ strike: "Tachado\nCtrl+Shift+X",
2722
+ code: "Código\nCtrl+E",
2723
+ superscript: "Superíndice",
2724
+ subscript: "Subíndice",
2725
+ highlight: "Resaltar",
2726
+ highlightPicker: "Color de resaltado",
2727
+ textColor: "Color del texto",
2728
+ link: "Enlace",
2729
+ addLink: "Insertar enlace",
2730
+ editLink: "Editar enlace",
2731
+ removeLink: "Quitar enlace",
2732
+ linkUrl: "URL del enlace",
2733
+ linkText: "Texto del enlace",
2734
+ openLink: "Abrir enlace",
2735
+ customColor: "Color personalizado",
2736
+ presets: "Predefinidos",
2737
+ },
2738
+ slashCommands: {
2739
+ heading1: {
2740
+ title: "Título 1",
2741
+ description: "Título de sección grande",
2742
+ keywords: ["heading", "h1", "title", "1", "header", "título", "titulo", "encabezado"],
2743
+ },
2744
+ heading2: {
2745
+ title: "Título 2",
2746
+ description: "Título de sección mediano",
2747
+ keywords: ["heading", "h2", "title", "2", "header", "título", "titulo", "subtítulo"],
2748
+ },
2749
+ heading3: {
2750
+ title: "Título 3",
2751
+ description: "Título de sección pequeño",
2752
+ keywords: ["heading", "h3", "title", "3", "header", "título", "titulo", "subtítulo"],
2753
+ },
2754
+ bulletList: {
2755
+ title: "Lista con viñetas",
2756
+ description: "Crear una lista con viñetas",
2757
+ keywords: ["bullet", "list", "ul", "unordered", "lista", "viñetas", "puntos"],
2758
+ },
2759
+ orderedList: {
2760
+ title: "Lista numerada",
2761
+ description: "Crear una lista numerada",
2762
+ keywords: ["ordered", "list", "ol", "numbered", "lista", "numerada", "ordenada"],
2763
+ },
2764
+ blockquote: {
2765
+ title: "Cita",
2766
+ description: "Añadir una cita",
2767
+ keywords: ["quote", "blockquote", "citation", "cita", "citar", "comillas"],
2768
+ },
2769
+ code: {
2770
+ title: "Bloque de código",
2771
+ description: "Añadir un bloque de código",
2772
+ keywords: ["code", "codeblock", "pre", "programming", "código", "codigo", "programación"],
2773
+ },
2774
+ image: {
2775
+ title: "Imagen",
2776
+ description: "Insertar una imagen",
2777
+ keywords: ["image", "photo", "picture", "img", "imagen", "foto"],
2778
+ },
2779
+ horizontalRule: {
2780
+ title: "Línea horizontal",
2781
+ description: "Añadir una línea divisoria",
2782
+ keywords: [
2783
+ "hr",
2784
+ "horizontal",
2785
+ "rule",
2786
+ "line",
2787
+ "separator",
2788
+ "línea",
2789
+ "linea",
2790
+ "divisor",
2791
+ "separador",
2792
+ ],
2793
+ },
2794
+ table: {
2795
+ title: "Tabla",
2796
+ description: "Insertar una tabla",
2797
+ keywords: [
2798
+ "table",
2799
+ "grid",
2800
+ "data",
2801
+ "rows",
2802
+ "columns",
2803
+ "tabla",
2804
+ "cuadrícula",
2805
+ "datos",
2806
+ "filas",
2807
+ "columnas",
2808
+ ],
2809
+ },
2810
+ tableOfContents: {
2811
+ title: "Índice",
2812
+ description: "Insertar un índice",
2813
+ keywords: [
2814
+ "toc",
2815
+ "table",
2816
+ "contents",
2817
+ "summary",
2818
+ "index",
2819
+ "headings",
2820
+ "outline",
2821
+ "índice",
2822
+ "indice",
2823
+ "contenido",
2824
+ "sumario",
2825
+ "títulos",
2826
+ ],
2827
+ },
2828
+ filterPlaceholder: "Filtrar...",
2829
+ },
2830
+ table: {
2831
+ addRowBefore: "Insertar fila arriba",
2832
+ addRowAfter: "Insertar fila abajo",
2833
+ deleteRow: "Eliminar fila",
2834
+ addColumnBefore: "Insertar columna a la izquierda",
2835
+ addColumnAfter: "Insertar columna a la derecha",
2836
+ deleteColumn: "Eliminar columna",
2837
+ deleteTable: "Eliminar tabla",
2838
+ toggleHeaderRow: "Alternar fila de encabezado",
2839
+ toggleHeaderColumn: "Alternar columna de encabezado",
2840
+ mergeCells: "Combinar celdas",
2841
+ splitCell: "Dividir celda",
2842
+ },
2843
+ imageUpload: {
2844
+ selectImage: "Seleccionar imagen",
2845
+ loadError: "Error al cargar la imagen",
2846
+ uploadingImage: "Subiendo imagen...",
2847
+ uploadProgress: "Progreso de la subida",
2848
+ uploadError: "Error al subir",
2849
+ uploadSuccess: "Subida completada",
2850
+ imageTooLarge: "Imagen demasiado grande",
2851
+ invalidFileType: "Tipo de archivo no válido",
2852
+ dragDropText: "Arrastra y suelta imágenes aquí",
2853
+ changeImage: "Cambiar imagen",
2854
+ downloadImage: "Descargar imagen",
2855
+ deleteImage: "Eliminar imagen",
2856
+ resizeSmall: "Pequeña",
2857
+ resizeMedium: "Mediana",
2858
+ resizeLarge: "Grande",
2859
+ resizeOriginal: "Original",
2860
+ alignLeft: "Alinear a la izquierda",
2861
+ alignCenter: "Centrar",
2862
+ alignRight: "Alinear a la derecha",
2863
+ resizing: "Redimensionando...",
2864
+ compressing: "Comprimiendo...",
2865
+ compressionError: "Error al comprimir la imagen",
2866
+ validating: "Validando archivo...",
2867
+ uploadingToServer: "Subiendo al servidor...",
2868
+ replacingImage: "Reemplazando imagen...",
2869
+ insertingImage: "Insertando en el editor...",
2870
+ noFileSelected: "Ningún archivo de imagen seleccionado",
2871
+ selectionCancelled: "Selección cancelada",
2872
+ },
2873
+ editor: {
2874
+ placeholder: "Empieza a escribir...",
2875
+ character: "carácter",
2876
+ characterPlural: "caracteres",
2877
+ word: "palabra",
2878
+ wordPlural: "palabras",
2879
+ linkPrompt: "Introduce la URL del enlace",
2880
+ linkUrlPrompt: "Introduce la URL",
2881
+ confirmDelete: "¿Seguro que quieres eliminar esto?",
2882
+ toggleEdit: "Cambiar al modo de edición",
2883
+ viewMode: "Cambiar al modo de lectura",
2884
+ blockAdd: "Haz clic para añadir un bloque",
2885
+ blockDrag: "Arrastra para mover este bloque",
2886
+ tableOfContents: "Índice",
2887
+ },
2888
+ common: {
2889
+ cancel: "Cancelar",
2890
+ confirm: "Confirmar",
2891
+ apply: "Aplicar",
2892
+ delete: "Eliminar",
2893
+ save: "Guardar",
2894
+ close: "Cerrar",
2895
+ loading: "Cargando",
2896
+ error: "Error",
2897
+ success: "Éxito",
2898
+ },
2899
+ export: {
2900
+ export: "Exportar",
2901
+ html: "HTML",
2902
+ markdown: "Markdown",
2903
+ text: "Texto sin formato",
2904
+ copyHtml: "Copiar como HTML",
2905
+ copyMarkdown: "Copiar como Markdown",
2906
+ copyText: "Copiar como texto sin formato",
2907
+ downloadHtml: "Descargar .html",
2908
+ downloadMarkdown: "Descargar .md",
2909
+ downloadText: "Descargar .txt",
2910
+ copiedSuccess: "¡Copiado al portapapeles!",
2911
+ },
2912
+ };
2913
+
2351
2914
  class AteI18nService {
2352
2915
  constructor() {
2353
2916
  this._currentLocale = signal("en");
@@ -2355,12 +2918,14 @@ class AteI18nService {
2355
2918
  en: ENGLISH_TRANSLATIONS,
2356
2919
  fr: FRENCH_TRANSLATIONS,
2357
2920
  de: GERMAN_TRANSLATIONS,
2921
+ pt: PORTUGUESE_TRANSLATIONS,
2922
+ es: SPANISH_TRANSLATIONS,
2358
2923
  });
2359
2924
  // Public signals
2360
2925
  this.currentLocale = this._currentLocale.asReadonly();
2361
2926
  /** All loaded translations (useful for dynamic key access) */
2362
2927
  this.allTranslations = this._translations.asReadonly();
2363
- this.translations = computed(() => this._translations()[this._currentLocale()] ?? this._translations().en);
2928
+ this.translations = computed(() => this.getTranslations(this._currentLocale()) ?? this._translations().en);
2364
2929
  // Fast translation methods
2365
2930
  this.t = computed(() => this.translations());
2366
2931
  this.toolbar = computed(() => this.translations().toolbar);
@@ -2395,14 +2960,20 @@ class AteI18nService {
2395
2960
  };
2396
2961
  });
2397
2962
  }
2398
- detectBrowserLanguage() {
2399
- const browserLang = navigator.language.toLowerCase();
2400
- if (browserLang.startsWith("fr")) {
2401
- this._currentLocale.set("fr");
2402
- }
2403
- else {
2404
- this._currentLocale.set("en");
2963
+ getTranslations(locale) {
2964
+ const resolved = this.resolveLocale(locale);
2965
+ return resolved ? this._translations()[resolved] : undefined;
2966
+ }
2967
+ resolveLocale(locale) {
2968
+ const all = this._translations();
2969
+ if (all[locale]) {
2970
+ return locale;
2405
2971
  }
2972
+ const language = locale.toLowerCase().split(/[-_]/)[0];
2973
+ return all[language] ? language : undefined;
2974
+ }
2975
+ detectBrowserLanguage() {
2976
+ this._currentLocale.set(this.resolveLocale(navigator.language) ?? "en");
2406
2977
  }
2407
2978
  // Utility methods for components
2408
2979
  getToolbarTitle(key) {
@@ -3475,12 +4046,13 @@ class AteImageService {
3475
4046
  const maxSize = options?.maxSize || 10 * 1024 * 1024;
3476
4047
  const allowedTypes = options?.allowedTypes || [];
3477
4048
  if (allowedTypes.length > 0 && !allowedTypes.includes(file.type)) {
3478
- return { valid: false, error: this.t().invalidFileType };
4049
+ return { valid: false, error: this.t().invalidFileType, reason: "invalid-type" };
3479
4050
  }
3480
4051
  if (file.size > maxSize) {
3481
4052
  return {
3482
4053
  valid: false,
3483
4054
  error: `${this.t().imageTooLarge} (max ${Math.round(maxSize / 1024 / 1024)}MB)`,
4055
+ reason: "too-large",
3484
4056
  };
3485
4057
  }
3486
4058
  return { valid: true };
@@ -3536,7 +4108,7 @@ class AteImageService {
3536
4108
  });
3537
4109
  }
3538
4110
  /** Core upload logic with progress tracking */
3539
- async uploadImageWithProgress(editor, file, insertionStrategy, actionMessage, options) {
4111
+ async uploadImageWithProgress(editor, file, insertionStrategy, actionMessage, options, source) {
3540
4112
  try {
3541
4113
  this.currentEditor = editor;
3542
4114
  this.isUploading.set(true);
@@ -3565,6 +4137,11 @@ class AteImageService {
3565
4137
  catch (error) {
3566
4138
  this.resetUploadState();
3567
4139
  console.error(this.t().uploadError, error);
4140
+ this.onImageRejectedCallback?.({
4141
+ reason: error instanceof AteImageValidationError ? error.reason : "upload-failed",
4142
+ file,
4143
+ source,
4144
+ });
3568
4145
  throw error;
3569
4146
  }
3570
4147
  }
@@ -3575,7 +4152,7 @@ class AteImageService {
3575
4152
  allowedTypes: options?.allowedTypes,
3576
4153
  });
3577
4154
  if (!validation.valid) {
3578
- throw new Error(validation.error);
4155
+ throw new AteImageValidationError(validation.reason ?? "invalid-type", validation.error ?? "");
3579
4156
  }
3580
4157
  onStep?.(30, this.t().compressing);
3581
4158
  const result = await this.compressImage(file, options?.quality || 0.8, options?.maxWidth || 1920, options?.maxHeight || 1200);
@@ -3631,7 +4208,7 @@ class AteImageService {
3631
4208
  this.currentEditor = null;
3632
4209
  }
3633
4210
  /** Main entry point for file upload and insertion */
3634
- async uploadAndInsertImage(editor, file, options) {
4211
+ async uploadAndInsertImage(editor, file, options, source = "api") {
3635
4212
  return this.uploadImageWithProgress(editor, file, (ed, result) => {
3636
4213
  this.insertImage(ed, {
3637
4214
  src: result.src,
@@ -3640,7 +4217,7 @@ class AteImageService {
3640
4217
  width: result.width,
3641
4218
  height: result.height,
3642
4219
  });
3643
- }, this.t().insertingImage, options);
4220
+ }, this.t().insertingImage, options, source);
3644
4221
  }
3645
4222
  /** Trigger an editor transaction to force decoration update */
3646
4223
  forceEditorUpdate() {
@@ -3666,7 +4243,7 @@ class AteImageService {
3666
4243
  const file = e.target.files?.[0];
3667
4244
  if (file && file.type.startsWith("image/")) {
3668
4245
  try {
3669
- await uploadMethod(editor, file, options);
4246
+ await uploadMethod(editor, file, options, "picker");
3670
4247
  resolve();
3671
4248
  }
3672
4249
  catch (error) {
@@ -3697,7 +4274,7 @@ class AteImageService {
3697
4274
  return this.selectFileAndProcess(editor, this.uploadAndReplaceImage.bind(this), options);
3698
4275
  }
3699
4276
  /** Internal helper used by replacement logic */
3700
- async uploadAndReplaceImage(editor, file, options) {
4277
+ async uploadAndReplaceImage(editor, file, options, source = "api") {
3701
4278
  // Store current position to ensure we can re-select the image even if selection blurs during upload
3702
4279
  const wasActive = editor.isActive("resizableImage");
3703
4280
  await this.uploadImageWithProgress(editor, file, (ed, result) => {
@@ -3727,7 +4304,7 @@ class AteImageService {
3727
4304
  }
3728
4305
  // After replacement, ensure the image is tracked in our signals
3729
4306
  this.selectImage(ed);
3730
- }, this.t().replacingImage, options);
4307
+ }, this.t().replacingImage, options, source);
3731
4308
  }
3732
4309
  /**
3733
4310
  * Handle image drop event.
@@ -3749,7 +4326,7 @@ class AteImageService {
3749
4326
  if (pos) {
3750
4327
  editor.commands.setTextSelection(pos.pos);
3751
4328
  }
3752
- void this.uploadAndInsertImage(editor, file, options);
4329
+ this.uploadAndInsertImage(editor, file, options, "drop").catch(() => undefined);
3753
4330
  return true;
3754
4331
  }
3755
4332
  /**
@@ -3765,7 +4342,7 @@ class AteImageService {
3765
4342
  return false;
3766
4343
  }
3767
4344
  event.preventDefault();
3768
- void this.uploadAndInsertImage(editor, imageFile, options);
4345
+ this.uploadAndInsertImage(editor, imageFile, options, "paste").catch(() => undefined);
3769
4346
  return true;
3770
4347
  }
3771
4348
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
@@ -4448,6 +5025,9 @@ class AteEditorCommandsService {
4448
5025
  set onImageUploaded(callback) {
4449
5026
  this.imageService.onImageUploadedCallback = callback || undefined;
4450
5027
  }
5028
+ set onImageRejected(callback) {
5029
+ this.imageService.onImageRejectedCallback = callback || undefined;
5030
+ }
4451
5031
  set uploadHandler(handler) {
4452
5032
  this.imageService.uploadHandler = handler;
4453
5033
  }
@@ -4519,10 +5099,10 @@ class AteEditorCommandsService {
4519
5099
  this.insertHorizontalRule(editor);
4520
5100
  break;
4521
5101
  case "insertImage":
4522
- this.insertImage(editor, args[0]);
5102
+ this.insertImage(editor, args[0]).catch(() => undefined);
4523
5103
  break;
4524
5104
  case "uploadImage":
4525
- this.uploadImage(editor, args[0], args[1]);
5105
+ this.uploadImage(editor, args[0], args[1]).catch(() => undefined);
4526
5106
  break;
4527
5107
  case "toggleHighlight":
4528
5108
  this.toggleHighlight(editor, args[0]);
@@ -5634,6 +6214,7 @@ const ATE_DEFAULT_CONFIG = {
5634
6214
  showTableMenu: true,
5635
6215
  showCellMenu: true,
5636
6216
  enableSlashCommands: true,
6217
+ enableBlockShortcuts: true,
5637
6218
  blockControls: "none",
5638
6219
  floatingToolbar: false,
5639
6220
  toolbar: ATE_DEFAULT_TOOLBAR_CONFIG,
@@ -5645,6 +6226,7 @@ const ATE_DEFAULT_CONFIG = {
5645
6226
  slashCommands: {},
5646
6227
  tiptapExtensions: [],
5647
6228
  tiptapOptions: {},
6229
+ starterKitOptions: {},
5648
6230
  stateCalculators: [],
5649
6231
  angularNodes: [],
5650
6232
  };
@@ -7297,6 +7879,16 @@ class AteColorBubbleMenuComponent extends AteBaseSubBubbleMenu {
7297
7879
  }
7298
7880
  return false;
7299
7881
  }
7882
+ findColoredElementInContent(start, contentRoot) {
7883
+ let current = start;
7884
+ while (current && current !== contentRoot && contentRoot.contains(current)) {
7885
+ if (current.matches('[style*="color"], [style*="background"], mark')) {
7886
+ return current;
7887
+ }
7888
+ current = current.parentElement;
7889
+ }
7890
+ return null;
7891
+ }
7300
7892
  getSelectionRect() {
7301
7893
  const trigger = this.colorPickerSvc.menuTrigger();
7302
7894
  const ed = this.editor();
@@ -7316,7 +7908,7 @@ class AteColorBubbleMenuComponent extends AteBaseSubBubbleMenu {
7316
7908
  try {
7317
7909
  const { node } = ed.view.domAtPos(from);
7318
7910
  const element = node instanceof Element ? node : node.parentElement;
7319
- const colorElement = element?.closest('[style*="color"], [style*="background"], mark');
7911
+ const colorElement = this.findColoredElementInContent(element, ed.view.dom);
7320
7912
  if (colorElement) {
7321
7913
  return colorElement.getBoundingClientRect();
7322
7914
  }
@@ -7699,6 +8291,7 @@ function createDefaultSlashCommands(i18n, commands, imageOptions) {
7699
8291
  quality: imageOptions?.quality,
7700
8292
  maxWidth: imageOptions?.maxWidth,
7701
8293
  maxHeight: imageOptions?.maxHeight,
8294
+ maxSize: imageOptions?.maxSize,
7702
8295
  allowedTypes: imageOptions?.allowedTypes,
7703
8296
  }),
7704
8297
  },
@@ -8848,6 +9441,99 @@ const AteBlockControlsExtension = Extension.create({
8848
9441
  },
8849
9442
  });
8850
9443
 
9444
+ function shallowArrayEqual(a, b) {
9445
+ return a === b || (a.length === b.length && a.every((item, i) => item === b[i]));
9446
+ }
9447
+ function shallowObjectEqual(a, b) {
9448
+ if (a === b) {
9449
+ return true;
9450
+ }
9451
+ const aKeys = Object.keys(a);
9452
+ const bKeys = Object.keys(b);
9453
+ return (aKeys.length === bKeys.length &&
9454
+ aKeys.every(key => Object.prototype.hasOwnProperty.call(b, key) &&
9455
+ a[key] === b[key]));
9456
+ }
9457
+
9458
+ /**
9459
+ * Maps the runtime `.name` of each extension bundled in `@tiptap/starter-kit`
9460
+ * to its corresponding option key in `StarterKitOptions`.
9461
+ */
9462
+ const STARTER_KIT_NAME_TO_OPTION = {
9463
+ blockquote: "blockquote",
9464
+ bold: "bold",
9465
+ bulletList: "bulletList",
9466
+ code: "code",
9467
+ codeBlock: "codeBlock",
9468
+ doc: "document",
9469
+ dropCursor: "dropcursor",
9470
+ gapCursor: "gapcursor",
9471
+ hardBreak: "hardBreak",
9472
+ heading: "heading",
9473
+ undoRedo: "undoRedo",
9474
+ horizontalRule: "horizontalRule",
9475
+ italic: "italic",
9476
+ listItem: "listItem",
9477
+ listKeymap: "listKeymap",
9478
+ link: "link",
9479
+ orderedList: "orderedList",
9480
+ paragraph: "paragraph",
9481
+ strike: "strike",
9482
+ text: "text",
9483
+ underline: "underline",
9484
+ trailingNode: "trailingNode",
9485
+ };
9486
+ /**
9487
+ * Describes which parts of Angular Tiptap Editor's UI or state calculators
9488
+ * depend on a given built-in or StarterKit extension name.
9489
+ */
9490
+ const ATE_BUILTIN_UI_DEPENDENCIES = {
9491
+ blockquote: "toolbar/slash menu blockquote buttons, AteStructureCalculator",
9492
+ bold: "toolbar/bubble menu bold buttons, AteMarksCalculator",
9493
+ bulletList: "toolbar/slash menu bullet list buttons, AteStructureCalculator",
9494
+ code: "toolbar/bubble menu inline code buttons, AteMarksCalculator",
9495
+ codeBlock: "toolbar/slash menu code block buttons, AteStructureCalculator",
9496
+ doc: "top-level ProseMirror document schema",
9497
+ dropCursor: "drag-and-drop cursor indicator",
9498
+ gapCursor: "gap cursor navigation around leaf block nodes",
9499
+ hardBreak: "Shift+Enter line break shortcut",
9500
+ heading: "toolbar/bubble menu/slash menu heading controls, table of contents, AteStructureCalculator",
9501
+ undoRedo: "toolbar undo/redo buttons, AteStructureCalculator",
9502
+ horizontalRule: "toolbar/slash menu horizontal rule buttons",
9503
+ italic: "toolbar/bubble menu italic buttons, AteMarksCalculator",
9504
+ listItem: "bullet/ordered list items, block shortcuts",
9505
+ listKeymap: "list backspace/delete keyboard navigation",
9506
+ link: "toolbar/bubble menu link editor, Mod+K shortcut, AteMarksCalculator",
9507
+ orderedList: "toolbar/slash menu ordered list buttons, AteStructureCalculator",
9508
+ paragraph: "default text block node, AteStructureCalculator",
9509
+ strike: "toolbar/bubble menu strikethrough buttons, AteMarksCalculator",
9510
+ text: "core inline text node",
9511
+ underline: "toolbar/bubble menu underline buttons, AteMarksCalculator",
9512
+ trailingNode: "automatic trailing paragraph after block nodes",
9513
+ textStyle: "color picker, AteMarksCalculator",
9514
+ color: "toolbar/bubble menu text color picker, AteMarksCalculator",
9515
+ placeholder: "empty editor placeholder decoration",
9516
+ superscript: "toolbar/bubble menu superscript buttons, AteMarksCalculator",
9517
+ subscript: "toolbar/bubble menu subscript buttons, AteMarksCalculator",
9518
+ textAlign: "toolbar/image bubble menu alignment buttons, AteStructureCalculator",
9519
+ ateLinkClickBehavior: "read-only and Ctrl+click link navigation",
9520
+ ateBlockShortcuts: "Mod+D and Mod+Shift+ArrowUp/Down block shortcuts",
9521
+ ateLinkShortcut: "Mod+K link editor shortcut",
9522
+ highlight: "toolbar/bubble menu highlight picker, AteMarksCalculator",
9523
+ resizableImage: "image node view, image bubble menu, image upload/resize service, AteImageCalculator",
9524
+ atePastedImage: "pasted HTML image sanitization and base64 re-hosting",
9525
+ ateUploadProgress: "image upload progress overlay",
9526
+ tableExtension: "toolbar/slash menu table insertion, table/cell bubble menus, AteTableCalculator",
9527
+ tableOfContents: "slash menu table of contents node, AteTableOfContentsComponent",
9528
+ tiptapState: "reactive editor state engine (toolbar, bubble menus, footer)",
9529
+ blockControls: "block plus button and drag handle",
9530
+ officePaste: "Word/Excel paste normalization",
9531
+ characterCount: "footer character/word counters and maxCharacters limit",
9532
+ };
9533
+ function getExtensionName(ext) {
9534
+ return ext?.name;
9535
+ }
9536
+
8851
9537
  function transformBooleanInput(val) {
8852
9538
  if (val === undefined || val === null) {
8853
9539
  return undefined;
@@ -8903,6 +9589,9 @@ class AngularTiptapEditorComponent {
8903
9589
  this.enableSlashCommands = input(undefined, {
8904
9590
  transform: transformBooleanInput,
8905
9591
  });
9592
+ this.enableBlockShortcuts = input(undefined, {
9593
+ transform: transformBooleanInput,
9594
+ });
8906
9595
  this.slashCommands = input(undefined);
8907
9596
  this.customSlashCommands = input(undefined);
8908
9597
  this.blockControls = input();
@@ -8919,6 +9608,7 @@ class AngularTiptapEditorComponent {
8919
9608
  this.spellcheck = input(undefined, { transform: transformBooleanInput });
8920
9609
  this.tiptapExtensions = input(undefined);
8921
9610
  this.tiptapOptions = input(undefined);
9611
+ this.starterKitOptions = input(undefined);
8922
9612
  // Nouveaux inputs pour les bubble menus
8923
9613
  this.showBubbleMenu = input(undefined, {
8924
9614
  transform: transformBooleanInput,
@@ -8978,6 +9668,8 @@ class AngularTiptapEditorComponent {
8978
9668
  this.editorBlur = output();
8979
9669
  this.editableChange = output();
8980
9670
  this.imageUploaded = output();
9671
+ /** Emitted when an image file is rejected (disallowed type, too large or failed upload) */
9672
+ this.imageRejected = output();
8981
9673
  /** Emitted when an image from pasted HTML is dropped (unreachable source or failed upload) */
8982
9674
  this.pastedImageRejected = output();
8983
9675
  // ViewChild with signal
@@ -9128,15 +9820,19 @@ class AngularTiptapEditorComponent {
9128
9820
  // Behavior
9129
9821
  this.finalAutofocus = computed(() => this.autofocus() ?? this.effectiveConfig().autofocus);
9130
9822
  this.finalMaxCharacters = computed(() => this.maxCharacters() ?? this.effectiveConfig().maxCharacters);
9823
+ this.finalEnableBlockShortcuts = computed(() => this.enableBlockShortcuts() ?? this.effectiveConfig().enableBlockShortcuts ?? true);
9131
9824
  this.finalBlockControls = computed(() => this.blockControls() ?? this.effectiveConfig().blockControls ?? "none");
9132
9825
  this.finalShowCharacterCount = computed(() => this.showCharacterCount() ?? this.effectiveConfig().showCharacterCount ?? true);
9133
9826
  this.finalShowWordCount = computed(() => this.showWordCount() ?? this.effectiveConfig().showWordCount ?? true);
9134
9827
  this.finalLocale = computed(() => this.locale() ?? this.effectiveConfig().locale);
9135
9828
  // Extensions & Options
9136
- this.finalTiptapExtensions = computed(() => this.tiptapExtensions() ?? this.effectiveConfig().tiptapExtensions ?? []);
9137
- this.finalTiptapOptions = computed(() => this.tiptapOptions() ?? this.effectiveConfig().tiptapOptions ?? {});
9829
+ this.finalTiptapExtensions = computed(() => this.tiptapExtensions() ?? this.effectiveConfig().tiptapExtensions ?? [], { equal: shallowArrayEqual });
9830
+ this.finalTiptapOptions = computed(() => this.tiptapOptions() ?? this.effectiveConfig().tiptapOptions ?? {}, { equal: shallowObjectEqual });
9831
+ this.finalStarterKitOptions = computed(() => this.starterKitOptions() ?? this.effectiveConfig().starterKitOptions ?? {}, { equal: shallowObjectEqual });
9138
9832
  this.finalStateCalculators = computed(() => this.stateCalculators() ?? this.effectiveConfig().stateCalculators ?? []);
9139
- this.finalAngularNodesConfig = computed(() => this.effectiveConfig().angularNodes ?? []);
9833
+ this.finalAngularNodesConfig = computed(() => this.effectiveConfig().angularNodes ?? [], {
9834
+ equal: shallowArrayEqual,
9835
+ });
9140
9836
  // Image Upload
9141
9837
  this.finalImageUploadConfig = computed(() => {
9142
9838
  const fromInput = this.imageUpload();
@@ -9157,8 +9853,7 @@ class AngularTiptapEditorComponent {
9157
9853
  this.currentTranslations = computed(() => {
9158
9854
  const localeOverride = this.finalLocale();
9159
9855
  if (localeOverride) {
9160
- const allTranslations = this.i18nService.allTranslations();
9161
- return allTranslations[localeOverride] || this.i18nService.translations();
9856
+ return this.i18nService.getTranslations(localeOverride) ?? this.i18nService.translations();
9162
9857
  }
9163
9858
  return this.i18nService.translations();
9164
9859
  });
@@ -9170,6 +9865,7 @@ class AngularTiptapEditorComponent {
9170
9865
  // Access editor state via service
9171
9866
  this.editorState = this.editorCommandsService.editorState;
9172
9867
  this.editorRegistry = inject(AteEditorRegistry);
9868
+ this.warnedExtensionOverrides = new Set();
9173
9869
  this.iconRegistry = inject(AteIconRegistry);
9174
9870
  this._registeredId = signal(null);
9175
9871
  this.registeredId = this._registeredId.asReadonly();
@@ -9255,6 +9951,7 @@ class AngularTiptapEditorComponent {
9255
9951
  // Monitor technical dependencies
9256
9952
  this.finalTiptapExtensions();
9257
9953
  this.finalTiptapOptions();
9954
+ this.finalStarterKitOptions();
9258
9955
  this.finalAngularNodesConfig();
9259
9956
  this.finalBlockControls();
9260
9957
  untracked(() => {
@@ -9272,6 +9969,9 @@ class AngularTiptapEditorComponent {
9272
9969
  this.editorCommandsService.onImageUploaded = result => {
9273
9970
  this.imageUploaded.emit(result);
9274
9971
  };
9972
+ this.editorCommandsService.onImageRejected = rejection => {
9973
+ this.imageRejected.emit(rejection);
9974
+ };
9275
9975
  }
9276
9976
  ngAfterViewInit() {
9277
9977
  // La vue est déjà complètement initialisée dans ngAfterViewInit
@@ -9293,15 +9993,46 @@ class AngularTiptapEditorComponent {
9293
9993
  }
9294
9994
  }
9295
9995
  initEditor() {
9296
- const extensions = [
9297
- StarterKit.configure({
9298
- link: {
9299
- openOnClick: false,
9996
+ const starterKitOptions = this.finalStarterKitOptions();
9997
+ const customExtensions = this.finalTiptapExtensions();
9998
+ const customNames = new Set(customExtensions.map(getExtensionName).filter((name) => !!name));
9999
+ const defaultLinkOptions = {
10000
+ openOnClick: false,
10001
+ HTMLAttributes: {
10002
+ class: "ate-link",
10003
+ },
10004
+ };
10005
+ const effectiveStarterKitOptions = {
10006
+ ...starterKitOptions,
10007
+ link: starterKitOptions.link === false
10008
+ ? false
10009
+ : {
10010
+ ...defaultLinkOptions,
10011
+ ...starterKitOptions.link,
9300
10012
  HTMLAttributes: {
9301
- class: "ate-link",
10013
+ ...defaultLinkOptions.HTMLAttributes,
10014
+ ...starterKitOptions.link?.HTMLAttributes,
9302
10015
  },
9303
10016
  },
9304
- }),
10017
+ };
10018
+ const replacedNames = [];
10019
+ const ignoredStarterKitOptionKeys = [];
10020
+ for (const customName of customNames) {
10021
+ const optionKey = STARTER_KIT_NAME_TO_OPTION[customName];
10022
+ if (!optionKey) {
10023
+ continue;
10024
+ }
10025
+ const userStarterKitValue = starterKitOptions[optionKey];
10026
+ if (userStarterKitValue !== undefined && userStarterKitValue !== false) {
10027
+ ignoredStarterKitOptionKeys.push(optionKey);
10028
+ }
10029
+ if (userStarterKitValue !== false) {
10030
+ replacedNames.push(customName);
10031
+ }
10032
+ effectiveStarterKitOptions[optionKey] = false;
10033
+ }
10034
+ const extensions = [
10035
+ StarterKit.configure(effectiveStarterKitOptions),
9305
10036
  TextStyle,
9306
10037
  Color.configure({
9307
10038
  types: ["textStyle"],
@@ -9315,6 +10046,9 @@ class AngularTiptapEditorComponent {
9315
10046
  types: ["heading", "paragraph", "resizableImage"],
9316
10047
  }),
9317
10048
  AteLinkClickBehavior,
10049
+ AteBlockShortcuts.configure({
10050
+ enabled: () => this.finalEnableBlockShortcuts(),
10051
+ }),
9318
10052
  AteLinkShortcut.configure({
9319
10053
  canOpen: () => this.editorCommandsService.editorState().can.toggleLink,
9320
10054
  open: editor => this.editorCommandsService.execute(editor, "toggleLink"),
@@ -9390,17 +10124,41 @@ class AngularTiptapEditorComponent {
9390
10124
  console.error("[ATE] Failed to auto-register node view:", e);
9391
10125
  }
9392
10126
  });
9393
- // Allow addition of custom extensions, but avoid duplicates by filtering by name
9394
- const customExtensions = this.finalTiptapExtensions();
10127
+ // Custom extensions in tiptapExtensions take precedence over built-in extensions of the same name
9395
10128
  if (customExtensions.length > 0) {
9396
- const existingNames = new Set(extensions
9397
- .map((ext) => ext?.name)
9398
- .filter((name) => !!name));
9399
- const toAdd = customExtensions.filter((ext) => {
9400
- const name = ext?.name;
9401
- return !name || !existingNames.has(name);
9402
- });
9403
- extensions.push(...toAdd);
10129
+ for (let i = extensions.length - 1; i >= 0; i--) {
10130
+ const name = getExtensionName(extensions[i]);
10131
+ if (name && customNames.has(name)) {
10132
+ replacedNames.push(name);
10133
+ extensions.splice(i, 1);
10134
+ }
10135
+ }
10136
+ extensions.push(...customExtensions);
10137
+ if (isDevMode()) {
10138
+ const newlyReplaced = replacedNames.filter(name => !this.warnedExtensionOverrides.has(`override:${name}`));
10139
+ const newlyIgnoredOptions = ignoredStarterKitOptionKeys.filter(key => !this.warnedExtensionOverrides.has(`conflict:${key}`));
10140
+ if (newlyReplaced.length > 0 || newlyIgnoredOptions.length > 0) {
10141
+ newlyReplaced.forEach(name => this.warnedExtensionOverrides.add(`override:${name}`));
10142
+ newlyIgnoredOptions.forEach(key => this.warnedExtensionOverrides.add(`conflict:${key}`));
10143
+ const parts = [];
10144
+ if (newlyReplaced.length > 0) {
10145
+ const details = newlyReplaced
10146
+ .map(name => {
10147
+ const deps = ATE_BUILTIN_UI_DEPENDENCIES[name];
10148
+ return deps ? `${name} (used by: ${deps})` : name;
10149
+ })
10150
+ .join("; ");
10151
+ parts.push(`Custom extension(s) in tiptapExtensions replaced built-in extension(s): ${details}.`);
10152
+ }
10153
+ if (newlyIgnoredOptions.length > 0) {
10154
+ const ignoredList = newlyIgnoredOptions
10155
+ .map(key => `starterKitOptions.${key}`)
10156
+ .join(", ");
10157
+ parts.push(`${ignoredList} was ignored because the custom extension in tiptapExtensions takes precedence.`);
10158
+ }
10159
+ console.warn(`[ATE] ${parts.join(" ")}`);
10160
+ }
10161
+ }
9404
10162
  }
9405
10163
  // Also allow any tiptap user options
9406
10164
  const userOptions = this.finalTiptapOptions();
@@ -9619,7 +10377,7 @@ class AngularTiptapEditorComponent {
9619
10377
  }
9620
10378
  }
9621
10379
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AngularTiptapEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9622
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AngularTiptapEditorComponent, isStandalone: true, selector: "angular-tiptap-editor", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", 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 }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, fillContainer: { classPropertyName: "fillContainer", publicName: "fillContainer", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showCharacterCount: { classPropertyName: "showCharacterCount", publicName: "showCharacterCount", isSignal: true, isRequired: false, transformFunction: null }, showWordCount: { classPropertyName: "showWordCount", publicName: "showWordCount", isSignal: true, isRequired: false, transformFunction: null }, maxCharacters: { classPropertyName: "maxCharacters", publicName: "maxCharacters", isSignal: true, isRequired: false, transformFunction: null }, enableOfficePaste: { classPropertyName: "enableOfficePaste", publicName: "enableOfficePaste", isSignal: true, isRequired: false, transformFunction: null }, enableSlashCommands: { classPropertyName: "enableSlashCommands", publicName: "enableSlashCommands", isSignal: true, isRequired: false, transformFunction: null }, slashCommands: { classPropertyName: "slashCommands", publicName: "slashCommands", isSignal: true, isRequired: false, transformFunction: null }, customSlashCommands: { classPropertyName: "customSlashCommands", publicName: "customSlashCommands", isSignal: true, isRequired: false, transformFunction: null }, blockControls: { classPropertyName: "blockControls", publicName: "blockControls", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, seamless: { classPropertyName: "seamless", publicName: "seamless", isSignal: true, isRequired: false, transformFunction: null }, floatingToolbar: { classPropertyName: "floatingToolbar", publicName: "floatingToolbar", isSignal: true, isRequired: false, transformFunction: null }, showEditToggle: { classPropertyName: "showEditToggle", publicName: "showEditToggle", isSignal: true, isRequired: false, transformFunction: null }, spellcheck: { classPropertyName: "spellcheck", publicName: "spellcheck", isSignal: true, isRequired: false, transformFunction: null }, tiptapExtensions: { classPropertyName: "tiptapExtensions", publicName: "tiptapExtensions", isSignal: true, isRequired: false, transformFunction: null }, tiptapOptions: { classPropertyName: "tiptapOptions", publicName: "tiptapOptions", isSignal: true, isRequired: false, transformFunction: null }, showBubbleMenu: { classPropertyName: "showBubbleMenu", publicName: "showBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, bubbleMenu: { classPropertyName: "bubbleMenu", publicName: "bubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, showImageBubbleMenu: { classPropertyName: "showImageBubbleMenu", publicName: "showImageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, imageBubbleMenu: { classPropertyName: "imageBubbleMenu", publicName: "imageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, showTableBubbleMenu: { classPropertyName: "showTableBubbleMenu", publicName: "showTableBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, tableBubbleMenu: { classPropertyName: "tableBubbleMenu", publicName: "tableBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, showCellBubbleMenu: { classPropertyName: "showCellBubbleMenu", publicName: "showCellBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, cellBubbleMenu: { classPropertyName: "cellBubbleMenu", publicName: "cellBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, stateCalculators: { classPropertyName: "stateCalculators", publicName: "stateCalculators", isSignal: true, isRequired: false, transformFunction: null }, imageUpload: { classPropertyName: "imageUpload", publicName: "imageUpload", isSignal: true, isRequired: false, transformFunction: null }, imageUploadHandler: { classPropertyName: "imageUploadHandler", publicName: "imageUploadHandler", isSignal: true, isRequired: false, transformFunction: null }, editorId: { classPropertyName: "editorId", publicName: "editorId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChange: "contentChange", editorCreated: "editorCreated", editorUpdate: "editorUpdate", editorFocus: "editorFocus", editorBlur: "editorBlur", editableChange: "editableChange", imageUploaded: "imageUploaded", pastedImageRejected: "pastedImageRejected" }, host: { properties: { "class.fill-container": "finalFillContainer()", "class.floating-toolbar": "finalFloatingToolbar()", "class.is-readonly": "!finalEditable() && !mergedDisabled()", "class.is-disabled": "mergedDisabled()", "style.--ate-border-width": "finalSeamless() || mergedDisabled() ? '0' : null", "style.--ate-background": "finalSeamless() ? 'transparent' : (mergedDisabled() ? 'var(--ate-surface-tertiary)' : null)", "style.--ate-toolbar-border-color": "finalSeamless() ? 'transparent' : null", "style.--ate-counter-background": "finalSeamless() ? 'transparent' : null", "style.--ate-counter-border-color": "finalSeamless() ? 'transparent' : null", "class.dark": "config().theme === 'dark'", "class.ate-blocks-inside": "finalBlockControls() === 'inside'", "class.ate-blocks-outside": "finalBlockControls() === 'outside'", "attr.data-theme": "config().theme" } }, providers: [
10380
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AngularTiptapEditorComponent, isStandalone: true, selector: "angular-tiptap-editor", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", 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 }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, fillContainer: { classPropertyName: "fillContainer", publicName: "fillContainer", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showCharacterCount: { classPropertyName: "showCharacterCount", publicName: "showCharacterCount", isSignal: true, isRequired: false, transformFunction: null }, showWordCount: { classPropertyName: "showWordCount", publicName: "showWordCount", isSignal: true, isRequired: false, transformFunction: null }, maxCharacters: { classPropertyName: "maxCharacters", publicName: "maxCharacters", isSignal: true, isRequired: false, transformFunction: null }, enableOfficePaste: { classPropertyName: "enableOfficePaste", publicName: "enableOfficePaste", isSignal: true, isRequired: false, transformFunction: null }, enableSlashCommands: { classPropertyName: "enableSlashCommands", publicName: "enableSlashCommands", isSignal: true, isRequired: false, transformFunction: null }, enableBlockShortcuts: { classPropertyName: "enableBlockShortcuts", publicName: "enableBlockShortcuts", isSignal: true, isRequired: false, transformFunction: null }, slashCommands: { classPropertyName: "slashCommands", publicName: "slashCommands", isSignal: true, isRequired: false, transformFunction: null }, customSlashCommands: { classPropertyName: "customSlashCommands", publicName: "customSlashCommands", isSignal: true, isRequired: false, transformFunction: null }, blockControls: { classPropertyName: "blockControls", publicName: "blockControls", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, seamless: { classPropertyName: "seamless", publicName: "seamless", isSignal: true, isRequired: false, transformFunction: null }, floatingToolbar: { classPropertyName: "floatingToolbar", publicName: "floatingToolbar", isSignal: true, isRequired: false, transformFunction: null }, showEditToggle: { classPropertyName: "showEditToggle", publicName: "showEditToggle", isSignal: true, isRequired: false, transformFunction: null }, spellcheck: { classPropertyName: "spellcheck", publicName: "spellcheck", isSignal: true, isRequired: false, transformFunction: null }, tiptapExtensions: { classPropertyName: "tiptapExtensions", publicName: "tiptapExtensions", isSignal: true, isRequired: false, transformFunction: null }, tiptapOptions: { classPropertyName: "tiptapOptions", publicName: "tiptapOptions", isSignal: true, isRequired: false, transformFunction: null }, starterKitOptions: { classPropertyName: "starterKitOptions", publicName: "starterKitOptions", isSignal: true, isRequired: false, transformFunction: null }, showBubbleMenu: { classPropertyName: "showBubbleMenu", publicName: "showBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, bubbleMenu: { classPropertyName: "bubbleMenu", publicName: "bubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, showImageBubbleMenu: { classPropertyName: "showImageBubbleMenu", publicName: "showImageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, imageBubbleMenu: { classPropertyName: "imageBubbleMenu", publicName: "imageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, showTableBubbleMenu: { classPropertyName: "showTableBubbleMenu", publicName: "showTableBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, tableBubbleMenu: { classPropertyName: "tableBubbleMenu", publicName: "tableBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, showCellBubbleMenu: { classPropertyName: "showCellBubbleMenu", publicName: "showCellBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, cellBubbleMenu: { classPropertyName: "cellBubbleMenu", publicName: "cellBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, stateCalculators: { classPropertyName: "stateCalculators", publicName: "stateCalculators", isSignal: true, isRequired: false, transformFunction: null }, imageUpload: { classPropertyName: "imageUpload", publicName: "imageUpload", isSignal: true, isRequired: false, transformFunction: null }, imageUploadHandler: { classPropertyName: "imageUploadHandler", publicName: "imageUploadHandler", isSignal: true, isRequired: false, transformFunction: null }, editorId: { classPropertyName: "editorId", publicName: "editorId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChange: "contentChange", editorCreated: "editorCreated", editorUpdate: "editorUpdate", editorFocus: "editorFocus", editorBlur: "editorBlur", editableChange: "editableChange", imageUploaded: "imageUploaded", imageRejected: "imageRejected", pastedImageRejected: "pastedImageRejected" }, host: { properties: { "class.fill-container": "finalFillContainer()", "class.floating-toolbar": "finalFloatingToolbar()", "class.is-readonly": "!finalEditable() && !mergedDisabled()", "class.is-disabled": "mergedDisabled()", "style.--ate-border-width": "finalSeamless() || mergedDisabled() ? '0' : null", "style.--ate-background": "finalSeamless() ? 'transparent' : (mergedDisabled() ? 'var(--ate-surface-tertiary)' : null)", "style.--ate-toolbar-border-color": "finalSeamless() ? 'transparent' : null", "style.--ate-counter-background": "finalSeamless() ? 'transparent' : null", "style.--ate-counter-border-color": "finalSeamless() ? 'transparent' : null", "class.dark": "config().theme === 'dark'", "class.ate-blocks-inside": "finalBlockControls() === 'inside'", "class.ate-blocks-outside": "finalBlockControls() === 'outside'", "attr.data-theme": "config().theme" } }, providers: [
9623
10381
  AteEditorCommandsService,
9624
10382
  AteImageService,
9625
10383
  AteColorPickerService,
@@ -10115,5 +10873,5 @@ const ATE_DEFAULT_TOC_CONFIG = {
10115
10873
  * Generated bundle index. Do not edit.
10116
10874
  */
10117
10875
 
10118
- export { ATE_BUBBLE_MENU_KEYS, ATE_CELL_BUBBLE_MENU_KEYS, ATE_DEFAULT_BUBBLE_MENU_CONFIG, ATE_DEFAULT_CELL_MENU_CONFIG, ATE_DEFAULT_CONFIG, ATE_DEFAULT_ICONS, ATE_DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, ATE_DEFAULT_IMAGE_UPLOAD_CONFIG, ATE_DEFAULT_SLASH_COMMANDS_CONFIG, ATE_DEFAULT_TABLE_MENU_CONFIG, ATE_DEFAULT_TOC_CONFIG, ATE_DEFAULT_TOOLBAR_CONFIG, ATE_GLOBAL_CONFIG, ATE_ICONS, ATE_IMAGE_BUBBLE_MENU_KEYS, ATE_INITIAL_EDITOR_STATE, ATE_MATERIAL_SYMBOLS_VIEWBOX, ATE_SLASH_COMMAND_KEYS, ATE_STROKE_ICONS, ATE_TABLE_BUBBLE_MENU_KEYS, ATE_TOOLBAR_KEYS, AngularTiptapEditorComponent, AteAngularNodeView, AteColorPickerService, AteDiscoveryCalculator, AteEditorCommandsService, AteEditorRef, AteEditorRegistry, AteExportService, AteI18nService, AteIconComponent, AteIconRegistry, AteImageCalculator, AteImageService, AteLinkService, AteLinkShortcut, AteMarksCalculator, AteNodeViewRenderer, AteNoopValueAccessorDirective, AtePastedImage, AteSelectionCalculator, AteStructureCalculator, AteTableCalculator, AteTableOfContentsComponent, AteTocNodeComponent, AteTocNodeOptions, AteTooltipDirective, classifyPastedImageSrc, createAngularComponentExtension, createDefaultSlashCommands, dataUriToFile, filterSlashCommands, getAteTocNodeExtension, isLinkShortcut, provideAteEditor, provideAteIcons, registerAngularComponent, sanitizePastedImages };
10876
+ export { ATE_BUBBLE_MENU_KEYS, ATE_CELL_BUBBLE_MENU_KEYS, ATE_DEFAULT_BUBBLE_MENU_CONFIG, ATE_DEFAULT_CELL_MENU_CONFIG, ATE_DEFAULT_CONFIG, ATE_DEFAULT_ICONS, ATE_DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, ATE_DEFAULT_IMAGE_UPLOAD_CONFIG, ATE_DEFAULT_SLASH_COMMANDS_CONFIG, ATE_DEFAULT_TABLE_MENU_CONFIG, ATE_DEFAULT_TOC_CONFIG, ATE_DEFAULT_TOOLBAR_CONFIG, ATE_GLOBAL_CONFIG, ATE_ICONS, ATE_IMAGE_BUBBLE_MENU_KEYS, ATE_INITIAL_EDITOR_STATE, ATE_MATERIAL_SYMBOLS_VIEWBOX, ATE_SLASH_COMMAND_KEYS, ATE_STROKE_ICONS, ATE_TABLE_BUBBLE_MENU_KEYS, ATE_TOOLBAR_KEYS, AngularTiptapEditorComponent, AteAngularNodeView, AteBlockShortcuts, AteColorPickerService, AteDiscoveryCalculator, AteEditorCommandsService, AteEditorRef, AteEditorRegistry, AteExportService, AteI18nService, AteIconComponent, AteIconRegistry, AteImageCalculator, AteImageService, AteImageValidationError, AteLinkService, AteLinkShortcut, AteMarksCalculator, AteNodeViewRenderer, AteNoopValueAccessorDirective, AtePastedImage, AteSelectionCalculator, AteStructureCalculator, AteTableCalculator, AteTableOfContentsComponent, AteTocNodeComponent, AteTocNodeOptions, AteTooltipDirective, classifyPastedImageSrc, createAngularComponentExtension, createDefaultSlashCommands, dataUriToFile, filterSlashCommands, getAteTocNodeExtension, isLinkShortcut, provideAteEditor, provideAteIcons, registerAngularComponent, sanitizePastedImages };
10119
10877
  //# sourceMappingURL=flogeez-angular-tiptap-editor.mjs.map