sanity-plugin-singleton-management 1.0.6 → 1.1.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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # sanity-plugin-singleton-tools
4
4
 
5
- > This is compatible with v4 and v3 of Sanity Studio.
5
+ > This is compatible with Sanity versions 3.x, 4.x, 5.x, and 6.x.
6
6
 
7
7
  ## What does this plugin do?
8
8
 
@@ -20,23 +20,23 @@ While Sanity Studio supports singleton documents through the Structure Builder A
20
20
  plugin eliminates the repetitive boilerplate and provides additional safeguards:
21
21
 
22
22
  ### Native Sanity Approach
23
+
23
24
  ```js
24
25
  // Requires manual Structure Builder configuration for each singleton
25
26
  export const structure = (S) =>
26
27
  S.list()
27
- .title('Content')
28
+ .title("Content")
28
29
  .items([
29
30
  S.listItem()
30
- .title('Site Settings')
31
+ .title("Site Settings")
31
32
  .child(
32
- S.document()
33
- .schemaType('siteSettings')
34
- .documentId('siteSettings')
33
+ S.document().schemaType("siteSettings").documentId("siteSettings"),
35
34
  ),
36
35
  // Must manually filter out singletons from main list
37
- ...S.documentTypeListItems().filter(listItem =>
38
- !['siteSettings'].includes(listItem.getId()))
39
- ])
36
+ ...S.documentTypeListItems().filter(
37
+ (listItem) => !["siteSettings"].includes(listItem.getId()),
38
+ ),
39
+ ]);
40
40
  ```
41
41
 
42
42
  **Issues:**
@@ -46,7 +46,6 @@ export const structure = (S) =>
46
46
  - Users can still create new versions via global Create menu
47
47
  - Manual filtering required to prevent duplicates in document lists
48
48
 
49
-
50
49
  **With This Plugin:**
51
50
 
52
51
  ```js
@@ -72,21 +71,21 @@ export const mySingleton = defineType({
72
71
  ```
73
72
 
74
73
  ```js
75
- // structure.js/ts
76
- export const structure = (S, context) =>
77
- S.list()
78
- .items([
79
- ...singletonDocumentListItems({ S, context }), // Auto-generates all singletons
80
- ...filteredDocumentListItems({ S, context }) // Auto-filters singletons from main list
81
- ])
74
+ // structure.js/ts
75
+ export const structure = (S, context) =>
76
+ S.list().items([
77
+ ...singletonDocumentListItems({ S, context }), // Auto-generates all singletons
78
+ ...filteredDocumentListItems({ S, context }), // Auto-filters singletons from main list
79
+ ]);
82
80
  ```
83
81
 
84
- Benefits:
85
- - ✅ Minimal configuration with `singleton: true`
86
- - ✅ Automatic action restrictions (no duplicate creation)
87
- - ✅ Global Create menu integration
88
- - ✅ Helper functions eliminate boilerplate
89
- - ✅ Consistent singleton behavior across your studio
82
+ Benefits:
83
+
84
+ - ✅ Minimal configuration with `singleton: true`
85
+ - ✅ Automatic action restrictions (no duplicate creation)
86
+ - ✅ Global Create menu integration
87
+ - ✅ Helper functions eliminate boilerplate
88
+ - ✅ Consistent singleton behavior across your studio
90
89
 
91
90
  ## Installation
92
91
 
@@ -99,17 +98,21 @@ npm install sanity-plugin-singleton-management
99
98
  This plugin is a modernized, actively maintained fork of `sanity-plugin-singleton-tools` with identical API compatibility. Migration is straightforward:
100
99
 
101
100
  ### Steps
101
+
102
102
  1. **Uninstall the old package**:
103
+
103
104
  ```sh
104
105
  npm uninstall sanity-plugin-singleton-tools
105
106
  ```
106
107
 
107
108
  2. **Install this package**:
109
+
108
110
  ```sh
109
111
  npm install sanity-plugin-singleton-management
110
112
  ```
111
113
 
112
114
  3. **Update your import statements**:
115
+
113
116
  ```diff
114
117
  // sanity.config.js
115
118
  - import { singletonTools } from 'sanity-plugin-singleton-tools'
@@ -123,6 +126,7 @@ This plugin is a modernized, actively maintained fork of `sanity-plugin-singleto
123
126
  **That's it!** No other code changes are required. Your existing schema configurations and structure customizations will work exactly the same.
124
127
 
125
128
  ### What's New
129
+
126
130
  - ✅ **React 18/19 Support**: Compatible with modern React versions
127
131
  - ✅ **Sanity v3/v4 Support**: Works with both Sanity Studio versions
128
132
  - ✅ **Modern Tooling**: ESM/CommonJS dual package, better TypeScript support
@@ -205,7 +209,7 @@ Other reading (Sanity docs):
205
209
 
206
210
  ## Credits
207
211
 
208
- This project is a fork of [sanity-plugin-singleton-tools](https://github.com/plsrd/sanity-plugin-singleton-tools)
212
+ This project is a fork of [sanity-plugin-singleton-tools](https://github.com/plsrd/sanity-plugin-singleton-tools)
209
213
  originally created by [RD Pennell](https://github.com/plsrd).
210
214
 
211
215
  ## License
@@ -216,4 +220,4 @@ MIT License \
216
220
  <div style="text-align: right">
217
221
  Copyright © 2025 <a href="https://github.com/rcmaples" target="_blank">RC Maples</a> </br>
218
222
  Copyright © 2024-2025 <a href="https://github.com/plsrd" target="_blank">RD Pennell</a>
219
- </div>
223
+ </div>
package/dist/index.cjs CHANGED
@@ -1,55 +1,39 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var sanity = require("sanity"), icons = require("@sanity/icons");
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let sanity = require("sanity"), _sanity_icons = require("@sanity/icons");
4
3
  const getSingletonDocuments = (schema) => {
5
- if (schema?._original?.types)
6
- return schema._original.types.filter(({ options }) => options?.singleton).map((s) => s.name);
7
- }, getIsSingleton = (schema, schemaType) => !schema?._original?.types || !schemaType ? !1 : schema._original.types.find(
8
- ({ name }) => name === schemaType
9
- )?.options?.singleton ?? !1, actions = (prev, { schema, schemaType }) => getIsSingleton(schema, schemaType) ? prev.filter(
10
- ({ action }) => ["publish", "discardChanges", "restore"].includes(action)
11
- ) : prev, newDocumentOptions = (prev, { schema, creationContext: { type, schemaType } }) => {
12
- const singletons = getSingletonDocuments(schema), filterSingletons = ({ templateId }) => !singletons?.includes(templateId);
13
- return type === "global" || singletons?.includes(schemaType ?? "") ? prev.filter(filterSingletons) : prev;
14
- }, singletonTools = sanity.definePlugin(() => ({
15
- name: "singleton-tools",
16
- document: {
17
- newDocumentOptions,
18
- actions
19
- }
4
+ if (schema?._original?.types) return schema._original.types.filter(({ options }) => options?.singleton).map((s) => s.name);
5
+ }, getIsSingleton = (schema, schemaType) => !schema?._original?.types || !schemaType ? !1 : schema._original.types.find(({ name }) => name === schemaType)?.options?.singleton ?? !1, actions = (prev, { schema, schemaType }) => getIsSingleton(schema, schemaType) ? prev.filter(({ action }) => [
6
+ "publish",
7
+ "discardChanges",
8
+ "restore"
9
+ ].includes(action)) : prev, newDocumentOptions = (prev, { schema, creationContext: { type, schemaType } }) => {
10
+ let singletons = getSingletonDocuments(schema), filterSingletons = ({ templateId }) => !singletons?.includes(templateId);
11
+ return type === "global" || singletons?.includes(schemaType ?? "") ? prev.filter(filterSingletons) : prev;
12
+ }, singletonTools = (0, sanity.definePlugin)(() => ({
13
+ name: "singleton-tools",
14
+ document: {
15
+ newDocumentOptions,
16
+ actions
17
+ }
20
18
  })), singletonDocumentListItem = (config) => {
21
- if (!config?.S || !config?.type || !config.context)
22
- throw new Error(
23
- "S, context, and type must be provided to singletonDocumentListItem. Example: singletonDocumentListItem({ S, context, type: 'product' })"
24
- );
25
- const { S, type, title, icon, id, context } = config, { schema } = context;
26
- if (!schema)
27
- throw new Error(
28
- "Schema is required in context for singletonDocumentListItem"
29
- );
30
- const schemaType = schema.get(type), listTitle = title ?? schemaType?.title ?? type, listIcon = icon ?? schemaType?.icon ?? icons.DocumentIcon, listId = id ?? type;
31
- return S.listItem().title(listTitle).icon(listIcon).child(S.document().schemaType(type).title(listTitle).id(listId));
19
+ if (!config?.S || !config?.type || !config.context) throw Error("S, context, and type must be provided to singletonDocumentListItem. Example: singletonDocumentListItem({ S, context, type: 'product' })");
20
+ let { S, type, title, icon, id, context } = config, { schema } = context;
21
+ if (!schema) throw Error("Schema is required in context for singletonDocumentListItem");
22
+ let schemaType = schema.get(type), listTitle = title ?? schemaType?.title ?? type, listIcon = icon ?? schemaType?.icon ?? _sanity_icons.DocumentIcon, listId = id ?? type;
23
+ return S.listItem().title(listTitle).icon(listIcon).child(S.document().schemaType(type).title(listTitle).id(listId));
32
24
  }, singletonDocumentListItems = (config) => {
33
- if (!config.S || !config.context)
34
- throw new Error(
35
- "S and context must be provided to singletonDocumentListItems. Example: singletonDocumentListItems({ S, context })"
36
- );
37
- const { S, context } = config, { schema } = context;
38
- return getSingletonDocuments(schema)?.map(
39
- (schemaType) => singletonDocumentListItem({ S, context, type: schemaType })
40
- ) || [];
25
+ if (!config.S || !config.context) throw Error("S and context must be provided to singletonDocumentListItems. Example: singletonDocumentListItems({ S, context })");
26
+ let { S, context } = config, { schema } = context;
27
+ return getSingletonDocuments(schema)?.map((schemaType) => singletonDocumentListItem({
28
+ S,
29
+ context,
30
+ type: schemaType
31
+ })) || [];
41
32
  }, filteredDocumentListItems = (config) => {
42
- if (!config.S || !config.context)
43
- throw new Error(
44
- "S and context must be provided to filteredDocumentListItems. Example: filteredDocumentListItems({ S, context })"
45
- );
46
- const { S, context } = config, { schema } = context, singletons = getSingletonDocuments(schema);
47
- return S.documentTypeListItems().filter(
48
- (type) => !singletons || !singletons.includes(type.getId())
49
- );
33
+ if (!config.S || !config.context) throw Error("S and context must be provided to filteredDocumentListItems. Example: filteredDocumentListItems({ S, context })");
34
+ let { S, context } = config, { schema } = context, singletons = getSingletonDocuments(schema);
35
+ return S.documentTypeListItems().filter((type) => !singletons || !singletons.includes(type.getId()));
50
36
  };
51
- exports.filteredDocumentListItems = filteredDocumentListItems;
52
- exports.singletonDocumentListItem = singletonDocumentListItem;
53
- exports.singletonDocumentListItems = singletonDocumentListItems;
54
- exports.singletonTools = singletonTools;
55
- //# sourceMappingURL=index.cjs.map
37
+ exports.filteredDocumentListItems = filteredDocumentListItems, exports.singletonDocumentListItem = singletonDocumentListItem, exports.singletonDocumentListItems = singletonDocumentListItems, exports.singletonTools = singletonTools;
38
+
39
+ //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/helpers/index.ts","../src/actions.ts","../src/newDocumentOptions.ts","../src/pluginConfig.ts","../src/structure/index.ts"],"sourcesContent":["import { Schema } from \"sanity\";\n\nimport { SingletonPluginOptions } from \"../types\";\n\nexport const getSingletonDocuments = (schema: Schema): string[] | undefined => {\n if (!schema?._original?.types) {\n return undefined;\n }\n\n return schema._original.types\n .filter(({ options }) => (options as SingletonPluginOptions)?.singleton)\n .map((s: { name: string }) => s.name);\n};\n\nexport const getIsSingleton = (schema: Schema, schemaType: string): boolean => {\n if (!schema?._original?.types || !schemaType) {\n return false;\n }\n\n const documentSchema = schema._original.types.find(\n ({ name }) => name === schemaType,\n );\n\n return (\n (documentSchema?.options as SingletonPluginOptions)?.singleton ?? false\n );\n};\n","import { DocumentActionsContext, DocumentActionsResolver } from \"sanity\";\n\nimport { getIsSingleton } from \"./helpers\";\n\nexport const actions: DocumentActionsResolver = (\n prev,\n { schema, schemaType }: DocumentActionsContext,\n) => {\n return getIsSingleton(schema, schemaType)\n ? prev.filter(({ action }) =>\n [\"publish\", \"discardChanges\", \"restore\"].includes(action as string),\n )\n : prev;\n};\n","import { NewDocumentOptionsContext, NewDocumentOptionsResolver } from \"sanity\";\n\nimport { getSingletonDocuments } from \"./helpers\";\n\nexport const newDocumentOptions: NewDocumentOptionsResolver = (\n prev,\n { schema, creationContext: { type, schemaType } }: NewDocumentOptionsContext,\n) => {\n const singletons = getSingletonDocuments(schema);\n\n const filterSingletons = ({ templateId }: { templateId: string }) =>\n !singletons?.includes(templateId);\n\n if (type === \"global\") return prev.filter(filterSingletons);\n\n return singletons?.includes(schemaType ?? \"\")\n ? prev.filter(filterSingletons)\n : prev;\n};\n","import { definePlugin } from \"sanity\";\n\nimport { actions } from \"./actions\";\nimport { newDocumentOptions } from \"./newDocumentOptions\";\n\nexport const singletonTools = definePlugin(() => {\n return {\n name: \"singleton-tools\",\n document: {\n newDocumentOptions,\n actions,\n },\n };\n});\n","import { DocumentIcon } from \"@sanity/icons\";\nimport type { ListItemBuilder } from \"sanity/structure\";\n\nimport { getSingletonDocuments } from \"../helpers\";\nimport {\n SingletonDocumentListItemConfig,\n SingletonPluginListItemsConfig,\n} from \"../types\";\n\nconst singletonDocumentListItem = (\n config: SingletonDocumentListItemConfig,\n): ListItemBuilder => {\n if (!config?.S || !config?.type || !config.context) {\n throw new Error(\n \"S, context, and type must be provided to singletonDocumentListItem. \" +\n \"Example: singletonDocumentListItem({ S, context, type: 'product' })\",\n );\n }\n const { S, type, title, icon, id, context } = config;\n const { schema } = context;\n\n if (!schema) {\n throw new Error(\n \"Schema is required in context for singletonDocumentListItem\",\n );\n }\n\n const schemaType = schema.get(type);\n const listTitle = title ?? schemaType?.title ?? type;\n const listIcon = icon ?? schemaType?.icon ?? DocumentIcon;\n const listId = id ?? type;\n\n return S.listItem()\n .title(listTitle)\n .icon(listIcon)\n .child(S.document().schemaType(type).title(listTitle).id(listId));\n};\n\nconst singletonDocumentListItems = (\n config: SingletonPluginListItemsConfig,\n): ListItemBuilder[] => {\n if (!config.S || !config.context) {\n throw new Error(\n \"S and context must be provided to singletonDocumentListItems. \" +\n \"Example: singletonDocumentListItems({ S, context })\",\n );\n }\n\n const { S, context } = config;\n const { schema } = context;\n\n const singletons = getSingletonDocuments(schema);\n\n return (\n singletons?.map((schemaType) =>\n singletonDocumentListItem({ S, context, type: schemaType }),\n ) || []\n );\n};\n\nconst filteredDocumentListItems = (\n config: SingletonPluginListItemsConfig,\n): ListItemBuilder[] => {\n if (!config.S || !config.context) {\n throw new Error(\n \"S and context must be provided to filteredDocumentListItems. \" +\n \"Example: filteredDocumentListItems({ S, context })\",\n );\n }\n const { S, context } = config;\n const { schema } = context;\n\n const singletons = getSingletonDocuments(schema);\n\n return S.documentTypeListItems().filter(\n (type) => !singletons || !singletons.includes(type.getId() as string),\n );\n};\n\nexport {\n filteredDocumentListItems,\n singletonDocumentListItem,\n singletonDocumentListItems,\n};\n"],"names":["definePlugin","DocumentIcon"],"mappings":";;;AAIO,MAAM,wBAAwB,CAAC,WAAyC;AAC7E,MAAK,QAAQ,WAAW;AAIxB,WAAO,OAAO,UAAU,MACrB,OAAO,CAAC,EAAE,QAAA,MAAe,SAAoC,SAAS,EACtE,IAAI,CAAC,MAAwB,EAAE,IAAI;AACxC,GAEa,iBAAiB,CAAC,QAAgB,eACzC,CAAC,QAAQ,WAAW,SAAS,CAAC,aACzB,KAGc,OAAO,UAAU,MAAM;AAAA,EAC5C,CAAC,EAAE,KAAA,MAAW,SAAS;AACzB,GAGmB,SAAoC,aAAa,ICpBzD,UAAmC,CAC9C,MACA,EAAE,QAAQ,WAAA,MAEH,eAAe,QAAQ,UAAU,IACpC,KAAK;AAAA,EAAO,CAAC,EAAE,OAAA,MACb,CAAC,WAAW,kBAAkB,SAAS,EAAE,SAAS,MAAgB;AACpE,IACA,MCRO,qBAAiD,CAC5D,MACA,EAAE,QAAQ,iBAAiB,EAAE,MAAM,WAAA,QAChC;AACH,QAAM,aAAa,sBAAsB,MAAM,GAEzC,mBAAmB,CAAC,EAAE,iBAC1B,CAAC,YAAY,SAAS,UAAU;AAElC,SAAI,SAAS,YAEN,YAAY,SAAS,cAAc,EAAE,IAFd,KAAK,OAAO,gBAAgB,IAItD;AACN,GCba,iBAAiBA,OAAAA,aAAa,OAClC;AAAA,EACL,MAAM;AAAA,EACN,UAAU;AAAA,IACR;AAAA,IACA;AAAA,EAAA;AAEJ,EACD,GCJK,4BAA4B,CAChC,WACoB;AACpB,MAAI,CAAC,QAAQ,KAAK,CAAC,QAAQ,QAAQ,CAAC,OAAO;AACzC,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAIJ,QAAM,EAAE,GAAG,MAAM,OAAO,MAAM,IAAI,YAAY,QACxC,EAAE,OAAA,IAAW;AAEnB,MAAI,CAAC;AACH,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAIJ,QAAM,aAAa,OAAO,IAAI,IAAI,GAC5B,YAAY,SAAS,YAAY,SAAS,MAC1C,WAAW,QAAQ,YAAY,QAAQC,oBACvC,SAAS,MAAM;AAErB,SAAO,EAAE,WACN,MAAM,SAAS,EACf,KAAK,QAAQ,EACb,MAAM,EAAE,SAAA,EAAW,WAAW,IAAI,EAAE,MAAM,SAAS,EAAE,GAAG,MAAM,CAAC;AACpE,GAEM,6BAA6B,CACjC,WACsB;AACtB,MAAI,CAAC,OAAO,KAAK,CAAC,OAAO;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAKJ,QAAM,EAAE,GAAG,QAAA,IAAY,QACjB,EAAE,WAAW;AAInB,SAFmB,sBAAsB,MAAM,GAGjC;AAAA,IAAI,CAAC,eACf,0BAA0B,EAAE,GAAG,SAAS,MAAM,YAAY;AAAA,EAAA,KACvD,CAAA;AAET,GAEM,4BAA4B,CAChC,WACsB;AACtB,MAAI,CAAC,OAAO,KAAK,CAAC,OAAO;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAIJ,QAAM,EAAE,GAAG,QAAA,IAAY,QACjB,EAAE,OAAA,IAAW,SAEb,aAAa,sBAAsB,MAAM;AAE/C,SAAO,EAAE,wBAAwB;AAAA,IAC/B,CAAC,SAAS,CAAC,cAAc,CAAC,WAAW,SAAS,KAAK,MAAA,CAAiB;AAAA,EAAA;AAExE;;;;;"}
1
+ {"version":3,"file":"index.cjs","names":["definePlugin","DocumentIcon"],"sources":["../src/helpers/index.ts","../src/actions.ts","../src/newDocumentOptions.ts","../src/pluginConfig.ts","../src/structure/index.ts"],"sourcesContent":["import { Schema } from \"sanity\";\n\nimport { SingletonPluginOptions } from \"../types\";\n\nexport const getSingletonDocuments = (schema: Schema): string[] | undefined => {\n if (!schema?._original?.types) {\n return undefined;\n }\n\n return schema._original.types\n .filter(({ options }) => (options as SingletonPluginOptions)?.singleton)\n .map((s: { name: string }) => s.name);\n};\n\nexport const getIsSingleton = (schema: Schema, schemaType: string): boolean => {\n if (!schema?._original?.types || !schemaType) {\n return false;\n }\n\n const documentSchema = schema._original.types.find(\n ({ name }) => name === schemaType,\n );\n\n return (\n (documentSchema?.options as SingletonPluginOptions)?.singleton ?? false\n );\n};\n","import { DocumentActionsContext, DocumentActionsResolver } from \"sanity\";\n\nimport { getIsSingleton } from \"./helpers\";\n\nexport const actions: DocumentActionsResolver = (\n prev,\n { schema, schemaType }: DocumentActionsContext,\n) => {\n return getIsSingleton(schema, schemaType)\n ? prev.filter(({ action }) =>\n [\"publish\", \"discardChanges\", \"restore\"].includes(action as string),\n )\n : prev;\n};\n","import { NewDocumentOptionsContext, NewDocumentOptionsResolver } from \"sanity\";\n\nimport { getSingletonDocuments } from \"./helpers\";\n\nexport const newDocumentOptions: NewDocumentOptionsResolver = (\n prev,\n { schema, creationContext: { type, schemaType } }: NewDocumentOptionsContext,\n) => {\n const singletons = getSingletonDocuments(schema);\n\n const filterSingletons = ({ templateId }: { templateId: string }) =>\n !singletons?.includes(templateId);\n\n if (type === \"global\") return prev.filter(filterSingletons);\n\n return singletons?.includes(schemaType ?? \"\")\n ? prev.filter(filterSingletons)\n : prev;\n};\n","import { definePlugin } from \"sanity\";\n\nimport { actions } from \"./actions\";\nimport { newDocumentOptions } from \"./newDocumentOptions\";\n\nexport const singletonTools = definePlugin(() => {\n return {\n name: \"singleton-tools\",\n document: {\n newDocumentOptions,\n actions,\n },\n };\n});\n","import { DocumentIcon } from \"@sanity/icons\";\nimport type { ListItemBuilder } from \"sanity/structure\";\n\nimport { getSingletonDocuments } from \"../helpers\";\nimport {\n SingletonDocumentListItemConfig,\n SingletonPluginListItemsConfig,\n} from \"../types\";\n\nconst singletonDocumentListItem = (\n config: SingletonDocumentListItemConfig,\n): ListItemBuilder => {\n if (!config?.S || !config?.type || !config.context) {\n throw new Error(\n \"S, context, and type must be provided to singletonDocumentListItem. \" +\n \"Example: singletonDocumentListItem({ S, context, type: 'product' })\",\n );\n }\n const { S, type, title, icon, id, context } = config;\n const { schema } = context;\n\n if (!schema) {\n throw new Error(\n \"Schema is required in context for singletonDocumentListItem\",\n );\n }\n\n const schemaType = schema.get(type);\n const listTitle = title ?? schemaType?.title ?? type;\n const listIcon = icon ?? schemaType?.icon ?? DocumentIcon;\n const listId = id ?? type;\n\n return S.listItem()\n .title(listTitle)\n .icon(listIcon)\n .child(S.document().schemaType(type).title(listTitle).id(listId));\n};\n\nconst singletonDocumentListItems = (\n config: SingletonPluginListItemsConfig,\n): ListItemBuilder[] => {\n if (!config.S || !config.context) {\n throw new Error(\n \"S and context must be provided to singletonDocumentListItems. \" +\n \"Example: singletonDocumentListItems({ S, context })\",\n );\n }\n\n const { S, context } = config;\n const { schema } = context;\n\n const singletons = getSingletonDocuments(schema);\n\n return (\n singletons?.map((schemaType) =>\n singletonDocumentListItem({ S, context, type: schemaType }),\n ) || []\n );\n};\n\nconst filteredDocumentListItems = (\n config: SingletonPluginListItemsConfig,\n): ListItemBuilder[] => {\n if (!config.S || !config.context) {\n throw new Error(\n \"S and context must be provided to filteredDocumentListItems. \" +\n \"Example: filteredDocumentListItems({ S, context })\",\n );\n }\n const { S, context } = config;\n const { schema } = context;\n\n const singletons = getSingletonDocuments(schema);\n\n return S.documentTypeListItems().filter(\n (type) => !singletons || !singletons.includes(type.getId() as string),\n );\n};\n\nexport {\n filteredDocumentListItems,\n singletonDocumentListItem,\n singletonDocumentListItems,\n};\n"],"mappings":";;AAIA,MAAa,yBAAyB,WAAyC;CACxE,YAAQ,WAAW,OAIxB,OAAO,OAAO,UAAU,MACrB,QAAQ,EAAE,cAAe,SAAoC,SAAS,CAAC,CACvE,KAAK,MAAwB,EAAE,IAAI;AACxC,GAEa,kBAAkB,QAAgB,eACzC,CAAC,QAAQ,WAAW,SAAS,CAAC,aACzB,KAGc,OAAO,UAAU,MAAM,MAC3C,EAAE,WAAW,SAAS,UAIT,CAAC,EAAE,SAAoC,aAAa,ICpBzD,WACX,MACA,EAAE,QAAQ,iBAEH,eAAe,QAAQ,UAAU,IACpC,KAAK,QAAQ,EAAE,aACb;CAAC;CAAW;CAAkB;AAAS,CAAC,CAAC,SAAS,MAAgB,CACpE,IACA,MCRO,sBACX,MACA,EAAE,QAAQ,iBAAiB,EAAE,MAAM,mBAChC;CACH,IAAM,aAAa,sBAAsB,MAAM,GAEzC,oBAAoB,EAAE,iBAC1B,CAAC,YAAY,SAAS,UAAU;CAIlC,OAFI,SAAS,YAEN,YAAY,SAAS,cAAc,EAAE,IAFd,KAAK,OAAO,gBAAgB,IAItD;AACN,GCba,kBAAA,GAAiBA,OAAAA,aAAAA,QACrB;CACL,MAAM;CACN,UAAU;EACR;EACA;CACF;AACF,EACD,GCJK,6BACJ,WACoB;CACpB,IAAI,CAAC,QAAQ,KAAK,CAAC,QAAQ,QAAQ,CAAC,OAAO,SACzC,MAAU,MACR,yIAEF;CAEF,IAAM,EAAE,GAAG,MAAM,OAAO,MAAM,IAAI,YAAY,QACxC,EAAE,WAAW;CAEnB,IAAI,CAAC,QACH,MAAU,MACR,6DACF;CAGF,IAAM,aAAa,OAAO,IAAI,IAAI,GAC5B,YAAY,SAAS,YAAY,SAAS,MAC1C,WAAW,QAAQ,YAAY,QAAQC,cAAAA,cACvC,SAAS,MAAM;CAErB,OAAO,EAAE,SAAS,CAAC,CAChB,MAAM,SAAS,CAAC,CAChB,KAAK,QAAQ,CAAC,CACd,MAAM,EAAE,SAAS,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC;AACpE,GAEM,8BACJ,WACsB;CACtB,IAAI,CAAC,OAAO,KAAK,CAAC,OAAO,SACvB,MAAU,MACR,mHAEF;CAGF,IAAM,EAAE,GAAG,YAAY,QACjB,EAAE,WAAW;CAInB,OAFmB,sBAAsB,MAG9B,CAAC,EAAE,KAAK,eACf,0BAA0B;EAAE;EAAG;EAAS,MAAM;CAAW,CAAC,CAC5D,KAAK,CAAC;AAEV,GAEM,6BACJ,WACsB;CACtB,IAAI,CAAC,OAAO,KAAK,CAAC,OAAO,SACvB,MAAU,MACR,iHAEF;CAEF,IAAM,EAAE,GAAG,YAAY,QACjB,EAAE,WAAW,SAEb,aAAa,sBAAsB,MAAM;CAE/C,OAAO,EAAE,sBAAsB,CAAC,CAAC,QAC9B,SAAS,CAAC,cAAc,CAAC,WAAW,SAAS,KAAK,MAAM,CAAW,CACtE;AACF"}
package/dist/index.d.cts CHANGED
@@ -1,19 +1,8 @@
1
- import { ComponentType } from "react";
1
+ import { ListItemBuilder, StructureBuilder } from "sanity/structure";
2
+ import { ComponentType, ReactNode } from "react";
2
3
  import { ConfigContext } from "sanity";
3
- import type { ListItemBuilder } from "sanity/structure";
4
- import { Plugin as Plugin_2 } from "sanity";
5
- import { ReactNode } from "react";
6
- import { StructureBuilder } from "sanity/structure";
7
-
8
- export declare const filteredDocumentListItems: (
9
- config: SingletonPluginListItemsConfig,
10
- ) => ListItemBuilder[];
11
-
12
- export declare const singletonDocumentListItem: (
13
- config: SingletonDocumentListItemConfig,
14
- ) => ListItemBuilder;
15
-
16
- declare interface SingletonDocumentListItemConfig {
4
+ declare const singletonTools: import("sanity").Plugin<void>;
5
+ interface SingletonDocumentListItemConfig {
17
6
  S: StructureBuilder;
18
7
  context: ConfigContext;
19
8
  type: string;
@@ -21,24 +10,18 @@ declare interface SingletonDocumentListItemConfig {
21
10
  id?: string;
22
11
  icon?: ComponentType | ReactNode;
23
12
  }
24
-
25
- export declare const singletonDocumentListItems: (
26
- config: SingletonPluginListItemsConfig,
27
- ) => ListItemBuilder[];
28
-
29
- declare interface SingletonPluginListItemsConfig {
13
+ interface SingletonPluginListItemsConfig {
30
14
  S: StructureBuilder;
31
15
  context: ConfigContext;
32
16
  }
33
-
34
- export declare interface SingletonPluginOptions {
17
+ interface SingletonPluginOptions {
35
18
  singleton?: boolean;
36
19
  }
37
-
38
- export declare const singletonTools: Plugin_2<void>;
39
-
40
- export {};
41
-
42
20
  declare module "sanity" {
43
21
  interface DocumentOptions extends SingletonPluginOptions {}
44
22
  }
23
+ declare const singletonDocumentListItem: (config: SingletonDocumentListItemConfig) => ListItemBuilder;
24
+ declare const singletonDocumentListItems: (config: SingletonPluginListItemsConfig) => ListItemBuilder[];
25
+ declare const filteredDocumentListItems: (config: SingletonPluginListItemsConfig) => ListItemBuilder[];
26
+ export { type SingletonPluginOptions, filteredDocumentListItems, singletonDocumentListItem, singletonDocumentListItems, singletonTools };
27
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,27 @@
1
+ import { ConfigContext } from "sanity";
2
+ import { ListItemBuilder, StructureBuilder } from "sanity/structure";
3
+ import { ComponentType, ReactNode } from "react";
4
+ declare const singletonTools: import("sanity").Plugin<void>;
5
+ interface SingletonDocumentListItemConfig {
6
+ S: StructureBuilder;
7
+ context: ConfigContext;
8
+ type: string;
9
+ title?: string;
10
+ id?: string;
11
+ icon?: ComponentType | ReactNode;
12
+ }
13
+ interface SingletonPluginListItemsConfig {
14
+ S: StructureBuilder;
15
+ context: ConfigContext;
16
+ }
17
+ interface SingletonPluginOptions {
18
+ singleton?: boolean;
19
+ }
20
+ declare module "sanity" {
21
+ interface DocumentOptions extends SingletonPluginOptions {}
22
+ }
23
+ declare const singletonDocumentListItem: (config: SingletonDocumentListItemConfig) => ListItemBuilder;
24
+ declare const singletonDocumentListItems: (config: SingletonPluginListItemsConfig) => ListItemBuilder[];
25
+ declare const filteredDocumentListItems: (config: SingletonPluginListItemsConfig) => ListItemBuilder[];
26
+ export { type SingletonPluginOptions, filteredDocumentListItems, singletonDocumentListItem, singletonDocumentListItems, singletonTools };
27
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ import { definePlugin } from "sanity";
2
+ import { DocumentIcon } from "@sanity/icons";
3
+ const getSingletonDocuments = (schema) => {
4
+ if (schema?._original?.types) return schema._original.types.filter(({ options }) => options?.singleton).map((s) => s.name);
5
+ }, getIsSingleton = (schema, schemaType) => !schema?._original?.types || !schemaType ? !1 : schema._original.types.find(({ name }) => name === schemaType)?.options?.singleton ?? !1, actions = (prev, { schema, schemaType }) => getIsSingleton(schema, schemaType) ? prev.filter(({ action }) => [
6
+ "publish",
7
+ "discardChanges",
8
+ "restore"
9
+ ].includes(action)) : prev, newDocumentOptions = (prev, { schema, creationContext: { type, schemaType } }) => {
10
+ let singletons = getSingletonDocuments(schema), filterSingletons = ({ templateId }) => !singletons?.includes(templateId);
11
+ return type === "global" || singletons?.includes(schemaType ?? "") ? prev.filter(filterSingletons) : prev;
12
+ }, singletonTools = definePlugin(() => ({
13
+ name: "singleton-tools",
14
+ document: {
15
+ newDocumentOptions,
16
+ actions
17
+ }
18
+ })), singletonDocumentListItem = (config) => {
19
+ if (!config?.S || !config?.type || !config.context) throw Error("S, context, and type must be provided to singletonDocumentListItem. Example: singletonDocumentListItem({ S, context, type: 'product' })");
20
+ let { S, type, title, icon, id, context } = config, { schema } = context;
21
+ if (!schema) throw Error("Schema is required in context for singletonDocumentListItem");
22
+ let schemaType = schema.get(type), listTitle = title ?? schemaType?.title ?? type, listIcon = icon ?? schemaType?.icon ?? DocumentIcon, listId = id ?? type;
23
+ return S.listItem().title(listTitle).icon(listIcon).child(S.document().schemaType(type).title(listTitle).id(listId));
24
+ }, singletonDocumentListItems = (config) => {
25
+ if (!config.S || !config.context) throw Error("S and context must be provided to singletonDocumentListItems. Example: singletonDocumentListItems({ S, context })");
26
+ let { S, context } = config, { schema } = context;
27
+ return getSingletonDocuments(schema)?.map((schemaType) => singletonDocumentListItem({
28
+ S,
29
+ context,
30
+ type: schemaType
31
+ })) || [];
32
+ }, filteredDocumentListItems = (config) => {
33
+ if (!config.S || !config.context) throw Error("S and context must be provided to filteredDocumentListItems. Example: filteredDocumentListItems({ S, context })");
34
+ let { S, context } = config, { schema } = context, singletons = getSingletonDocuments(schema);
35
+ return S.documentTypeListItems().filter((type) => !singletons || !singletons.includes(type.getId()));
36
+ };
37
+ export { filteredDocumentListItems, singletonDocumentListItem, singletonDocumentListItems, singletonTools };
38
+
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/helpers/index.ts","../src/actions.ts","../src/newDocumentOptions.ts","../src/pluginConfig.ts","../src/structure/index.ts"],"sourcesContent":["import { Schema } from \"sanity\";\n\nimport { SingletonPluginOptions } from \"../types\";\n\nexport const getSingletonDocuments = (schema: Schema): string[] | undefined => {\n if (!schema?._original?.types) {\n return undefined;\n }\n\n return schema._original.types\n .filter(({ options }) => (options as SingletonPluginOptions)?.singleton)\n .map((s: { name: string }) => s.name);\n};\n\nexport const getIsSingleton = (schema: Schema, schemaType: string): boolean => {\n if (!schema?._original?.types || !schemaType) {\n return false;\n }\n\n const documentSchema = schema._original.types.find(\n ({ name }) => name === schemaType,\n );\n\n return (\n (documentSchema?.options as SingletonPluginOptions)?.singleton ?? false\n );\n};\n","import { DocumentActionsContext, DocumentActionsResolver } from \"sanity\";\n\nimport { getIsSingleton } from \"./helpers\";\n\nexport const actions: DocumentActionsResolver = (\n prev,\n { schema, schemaType }: DocumentActionsContext,\n) => {\n return getIsSingleton(schema, schemaType)\n ? prev.filter(({ action }) =>\n [\"publish\", \"discardChanges\", \"restore\"].includes(action as string),\n )\n : prev;\n};\n","import { NewDocumentOptionsContext, NewDocumentOptionsResolver } from \"sanity\";\n\nimport { getSingletonDocuments } from \"./helpers\";\n\nexport const newDocumentOptions: NewDocumentOptionsResolver = (\n prev,\n { schema, creationContext: { type, schemaType } }: NewDocumentOptionsContext,\n) => {\n const singletons = getSingletonDocuments(schema);\n\n const filterSingletons = ({ templateId }: { templateId: string }) =>\n !singletons?.includes(templateId);\n\n if (type === \"global\") return prev.filter(filterSingletons);\n\n return singletons?.includes(schemaType ?? \"\")\n ? prev.filter(filterSingletons)\n : prev;\n};\n","import { definePlugin } from \"sanity\";\n\nimport { actions } from \"./actions\";\nimport { newDocumentOptions } from \"./newDocumentOptions\";\n\nexport const singletonTools = definePlugin(() => {\n return {\n name: \"singleton-tools\",\n document: {\n newDocumentOptions,\n actions,\n },\n };\n});\n","import { DocumentIcon } from \"@sanity/icons\";\nimport type { ListItemBuilder } from \"sanity/structure\";\n\nimport { getSingletonDocuments } from \"../helpers\";\nimport {\n SingletonDocumentListItemConfig,\n SingletonPluginListItemsConfig,\n} from \"../types\";\n\nconst singletonDocumentListItem = (\n config: SingletonDocumentListItemConfig,\n): ListItemBuilder => {\n if (!config?.S || !config?.type || !config.context) {\n throw new Error(\n \"S, context, and type must be provided to singletonDocumentListItem. \" +\n \"Example: singletonDocumentListItem({ S, context, type: 'product' })\",\n );\n }\n const { S, type, title, icon, id, context } = config;\n const { schema } = context;\n\n if (!schema) {\n throw new Error(\n \"Schema is required in context for singletonDocumentListItem\",\n );\n }\n\n const schemaType = schema.get(type);\n const listTitle = title ?? schemaType?.title ?? type;\n const listIcon = icon ?? schemaType?.icon ?? DocumentIcon;\n const listId = id ?? type;\n\n return S.listItem()\n .title(listTitle)\n .icon(listIcon)\n .child(S.document().schemaType(type).title(listTitle).id(listId));\n};\n\nconst singletonDocumentListItems = (\n config: SingletonPluginListItemsConfig,\n): ListItemBuilder[] => {\n if (!config.S || !config.context) {\n throw new Error(\n \"S and context must be provided to singletonDocumentListItems. \" +\n \"Example: singletonDocumentListItems({ S, context })\",\n );\n }\n\n const { S, context } = config;\n const { schema } = context;\n\n const singletons = getSingletonDocuments(schema);\n\n return (\n singletons?.map((schemaType) =>\n singletonDocumentListItem({ S, context, type: schemaType }),\n ) || []\n );\n};\n\nconst filteredDocumentListItems = (\n config: SingletonPluginListItemsConfig,\n): ListItemBuilder[] => {\n if (!config.S || !config.context) {\n throw new Error(\n \"S and context must be provided to filteredDocumentListItems. \" +\n \"Example: filteredDocumentListItems({ S, context })\",\n );\n }\n const { S, context } = config;\n const { schema } = context;\n\n const singletons = getSingletonDocuments(schema);\n\n return S.documentTypeListItems().filter(\n (type) => !singletons || !singletons.includes(type.getId() as string),\n );\n};\n\nexport {\n filteredDocumentListItems,\n singletonDocumentListItem,\n singletonDocumentListItems,\n};\n"],"mappings":";;AAIA,MAAa,yBAAyB,WAAyC;CACxE,YAAQ,WAAW,OAIxB,OAAO,OAAO,UAAU,MACrB,QAAQ,EAAE,cAAe,SAAoC,SAAS,CAAC,CACvE,KAAK,MAAwB,EAAE,IAAI;AACxC,GAEa,kBAAkB,QAAgB,eACzC,CAAC,QAAQ,WAAW,SAAS,CAAC,aACzB,KAGc,OAAO,UAAU,MAAM,MAC3C,EAAE,WAAW,SAAS,UAIT,CAAC,EAAE,SAAoC,aAAa,ICpBzD,WACX,MACA,EAAE,QAAQ,iBAEH,eAAe,QAAQ,UAAU,IACpC,KAAK,QAAQ,EAAE,aACb;CAAC;CAAW;CAAkB;AAAS,CAAC,CAAC,SAAS,MAAgB,CACpE,IACA,MCRO,sBACX,MACA,EAAE,QAAQ,iBAAiB,EAAE,MAAM,mBAChC;CACH,IAAM,aAAa,sBAAsB,MAAM,GAEzC,oBAAoB,EAAE,iBAC1B,CAAC,YAAY,SAAS,UAAU;CAIlC,OAFI,SAAS,YAEN,YAAY,SAAS,cAAc,EAAE,IAFd,KAAK,OAAO,gBAAgB,IAItD;AACN,GCba,iBAAiB,oBACrB;CACL,MAAM;CACN,UAAU;EACR;EACA;CACF;AACF,EACD,GCJK,6BACJ,WACoB;CACpB,IAAI,CAAC,QAAQ,KAAK,CAAC,QAAQ,QAAQ,CAAC,OAAO,SACzC,MAAU,MACR,yIAEF;CAEF,IAAM,EAAE,GAAG,MAAM,OAAO,MAAM,IAAI,YAAY,QACxC,EAAE,WAAW;CAEnB,IAAI,CAAC,QACH,MAAU,MACR,6DACF;CAGF,IAAM,aAAa,OAAO,IAAI,IAAI,GAC5B,YAAY,SAAS,YAAY,SAAS,MAC1C,WAAW,QAAQ,YAAY,QAAQ,cACvC,SAAS,MAAM;CAErB,OAAO,EAAE,SAAS,CAAC,CAChB,MAAM,SAAS,CAAC,CAChB,KAAK,QAAQ,CAAC,CACd,MAAM,EAAE,SAAS,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC;AACpE,GAEM,8BACJ,WACsB;CACtB,IAAI,CAAC,OAAO,KAAK,CAAC,OAAO,SACvB,MAAU,MACR,mHAEF;CAGF,IAAM,EAAE,GAAG,YAAY,QACjB,EAAE,WAAW;CAInB,OAFmB,sBAAsB,MAG9B,CAAC,EAAE,KAAK,eACf,0BAA0B;EAAE;EAAG;EAAS,MAAM;CAAW,CAAC,CAC5D,KAAK,CAAC;AAEV,GAEM,6BACJ,WACsB;CACtB,IAAI,CAAC,OAAO,KAAK,CAAC,OAAO,SACvB,MAAU,MACR,iHAEF;CAEF,IAAM,EAAE,GAAG,YAAY,QACjB,EAAE,WAAW,SAEb,aAAa,sBAAsB,MAAM;CAE/C,OAAO,EAAE,sBAAsB,CAAC,CAAC,QAC9B,SAAS,CAAC,cAAc,CAAC,WAAW,SAAS,KAAK,MAAM,CAAW,CACtE;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-singleton-management",
3
- "version": "1.0.6",
3
+ "version": "1.1.0",
4
4
  "description": "A plugin to streamline singleton management in your Sanity Studio",
5
5
  "keywords": [
6
6
  "sanity",
@@ -14,16 +14,16 @@
14
14
  "exports": {
15
15
  ".": {
16
16
  "source": "./src/index.ts",
17
- "import": "./dist/index.esm.js",
17
+ "import": "./dist/index.js",
18
18
  "require": "./dist/index.cjs",
19
- "default": "./dist/index.esm.js"
19
+ "default": "./dist/index.js"
20
20
  },
21
21
  "./package.json": "./package.json"
22
22
  },
23
23
  "type": "module",
24
24
  "main": "./dist/index.cjs",
25
- "module": "./dist/index.esm.js",
26
- "types": "./dist/index.esm.d.ts",
25
+ "module": "./dist/index.js",
26
+ "types": "./dist/index.d.cts",
27
27
  "browserslist": "extends @sanity/browserslist-config",
28
28
  "files": [
29
29
  "dist",
@@ -49,61 +49,81 @@
49
49
  "test:coverage": "vitest run --coverage"
50
50
  },
51
51
  "dependencies": {
52
- "@sanity/icons": "^3.7.4",
52
+ "@sanity/icons": "^5.2.1",
53
53
  "@sanity/incompatible-plugin": "^1.0.5"
54
54
  },
55
55
  "devDependencies": {
56
- "@commitlint/cli": "^20.1.0",
57
- "@commitlint/config-conventional": "^20.0.0",
58
- "@commitlint/prompt-cli": "^20.1.0",
56
+ "@emnapi/core": "^1.11.3",
57
+ "@emnapi/runtime": "^1.11.3",
58
+ "@commitlint/cli": "^21.2.2",
59
+ "@commitlint/config-conventional": "^21.2.2",
60
+ "@commitlint/prompt-cli": "^21.2.2",
61
+ "@eslint-react/eslint-plugin": "^5.18.6",
62
+ "@eslint/js": "^10.0.1",
59
63
  "@sanity/browserslist-config": "^1.0.5",
60
- "@sanity/pkg-utils": "^10.2.1",
61
- "@sanity/plugin-kit": "^4.0.20",
62
- "@semantic-release/changelog": "^6.0.3",
63
- "@semantic-release/git": "^10.0.1",
64
- "@semantic-release/github": "^11.0.6",
65
- "@semantic-release/npm": "^13.1.2",
66
- "@testing-library/jest-dom": "^6.4.6",
67
- "@types/react": "^19.2.7",
68
- "@typescript-eslint/eslint-plugin": "^8.44.0",
69
- "@typescript-eslint/parser": "^8.44.0",
70
- "@vitest/coverage-v8": "^4.0.4",
71
- "@vitest/ui": "^4.0.1",
72
- "eslint": "^9.35.0",
64
+ "@sanity/pkg-utils": "^12.1.2",
65
+ "@sanity/plugin-kit": "^10.0.5",
66
+ "@semantic-release/changelog": "^7.0.0",
67
+ "@semantic-release/git": "^11.0.1",
68
+ "@semantic-release/github": "^12.0.9",
69
+ "@semantic-release/npm": "^13.1.5",
70
+ "@testing-library/jest-dom": "^7.0.1",
71
+ "@types/react": "^19.2.18",
72
+ "@vitest/coverage-v8": "^4.1.10",
73
+ "@vitest/ui": "^4.1.10",
74
+ "eslint": "^10.8.1",
73
75
  "eslint-config-prettier": "^10.1.8",
74
- "eslint-config-sanity": "^7.1.1",
75
- "eslint-plugin-prettier": "^5.1.3",
76
- "eslint-plugin-react": "^7.34.0",
77
- "eslint-plugin-react-hooks": "^7.0.0",
76
+ "eslint-plugin-react-hooks": "7.1.1",
78
77
  "husky": "^9.1.7",
79
- "jsdom": "^27.0.0",
80
78
  "npm-run-all": "^4.1.5",
81
- "prettier": "^3.2.5",
82
- "prettier-plugin-packagejson": "^2.4.12",
83
- "react": "^19.2.3",
84
- "react-dom": "^19.2.3",
85
- "react-is": "^19.2.3",
86
- "rimraf": "^6.0.1",
87
- "sanity": "^5.0.0",
88
- "semantic-release": "^25.0.2",
89
- "styled-components": "^6.1.15",
90
- "typescript": "^5.3.3",
91
- "typescript-eslint": "^8.44.0",
92
- "vitest": "^4.0.1"
79
+ "prettier": "^3.9.6",
80
+ "prettier-plugin-packagejson": "^3.0.2",
81
+ "react": "^19.2.8",
82
+ "react-dom": "^19.2.8",
83
+ "react-is": "^19.2.8",
84
+ "rimraf": "^6.1.3",
85
+ "sanity": "^6.9.2",
86
+ "semantic-release": "^25.0.9",
87
+ "styled-components": "^6.5.3",
88
+ "typescript": "^6.0.3",
89
+ "typescript-eslint": "^8.67.0",
90
+ "vitest": "^4.1.10"
93
91
  },
94
92
  "overrides": {
95
93
  "esbuild": "0.25.0",
96
94
  "prismjs": "1.30.0",
97
95
  "tmp": "0.2.4",
98
96
  "min-document": "2.19.0",
99
- "glob": "^10.5.0"
97
+ "minimatch": "^10.2.1",
98
+ "serialize-javascript": "^7.0.3",
99
+ "glob": "^10.5.0",
100
+ "flatted": "^3.4.2",
101
+ "js-yaml": "^3.14.2",
102
+ "ajv": "^8.18.0",
103
+ "lodash": "^4.18.0",
104
+ "brace-expansion": "^5.0.9",
105
+ "picomatch": "^4.0.4",
106
+ "smol-toml": "^1.6.1",
107
+ "typescript": "^6.0.3",
108
+ "typeid-js": {
109
+ "uuid": "^11.1.1"
110
+ },
111
+ "eslint": {
112
+ "ajv": "^6.14.0"
113
+ },
114
+ "@module-federation/dts-plugin": {
115
+ "undici": "^7.29.0"
116
+ },
117
+ "@sanity/pkg-utils": {
118
+ "typescript": "^6.0.3"
119
+ }
100
120
  },
101
121
  "peerDependencies": {
102
122
  "react": "^18 || ^19.2.1",
103
- "sanity": "^3 || ^4 || ^5.0.0-0"
123
+ "sanity": "^3 || ^4 || ^5.0.0-0 || ^6"
104
124
  },
105
125
  "engines": {
106
- "node": ">=20"
126
+ "node": ">=24"
107
127
  },
108
128
  "repository": {
109
129
  "type": "git",
@@ -113,9 +133,9 @@
113
133
  "publishConfig": {
114
134
  "exports": {
115
135
  ".": {
116
- "import": "./dist/index.esm.js",
136
+ "import": "./dist/index.js",
117
137
  "require": "./dist/index.cjs",
118
- "default": "./dist/index.esm.js"
138
+ "default": "./dist/index.js"
119
139
  },
120
140
  "./package.json": "./package.json"
121
141
  }
@@ -1,44 +0,0 @@
1
- import { ComponentType } from "react";
2
- import { ConfigContext } from "sanity";
3
- import type { ListItemBuilder } from "sanity/structure";
4
- import { Plugin as Plugin_2 } from "sanity";
5
- import { ReactNode } from "react";
6
- import { StructureBuilder } from "sanity/structure";
7
-
8
- export declare const filteredDocumentListItems: (
9
- config: SingletonPluginListItemsConfig,
10
- ) => ListItemBuilder[];
11
-
12
- export declare const singletonDocumentListItem: (
13
- config: SingletonDocumentListItemConfig,
14
- ) => ListItemBuilder;
15
-
16
- declare interface SingletonDocumentListItemConfig {
17
- S: StructureBuilder;
18
- context: ConfigContext;
19
- type: string;
20
- title?: string;
21
- id?: string;
22
- icon?: ComponentType | ReactNode;
23
- }
24
-
25
- export declare const singletonDocumentListItems: (
26
- config: SingletonPluginListItemsConfig,
27
- ) => ListItemBuilder[];
28
-
29
- declare interface SingletonPluginListItemsConfig {
30
- S: StructureBuilder;
31
- context: ConfigContext;
32
- }
33
-
34
- export declare interface SingletonPluginOptions {
35
- singleton?: boolean;
36
- }
37
-
38
- export declare const singletonTools: Plugin_2<void>;
39
-
40
- export {};
41
-
42
- declare module "sanity" {
43
- interface DocumentOptions extends SingletonPluginOptions {}
44
- }
package/dist/index.esm.js DELETED
@@ -1,56 +0,0 @@
1
- import { definePlugin } from "sanity";
2
- import { DocumentIcon } from "@sanity/icons";
3
- const getSingletonDocuments = (schema) => {
4
- if (schema?._original?.types)
5
- return schema._original.types.filter(({ options }) => options?.singleton).map((s) => s.name);
6
- }, getIsSingleton = (schema, schemaType) => !schema?._original?.types || !schemaType ? !1 : schema._original.types.find(
7
- ({ name }) => name === schemaType
8
- )?.options?.singleton ?? !1, actions = (prev, { schema, schemaType }) => getIsSingleton(schema, schemaType) ? prev.filter(
9
- ({ action }) => ["publish", "discardChanges", "restore"].includes(action)
10
- ) : prev, newDocumentOptions = (prev, { schema, creationContext: { type, schemaType } }) => {
11
- const singletons = getSingletonDocuments(schema), filterSingletons = ({ templateId }) => !singletons?.includes(templateId);
12
- return type === "global" || singletons?.includes(schemaType ?? "") ? prev.filter(filterSingletons) : prev;
13
- }, singletonTools = definePlugin(() => ({
14
- name: "singleton-tools",
15
- document: {
16
- newDocumentOptions,
17
- actions
18
- }
19
- })), singletonDocumentListItem = (config) => {
20
- if (!config?.S || !config?.type || !config.context)
21
- throw new Error(
22
- "S, context, and type must be provided to singletonDocumentListItem. Example: singletonDocumentListItem({ S, context, type: 'product' })"
23
- );
24
- const { S, type, title, icon, id, context } = config, { schema } = context;
25
- if (!schema)
26
- throw new Error(
27
- "Schema is required in context for singletonDocumentListItem"
28
- );
29
- const schemaType = schema.get(type), listTitle = title ?? schemaType?.title ?? type, listIcon = icon ?? schemaType?.icon ?? DocumentIcon, listId = id ?? type;
30
- return S.listItem().title(listTitle).icon(listIcon).child(S.document().schemaType(type).title(listTitle).id(listId));
31
- }, singletonDocumentListItems = (config) => {
32
- if (!config.S || !config.context)
33
- throw new Error(
34
- "S and context must be provided to singletonDocumentListItems. Example: singletonDocumentListItems({ S, context })"
35
- );
36
- const { S, context } = config, { schema } = context;
37
- return getSingletonDocuments(schema)?.map(
38
- (schemaType) => singletonDocumentListItem({ S, context, type: schemaType })
39
- ) || [];
40
- }, filteredDocumentListItems = (config) => {
41
- if (!config.S || !config.context)
42
- throw new Error(
43
- "S and context must be provided to filteredDocumentListItems. Example: filteredDocumentListItems({ S, context })"
44
- );
45
- const { S, context } = config, { schema } = context, singletons = getSingletonDocuments(schema);
46
- return S.documentTypeListItems().filter(
47
- (type) => !singletons || !singletons.includes(type.getId())
48
- );
49
- };
50
- export {
51
- filteredDocumentListItems,
52
- singletonDocumentListItem,
53
- singletonDocumentListItems,
54
- singletonTools
55
- };
56
- //# sourceMappingURL=index.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/helpers/index.ts","../src/actions.ts","../src/newDocumentOptions.ts","../src/pluginConfig.ts","../src/structure/index.ts"],"sourcesContent":["import { Schema } from \"sanity\";\n\nimport { SingletonPluginOptions } from \"../types\";\n\nexport const getSingletonDocuments = (schema: Schema): string[] | undefined => {\n if (!schema?._original?.types) {\n return undefined;\n }\n\n return schema._original.types\n .filter(({ options }) => (options as SingletonPluginOptions)?.singleton)\n .map((s: { name: string }) => s.name);\n};\n\nexport const getIsSingleton = (schema: Schema, schemaType: string): boolean => {\n if (!schema?._original?.types || !schemaType) {\n return false;\n }\n\n const documentSchema = schema._original.types.find(\n ({ name }) => name === schemaType,\n );\n\n return (\n (documentSchema?.options as SingletonPluginOptions)?.singleton ?? false\n );\n};\n","import { DocumentActionsContext, DocumentActionsResolver } from \"sanity\";\n\nimport { getIsSingleton } from \"./helpers\";\n\nexport const actions: DocumentActionsResolver = (\n prev,\n { schema, schemaType }: DocumentActionsContext,\n) => {\n return getIsSingleton(schema, schemaType)\n ? prev.filter(({ action }) =>\n [\"publish\", \"discardChanges\", \"restore\"].includes(action as string),\n )\n : prev;\n};\n","import { NewDocumentOptionsContext, NewDocumentOptionsResolver } from \"sanity\";\n\nimport { getSingletonDocuments } from \"./helpers\";\n\nexport const newDocumentOptions: NewDocumentOptionsResolver = (\n prev,\n { schema, creationContext: { type, schemaType } }: NewDocumentOptionsContext,\n) => {\n const singletons = getSingletonDocuments(schema);\n\n const filterSingletons = ({ templateId }: { templateId: string }) =>\n !singletons?.includes(templateId);\n\n if (type === \"global\") return prev.filter(filterSingletons);\n\n return singletons?.includes(schemaType ?? \"\")\n ? prev.filter(filterSingletons)\n : prev;\n};\n","import { definePlugin } from \"sanity\";\n\nimport { actions } from \"./actions\";\nimport { newDocumentOptions } from \"./newDocumentOptions\";\n\nexport const singletonTools = definePlugin(() => {\n return {\n name: \"singleton-tools\",\n document: {\n newDocumentOptions,\n actions,\n },\n };\n});\n","import { DocumentIcon } from \"@sanity/icons\";\nimport type { ListItemBuilder } from \"sanity/structure\";\n\nimport { getSingletonDocuments } from \"../helpers\";\nimport {\n SingletonDocumentListItemConfig,\n SingletonPluginListItemsConfig,\n} from \"../types\";\n\nconst singletonDocumentListItem = (\n config: SingletonDocumentListItemConfig,\n): ListItemBuilder => {\n if (!config?.S || !config?.type || !config.context) {\n throw new Error(\n \"S, context, and type must be provided to singletonDocumentListItem. \" +\n \"Example: singletonDocumentListItem({ S, context, type: 'product' })\",\n );\n }\n const { S, type, title, icon, id, context } = config;\n const { schema } = context;\n\n if (!schema) {\n throw new Error(\n \"Schema is required in context for singletonDocumentListItem\",\n );\n }\n\n const schemaType = schema.get(type);\n const listTitle = title ?? schemaType?.title ?? type;\n const listIcon = icon ?? schemaType?.icon ?? DocumentIcon;\n const listId = id ?? type;\n\n return S.listItem()\n .title(listTitle)\n .icon(listIcon)\n .child(S.document().schemaType(type).title(listTitle).id(listId));\n};\n\nconst singletonDocumentListItems = (\n config: SingletonPluginListItemsConfig,\n): ListItemBuilder[] => {\n if (!config.S || !config.context) {\n throw new Error(\n \"S and context must be provided to singletonDocumentListItems. \" +\n \"Example: singletonDocumentListItems({ S, context })\",\n );\n }\n\n const { S, context } = config;\n const { schema } = context;\n\n const singletons = getSingletonDocuments(schema);\n\n return (\n singletons?.map((schemaType) =>\n singletonDocumentListItem({ S, context, type: schemaType }),\n ) || []\n );\n};\n\nconst filteredDocumentListItems = (\n config: SingletonPluginListItemsConfig,\n): ListItemBuilder[] => {\n if (!config.S || !config.context) {\n throw new Error(\n \"S and context must be provided to filteredDocumentListItems. \" +\n \"Example: filteredDocumentListItems({ S, context })\",\n );\n }\n const { S, context } = config;\n const { schema } = context;\n\n const singletons = getSingletonDocuments(schema);\n\n return S.documentTypeListItems().filter(\n (type) => !singletons || !singletons.includes(type.getId() as string),\n );\n};\n\nexport {\n filteredDocumentListItems,\n singletonDocumentListItem,\n singletonDocumentListItems,\n};\n"],"names":[],"mappings":";;AAIO,MAAM,wBAAwB,CAAC,WAAyC;AAC7E,MAAK,QAAQ,WAAW;AAIxB,WAAO,OAAO,UAAU,MACrB,OAAO,CAAC,EAAE,QAAA,MAAe,SAAoC,SAAS,EACtE,IAAI,CAAC,MAAwB,EAAE,IAAI;AACxC,GAEa,iBAAiB,CAAC,QAAgB,eACzC,CAAC,QAAQ,WAAW,SAAS,CAAC,aACzB,KAGc,OAAO,UAAU,MAAM;AAAA,EAC5C,CAAC,EAAE,KAAA,MAAW,SAAS;AACzB,GAGmB,SAAoC,aAAa,ICpBzD,UAAmC,CAC9C,MACA,EAAE,QAAQ,WAAA,MAEH,eAAe,QAAQ,UAAU,IACpC,KAAK;AAAA,EAAO,CAAC,EAAE,OAAA,MACb,CAAC,WAAW,kBAAkB,SAAS,EAAE,SAAS,MAAgB;AACpE,IACA,MCRO,qBAAiD,CAC5D,MACA,EAAE,QAAQ,iBAAiB,EAAE,MAAM,WAAA,QAChC;AACH,QAAM,aAAa,sBAAsB,MAAM,GAEzC,mBAAmB,CAAC,EAAE,iBAC1B,CAAC,YAAY,SAAS,UAAU;AAElC,SAAI,SAAS,YAEN,YAAY,SAAS,cAAc,EAAE,IAFd,KAAK,OAAO,gBAAgB,IAItD;AACN,GCba,iBAAiB,aAAa,OAClC;AAAA,EACL,MAAM;AAAA,EACN,UAAU;AAAA,IACR;AAAA,IACA;AAAA,EAAA;AAEJ,EACD,GCJK,4BAA4B,CAChC,WACoB;AACpB,MAAI,CAAC,QAAQ,KAAK,CAAC,QAAQ,QAAQ,CAAC,OAAO;AACzC,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAIJ,QAAM,EAAE,GAAG,MAAM,OAAO,MAAM,IAAI,YAAY,QACxC,EAAE,OAAA,IAAW;AAEnB,MAAI,CAAC;AACH,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAIJ,QAAM,aAAa,OAAO,IAAI,IAAI,GAC5B,YAAY,SAAS,YAAY,SAAS,MAC1C,WAAW,QAAQ,YAAY,QAAQ,cACvC,SAAS,MAAM;AAErB,SAAO,EAAE,WACN,MAAM,SAAS,EACf,KAAK,QAAQ,EACb,MAAM,EAAE,SAAA,EAAW,WAAW,IAAI,EAAE,MAAM,SAAS,EAAE,GAAG,MAAM,CAAC;AACpE,GAEM,6BAA6B,CACjC,WACsB;AACtB,MAAI,CAAC,OAAO,KAAK,CAAC,OAAO;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAKJ,QAAM,EAAE,GAAG,QAAA,IAAY,QACjB,EAAE,WAAW;AAInB,SAFmB,sBAAsB,MAAM,GAGjC;AAAA,IAAI,CAAC,eACf,0BAA0B,EAAE,GAAG,SAAS,MAAM,YAAY;AAAA,EAAA,KACvD,CAAA;AAET,GAEM,4BAA4B,CAChC,WACsB;AACtB,MAAI,CAAC,OAAO,KAAK,CAAC,OAAO;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAIJ,QAAM,EAAE,GAAG,QAAA,IAAY,QACjB,EAAE,OAAA,IAAW,SAEb,aAAa,sBAAsB,MAAM;AAE/C,SAAO,EAAE,wBAAwB;AAAA,IAC/B,CAAC,SAAS,CAAC,cAAc,CAAC,WAAW,SAAS,KAAK,MAAA,CAAiB;AAAA,EAAA;AAExE;"}