payload-plugin-newsletter 0.15.0 → 0.15.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.
@@ -529,6 +529,103 @@ import {
529
529
  InlineToolbarFeature,
530
530
  lexicalEditor
531
531
  } from "@payloadcms/richtext-lexical";
532
+
533
+ // src/utils/blockValidation.ts
534
+ var EMAIL_INCOMPATIBLE_TYPES = [
535
+ "chart",
536
+ "dataTable",
537
+ "interactive",
538
+ "streamable",
539
+ "video",
540
+ "iframe",
541
+ "form",
542
+ "carousel",
543
+ "tabs",
544
+ "accordion",
545
+ "map"
546
+ ];
547
+ var validateEmailBlocks = (blocks) => {
548
+ blocks.forEach((block) => {
549
+ if (EMAIL_INCOMPATIBLE_TYPES.includes(block.slug)) {
550
+ console.warn(`\u26A0\uFE0F Block "${block.slug}" may not be email-compatible. Consider creating an email-specific version.`);
551
+ }
552
+ const hasComplexFields = block.fields?.some((field) => {
553
+ const complexTypes = ["code", "json", "richText", "blocks", "array"];
554
+ return complexTypes.includes(field.type);
555
+ });
556
+ if (hasComplexFields) {
557
+ console.warn(`\u26A0\uFE0F Block "${block.slug}" contains complex field types that may not render consistently in email clients.`);
558
+ }
559
+ });
560
+ };
561
+ var createEmailSafeBlocks = (customBlocks = []) => {
562
+ validateEmailBlocks(customBlocks);
563
+ const baseBlocks = [
564
+ {
565
+ slug: "button",
566
+ fields: [
567
+ {
568
+ name: "text",
569
+ type: "text",
570
+ label: "Button Text",
571
+ required: true
572
+ },
573
+ {
574
+ name: "url",
575
+ type: "text",
576
+ label: "Button URL",
577
+ required: true,
578
+ admin: {
579
+ description: "Enter the full URL (including https://)"
580
+ }
581
+ },
582
+ {
583
+ name: "style",
584
+ type: "select",
585
+ label: "Button Style",
586
+ defaultValue: "primary",
587
+ options: [
588
+ { label: "Primary", value: "primary" },
589
+ { label: "Secondary", value: "secondary" },
590
+ { label: "Outline", value: "outline" }
591
+ ]
592
+ }
593
+ ],
594
+ interfaceName: "EmailButton",
595
+ labels: {
596
+ singular: "Button",
597
+ plural: "Buttons"
598
+ }
599
+ },
600
+ {
601
+ slug: "divider",
602
+ fields: [
603
+ {
604
+ name: "style",
605
+ type: "select",
606
+ label: "Divider Style",
607
+ defaultValue: "solid",
608
+ options: [
609
+ { label: "Solid", value: "solid" },
610
+ { label: "Dashed", value: "dashed" },
611
+ { label: "Dotted", value: "dotted" }
612
+ ]
613
+ }
614
+ ],
615
+ interfaceName: "EmailDivider",
616
+ labels: {
617
+ singular: "Divider",
618
+ plural: "Dividers"
619
+ }
620
+ }
621
+ ];
622
+ return [
623
+ ...baseBlocks,
624
+ ...customBlocks
625
+ ];
626
+ };
627
+
628
+ // src/fields/emailContent.ts
532
629
  var createEmailSafeFeatures = (additionalBlocks) => {
533
630
  const baseBlocks = [
534
631
  {
@@ -666,16 +763,89 @@ var createEmailSafeFeatures = (additionalBlocks) => {
666
763
  })
667
764
  ];
668
765
  };
766
+ var createEmailLexicalEditor = (customBlocks = []) => {
767
+ const emailSafeBlocks = createEmailSafeBlocks(customBlocks);
768
+ return lexicalEditor({
769
+ features: [
770
+ // Toolbars
771
+ FixedToolbarFeature(),
772
+ InlineToolbarFeature(),
773
+ // Basic text formatting
774
+ BoldFeature(),
775
+ ItalicFeature(),
776
+ UnderlineFeature(),
777
+ StrikethroughFeature(),
778
+ // Links with enhanced configuration
779
+ LinkFeature({
780
+ fields: [
781
+ {
782
+ name: "url",
783
+ type: "text",
784
+ required: true,
785
+ admin: {
786
+ description: "Enter the full URL (including https://)"
787
+ }
788
+ },
789
+ {
790
+ name: "newTab",
791
+ type: "checkbox",
792
+ label: "Open in new tab",
793
+ defaultValue: false
794
+ }
795
+ ]
796
+ }),
797
+ // Lists
798
+ OrderedListFeature(),
799
+ UnorderedListFeature(),
800
+ // Headings - limited to h1, h2, h3 for email compatibility
801
+ HeadingFeature({
802
+ enabledHeadingSizes: ["h1", "h2", "h3"]
803
+ }),
804
+ // Basic paragraph and alignment
805
+ ParagraphFeature(),
806
+ AlignFeature(),
807
+ // Blockquotes
808
+ BlockquoteFeature(),
809
+ // Upload feature for images
810
+ UploadFeature({
811
+ collections: {
812
+ media: {
813
+ fields: [
814
+ {
815
+ name: "caption",
816
+ type: "text",
817
+ admin: {
818
+ description: "Optional caption for the image"
819
+ }
820
+ },
821
+ {
822
+ name: "altText",
823
+ type: "text",
824
+ label: "Alt Text",
825
+ required: true,
826
+ admin: {
827
+ description: "Alternative text for accessibility and when image cannot be displayed"
828
+ }
829
+ }
830
+ ]
831
+ }
832
+ }
833
+ }),
834
+ // Email-safe blocks (processed server-side)
835
+ BlocksFeature({
836
+ blocks: emailSafeBlocks
837
+ })
838
+ ]
839
+ });
840
+ };
669
841
  var emailSafeFeatures = createEmailSafeFeatures();
670
842
  var createEmailContentField = (overrides) => {
671
- const features = createEmailSafeFeatures(overrides?.additionalBlocks);
843
+ const editor = overrides?.editor || createEmailLexicalEditor(overrides?.additionalBlocks);
672
844
  return {
673
845
  name: "content",
674
846
  type: "richText",
675
847
  required: true,
676
- editor: lexicalEditor({
677
- features
678
- }),
848
+ editor,
679
849
  admin: {
680
850
  description: "Email content with limited formatting for compatibility",
681
851
  ...overrides?.admin
@@ -1027,13 +1197,15 @@ var createBroadcastsCollection = (pluginConfig) => {
1027
1197
  }
1028
1198
  },
1029
1199
  // Apply content field customization if provided
1030
- customizations?.fieldOverrides?.content ? customizations.fieldOverrides.content(createEmailContentField({
1031
- admin: { description: "Email content" },
1032
- additionalBlocks: customizations.customBlocks
1033
- })) : createEmailContentField({
1034
- admin: { description: "Email content" },
1035
- additionalBlocks: customizations?.customBlocks
1036
- })
1200
+ // Process blocks server-side to avoid client serialization issues
1201
+ (() => {
1202
+ const emailEditor = createEmailLexicalEditor(customizations?.customBlocks);
1203
+ const baseField = createEmailContentField({
1204
+ admin: { description: "Email content" },
1205
+ editor: emailEditor
1206
+ });
1207
+ return customizations?.fieldOverrides?.content ? customizations.fieldOverrides.content(baseField) : baseField;
1208
+ })()
1037
1209
  ]
1038
1210
  },
1039
1211
  {