@adminforth/rich-editor 2.1.2 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,9 @@
4
4
 
5
5
  [![Ask AI](https://tluma.ai/badge)](https://tluma.ai/ask-ai/devforth/adminforth)
6
6
 
7
+ > [!WARNING]
8
+ > **This plugin is not recommended for new projects.** Use the [Markdown plugin](https://adminforth.dev/docs/tutorial/Plugins/markdown/) (`@adminforth/markdown`) for editing formatted text instead. It stores content as Markdown, which suits the agentic era much better than HTML: AI agents read and write Markdown reliably, it stays readable as plain text and gives clean diffs. RichEditor keeps working for apps which already store HTML.
9
+
7
10
  Allows to add a rich text editor to your AdminForth text columns.
8
11
 
9
12
  ## Features
package/build.log CHANGED
@@ -10,5 +10,5 @@ custom/package.json
10
10
  custom/quillEditor.vue
11
11
  custom/tsconfig.json
12
12
 
13
- sent 35,541 bytes received 115 bytes 71,312.00 bytes/sec
14
- total size is 35,118 speedup is 0.98
13
+ sent 38,509 bytes received 115 bytes 77,248.00 bytes/sec
14
+ total size is 38,086 speedup is 0.99
@@ -1,10 +1,11 @@
1
1
  <template>
2
2
  <div
3
3
  v-if="wasQuillInitializedSuccessfully"
4
- class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500
5
- focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400
6
- dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 whitespace-normal af-quill-editor"
7
- :class="'bg-lightInputBackground placeholder-lightInputPlaceholderText text-lightInputText border-lightInputBorder dark:!bg-darkInputBackground dark:!placeholder-darkInputPlaceholderText dark:!text-darkInputText dark:!border-darkInputBorder'"
4
+ class="af-quill-editor block w-full whitespace-normal rounded-default border shadow-customLight transition-colors
5
+ bg-lightInputBackground text-lightInputText border-lightInputBorder hover:border-lightInputBorderHover
6
+ focus-within:border-lightInputFocusBorder focus-within:ring-[3px] focus-within:ring-lightInputFocusRing
7
+ dark:bg-darkInputBackground dark:text-darkInputText dark:border-darkInputBorder dark:hover:border-darkInputBorderHover
8
+ dark:focus-within:border-darkInputFocusBorder dark:focus-within:ring-darkInputFocusRing"
8
9
  >
9
10
  <div
10
11
  ref="editor"
@@ -28,7 +29,7 @@
28
29
  </template>
29
30
 
30
31
  <script setup lang="ts">
31
- import { onMounted, ref, onUnmounted, watch, type Ref } from "vue";
32
+ import { onMounted, ref, onUnmounted, watch, h, render, type Ref, type FunctionalComponent } from "vue";
32
33
  import { callAdminForthApi } from '@/utils';
33
34
  import { AdminForthColumnCommon } from '@/types/Common';
34
35
  import adminforth from '@/adminforth';
@@ -39,6 +40,11 @@ import "quill/dist/quill.snow.css";
39
40
  import QuillTableBetter from 'quill-table-better-yaroslav8765';
40
41
  import 'quill-table-better-yaroslav8765/dist/quill-table-better.css';
41
42
  import { Textarea } from '@/afcl'
43
+ import {
44
+ IconAlignCenter, IconAlignJustify, IconAlignLeft, IconAlignRight, IconBold, IconCode, IconHeading2, IconHeading3,
45
+ IconImage, IconItalic, IconLink, IconList, IconListChecks, IconListOrdered, IconRemoveFormatting, IconStrikethrough,
46
+ IconTable, IconTextQuote, IconUnderline,
47
+ } from '@iconify-prerendered/vue-lucide';
42
48
 
43
49
  import { useI18n } from 'vue-i18n';
44
50
  import { ok } from "assert";
@@ -131,6 +137,31 @@ Quill.register({
131
137
  'modules/table-better': QuillTableBetter
132
138
  }, true);
133
139
 
140
+ // the toolbar draws Lucide icons like the rest of the UI; Quill takes icons as SVG strings,
141
+ // so they are set after the table module registered its own one
142
+ function iconSvg(icon: FunctionalComponent) {
143
+ const holder = document.createElement('div');
144
+ render(h(icon), holder);
145
+ return holder.innerHTML;
146
+ }
147
+
148
+ const quillIcons = Quill.import('ui/icons') as Record<string, any>;
149
+ Object.assign(quillIcons, {
150
+ bold: iconSvg(IconBold),
151
+ italic: iconSvg(IconItalic),
152
+ underline: iconSvg(IconUnderline),
153
+ strike: iconSvg(IconStrikethrough),
154
+ 'table-better': iconSvg(IconTable),
155
+ blockquote: iconSvg(IconTextQuote),
156
+ 'code-block': iconSvg(IconCode),
157
+ link: iconSvg(IconLink),
158
+ image: iconSvg(IconImage),
159
+ clean: iconSvg(IconRemoveFormatting),
160
+ header: { ...quillIcons.header, 2: iconSvg(IconHeading2), 3: iconSvg(IconHeading3) },
161
+ list: { ...quillIcons.list, ordered: iconSvg(IconListOrdered), bullet: iconSvg(IconList), check: iconSvg(IconListChecks) },
162
+ align: { ...quillIcons.align, '': iconSvg(IconAlignLeft), center: iconSvg(IconAlignCenter), right: iconSvg(IconAlignRight), justify: iconSvg(IconAlignJustify) },
163
+ });
164
+
134
165
 
135
166
  const updaterQueue = new AsyncQueue();
136
167
 
@@ -630,34 +661,61 @@ function removeCompletionOnBlur() {
630
661
 
631
662
  .af-quill-editor {
632
663
 
664
+ // the toolbar sits on a hairline over the text, its buttons are quiet like AFCL ghost icon buttons
633
665
  .ql-toolbar.ql-snow[class] {
634
- border: none;
635
- padding: 0 0 1rem 0;
636
- .ql-picker-label{
637
- padding-left: 0;
666
+ @apply flex flex-wrap items-center gap-0.5 border-0 border-b border-lightInputBorder px-1.5 py-1 dark:border-darkInputBorder;
667
+ font-family: inherit;
668
+
669
+ .ql-formats {
670
+ @apply inline-flex items-center gap-0.5 mr-2;
671
+ }
672
+
673
+ button, .ql-picker-label {
674
+ @apply w-7 h-7 p-1.5 rounded-default border-0 text-lightInputIconColor transition-colors dark:text-darkInputIconColor;
675
+ }
676
+
677
+ button svg, .ql-picker-label svg {
678
+ @apply w-4 h-4;
679
+ }
680
+
681
+ button:hover, .ql-picker-label:hover {
682
+ @apply bg-lightSecondaryDarken text-lightInputText dark:bg-darkSecondaryLighten dark:text-darkInputText;
683
+ }
684
+
685
+ button.ql-active, .ql-picker-label.ql-active, .ql-picker-item.ql-selected {
686
+ @apply text-lightPrimary dark:text-darkPrimary;
687
+ }
688
+
689
+ .ql-picker.ql-icon-picker {
690
+ @apply w-7 h-7;
691
+ }
692
+
693
+ .ql-picker-options {
694
+ @apply p-1 rounded-lg border-0 bg-lightDropdownOptionsBackground shadow-popover dark:bg-darkDropdownOptionsBackground dark:shadow-darkPopover;
695
+ }
696
+
697
+ .ql-picker-item {
698
+ @apply w-7 h-7 p-1.5 rounded-md text-lightInputIconColor hover:bg-lightDropdownOptionsHoverBackground hover:text-lightInputText dark:text-darkInputIconColor dark:hover:bg-darkDropdownOptionsHoverBackground dark:hover:text-darkInputText;
638
699
  }
639
700
  }
640
701
 
641
702
  .ql-container {
642
703
  border: 0;
704
+ font-family: inherit;
705
+ font-size: inherit;
706
+
643
707
  .ql-editor {
644
708
  position: relative;
645
- padding: 0;
709
+ @apply px-3 py-2.5 text-sm;
646
710
  min-height: 100px;
647
711
  &.ql-blank::before {
648
- left: 0px;
649
- font-style: normal;
712
+ @apply left-3 right-3 not-italic text-lightInputPlaceholderText dark:text-darkInputPlaceholderText;
650
713
  }
651
714
  }
652
715
  }
653
716
 
654
- // .ql-editor:not(:focus) [completer] {
655
- // display: none;
656
- // }
657
-
658
717
  .ql-editor [completer] {
659
- color: gray;
660
- font-style: italic;
718
+ @apply italic text-lightInputPlaceholderText dark:text-darkInputPlaceholderText;
661
719
  }
662
720
 
663
721
  // basic typography
@@ -690,23 +748,21 @@ function removeCompletionOnBlur() {
690
748
  /* Horizontal rule */
691
749
  hr {
692
750
  margin: 0.8rem 0;
693
- border: none;
694
- border-top: 1px solid #ddd;
751
+ @apply border-0 border-t border-lightInputBorder dark:border-darkInputBorder;
695
752
  }
696
753
 
697
754
  /* Blockquotes */
698
755
  blockquote {
699
756
  margin: 0.8rem 0;
700
757
  padding-left: 0.8rem;
701
- border-left: 2px solid #ccc;
758
+ @apply border-0 border-l-2 border-lightInputBorder text-lightInputIconColor dark:border-darkInputBorder dark:text-darkInputIconColor;
702
759
  }
703
760
 
704
761
  /* Preformatted text */
705
762
  pre {
706
763
  margin: 0.8rem 0;
707
764
  padding: 0.4rem;
708
- background: #f8f9fa;
709
- border-radius: 3px;
765
+ @apply rounded bg-lightSecondaryDarken text-lightInputText dark:bg-darkSecondaryLighten dark:text-darkInputText;
710
766
  }
711
767
 
712
768
  /* Tables */
@@ -717,11 +773,11 @@ function removeCompletionOnBlur() {
717
773
 
718
774
  th, td {
719
775
  padding: 0.3rem;
720
- border: 1px solid #ddd;
776
+ @apply border border-lightInputBorder dark:border-darkInputBorder;
721
777
  }
722
778
 
723
779
  thead th {
724
- border-bottom: 1.5px solid #aaa;
780
+ @apply border-b-2;
725
781
  }
726
782
 
727
783
  /* Images */
@@ -732,27 +788,21 @@ function removeCompletionOnBlur() {
732
788
  }
733
789
  }
734
790
 
791
+ // Quill's own icons which are left (table menus) follow the muted icon color too
735
792
  .ql-snow .ql-stroke {
736
- @apply dark:stroke-darkPrimary;
737
- @apply stroke-lightPrimary;
738
-
739
- }
740
- .ql-snow button:hover .ql-stroke,
741
- .ql-snow [role="button"]:hover .ql-stroke {
742
- @apply dark:stroke-darkPrimary;
743
- @apply stroke-lightPrimary;
744
- filter: brightness(1.3);
793
+ @apply stroke-lightInputIconColor dark:stroke-darkInputIconColor;
745
794
  }
746
795
 
747
796
  .ql-snow .ql-fill {
748
- @apply dark:fill-darkPrimary;
749
- @apply fill-lightPrimary;
797
+ @apply fill-lightInputIconColor dark:fill-darkInputIconColor;
750
798
  }
751
799
 
752
- .ql-snow button:hover .ql-fill {
753
- @apply dark:fill-darkPrimary;
754
- @apply fill-lightPrimary;
755
- filter: brightness(1.3);
800
+ .ql-snow .ql-active .ql-stroke {
801
+ @apply stroke-lightPrimary dark:stroke-darkPrimary;
802
+ }
803
+
804
+ .ql-snow .ql-active .ql-fill {
805
+ @apply fill-lightPrimary dark:fill-darkPrimary;
756
806
  }
757
807
 
758
808
  }
@@ -779,11 +829,6 @@ function removeCompletionOnBlur() {
779
829
  }
780
830
  }
781
831
 
782
- .ql-table-better svg path {
783
- @apply dark:fill-darkPrimary;
784
- @apply fill-lightPrimary;
785
- }
786
-
787
832
  .ql-table-select-container {
788
833
  @apply dark:bg-darkForm;
789
834
  @apply bg-lightForm;
@@ -1,10 +1,11 @@
1
1
  <template>
2
2
  <div
3
3
  v-if="wasQuillInitializedSuccessfully"
4
- class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500
5
- focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400
6
- dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 whitespace-normal af-quill-editor"
7
- :class="'bg-lightInputBackground placeholder-lightInputPlaceholderText text-lightInputText border-lightInputBorder dark:!bg-darkInputBackground dark:!placeholder-darkInputPlaceholderText dark:!text-darkInputText dark:!border-darkInputBorder'"
4
+ class="af-quill-editor block w-full whitespace-normal rounded-default border shadow-customLight transition-colors
5
+ bg-lightInputBackground text-lightInputText border-lightInputBorder hover:border-lightInputBorderHover
6
+ focus-within:border-lightInputFocusBorder focus-within:ring-[3px] focus-within:ring-lightInputFocusRing
7
+ dark:bg-darkInputBackground dark:text-darkInputText dark:border-darkInputBorder dark:hover:border-darkInputBorderHover
8
+ dark:focus-within:border-darkInputFocusBorder dark:focus-within:ring-darkInputFocusRing"
8
9
  >
9
10
  <div
10
11
  ref="editor"
@@ -28,7 +29,7 @@
28
29
  </template>
29
30
 
30
31
  <script setup lang="ts">
31
- import { onMounted, ref, onUnmounted, watch, type Ref } from "vue";
32
+ import { onMounted, ref, onUnmounted, watch, h, render, type Ref, type FunctionalComponent } from "vue";
32
33
  import { callAdminForthApi } from '@/utils';
33
34
  import { AdminForthColumnCommon } from '@/types/Common';
34
35
  import adminforth from '@/adminforth';
@@ -39,6 +40,11 @@ import "quill/dist/quill.snow.css";
39
40
  import QuillTableBetter from 'quill-table-better-yaroslav8765';
40
41
  import 'quill-table-better-yaroslav8765/dist/quill-table-better.css';
41
42
  import { Textarea } from '@/afcl'
43
+ import {
44
+ IconAlignCenter, IconAlignJustify, IconAlignLeft, IconAlignRight, IconBold, IconCode, IconHeading2, IconHeading3,
45
+ IconImage, IconItalic, IconLink, IconList, IconListChecks, IconListOrdered, IconRemoveFormatting, IconStrikethrough,
46
+ IconTable, IconTextQuote, IconUnderline,
47
+ } from '@iconify-prerendered/vue-lucide';
42
48
 
43
49
  import { useI18n } from 'vue-i18n';
44
50
  import { ok } from "assert";
@@ -131,6 +137,31 @@ Quill.register({
131
137
  'modules/table-better': QuillTableBetter
132
138
  }, true);
133
139
 
140
+ // the toolbar draws Lucide icons like the rest of the UI; Quill takes icons as SVG strings,
141
+ // so they are set after the table module registered its own one
142
+ function iconSvg(icon: FunctionalComponent) {
143
+ const holder = document.createElement('div');
144
+ render(h(icon), holder);
145
+ return holder.innerHTML;
146
+ }
147
+
148
+ const quillIcons = Quill.import('ui/icons') as Record<string, any>;
149
+ Object.assign(quillIcons, {
150
+ bold: iconSvg(IconBold),
151
+ italic: iconSvg(IconItalic),
152
+ underline: iconSvg(IconUnderline),
153
+ strike: iconSvg(IconStrikethrough),
154
+ 'table-better': iconSvg(IconTable),
155
+ blockquote: iconSvg(IconTextQuote),
156
+ 'code-block': iconSvg(IconCode),
157
+ link: iconSvg(IconLink),
158
+ image: iconSvg(IconImage),
159
+ clean: iconSvg(IconRemoveFormatting),
160
+ header: { ...quillIcons.header, 2: iconSvg(IconHeading2), 3: iconSvg(IconHeading3) },
161
+ list: { ...quillIcons.list, ordered: iconSvg(IconListOrdered), bullet: iconSvg(IconList), check: iconSvg(IconListChecks) },
162
+ align: { ...quillIcons.align, '': iconSvg(IconAlignLeft), center: iconSvg(IconAlignCenter), right: iconSvg(IconAlignRight), justify: iconSvg(IconAlignJustify) },
163
+ });
164
+
134
165
 
135
166
  const updaterQueue = new AsyncQueue();
136
167
 
@@ -630,34 +661,61 @@ function removeCompletionOnBlur() {
630
661
 
631
662
  .af-quill-editor {
632
663
 
664
+ // the toolbar sits on a hairline over the text, its buttons are quiet like AFCL ghost icon buttons
633
665
  .ql-toolbar.ql-snow[class] {
634
- border: none;
635
- padding: 0 0 1rem 0;
636
- .ql-picker-label{
637
- padding-left: 0;
666
+ @apply flex flex-wrap items-center gap-0.5 border-0 border-b border-lightInputBorder px-1.5 py-1 dark:border-darkInputBorder;
667
+ font-family: inherit;
668
+
669
+ .ql-formats {
670
+ @apply inline-flex items-center gap-0.5 mr-2;
671
+ }
672
+
673
+ button, .ql-picker-label {
674
+ @apply w-7 h-7 p-1.5 rounded-default border-0 text-lightInputIconColor transition-colors dark:text-darkInputIconColor;
675
+ }
676
+
677
+ button svg, .ql-picker-label svg {
678
+ @apply w-4 h-4;
679
+ }
680
+
681
+ button:hover, .ql-picker-label:hover {
682
+ @apply bg-lightSecondaryDarken text-lightInputText dark:bg-darkSecondaryLighten dark:text-darkInputText;
683
+ }
684
+
685
+ button.ql-active, .ql-picker-label.ql-active, .ql-picker-item.ql-selected {
686
+ @apply text-lightPrimary dark:text-darkPrimary;
687
+ }
688
+
689
+ .ql-picker.ql-icon-picker {
690
+ @apply w-7 h-7;
691
+ }
692
+
693
+ .ql-picker-options {
694
+ @apply p-1 rounded-lg border-0 bg-lightDropdownOptionsBackground shadow-popover dark:bg-darkDropdownOptionsBackground dark:shadow-darkPopover;
695
+ }
696
+
697
+ .ql-picker-item {
698
+ @apply w-7 h-7 p-1.5 rounded-md text-lightInputIconColor hover:bg-lightDropdownOptionsHoverBackground hover:text-lightInputText dark:text-darkInputIconColor dark:hover:bg-darkDropdownOptionsHoverBackground dark:hover:text-darkInputText;
638
699
  }
639
700
  }
640
701
 
641
702
  .ql-container {
642
703
  border: 0;
704
+ font-family: inherit;
705
+ font-size: inherit;
706
+
643
707
  .ql-editor {
644
708
  position: relative;
645
- padding: 0;
709
+ @apply px-3 py-2.5 text-sm;
646
710
  min-height: 100px;
647
711
  &.ql-blank::before {
648
- left: 0px;
649
- font-style: normal;
712
+ @apply left-3 right-3 not-italic text-lightInputPlaceholderText dark:text-darkInputPlaceholderText;
650
713
  }
651
714
  }
652
715
  }
653
716
 
654
- // .ql-editor:not(:focus) [completer] {
655
- // display: none;
656
- // }
657
-
658
717
  .ql-editor [completer] {
659
- color: gray;
660
- font-style: italic;
718
+ @apply italic text-lightInputPlaceholderText dark:text-darkInputPlaceholderText;
661
719
  }
662
720
 
663
721
  // basic typography
@@ -690,23 +748,21 @@ function removeCompletionOnBlur() {
690
748
  /* Horizontal rule */
691
749
  hr {
692
750
  margin: 0.8rem 0;
693
- border: none;
694
- border-top: 1px solid #ddd;
751
+ @apply border-0 border-t border-lightInputBorder dark:border-darkInputBorder;
695
752
  }
696
753
 
697
754
  /* Blockquotes */
698
755
  blockquote {
699
756
  margin: 0.8rem 0;
700
757
  padding-left: 0.8rem;
701
- border-left: 2px solid #ccc;
758
+ @apply border-0 border-l-2 border-lightInputBorder text-lightInputIconColor dark:border-darkInputBorder dark:text-darkInputIconColor;
702
759
  }
703
760
 
704
761
  /* Preformatted text */
705
762
  pre {
706
763
  margin: 0.8rem 0;
707
764
  padding: 0.4rem;
708
- background: #f8f9fa;
709
- border-radius: 3px;
765
+ @apply rounded bg-lightSecondaryDarken text-lightInputText dark:bg-darkSecondaryLighten dark:text-darkInputText;
710
766
  }
711
767
 
712
768
  /* Tables */
@@ -717,11 +773,11 @@ function removeCompletionOnBlur() {
717
773
 
718
774
  th, td {
719
775
  padding: 0.3rem;
720
- border: 1px solid #ddd;
776
+ @apply border border-lightInputBorder dark:border-darkInputBorder;
721
777
  }
722
778
 
723
779
  thead th {
724
- border-bottom: 1.5px solid #aaa;
780
+ @apply border-b-2;
725
781
  }
726
782
 
727
783
  /* Images */
@@ -732,27 +788,21 @@ function removeCompletionOnBlur() {
732
788
  }
733
789
  }
734
790
 
791
+ // Quill's own icons which are left (table menus) follow the muted icon color too
735
792
  .ql-snow .ql-stroke {
736
- @apply dark:stroke-darkPrimary;
737
- @apply stroke-lightPrimary;
738
-
739
- }
740
- .ql-snow button:hover .ql-stroke,
741
- .ql-snow [role="button"]:hover .ql-stroke {
742
- @apply dark:stroke-darkPrimary;
743
- @apply stroke-lightPrimary;
744
- filter: brightness(1.3);
793
+ @apply stroke-lightInputIconColor dark:stroke-darkInputIconColor;
745
794
  }
746
795
 
747
796
  .ql-snow .ql-fill {
748
- @apply dark:fill-darkPrimary;
749
- @apply fill-lightPrimary;
797
+ @apply fill-lightInputIconColor dark:fill-darkInputIconColor;
750
798
  }
751
799
 
752
- .ql-snow button:hover .ql-fill {
753
- @apply dark:fill-darkPrimary;
754
- @apply fill-lightPrimary;
755
- filter: brightness(1.3);
800
+ .ql-snow .ql-active .ql-stroke {
801
+ @apply stroke-lightPrimary dark:stroke-darkPrimary;
802
+ }
803
+
804
+ .ql-snow .ql-active .ql-fill {
805
+ @apply fill-lightPrimary dark:fill-darkPrimary;
756
806
  }
757
807
 
758
808
  }
@@ -779,11 +829,6 @@ function removeCompletionOnBlur() {
779
829
  }
780
830
  }
781
831
 
782
- .ql-table-better svg path {
783
- @apply dark:fill-darkPrimary;
784
- @apply fill-lightPrimary;
785
- }
786
-
787
832
  .ql-table-select-container {
788
833
  @apply dark:bg-darkForm;
789
834
  @apply bg-lightForm;
package/dist/index.js CHANGED
@@ -135,9 +135,9 @@ export default class RichEditorPlugin extends AdminForthPlugin {
135
135
  }));
136
136
  // after edit we need to delete attachments that are not in the html anymore
137
137
  // and add new ones
138
- (resourceConfig.hooks.edit.afterSave).push((_a) => __awaiter(this, [_a], void 0, function* ({ recordId, record, adminUser }) {
139
- process.env.HEAVY_DEBUG && console.log('⚓ Cought hook', recordId, 'rec', record);
140
- if (record[this.options.htmlFieldName] === undefined) {
138
+ (resourceConfig.hooks.edit.afterSave).push((_a) => __awaiter(this, [_a], void 0, function* ({ recordId, updates, adminUser }) {
139
+ process.env.HEAVY_DEBUG && console.log('⚓ Cought hook', recordId, 'updates', updates);
140
+ if (updates[this.options.htmlFieldName] === undefined) {
141
141
  // field was not changed, do nothing
142
142
  return { ok: true };
143
143
  }
@@ -146,7 +146,7 @@ export default class RichEditorPlugin extends AdminForthPlugin {
146
146
  Filters.EQ(this.options.attachments.attachmentResourceIdFieldName, resourceConfig.resourceId)
147
147
  ]);
148
148
  const existingS3Paths = existingAparts.map((a) => a[this.options.attachments.attachmentFieldName]);
149
- const newS3Paths = getAttachmentPathes(record[this.options.htmlFieldName]);
149
+ const newS3Paths = getAttachmentPathes(updates[this.options.htmlFieldName]);
150
150
  process.env.HEAVY_DEBUG && console.log('📸 Existing s3Paths (from db)', existingS3Paths);
151
151
  process.env.HEAVY_DEBUG && console.log('📸 Found new s3Paths (from text)', newS3Paths);
152
152
  const toDelete = existingS3Paths.filter(s3Path => !newS3Paths.includes(s3Path));
package/index.ts CHANGED
@@ -172,9 +172,9 @@ export default class RichEditorPlugin extends AdminForthPlugin {
172
172
  // after edit we need to delete attachments that are not in the html anymore
173
173
  // and add new ones
174
174
  (resourceConfig.hooks.edit.afterSave).push(
175
- async ({ recordId, record, adminUser }: { recordId: any, record: any, adminUser: AdminUser }) => {
176
- process.env.HEAVY_DEBUG && console.log('⚓ Cought hook', recordId, 'rec', record);
177
- if (record[this.options.htmlFieldName] === undefined) {
175
+ async ({ recordId, updates, adminUser }: { recordId: any, updates: any, adminUser: AdminUser }) => {
176
+ process.env.HEAVY_DEBUG && console.log('⚓ Cought hook', recordId, 'updates', updates);
177
+ if (updates[this.options.htmlFieldName] === undefined) {
178
178
  // field was not changed, do nothing
179
179
  return { ok: true };
180
180
  }
@@ -183,7 +183,7 @@ export default class RichEditorPlugin extends AdminForthPlugin {
183
183
  Filters.EQ(this.options.attachments.attachmentResourceIdFieldName, resourceConfig.resourceId)
184
184
  ]);
185
185
  const existingS3Paths = existingAparts.map((a: any) => a[this.options.attachments.attachmentFieldName]);
186
- const newS3Paths = getAttachmentPathes(record[this.options.htmlFieldName]);
186
+ const newS3Paths = getAttachmentPathes(updates[this.options.htmlFieldName]);
187
187
  process.env.HEAVY_DEBUG && console.log('📸 Existing s3Paths (from db)', existingS3Paths)
188
188
  process.env.HEAVY_DEBUG && console.log('📸 Found new s3Paths (from text)', newS3Paths);
189
189
  const toDelete = existingS3Paths.filter(s3Path => !newS3Paths.includes(s3Path));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/rich-editor",
3
- "version": "2.1.2",
3
+ "version": "3.0.1",
4
4
  "description": "Rich editor plugin for adminforth",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -27,11 +27,11 @@
27
27
  "zod": "^4.3.6"
28
28
  },
29
29
  "peerDependencies": {
30
- "adminforth": "^3.8.2"
30
+ "adminforth": "^4.4.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^22.10.7",
34
- "adminforth": "^3.8.2",
34
+ "adminforth": "^4.7.3",
35
35
  "semantic-release": "^24.2.1",
36
36
  "semantic-release-slack-bot": "^4.0.2",
37
37
  "typescript": "^5.7.3"