sanity-plugin-seofields 1.5.3 → 1.5.5

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/dist/index.d.cts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as sanity from 'sanity';
2
2
  import { SchemaTypeDefinition } from 'sanity';
3
+ import React from 'react';
3
4
  import { D as DocumentWithSeoHealth, c as DeprecationWarning } from './types-R3n9Fu4w.cjs';
4
5
  export { d as SeoHealthMetrics, e as SeoHealthStatus } from './types-R3n9Fu4w.cjs';
5
6
  import { StructureBuilder, ComponentBuilder } from 'sanity/structure';
6
- import React from 'react';
7
7
 
8
8
  interface SeoFieldConfig {
9
9
  title?: string;
@@ -13,6 +13,31 @@ type SeoFieldKeys = 'title' | 'description' | 'canonicalUrl' | 'metaImage' | 'ke
13
13
  type openGraphFieldKeys = 'openGraphUrl' | 'openGraphTitle' | 'openGraphDescription' | 'openGraphSiteName' | 'openGraphType' | 'openGraphImageType' | 'openGraphImage' | 'openGraphImageUrl';
14
14
  type twitterFieldKeys = 'twitterCard' | 'twitterSite' | 'twitterCreator' | 'twitterTitle' | 'twitterDescription' | 'twitterImageType' | 'twitterImage' | 'twitterImageUrl';
15
15
  type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys;
16
+ /**
17
+ * Names of top-level fields inside the `seoFields` object type.
18
+ * Use these when assigning fields to groups in `fieldGroups`.
19
+ */
20
+ type SeoObjectFieldName = 'robots' | 'preview' | 'title' | 'description' | 'metaImage' | 'metaAttributes' | 'keywords' | 'canonicalUrl' | 'openGraph' | 'twitter';
21
+ /**
22
+ * Defines a single tab/group within the `seoFields` object.
23
+ */
24
+ interface SeoFieldGroup {
25
+ /** Unique key for this group (used internally by Sanity). */
26
+ name: string;
27
+ /** Human-readable label shown as the tab title. */
28
+ title: string;
29
+ /** Whether this tab is selected by default. Only one group should be `true`. */
30
+ default?: boolean;
31
+ /**
32
+ * Field names to include in this group.
33
+ * Use the top-level seoFields field names: `'title'`, `'description'`, `'metaImage'`,
34
+ * `'keywords'`, `'canonicalUrl'`, `'metaAttributes'`, `'robots'`, `'preview'`,
35
+ * `'openGraph'`, `'twitter'`.
36
+ */
37
+ fields: SeoObjectFieldName[];
38
+ /** Optional icon displayed next to the tab title. Must be a React component. */
39
+ icon?: React.ComponentType;
40
+ }
16
41
  type ValidHiddenFieldKeys = Exclude<AllFieldKeys, 'openGraphImageUrl' | 'twitterImageUrl' | 'openGraphImageType' | 'twitterImageType'>;
17
42
  interface FieldVisibilityConfig {
18
43
  hiddenFields?: ValidHiddenFieldKeys[];
@@ -51,6 +76,20 @@ interface SeoFieldsPluginConfig {
51
76
  * This can be overridden by specific document type settings in `fieldVisibility`.
52
77
  */
53
78
  defaultHiddenFields?: ValidHiddenFieldKeys[];
79
+ /**
80
+ * Group the SEO fields into tabbed sections inside the `seoFields` object.
81
+ * When configured, the Studio shows tabs (Sanity groups) so editors can
82
+ * switch between e.g. "Meta", "Open Graph", and "Twitter Card" panels.
83
+ *
84
+ * @example
85
+ * fieldGroups: [
86
+ * { name: 'meta', title: 'Meta', default: true,
87
+ * fields: ['title', 'description', 'metaImage', 'keywords', 'canonicalUrl', 'metaAttributes', 'robots', 'preview'] },
88
+ * { name: 'openGraph', title: 'Open Graph', fields: ['openGraph'] },
89
+ * { name: 'twitter', title: 'Twitter Card', fields: ['twitter'] },
90
+ * ]
91
+ */
92
+ fieldGroups?: SeoFieldGroup[];
54
93
  /**
55
94
  * The base URL of your website, used for generating full URLs in the SEO preview.
56
95
  * Defaults to 'https://www.example.com' if not provided.
@@ -273,6 +312,8 @@ declare function seoFieldsSchema(config?: SeoFieldsPluginConfig): SchemaTypeDefi
273
312
 
274
313
  declare function types(config?: SeoFieldsPluginConfig): SchemaTypeDefinition[];
275
314
 
315
+ declare function baseMeta(config?: SeoFieldsPluginConfig): SchemaTypeDefinition;
316
+
276
317
  declare const _default$2: {
277
318
  type: "object";
278
319
  name: "metaAttribute";
@@ -500,4 +541,4 @@ interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuer
500
541
  */
501
542
  declare function createSeoHealthPane(optionsOrS: StructureBuilder, optionsWhenS: SeoHealthPaneOptions): ComponentBuilder;
502
543
 
503
- export { type AllFieldKeys, DocumentWithSeoHealth, type FieldVisibilityConfig, type SeoFieldConfig, type SeoFieldKeys, type SeoFieldsPluginConfig, type SeoHealthPaneOptions, type ValidHiddenFieldKeys, types as allSchemas, createSeoHealthPane, seofields as default, _default$2 as metaAttributeSchema, _default$1 as metaTagSchema, type openGraphFieldKeys, openGraph as openGraphSchema, _default as robotsSchema, seoFieldsSchema, type twitterFieldKeys, twitter as twitterSchema };
544
+ export { type AllFieldKeys, DocumentWithSeoHealth, type FieldVisibilityConfig, type SeoFieldConfig, type SeoFieldGroup, type SeoFieldKeys, type SeoFieldsPluginConfig, type SeoHealthPaneOptions, type SeoObjectFieldName, type ValidHiddenFieldKeys, types as allSchemas, baseMeta as baseMetaSchema, createSeoHealthPane, seofields as default, _default$2 as metaAttributeSchema, _default$1 as metaTagSchema, type openGraphFieldKeys, openGraph as openGraphSchema, _default as robotsSchema, seoFieldsSchema, type twitterFieldKeys, twitter as twitterSchema };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as sanity from 'sanity';
2
2
  import { SchemaTypeDefinition } from 'sanity';
3
+ import React from 'react';
3
4
  import { D as DocumentWithSeoHealth, c as DeprecationWarning } from './types-R3n9Fu4w.js';
4
5
  export { d as SeoHealthMetrics, e as SeoHealthStatus } from './types-R3n9Fu4w.js';
5
6
  import { StructureBuilder, ComponentBuilder } from 'sanity/structure';
6
- import React from 'react';
7
7
 
8
8
  interface SeoFieldConfig {
9
9
  title?: string;
@@ -13,6 +13,31 @@ type SeoFieldKeys = 'title' | 'description' | 'canonicalUrl' | 'metaImage' | 'ke
13
13
  type openGraphFieldKeys = 'openGraphUrl' | 'openGraphTitle' | 'openGraphDescription' | 'openGraphSiteName' | 'openGraphType' | 'openGraphImageType' | 'openGraphImage' | 'openGraphImageUrl';
14
14
  type twitterFieldKeys = 'twitterCard' | 'twitterSite' | 'twitterCreator' | 'twitterTitle' | 'twitterDescription' | 'twitterImageType' | 'twitterImage' | 'twitterImageUrl';
15
15
  type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys;
16
+ /**
17
+ * Names of top-level fields inside the `seoFields` object type.
18
+ * Use these when assigning fields to groups in `fieldGroups`.
19
+ */
20
+ type SeoObjectFieldName = 'robots' | 'preview' | 'title' | 'description' | 'metaImage' | 'metaAttributes' | 'keywords' | 'canonicalUrl' | 'openGraph' | 'twitter';
21
+ /**
22
+ * Defines a single tab/group within the `seoFields` object.
23
+ */
24
+ interface SeoFieldGroup {
25
+ /** Unique key for this group (used internally by Sanity). */
26
+ name: string;
27
+ /** Human-readable label shown as the tab title. */
28
+ title: string;
29
+ /** Whether this tab is selected by default. Only one group should be `true`. */
30
+ default?: boolean;
31
+ /**
32
+ * Field names to include in this group.
33
+ * Use the top-level seoFields field names: `'title'`, `'description'`, `'metaImage'`,
34
+ * `'keywords'`, `'canonicalUrl'`, `'metaAttributes'`, `'robots'`, `'preview'`,
35
+ * `'openGraph'`, `'twitter'`.
36
+ */
37
+ fields: SeoObjectFieldName[];
38
+ /** Optional icon displayed next to the tab title. Must be a React component. */
39
+ icon?: React.ComponentType;
40
+ }
16
41
  type ValidHiddenFieldKeys = Exclude<AllFieldKeys, 'openGraphImageUrl' | 'twitterImageUrl' | 'openGraphImageType' | 'twitterImageType'>;
17
42
  interface FieldVisibilityConfig {
18
43
  hiddenFields?: ValidHiddenFieldKeys[];
@@ -51,6 +76,20 @@ interface SeoFieldsPluginConfig {
51
76
  * This can be overridden by specific document type settings in `fieldVisibility`.
52
77
  */
53
78
  defaultHiddenFields?: ValidHiddenFieldKeys[];
79
+ /**
80
+ * Group the SEO fields into tabbed sections inside the `seoFields` object.
81
+ * When configured, the Studio shows tabs (Sanity groups) so editors can
82
+ * switch between e.g. "Meta", "Open Graph", and "Twitter Card" panels.
83
+ *
84
+ * @example
85
+ * fieldGroups: [
86
+ * { name: 'meta', title: 'Meta', default: true,
87
+ * fields: ['title', 'description', 'metaImage', 'keywords', 'canonicalUrl', 'metaAttributes', 'robots', 'preview'] },
88
+ * { name: 'openGraph', title: 'Open Graph', fields: ['openGraph'] },
89
+ * { name: 'twitter', title: 'Twitter Card', fields: ['twitter'] },
90
+ * ]
91
+ */
92
+ fieldGroups?: SeoFieldGroup[];
54
93
  /**
55
94
  * The base URL of your website, used for generating full URLs in the SEO preview.
56
95
  * Defaults to 'https://www.example.com' if not provided.
@@ -273,6 +312,8 @@ declare function seoFieldsSchema(config?: SeoFieldsPluginConfig): SchemaTypeDefi
273
312
 
274
313
  declare function types(config?: SeoFieldsPluginConfig): SchemaTypeDefinition[];
275
314
 
315
+ declare function baseMeta(config?: SeoFieldsPluginConfig): SchemaTypeDefinition;
316
+
276
317
  declare const _default$2: {
277
318
  type: "object";
278
319
  name: "metaAttribute";
@@ -500,4 +541,4 @@ interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuer
500
541
  */
501
542
  declare function createSeoHealthPane(optionsOrS: StructureBuilder, optionsWhenS: SeoHealthPaneOptions): ComponentBuilder;
502
543
 
503
- export { type AllFieldKeys, DocumentWithSeoHealth, type FieldVisibilityConfig, type SeoFieldConfig, type SeoFieldKeys, type SeoFieldsPluginConfig, type SeoHealthPaneOptions, type ValidHiddenFieldKeys, types as allSchemas, createSeoHealthPane, seofields as default, _default$2 as metaAttributeSchema, _default$1 as metaTagSchema, type openGraphFieldKeys, openGraph as openGraphSchema, _default as robotsSchema, seoFieldsSchema, type twitterFieldKeys, twitter as twitterSchema };
544
+ export { type AllFieldKeys, DocumentWithSeoHealth, type FieldVisibilityConfig, type SeoFieldConfig, type SeoFieldGroup, type SeoFieldKeys, type SeoFieldsPluginConfig, type SeoHealthPaneOptions, type SeoObjectFieldName, type ValidHiddenFieldKeys, types as allSchemas, baseMeta as baseMetaSchema, createSeoHealthPane, seofields as default, _default$2 as metaAttributeSchema, _default$1 as metaTagSchema, type openGraphFieldKeys, openGraph as openGraphSchema, _default as robotsSchema, seoFieldsSchema, type twitterFieldKeys, twitter as twitterSchema };
package/dist/index.js CHANGED
@@ -655,69 +655,181 @@ function twitter(config = {}) {
655
655
  // src/schemas/index.ts
656
656
  var LazySeoPreview = React12.lazy(() => import('./SeoPreview-G3LPA7GV.js'));
657
657
  var SeoPreviewWrapper = (props) => React12.createElement(React12.Suspense, { fallback: null }, React12.createElement(LazySeoPreview, props));
658
+ function buildFieldGroupMap(groups) {
659
+ const map = /* @__PURE__ */ new Map();
660
+ for (const g of groups) {
661
+ for (const fieldName of g.fields) {
662
+ const existing = map.get(fieldName);
663
+ if (existing) {
664
+ existing.push(g.name);
665
+ } else {
666
+ map.set(fieldName, [g.name]);
667
+ }
668
+ }
669
+ }
670
+ return map;
671
+ }
672
+ function toSanityGroups(groups) {
673
+ return groups.map((g) => {
674
+ const def = {
675
+ name: g.name,
676
+ title: g.title,
677
+ default: g.default
678
+ };
679
+ if (g.icon && typeof g.icon !== "string") {
680
+ def.icon = g.icon;
681
+ }
682
+ return def;
683
+ });
684
+ }
685
+ function withGroup(field, fieldGroupMap) {
686
+ if (!fieldGroupMap) return field;
687
+ const groups = fieldGroupMap.get(field.name);
688
+ if (!groups || groups.length === 0) return field;
689
+ return __spreadProps(__spreadValues({}, field), { group: groups.length === 1 ? groups[0] : groups });
690
+ }
658
691
  function seoFieldsSchema(config = {}) {
659
- return defineType({
692
+ const groupsCfg = config.fieldGroups;
693
+ const fieldGroupMap = (groupsCfg == null ? void 0 : groupsCfg.length) ? buildFieldGroupMap(groupsCfg) : void 0;
694
+ const sanityGroups = (groupsCfg == null ? void 0 : groupsCfg.length) ? toSanityGroups(groupsCfg) : void 0;
695
+ return defineType(__spreadProps(__spreadValues({
660
696
  name: "seoFields",
661
697
  title: "SEO Fields",
662
- type: "object",
698
+ type: "object"
699
+ }, sanityGroups ? { groups: sanityGroups } : {}), {
663
700
  fields: [
664
- defineField({
665
- name: "robots",
666
- title: "Robots Settings",
667
- type: "robots",
668
- // Use the separate robots type here
669
- hidden: getFieldHiddenFunction("robots", config)
670
- }),
701
+ withGroup(
702
+ defineField({
703
+ name: "robots",
704
+ title: "Robots Settings",
705
+ type: "robots",
706
+ hidden: getFieldHiddenFunction("robots", config)
707
+ }),
708
+ fieldGroupMap
709
+ ),
671
710
  // 👇 conditionally spread preview field
672
711
  ...typeof config.seoPreview === "boolean" && config.seoPreview || typeof config.seoPreview === "object" && !isEmpty(config.seoPreview) ? [
673
- defineField({
674
- name: "preview",
675
- title: "SEO Preview",
676
- type: "string",
677
- components: { input: SeoPreviewWrapper },
678
- options: __spreadValues({
679
- baseUrl: config.baseUrl || "https://www.example.com"
680
- }, typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.prefix ? { prefix: config.seoPreview.prefix } : {}),
681
- // Use a readOnly field to prevent editing
682
- // This field is just for preview purposes
683
- initialValue: "",
684
- // Set an initial value
685
- readOnly: true
686
- })
712
+ withGroup(
713
+ defineField({
714
+ name: "preview",
715
+ title: "SEO Preview",
716
+ type: "string",
717
+ components: { input: SeoPreviewWrapper },
718
+ options: __spreadValues({
719
+ baseUrl: config.baseUrl || "https://www.example.com"
720
+ }, typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.prefix ? { prefix: config.seoPreview.prefix } : {}),
721
+ initialValue: "",
722
+ readOnly: true
723
+ }),
724
+ fieldGroupMap
725
+ )
687
726
  ] : [],
727
+ withGroup(
728
+ defineField(__spreadProps(__spreadValues({
729
+ name: "title"
730
+ }, getFieldInfo("title", config.fieldOverrides)), {
731
+ type: "string",
732
+ components: {
733
+ input: MetaTitle_default
734
+ },
735
+ hidden: getFieldHiddenFunction("title", config)
736
+ })),
737
+ fieldGroupMap
738
+ ),
739
+ withGroup(
740
+ defineField(__spreadProps(__spreadValues({
741
+ name: "description"
742
+ }, getFieldInfo("description", config.fieldOverrides)), {
743
+ type: "text",
744
+ rows: 3,
745
+ components: {
746
+ input: MetaDescription_default
747
+ },
748
+ hidden: getFieldHiddenFunction("description", config)
749
+ })),
750
+ fieldGroupMap
751
+ ),
752
+ withGroup(
753
+ defineField(__spreadProps(__spreadValues({
754
+ name: "metaImage"
755
+ }, getFieldInfo("metaImage", config.fieldOverrides)), {
756
+ type: "image",
757
+ options: {
758
+ hotspot: true
759
+ },
760
+ components: {
761
+ input: MetaImage_default
762
+ },
763
+ hidden: getFieldHiddenFunction("metaImage", config)
764
+ })),
765
+ fieldGroupMap
766
+ ),
767
+ withGroup(
768
+ defineField(__spreadProps(__spreadValues({
769
+ name: "metaAttributes"
770
+ }, getFieldInfo("metaAttributes", config.fieldOverrides)), {
771
+ type: "array",
772
+ of: [{ type: "metaAttribute" }],
773
+ hidden: getFieldHiddenFunction("metaAttributes", config)
774
+ })),
775
+ fieldGroupMap
776
+ ),
777
+ withGroup(
778
+ defineField(__spreadProps(__spreadValues({
779
+ name: "keywords"
780
+ }, getFieldInfo("keywords", config.fieldOverrides)), {
781
+ title: "Keywords",
782
+ type: "array",
783
+ of: [{ type: "string" }],
784
+ description: "Add relevant keywords for this page. These keywords will be used for SEO purposes.",
785
+ hidden: getFieldHiddenFunction("keywords", config)
786
+ })),
787
+ fieldGroupMap
788
+ ),
789
+ withGroup(
790
+ defineField(__spreadProps(__spreadValues({
791
+ name: "canonicalUrl"
792
+ }, getFieldInfo("canonicalUrl", config.fieldOverrides)), {
793
+ title: "Canonical URL",
794
+ type: "url",
795
+ description: "Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.",
796
+ hidden: getFieldHiddenFunction("canonicalUrl", config)
797
+ })),
798
+ fieldGroupMap
799
+ ),
800
+ withGroup(openGraph(config), fieldGroupMap),
801
+ withGroup(twitter(config), fieldGroupMap)
802
+ ]
803
+ }));
804
+ }
805
+ function baseMeta(config = {}) {
806
+ return defineType({
807
+ name: "baseMeta",
808
+ title: "Basic Meta Settings",
809
+ type: "object",
810
+ fields: [
688
811
  defineField(__spreadProps(__spreadValues({
689
812
  name: "title"
690
813
  }, getFieldInfo("title", config.fieldOverrides)), {
691
- // title: 'Meta Title',
692
814
  type: "string",
693
- // description:
694
- // 'The meta title is displayed in search engine results as the clickable headline for a given result. It should be concise and accurately reflect the content of the page.',
695
815
  components: {
696
816
  input: MetaTitle_default
697
817
  },
698
- // validation: (Rule) => Rule.max(60).warning('Meta title should be under 60 characters.'),
699
818
  hidden: getFieldHiddenFunction("title", config)
700
819
  })),
701
820
  defineField(__spreadProps(__spreadValues({
702
821
  name: "description"
703
822
  }, getFieldInfo("description", config.fieldOverrides)), {
704
- // title: 'Meta Description',
705
- // description:
706
- // 'Provide a concise summary of the page content. This description may be used by search engines in search results.',
707
823
  type: "text",
708
824
  rows: 3,
709
825
  components: {
710
826
  input: MetaDescription_default
711
827
  },
712
- // validation: (Rule) => Rule.max(160).warning('Meta description should be under 160 characters.'),
713
828
  hidden: getFieldHiddenFunction("description", config)
714
829
  })),
715
830
  defineField(__spreadProps(__spreadValues({
716
831
  name: "metaImage"
717
832
  }, getFieldInfo("metaImage", config.fieldOverrides)), {
718
- // title: 'Meta Image',
719
- // description:
720
- // 'Upload an image that represents the content of the page. This image may be used in social media previews and search engine results.',
721
833
  type: "image",
722
834
  options: {
723
835
  hotspot: true
@@ -727,15 +839,6 @@ function seoFieldsSchema(config = {}) {
727
839
  },
728
840
  hidden: getFieldHiddenFunction("metaImage", config)
729
841
  })),
730
- defineField(__spreadProps(__spreadValues({
731
- name: "metaAttributes"
732
- }, getFieldInfo("metaAttributes", config.fieldOverrides)), {
733
- type: "array",
734
- of: [{ type: "metaAttribute" }],
735
- // description:
736
- // 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',
737
- hidden: getFieldHiddenFunction("metaAttributes", config)
738
- })),
739
842
  defineField(__spreadProps(__spreadValues({
740
843
  name: "keywords"
741
844
  }, getFieldInfo("keywords", config.fieldOverrides)), {
@@ -753,8 +856,13 @@ function seoFieldsSchema(config = {}) {
753
856
  description: "Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.",
754
857
  hidden: getFieldHiddenFunction("canonicalUrl", config)
755
858
  })),
756
- openGraph(config),
757
- twitter(config)
859
+ defineField(__spreadProps(__spreadValues({
860
+ name: "metaAttributes"
861
+ }, getFieldInfo("metaAttributes", config.fieldOverrides)), {
862
+ type: "array",
863
+ of: [{ type: "metaAttribute" }],
864
+ hidden: getFieldHiddenFunction("metaAttributes", config)
865
+ }))
758
866
  ]
759
867
  });
760
868
  }
@@ -858,6 +966,8 @@ function types(config = {}) {
858
966
  return [
859
967
  seoFieldsSchema(config),
860
968
  // pass config here
969
+ baseMeta(config),
970
+ // pass config here
861
971
  openGraph(config),
862
972
  // pass config here
863
973
  twitter(config),
@@ -1053,6 +1163,6 @@ function createSeoHealthPane(optionsOrS, optionsWhenS) {
1053
1163
  // src/index.ts
1054
1164
  var src_default = plugin_default;
1055
1165
 
1056
- export { types as allSchemas, createSeoHealthPane, src_default as default, metaAttribute_default as metaAttributeSchema, metaTag_default as metaTagSchema, openGraph as openGraphSchema, robots_default as robotsSchema, seoFieldsSchema, twitter as twitterSchema };
1166
+ export { types as allSchemas, baseMeta as baseMetaSchema, createSeoHealthPane, src_default as default, metaAttribute_default as metaAttributeSchema, metaTag_default as metaTagSchema, openGraph as openGraphSchema, robots_default as robotsSchema, seoFieldsSchema, twitter as twitterSchema };
1057
1167
  //# sourceMappingURL=index.js.map
1058
1168
  //# sourceMappingURL=index.js.map