sanity-plugin-seofields 1.5.4 → 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.
@@ -502,4 +541,4 @@ interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuer
502
541
  */
503
542
  declare function createSeoHealthPane(optionsOrS: StructureBuilder, optionsWhenS: SeoHealthPaneOptions): ComponentBuilder;
504
543
 
505
- export { type AllFieldKeys, DocumentWithSeoHealth, type FieldVisibilityConfig, type SeoFieldConfig, type SeoFieldKeys, type SeoFieldsPluginConfig, type SeoHealthPaneOptions, 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 };
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.
@@ -502,4 +541,4 @@ interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuer
502
541
  */
503
542
  declare function createSeoHealthPane(optionsOrS: StructureBuilder, optionsWhenS: SeoHealthPaneOptions): ComponentBuilder;
504
543
 
505
- export { type AllFieldKeys, DocumentWithSeoHealth, type FieldVisibilityConfig, type SeoFieldConfig, type SeoFieldKeys, type SeoFieldsPluginConfig, type SeoHealthPaneOptions, 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 };
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,108 +655,152 @@ 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
  ] : [],
688
- defineField(__spreadProps(__spreadValues({
689
- name: "title"
690
- }, getFieldInfo("title", config.fieldOverrides)), {
691
- // title: 'Meta Title',
692
- 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
- components: {
696
- input: MetaTitle_default
697
- },
698
- // validation: (Rule) => Rule.max(60).warning('Meta title should be under 60 characters.'),
699
- hidden: getFieldHiddenFunction("title", config)
700
- })),
701
- defineField(__spreadProps(__spreadValues({
702
- name: "description"
703
- }, 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
- type: "text",
708
- rows: 3,
709
- components: {
710
- input: MetaDescription_default
711
- },
712
- // validation: (Rule) => Rule.max(160).warning('Meta description should be under 160 characters.'),
713
- hidden: getFieldHiddenFunction("description", config)
714
- })),
715
- defineField(__spreadProps(__spreadValues({
716
- name: "metaImage"
717
- }, 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
- type: "image",
722
- options: {
723
- hotspot: true
724
- },
725
- components: {
726
- input: MetaImage_default
727
- },
728
- hidden: getFieldHiddenFunction("metaImage", config)
729
- })),
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
- defineField(__spreadProps(__spreadValues({
740
- name: "keywords"
741
- }, getFieldInfo("keywords", config.fieldOverrides)), {
742
- title: "Keywords",
743
- type: "array",
744
- of: [{ type: "string" }],
745
- description: "Add relevant keywords for this page. These keywords will be used for SEO purposes.",
746
- hidden: getFieldHiddenFunction("keywords", config)
747
- })),
748
- defineField(__spreadProps(__spreadValues({
749
- name: "canonicalUrl"
750
- }, getFieldInfo("canonicalUrl", config.fieldOverrides)), {
751
- title: "Canonical URL",
752
- type: "url",
753
- description: "Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.",
754
- hidden: getFieldHiddenFunction("canonicalUrl", config)
755
- })),
756
- openGraph(config),
757
- twitter(config)
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)
758
802
  ]
759
- });
803
+ }));
760
804
  }
761
805
  function baseMeta(config = {}) {
762
806
  return defineType({