@sanity/presets 0.1.0 → 0.3.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 +438 -10
- package/dist/index.d.ts +89 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +434 -82
- package/dist/index.js.map +1 -1
- package/package.json +19 -3
package/README.md
CHANGED
|
@@ -1,18 +1,446 @@
|
|
|
1
1
|
# @sanity/presets
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> The API is unstable and will change without notice. Do not install it as a dependency.
|
|
3
|
+
## Overview
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
`@sanity/presets` provides ready-made helpers for creating schema types for common content patterns in Sanity Studio. Instead of modelling pages, links, images, and metadata from scratch, call a `define<Type>` function and get a working schema type with sensible defaults.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
**Included presets:**
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
- `definePage` — document type for page building (content blocks, slug, SEO metadata)
|
|
10
|
+
- `defineLink` — internal and external links with conditional fields
|
|
11
|
+
- `defineCta` — call-to-action with an inline link and semantic importance level
|
|
12
|
+
- `defineSeo` — search engine metadata (title, description, Open Graph image)
|
|
13
|
+
- `defineImage` — image with optional alt text, caption, and hotspot
|
|
14
|
+
- `defineRichText` — Portable Text with link annotations, image blocks, and CTA inline objects; embedded objects default on, opt out with `objects: false` or `objects: {link: false}`
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
**When to use presets:**
|
|
13
17
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
18
|
+
- You want opinionated defaults to get started quickly.
|
|
19
|
+
- You don't yet have a need for highly custom content modelling.
|
|
20
|
+
- You have not chosen to use LLMs for schema generation.
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
Presets are designed to be extended — add fields, groups, and map hooks as your needs evolve. When a preset no longer fits, replace it with your own schema type using `defineType` directly.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
**Prerequisites:** A Sanity Studio project with `sanity` installed. See the [getting started guide](https://www.sanity.io/docs/getting-started) if you're starting from scratch.
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npm install @sanity/presets
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
pnpm add @sanity/presets
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
yarn add @sanity/presets
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Import `createPresetsRegistry` and create a registry instance. The registry returns `define<Type>` functions that produce schema types:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import {createPresetsRegistry} from '@sanity/presets'
|
|
44
|
+
|
|
45
|
+
const {defineLink, defineCta, defineSeo, defineImage, definePage} = createPresetsRegistry({
|
|
46
|
+
link: {
|
|
47
|
+
internalTypes: ['page', 'post'],
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The `define<Type>` functions are used directly in your `schema.types` configuration, alongside standard `defineType` and `defineField` calls:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import {defineConfig} from 'sanity'
|
|
56
|
+
|
|
57
|
+
export default defineConfig({
|
|
58
|
+
// ...
|
|
59
|
+
schema: {
|
|
60
|
+
types: [
|
|
61
|
+
definePage({
|
|
62
|
+
name: 'marketingPage',
|
|
63
|
+
title: 'Marketing Page',
|
|
64
|
+
// Each page builder block must be a type you've defined in your
|
|
65
|
+
// schema. See "Use presets alongside custom types" for more.
|
|
66
|
+
pageBuilderBlocks: ['hero', 'featureGrid'],
|
|
67
|
+
}),
|
|
68
|
+
// your other types...
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Concepts
|
|
75
|
+
|
|
76
|
+
### Registry
|
|
77
|
+
|
|
78
|
+
The **presets registry** is the entry point to `@sanity/presets`. Call `createPresetsRegistry()` to get a set of `define<Type>` functions that produce schema types.
|
|
79
|
+
|
|
80
|
+
The registry serves two purposes:
|
|
81
|
+
|
|
82
|
+
1. **Global configuration.** Presets can be configured at the registry level, providing defaults that apply everywhere a preset is used. For example, configuring `link.internalTypes` once means every link — whether standalone, inside a CTA, or inside rich text — knows which document types are available for internal links.
|
|
83
|
+
|
|
84
|
+
2. **Composition.** Some presets compose other presets internally. The CTA preset includes a link field; the page preset includes SEO fields. The registry ensures these composed presets share the same global configuration.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const {defineLink, defineCta, definePage} = createPresetsRegistry({
|
|
88
|
+
link: {
|
|
89
|
+
// Every link in this registry — standalone, inside CTAs,
|
|
90
|
+
// inside rich text — will offer these types for internal links.
|
|
91
|
+
internalTypes: ['marketingPage', 'blogPost'],
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Global configuration can be overridden at the call site. If a specific link instance needs different internal types, pass them directly:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
defineLink({
|
|
100
|
+
name: 'specialLink',
|
|
101
|
+
// Overrides the registry-level internalTypes for this instance only.
|
|
102
|
+
internalTypes: ['product'],
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Composition
|
|
107
|
+
|
|
108
|
+
Presets can compose other presets. This means configuring one preset can affect others that depend on it.
|
|
109
|
+
|
|
110
|
+
The **link** preset is the clearest example. When you configure `link.internalTypes` at the registry level, that configuration cascades to:
|
|
111
|
+
|
|
112
|
+
- **CTA (call to action)** — the CTA preset includes an inline link field. The link field automatically uses the registry-level `internalTypes` configuration.
|
|
113
|
+
- **Rich text** — the rich text preset includes link annotations. Those annotations also use the registry-level `internalTypes` configuration.
|
|
114
|
+
|
|
115
|
+
This means you configure link behaviour once, and every preset that uses links inherits that configuration automatically.
|
|
116
|
+
|
|
117
|
+
### Map hooks
|
|
118
|
+
|
|
119
|
+
Every preset accepts a `map` option containing **map hooks** — functions that receive the produced schema type and return a modified version.
|
|
120
|
+
|
|
121
|
+
Map hooks exist as an escape hatch. They give you full control over the schema type a preset produces, including the ability to reorder, rename, or remove fields.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import {defineField} from 'sanity'
|
|
125
|
+
|
|
126
|
+
definePage({
|
|
127
|
+
name: 'marketingPage',
|
|
128
|
+
title: 'Marketing Page',
|
|
129
|
+
map: {
|
|
130
|
+
// Prepend a "Subtitle" field before all other fields.
|
|
131
|
+
fields: (fields = []) => [
|
|
132
|
+
defineField({
|
|
133
|
+
name: 'subtitle',
|
|
134
|
+
title: 'Subtitle',
|
|
135
|
+
type: 'string',
|
|
136
|
+
group: 'main',
|
|
137
|
+
}),
|
|
138
|
+
...fields,
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Each hook receives the value from the produced schema type (after any `fields`, `groups`, or other options have been applied) and must return a compatible value.
|
|
145
|
+
|
|
146
|
+
**Use map hooks carefully.** They have the final say in the produced schema type, which means they can unintentionally break a preset's intended functionality. A few guidelines:
|
|
147
|
+
|
|
148
|
+
- If you find yourself heavily rewriting the produced schema type with map hooks, it may be a sign that you should model the content type yourself using `defineType` and `defineField` directly. See the [schema type documentation](https://www.sanity.io/docs/apis-and-sdks/introduction-to-schemas) for more.
|
|
149
|
+
- If you use map hooks to rename fields, existing documents may need to be migrated. See the [schema and content migrations documentation](https://www.sanity.io/docs/content-lake/schema-and-content-migrations).
|
|
150
|
+
|
|
151
|
+
## Usage
|
|
152
|
+
|
|
153
|
+
### Page
|
|
154
|
+
|
|
155
|
+
The page preset produces a document type designed for page building. It includes fields for a page name, slug, content (an array of page-builder blocks), and SEO metadata.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
definePage({
|
|
159
|
+
name: 'marketingPage',
|
|
160
|
+
title: 'Marketing Page',
|
|
161
|
+
// Each page builder block must be a type you've defined in your schema.
|
|
162
|
+
// See "Use presets alongside custom types" for more.
|
|
163
|
+
pageBuilderBlocks: ['hero', 'featureGrid', 'testimonial'],
|
|
164
|
+
})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Fields:**
|
|
168
|
+
|
|
169
|
+
| Field | Type | Group | Description |
|
|
170
|
+
| --------- | -------- | -------- | -------------------------------------------------------------------------------- |
|
|
171
|
+
| `name` | `string` | Main | The page's display name. Required. |
|
|
172
|
+
| `slug` | `slug` | Main | URL-friendly slug, sourced from `name`. |
|
|
173
|
+
| `content` | `array` | Main | Page builder blocks. Types are specified via `pageBuilderBlocks`. |
|
|
174
|
+
| `seo` | `object` | Metadata | SEO fields (title, description, Open Graph image). Composed from the SEO preset. |
|
|
175
|
+
|
|
176
|
+
**Groups:** Main (default), Metadata.
|
|
177
|
+
|
|
178
|
+
**Options:**
|
|
179
|
+
|
|
180
|
+
| Option | Type | Description |
|
|
181
|
+
| ------------------- | ------------------------ | ----------------------------------------------- |
|
|
182
|
+
| `pageBuilderBlocks` | `string[]` | Type names to include in the content array. |
|
|
183
|
+
| `fields` | `FieldDefinition[]` | Additional fields to append. |
|
|
184
|
+
| `groups` | `FieldGroupDefinition[]` | Additional groups to append after the defaults. |
|
|
185
|
+
|
|
186
|
+
The page preset is not the only way to create page documents. It provides opinionated defaults to get started quickly. For specialised page types, use `defineType` directly. See the [document type documentation](https://www.sanity.io/docs/studio/document-type).
|
|
187
|
+
|
|
188
|
+
### Link
|
|
189
|
+
|
|
190
|
+
The link preset produces an object type for internal and external links. It includes fields for the link type (internal or external), a reference field for internal links, a URL field for external links, and an "open in new tab" option.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
defineLink({
|
|
194
|
+
name: 'primaryLink',
|
|
195
|
+
title: 'Primary Link',
|
|
196
|
+
// Document types available for internal links. Falls back to
|
|
197
|
+
// the registry-level link.internalTypes if not provided here.
|
|
198
|
+
internalTypes: ['page', 'post'],
|
|
199
|
+
})
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Fields:**
|
|
203
|
+
|
|
204
|
+
| Field | Type | Description |
|
|
205
|
+
| -------------- | ----------- | -------------------------------------------------------------------------------------------------------- |
|
|
206
|
+
| `linkType` | `string` | "Internal" or "External". Defaults to "Internal". |
|
|
207
|
+
| `reference` | `reference` | Internal link. Hidden when link type is external. Targets configured via `internalTypes`. |
|
|
208
|
+
| `url` | `url` | External URL. Hidden when link type is internal. Validates `http`, `https`, `mailto`, and `tel` schemes. |
|
|
209
|
+
| `openInNewTab` | `boolean` | Whether to open in a new tab. Hidden for internal links. |
|
|
210
|
+
|
|
211
|
+
**Options:**
|
|
212
|
+
|
|
213
|
+
| Option | Type | Description |
|
|
214
|
+
| --------------- | ---------- | --------------------------------------------------------------------------------------------------- |
|
|
215
|
+
| `internalTypes` | `string[]` | Document types available for internal links. Falls back to the registry-level `link.internalTypes`. |
|
|
216
|
+
|
|
217
|
+
### CTA (call to action)
|
|
218
|
+
|
|
219
|
+
The CTA preset produces an object type for call-to-action elements. It includes an inline link field (composed from the link preset) and a level selector for semantic importance.
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
defineCta({
|
|
223
|
+
name: 'heroCta',
|
|
224
|
+
title: 'Hero CTA',
|
|
225
|
+
})
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Fields:**
|
|
229
|
+
|
|
230
|
+
| Field | Type | Description |
|
|
231
|
+
| ------- | -------- | ------------------------------------------------------------------------------------------ |
|
|
232
|
+
| `link` | `object` | An inline link, composed from the link preset. Inherits `internalTypes` from the registry. |
|
|
233
|
+
| `level` | `number` | Semantic importance level (1, 2, or 3). |
|
|
234
|
+
|
|
235
|
+
### SEO (search engine optimization)
|
|
236
|
+
|
|
237
|
+
The SEO preset produces an object type for search engine metadata. It includes fields for a title, description, and Open Graph image with dimension validation.
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
defineSeo({
|
|
241
|
+
name: 'metadata',
|
|
242
|
+
title: 'Metadata',
|
|
243
|
+
group: 'metadata',
|
|
244
|
+
})
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Fields:**
|
|
248
|
+
|
|
249
|
+
| Field | Type | Description |
|
|
250
|
+
| ------------- | -------- | ------------------------------------------------------------------ |
|
|
251
|
+
| `title` | `string` | Page title for search engines. Warns when exceeding 70 characters. |
|
|
252
|
+
| `description` | `text` | Meta description. Warns when exceeding 150 characters. |
|
|
253
|
+
| `ogImage` | `image` | Open Graph image. Validates dimensions are exactly 1200×630. |
|
|
254
|
+
|
|
255
|
+
The SEO preset is also composed into the page preset, where it appears as an inline object field in the Metadata group.
|
|
256
|
+
|
|
257
|
+
### Image
|
|
258
|
+
|
|
259
|
+
The image preset produces an object type for images with optional alt text and caption fields. It includes built-in preview configuration.
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
defineImage({
|
|
263
|
+
name: 'heroImage',
|
|
264
|
+
title: 'Hero Image',
|
|
265
|
+
altText: true,
|
|
266
|
+
caption: false,
|
|
267
|
+
hotspot: true,
|
|
268
|
+
})
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Fields:**
|
|
272
|
+
|
|
273
|
+
| Field | Type | Description |
|
|
274
|
+
| --------- | -------- | -------------------------------------------------------------------------------------- |
|
|
275
|
+
| `image` | `image` | The image asset. Hotspot is enabled by default. |
|
|
276
|
+
| `altText` | `string` | Alt text for accessibility. Enabled by default. Shows a validation warning when empty. |
|
|
277
|
+
| `caption` | `text` | Image caption. Enabled by default. |
|
|
278
|
+
|
|
279
|
+
**Options:**
|
|
280
|
+
|
|
281
|
+
| Option | Type | Default | Description |
|
|
282
|
+
| --------- | --------- | ------- | --------------------------- |
|
|
283
|
+
| `altText` | `boolean` | `true` | Include the alt text field. |
|
|
284
|
+
| `caption` | `boolean` | `true` | Include the caption field. |
|
|
285
|
+
| `hotspot` | `boolean` | `true` | Enable image hotspot. |
|
|
286
|
+
|
|
287
|
+
### Rich text
|
|
288
|
+
|
|
289
|
+
The rich text preset produces a Portable Text array type with link annotations, image blocks, and inline call-to-action (CTA) objects. All three embedded objects are on by default.
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
defineRichText({
|
|
293
|
+
name: 'body',
|
|
294
|
+
title: 'Body',
|
|
295
|
+
})
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Embedded objects:**
|
|
299
|
+
|
|
300
|
+
| Object | Type | Description |
|
|
301
|
+
| ------- | ------------------------ | ----------------------------------------------------------- |
|
|
302
|
+
| `link` | Portable Text annotation | Adds the link preset as an inline annotation on blocks. |
|
|
303
|
+
| `image` | Array member | Adds the image preset as a block-level member of the array. |
|
|
304
|
+
| `cta` | Inline object | Adds the CTA preset as an inline object within blocks. |
|
|
305
|
+
|
|
306
|
+
**Options:**
|
|
307
|
+
|
|
308
|
+
| Option | Type | Default | Description |
|
|
309
|
+
| --------- | ------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------- |
|
|
310
|
+
| `objects` | `boolean \| {link?: boolean, image?: boolean, cta?: boolean}` | `true` | Toggles embedded objects on or off. Pass `false` to disable all, or an object per entry. |
|
|
311
|
+
|
|
312
|
+
To disable all embedded objects for a plain Portable Text field:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
defineRichText({
|
|
316
|
+
name: 'plainBody',
|
|
317
|
+
objects: false,
|
|
318
|
+
})
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
To disable individual embedded objects:
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
defineRichText({
|
|
325
|
+
name: 'body',
|
|
326
|
+
objects: {cta: false},
|
|
327
|
+
})
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
#### Configuring the embedded presets
|
|
331
|
+
|
|
332
|
+
Configure each object's options (link `internalTypes`, image `altText`, and so on) at the registry level. Those options cascade into every rich text field:
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
const {defineRichText} = createPresetsRegistry({
|
|
336
|
+
link: {
|
|
337
|
+
internalTypes: ['page', 'post'],
|
|
338
|
+
},
|
|
339
|
+
image: {
|
|
340
|
+
altText: true,
|
|
341
|
+
caption: false,
|
|
342
|
+
},
|
|
343
|
+
})
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
The `objects` option only toggles embedded objects on or off. To reshape the array members on a specific rich text field, use the [map hooks escape hatch](#reserve-map-hooks-for-when-you-need-full-control).
|
|
347
|
+
|
|
348
|
+
## Recommended patterns
|
|
349
|
+
|
|
350
|
+
### Use presets alongside custom types
|
|
351
|
+
|
|
352
|
+
Presets are not intended to replace all content modelling. They provide opinionated defaults for common patterns — pages, links, images, metadata — but your schema will likely include custom types that are specific to your project.
|
|
353
|
+
|
|
354
|
+
Custom types and presets work well together. You can use presets inside custom types, and reference custom types from presets:
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
import {defineType, defineField} from 'sanity'
|
|
358
|
+
|
|
359
|
+
// A custom "blockquote" type that includes a link preset.
|
|
360
|
+
// This type must be added to schema.types alongside your presets.
|
|
361
|
+
defineType({
|
|
362
|
+
name: 'blockquote',
|
|
363
|
+
title: 'Blockquote',
|
|
364
|
+
type: 'object',
|
|
365
|
+
fields: [
|
|
366
|
+
defineField({name: 'quote', title: 'Quote', type: 'text'}),
|
|
367
|
+
defineField({name: 'author', title: 'Author', type: 'string'}),
|
|
368
|
+
defineLink({name: 'source', title: 'Source'}),
|
|
369
|
+
],
|
|
370
|
+
})
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
When a preset references a custom type — for example, passing `pageBuilderBlocks: ["blockquote"]` to `definePage` — that type must be defined in your schema. Presets don't create these types for you.
|
|
374
|
+
|
|
375
|
+
### Extend presets with fields and groups
|
|
376
|
+
|
|
377
|
+
Rather than reaching for [map hooks](#map-hooks), use the `fields` and `groups` options to extend a preset. Fields and groups added this way are appended after the preset's own fields and groups:
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
definePage({
|
|
381
|
+
name: 'blogPost',
|
|
382
|
+
title: 'Blog Post',
|
|
383
|
+
// These types must be defined in your schema.
|
|
384
|
+
// See "Use presets alongside custom types" for more.
|
|
385
|
+
pageBuilderBlocks: ['richText', 'image'],
|
|
386
|
+
groups: [{name: 'settings', title: 'Settings'}],
|
|
387
|
+
fields: [
|
|
388
|
+
defineField({
|
|
389
|
+
name: 'publishedAt',
|
|
390
|
+
title: 'Published at',
|
|
391
|
+
type: 'datetime',
|
|
392
|
+
group: 'metadata',
|
|
393
|
+
}),
|
|
394
|
+
defineField({
|
|
395
|
+
name: 'featured',
|
|
396
|
+
title: 'Featured',
|
|
397
|
+
type: 'boolean',
|
|
398
|
+
group: 'settings',
|
|
399
|
+
}),
|
|
400
|
+
],
|
|
401
|
+
})
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Reserve map hooks for when you need full control
|
|
405
|
+
|
|
406
|
+
The [`fields` option](#extend-presets-with-fields-and-groups) is sufficient for adding new fields to a preset. Use map hooks when you need full control over the produced schema type — for example, reordering or wrapping existing fields:
|
|
407
|
+
|
|
408
|
+
```ts
|
|
409
|
+
import {defineField} from 'sanity'
|
|
410
|
+
|
|
411
|
+
definePage({
|
|
412
|
+
name: 'marketingPage',
|
|
413
|
+
title: 'Marketing Page',
|
|
414
|
+
map: {
|
|
415
|
+
// Prepend a "Subtitle" field before all other fields.
|
|
416
|
+
fields: (fields = []) => [
|
|
417
|
+
defineField({
|
|
418
|
+
name: 'subtitle',
|
|
419
|
+
title: 'Subtitle',
|
|
420
|
+
type: 'string',
|
|
421
|
+
group: 'main',
|
|
422
|
+
}),
|
|
423
|
+
...fields,
|
|
424
|
+
],
|
|
425
|
+
},
|
|
426
|
+
})
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
A few guidelines for using map hooks:
|
|
430
|
+
|
|
431
|
+
- If you find yourself heavily rewriting the produced schema type with map hooks, it may be a sign that you should model the content type yourself. See the [schema type documentation](https://www.sanity.io/docs/apis-and-sdks/introduction-to-schemas) for more.
|
|
432
|
+
- If you use map hooks to rename fields, existing documents may need to be migrated to reflect the new field names. See the [schema and content migrations documentation](https://www.sanity.io/docs/content-lake/schema-and-content-migrations).
|
|
433
|
+
|
|
434
|
+
### Configure links globally
|
|
435
|
+
|
|
436
|
+
The [link preset](#link) is used by multiple other presets ([CTA](#cta-call-to-action), [rich text](#rich-text)). Configure `internalTypes` at the registry level so all links share the same set of linkable document types:
|
|
437
|
+
|
|
438
|
+
```ts
|
|
439
|
+
const {defineLink, defineCta, definePage} = createPresetsRegistry({
|
|
440
|
+
link: {
|
|
441
|
+
internalTypes: ['page', 'post', 'product'],
|
|
442
|
+
},
|
|
443
|
+
})
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
This single configuration flows into every `defineLink`, `defineCta`, and `defineRichText` call from this registry. Override at the call site only when a specific instance needs different behaviour.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,93 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { DefineSchemaBase, FieldDefinition, FieldDefinitionBase, IntrinsicTypeName, PreviewConfig, SchemaTypeDefinition } from "sanity";
|
|
2
|
+
type PartialSchemaDefinition<TypeName extends IntrinsicTypeName> = Partial<DefineSchemaBase<TypeName, TypeName> & {
|
|
3
|
+
preview: PreviewConfig;
|
|
4
|
+
}>;
|
|
5
|
+
interface RegistryContext {
|
|
6
|
+
getPreset: (presetName: string, config?: Record<string, unknown>) => FieldDefinition;
|
|
4
7
|
}
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
type ProhibitedProperties = 'type';
|
|
9
|
+
type SanitizeProperties<Properties, ExcludedProperties extends string | undefined> = [ExcludedProperties] extends [PropertyKey] ? Omit<Properties, ExcludedProperties> : Properties;
|
|
10
|
+
type DerivedConfig<Context, AliasedType extends IntrinsicTypeName | undefined = undefined, LockedProperties extends string | undefined = undefined> = Context & FieldDefinitionBase & (AliasedType extends string ? SanitizeProperties<PartialSchemaDefinition<AliasedType>, ProhibitedProperties | LockedProperties> : {}) & {
|
|
11
|
+
map?: AliasedType extends string ? { [Key in keyof PartialSchemaDefinition<AliasedType>]?: (input: PartialSchemaDefinition<AliasedType>[Key]) => PartialSchemaDefinition<AliasedType>[Key] } : {};
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The public-facing config shape that a registry's `define<Name>` function
|
|
15
|
+
* accepts at the call site. Includes the full `DerivedConfig` (with optional
|
|
16
|
+
* `map` and optional `name` — the registry falls back to the preset's default
|
|
17
|
+
* name when `name` is omitted).
|
|
18
|
+
*/
|
|
19
|
+
type UserConfig<Context = {}, AliasedType extends IntrinsicTypeName | undefined = undefined, LockedProperties extends string | undefined = undefined> = DerivedConfig<Context, AliasedType, LockedProperties>;
|
|
20
|
+
/**
|
|
21
|
+
* A preset definition describes how to produce a Sanity schema type.
|
|
22
|
+
*
|
|
23
|
+
* - `name` is the default schema type name. Consumers can override this at the
|
|
24
|
+
* call site (e.g. `defineLink({name: 'myLink'})`); the registry will make
|
|
25
|
+
* sure the override reaches the `schemaType` factory via its config.
|
|
26
|
+
* - `identifier` is an optional stable identifier used for telemetry.
|
|
27
|
+
* - `schemaType` is the factory that produces the Sanity schema type. It
|
|
28
|
+
* receives the merged config (minus `map`, with `name` guaranteed by the
|
|
29
|
+
* registry) and the registry context, and returns a `SchemaTypeDefinition`.
|
|
30
|
+
*/
|
|
31
|
+
interface PresetDefinition<Context = {}, AliasedType extends IntrinsicTypeName | undefined = undefined, LockedProperties extends string | undefined = undefined> {
|
|
32
|
+
name: string;
|
|
33
|
+
identifier?: string;
|
|
34
|
+
schemaType: (config: Omit<DerivedConfig<Context, AliasedType, LockedProperties>, 'map' | 'name'> & {
|
|
35
|
+
name: string;
|
|
36
|
+
}, registry: RegistryContext) => SchemaTypeDefinition;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A preset definition with its generic parameters erased, for use in code
|
|
40
|
+
* that handles presets generically (e.g. the registry).
|
|
41
|
+
*/
|
|
42
|
+
type AnyPresetDefinition = PresetDefinition<any, any, any>;
|
|
43
|
+
declare const ctaType: PresetDefinition<{}, "object", "preview">;
|
|
44
|
+
interface ImageTypeConfig {
|
|
45
|
+
altText?: boolean;
|
|
46
|
+
caption?: boolean;
|
|
47
|
+
hotspot?: boolean;
|
|
48
|
+
}
|
|
49
|
+
declare const imageType: PresetDefinition<ImageTypeConfig, "object", "preview">;
|
|
7
50
|
interface LinkTypeConfig {
|
|
8
|
-
internalTypes
|
|
51
|
+
internalTypes?: string[];
|
|
52
|
+
}
|
|
53
|
+
declare const linkType: PresetDefinition<LinkTypeConfig, "object", "preview">;
|
|
54
|
+
interface PageTypeConfig {
|
|
55
|
+
pageBuilderBlocks?: string[];
|
|
56
|
+
}
|
|
57
|
+
declare const pageType: PresetDefinition<PageTypeConfig, "document", undefined>;
|
|
58
|
+
interface RichTextObjectsConfig {
|
|
59
|
+
link?: boolean;
|
|
60
|
+
image?: boolean;
|
|
61
|
+
cta?: boolean;
|
|
62
|
+
}
|
|
63
|
+
interface RichTextTypeConfig {
|
|
64
|
+
/**
|
|
65
|
+
* Toggle the embedded objects (link annotations, image blocks, inline CTAs).
|
|
66
|
+
* Defaults to all enabled. Pass `false` to disable every object, or an
|
|
67
|
+
* object to toggle individual ones (e.g. `{link: false}`).
|
|
68
|
+
*
|
|
69
|
+
* Each object's options (link `internalTypes`, image `altText`, …) are
|
|
70
|
+
* configured on `createPresetsRegistry` and cascade into every rich text
|
|
71
|
+
* field. Use `map.of` for per-field structural changes.
|
|
72
|
+
*/
|
|
73
|
+
objects?: boolean | RichTextObjectsConfig;
|
|
74
|
+
}
|
|
75
|
+
declare const richTextType: PresetDefinition<RichTextTypeConfig, "array", "of">;
|
|
76
|
+
declare const seoType: PresetDefinition<{}, "object", undefined>;
|
|
77
|
+
interface PresetsRegistryConfig {
|
|
78
|
+
link?: LinkTypeConfig;
|
|
79
|
+
image?: ImageTypeConfig;
|
|
80
|
+
page?: PageTypeConfig;
|
|
81
|
+
}
|
|
82
|
+
type DefineFunction<Preset extends AnyPresetDefinition> = Preset extends PresetDefinition<infer Context, infer AliasedType, infer LockedProperties> ? (config?: UserConfig<Context, AliasedType, LockedProperties>) => SchemaTypeDefinition & FieldDefinition : never;
|
|
83
|
+
interface PresetsRegistry {
|
|
84
|
+
defineLink: DefineFunction<typeof linkType>;
|
|
85
|
+
defineCta: DefineFunction<typeof ctaType>;
|
|
86
|
+
defineSeo: DefineFunction<typeof seoType>;
|
|
87
|
+
defineImage: DefineFunction<typeof imageType>;
|
|
88
|
+
definePage: DefineFunction<typeof pageType>;
|
|
89
|
+
defineRichText: DefineFunction<typeof richTextType>;
|
|
9
90
|
}
|
|
10
|
-
declare function
|
|
11
|
-
export {
|
|
91
|
+
declare function createPresetsRegistry(config?: PresetsRegistryConfig): PresetsRegistry;
|
|
92
|
+
export { type PresetsRegistry, type PresetsRegistryConfig, createPresetsRegistry };
|
|
12
93
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/definePresetType.ts","../src/presets/cta-type/index.ts","../src/presets/image-type/index.ts","../src/presets/link-type/index.ts","../src/presets/page-type/index.ts","../src/presets/rich-text-type/index.ts","../src/presets/seo-type/index.ts","../src/registry.tsx"],"mappings":";KAEY,uBAAA,kBAAyC,iBAAA,IAAqB,OAAA,CACxE,gBAAA,CAAiB,QAAA,EAAU,QAAA;EAAa,OAAA,EAAS,aAAA;AAAA;AAAA,UCMlC,eAAA;EACf,SAAA,GAAY,UAAA,UAAoB,MAAA,GAAS,MAAA,sBAA4B,eAAA;AAAA;AAAA,KAGlE,oBAAA;AAAA,KAEA,kBAAA,+DACH,kBAAA,WACS,WAAA,IACP,IAAA,CAAK,UAAA,EAAY,kBAAA,IACjB,UAAA;AAAA,KAEQ,aAAA,8BAEU,iBAAA,qFAElB,OAAA,GACF,mBAAA,IACC,WAAA,kBACG,kBAAA,CACE,uBAAA,CAAwB,WAAA,GACxB,oBAAA,GAAuB,gBAAA;EAG3B,GAAA,GAAM,WAAA,kCAEc,uBAAA,CAAwB,WAAA,MACpC,KAAA,EAAO,uBAAA,CAAwB,WAAA,EAAa,GAAA,MACzC,uBAAA,CAAwB,WAAA,EAAa,GAAA;AAAA;;;;;;;KAWxC,UAAA,mCAEU,iBAAA,qFAElB,aAAA,CAAc,OAAA,EAAS,WAAA,EAAa,gBAAA;;;;AA3CxC;;;;;;;;UAwDiB,gBAAA,mCAEK,iBAAA;EAGpB,IAAA;EACA,UAAA;EACA,UAAA,GACE,MAAA,EAAQ,IAAA,CAAK,aAAA,CAAc,OAAA,EAAS,WAAA,EAAa,gBAAA;IAC/C,IAAA;EAAA,GAEF,QAAA,EAAU,eAAA,KACP,oBAAA;AAAA;;;;;KA0BK,mBAAA,GAAsB,gBAAA;AAAA,cCnGrB,OAAA,EAsCX,gBAAA;AAAA,UCtCe,eAAA;EACf,OAAA;EACA,OAAA;EACA,OAAA;AAAA;AAAA,cAGW,SAAA,EAAS,gBAAA,CAAA,eAAA;AAAA,UCNL,cAAA;EACf,aAAA;AAAA;AAAA,cAGW,QAAA,EAAQ,gBAAA,CAAA,cAAA;AAAA,UCJJ,cAAA;EACf,iBAAA;AAAA;AAAA,cAGW,QAAA,EAAQ,gBAAA,CAAA,cAAA;AAAA,UCJJ,qBAAA;EACf,IAAA;EACA,KAAA;EACA,GAAA;AAAA;AAAA,UAGe,kBAAA;ENPE;;;;;;;;;EMiBjB,OAAA,aAAoB,qBAAA;AAAA;AAAA,cAUT,YAAA,EAAY,gBAAA,CAAA,kBAAA;AAAA,cCzBZ,OAAA,EAyDX,gBAAA;AAAA,UCzCe,qBAAA;EACf,IAAA,GAAO,cAAA;EACP,KAAA,GAAQ,eAAA;EACR,IAAA,GAAO,cAAA;AAAA;AAAA,KAGJ,cAAA,gBAA8B,mBAAA,IACjC,MAAA,SAAe,gBAAA,8DAET,MAAA,GAAS,UAAA,CAAW,OAAA,EAAS,WAAA,EAAa,gBAAA,MACvC,oBAAA,GAAuB,eAAA;AAAA,UAGjB,eAAA;EACf,UAAA,EAAY,cAAA,QAAsB,QAAA;EAClC,SAAA,EAAW,cAAA,QAAsB,OAAA;EACjC,SAAA,EAAW,cAAA,QAAsB,OAAA;EACjC,WAAA,EAAa,cAAA,QAAsB,SAAA;EACnC,UAAA,EAAY,cAAA,QAAsB,QAAA;EAClC,cAAA,EAAgB,cAAA,QAAsB,YAAA;AAAA;AAAA,iBAGxB,qBAAA,CAAsB,MAAA,GAAQ,qBAAA,GAA6B,eAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,96 +1,448 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { uuid } from "@sanity/uuid";
|
|
3
|
+
import { c } from "react/compiler-runtime";
|
|
4
|
+
import { useTelemetry } from "@sanity/telemetry/react";
|
|
5
|
+
import { useEffect } from "react";
|
|
6
|
+
import { defineEvent } from "@sanity/telemetry";
|
|
7
|
+
import { defineType, defineField, ALL_FIELDS_GROUP, defineArrayMember } from "sanity";
|
|
8
|
+
import { getImageDimensions } from "@sanity/asset-utils";
|
|
9
|
+
const PresetsAdded = defineEvent({
|
|
10
|
+
name: "Presets Added",
|
|
11
|
+
version: 1,
|
|
12
|
+
description: "Workspace using presets was accessed"
|
|
13
|
+
}), registries = /* @__PURE__ */ new Map();
|
|
14
|
+
function registerRegistry(id) {
|
|
15
|
+
registries.set(id, {
|
|
16
|
+
id,
|
|
17
|
+
presets: /* @__PURE__ */ new Set(),
|
|
18
|
+
logged: !1
|
|
19
|
+
});
|
|
5
20
|
}
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
name: "@sanity/presets",
|
|
9
|
-
schema: {
|
|
10
|
-
types: collectTypes(types)
|
|
11
|
-
}
|
|
12
|
-
};
|
|
21
|
+
function recordPresetUsage(registryId, identifier) {
|
|
22
|
+
registries.get(registryId)?.presets.add(identifier);
|
|
13
23
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
function collectPresetsRegistryTelemetry(registryId, telemetry) {
|
|
25
|
+
const record = registries.get(registryId);
|
|
26
|
+
!record || record.logged || (record.logged = !0, record.presets.size > 0 && telemetry.log(PresetsAdded, {
|
|
27
|
+
presetNames: [...record.presets]
|
|
18
28
|
}));
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
}
|
|
30
|
+
const PresetsTelemetryCollector = (t0) => {
|
|
31
|
+
const $ = c(4), {
|
|
32
|
+
registryId,
|
|
33
|
+
userInput: UserInput,
|
|
34
|
+
...props
|
|
35
|
+
} = t0, telemetry = useTelemetry();
|
|
36
|
+
let t1, t2;
|
|
37
|
+
return $[0] !== registryId || $[1] !== telemetry ? (t1 = () => {
|
|
38
|
+
collectPresetsRegistryTelemetry(registryId, telemetry);
|
|
39
|
+
}, t2 = [registryId, telemetry], $[0] = registryId, $[1] = telemetry, $[2] = t1, $[3] = t2) : (t1 = $[2], t2 = $[3]), useEffect(t1, t2), UserInput ? /* @__PURE__ */ jsx(UserInput, { ...props }) : props.renderDefault(props);
|
|
40
|
+
};
|
|
41
|
+
const ctaType = {
|
|
42
|
+
name: "cta",
|
|
43
|
+
identifier: "core.cta",
|
|
44
|
+
schemaType: (config, registry) => {
|
|
45
|
+
const {
|
|
46
|
+
fields,
|
|
47
|
+
...objectConfig
|
|
48
|
+
} = config;
|
|
49
|
+
return defineType({
|
|
50
|
+
title: "Call to action",
|
|
51
|
+
...objectConfig,
|
|
52
|
+
type: "object",
|
|
53
|
+
fields: [registry.getPreset("link", {
|
|
54
|
+
name: "link",
|
|
55
|
+
title: "Link"
|
|
56
|
+
}), defineField({
|
|
57
|
+
name: "level",
|
|
58
|
+
title: "Level",
|
|
59
|
+
type: "number",
|
|
60
|
+
options: {
|
|
61
|
+
layout: "radio",
|
|
62
|
+
list: [1, 2, 3]
|
|
63
|
+
}
|
|
64
|
+
}), ...fields ?? []],
|
|
65
|
+
preview: {
|
|
66
|
+
select: {
|
|
67
|
+
linkType: "link.linkType",
|
|
68
|
+
url: "link.url",
|
|
69
|
+
referenceTitle: "link.reference.title",
|
|
70
|
+
referenceName: "link.reference.name"
|
|
71
|
+
},
|
|
72
|
+
prepare({
|
|
73
|
+
linkType: linkType2,
|
|
74
|
+
url,
|
|
75
|
+
referenceTitle,
|
|
76
|
+
referenceName
|
|
77
|
+
}) {
|
|
78
|
+
return {
|
|
79
|
+
title: linkType2 === "external" ? url || "No URL" : referenceTitle || referenceName || "No reference",
|
|
80
|
+
subtitle: "Button"
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}, imageType = {
|
|
87
|
+
name: "image",
|
|
88
|
+
identifier: "core.image",
|
|
89
|
+
schemaType: (config) => {
|
|
90
|
+
const {
|
|
91
|
+
altText = !0,
|
|
92
|
+
caption = !0,
|
|
93
|
+
hotspot = !0,
|
|
94
|
+
fields,
|
|
95
|
+
...objectConfig
|
|
96
|
+
} = config;
|
|
97
|
+
return defineType({
|
|
98
|
+
title: "Image",
|
|
99
|
+
...objectConfig,
|
|
100
|
+
type: "object",
|
|
101
|
+
fields: [defineField({
|
|
102
|
+
name: "image",
|
|
103
|
+
title: "Image",
|
|
104
|
+
type: "image",
|
|
105
|
+
options: {
|
|
106
|
+
hotspot
|
|
107
|
+
}
|
|
108
|
+
}), ...altText ? [defineField({
|
|
109
|
+
name: "altText",
|
|
110
|
+
title: "Alt text",
|
|
111
|
+
type: "string",
|
|
112
|
+
validation: (rule) => rule.warning("Alt text improves accessibility.")
|
|
113
|
+
})] : [], ...caption ? [defineField({
|
|
114
|
+
name: "caption",
|
|
115
|
+
title: "Caption",
|
|
116
|
+
type: "text"
|
|
117
|
+
})] : [], ...fields ?? []],
|
|
118
|
+
preview: {
|
|
119
|
+
select: {
|
|
120
|
+
title: altText ? "altText" : caption ? "caption" : "image.asset.originalFilename",
|
|
121
|
+
media: "image"
|
|
122
|
+
}
|
|
37
123
|
}
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}, linkType = {
|
|
127
|
+
name: "link",
|
|
128
|
+
identifier: "core.link",
|
|
129
|
+
schemaType: ({
|
|
130
|
+
internalTypes,
|
|
131
|
+
fields,
|
|
132
|
+
...objectConfig
|
|
133
|
+
}) => {
|
|
134
|
+
const referenceTargets = (internalTypes ?? []).map((type) => ({
|
|
135
|
+
type
|
|
136
|
+
}));
|
|
137
|
+
return defineType({
|
|
138
|
+
title: "Link",
|
|
139
|
+
...objectConfig,
|
|
140
|
+
type: "object",
|
|
141
|
+
fields: [defineField({
|
|
142
|
+
name: "linkType",
|
|
143
|
+
type: "string",
|
|
144
|
+
title: "Link Type",
|
|
145
|
+
initialValue: "internal",
|
|
146
|
+
options: {
|
|
147
|
+
layout: "radio",
|
|
148
|
+
list: [{
|
|
149
|
+
title: "Internal",
|
|
150
|
+
value: "internal"
|
|
151
|
+
}, {
|
|
152
|
+
title: "External",
|
|
153
|
+
value: "external"
|
|
154
|
+
}]
|
|
155
|
+
}
|
|
156
|
+
}), defineField({
|
|
157
|
+
name: "reference",
|
|
158
|
+
type: "reference",
|
|
159
|
+
title: "Internal Link",
|
|
160
|
+
to: referenceTargets,
|
|
161
|
+
hidden: ({
|
|
162
|
+
parent
|
|
163
|
+
}) => parent?.linkType === "external"
|
|
164
|
+
}), defineField({
|
|
165
|
+
name: "url",
|
|
166
|
+
type: "url",
|
|
167
|
+
title: "URL",
|
|
168
|
+
hidden: ({
|
|
169
|
+
parent
|
|
170
|
+
}) => parent?.linkType === "internal",
|
|
171
|
+
validation: (rule) => rule.uri({
|
|
172
|
+
scheme: ["http", "https", "mailto", "tel"]
|
|
173
|
+
})
|
|
174
|
+
}), defineField({
|
|
175
|
+
name: "openInNewTab",
|
|
176
|
+
type: "boolean",
|
|
177
|
+
title: "Open in New Tab",
|
|
178
|
+
initialValue: !1,
|
|
179
|
+
hidden: ({
|
|
180
|
+
parent
|
|
181
|
+
}) => parent?.linkType === "internal"
|
|
182
|
+
}), ...fields ?? []],
|
|
183
|
+
preview: {
|
|
184
|
+
select: {
|
|
185
|
+
linkType: "linkType",
|
|
186
|
+
url: "url",
|
|
187
|
+
referenceTitle: "reference.title",
|
|
188
|
+
referenceName: "reference.name"
|
|
189
|
+
},
|
|
190
|
+
prepare({
|
|
191
|
+
linkType: linkType2,
|
|
192
|
+
url,
|
|
193
|
+
referenceTitle,
|
|
194
|
+
referenceName
|
|
195
|
+
}) {
|
|
196
|
+
return {
|
|
197
|
+
title: linkType2 === "external" ? url || "No URL" : referenceTitle || referenceName || "No reference",
|
|
198
|
+
subtitle: linkType2 === "external" ? "External link" : "Internal link"
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}, pageType = {
|
|
205
|
+
name: "page",
|
|
206
|
+
identifier: "core.page",
|
|
207
|
+
schemaType: (config, registry) => {
|
|
208
|
+
const {
|
|
209
|
+
pageBuilderBlocks,
|
|
210
|
+
groups,
|
|
211
|
+
fields,
|
|
212
|
+
...documentConfig
|
|
213
|
+
} = config;
|
|
214
|
+
return defineType({
|
|
215
|
+
title: "Page",
|
|
216
|
+
...documentConfig,
|
|
217
|
+
type: "document",
|
|
218
|
+
groups: [{
|
|
219
|
+
...ALL_FIELDS_GROUP,
|
|
220
|
+
hidden: !0
|
|
221
|
+
}, {
|
|
222
|
+
name: "main",
|
|
223
|
+
title: "Main",
|
|
224
|
+
default: !0
|
|
225
|
+
}, {
|
|
226
|
+
name: "metadata",
|
|
227
|
+
title: "Metadata"
|
|
228
|
+
}, ...groups ?? []],
|
|
229
|
+
fields: [defineField({
|
|
230
|
+
name: "name",
|
|
231
|
+
title: "Name",
|
|
232
|
+
type: "string",
|
|
233
|
+
group: "main",
|
|
234
|
+
validation: (rule) => rule.required()
|
|
235
|
+
}), defineField({
|
|
236
|
+
name: "slug",
|
|
237
|
+
title: "Slug",
|
|
238
|
+
type: "slug",
|
|
239
|
+
group: "main",
|
|
240
|
+
options: {
|
|
241
|
+
source: "name"
|
|
242
|
+
}
|
|
243
|
+
}), defineField({
|
|
244
|
+
name: "content",
|
|
245
|
+
title: "Content",
|
|
246
|
+
group: "main",
|
|
247
|
+
type: "array",
|
|
248
|
+
of: (pageBuilderBlocks ?? []).map((typeName) => defineArrayMember({
|
|
249
|
+
type: typeName
|
|
250
|
+
}))
|
|
251
|
+
}), registry.getPreset("seo", {
|
|
252
|
+
name: "seo",
|
|
253
|
+
title: "SEO",
|
|
254
|
+
group: "metadata"
|
|
255
|
+
}), ...fields ?? []]
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
function resolveObjects(objects) {
|
|
260
|
+
if (objects === !1) return {
|
|
261
|
+
link: !1,
|
|
262
|
+
image: !1,
|
|
263
|
+
cta: !1
|
|
264
|
+
};
|
|
265
|
+
if (objects === !0 || objects === void 0) return {
|
|
266
|
+
link: !0,
|
|
267
|
+
image: !0,
|
|
268
|
+
cta: !0
|
|
269
|
+
};
|
|
270
|
+
const {
|
|
271
|
+
link = !0,
|
|
272
|
+
image = !0,
|
|
273
|
+
cta = !0
|
|
274
|
+
} = objects;
|
|
275
|
+
return {
|
|
276
|
+
link,
|
|
277
|
+
image,
|
|
278
|
+
cta
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
const richTextType = {
|
|
282
|
+
name: "richText",
|
|
283
|
+
identifier: "core.richText",
|
|
284
|
+
schemaType: (config, registry) => {
|
|
285
|
+
const {
|
|
286
|
+
objects,
|
|
287
|
+
...arrayConfig
|
|
288
|
+
} = config, {
|
|
289
|
+
link,
|
|
290
|
+
image,
|
|
291
|
+
cta
|
|
292
|
+
} = resolveObjects(objects), linkAnnotation = link ? registry.getPreset("link", {
|
|
293
|
+
name: "link",
|
|
294
|
+
title: "Link"
|
|
295
|
+
}) : void 0, ctaInline = cta ? registry.getPreset("cta", {
|
|
296
|
+
name: "cta",
|
|
297
|
+
title: "CTA"
|
|
298
|
+
}) : void 0, imageMember = image ? registry.getPreset("image", {
|
|
299
|
+
name: "richTextImage",
|
|
300
|
+
title: "Image"
|
|
301
|
+
}) : void 0, blockMember = defineArrayMember({
|
|
302
|
+
type: "block",
|
|
303
|
+
marks: {
|
|
304
|
+
annotations: linkAnnotation ? [linkAnnotation] : []
|
|
70
305
|
},
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
url,
|
|
74
|
-
referenceTitle
|
|
75
|
-
}) {
|
|
76
|
-
return {
|
|
77
|
-
title: linkType2 === "external" ? url || "No URL" : referenceTitle || "No reference",
|
|
78
|
-
subtitle: linkType2 === "external" ? "External link" : "Internal link"
|
|
79
|
-
};
|
|
306
|
+
...ctaInline && {
|
|
307
|
+
of: [ctaInline]
|
|
80
308
|
}
|
|
309
|
+
});
|
|
310
|
+
return defineType({
|
|
311
|
+
title: "Rich text",
|
|
312
|
+
...arrayConfig,
|
|
313
|
+
type: "array",
|
|
314
|
+
of: imageMember ? [blockMember, imageMember] : [blockMember]
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}, seoType = {
|
|
318
|
+
name: "seo",
|
|
319
|
+
identifier: "core.seo",
|
|
320
|
+
schemaType: (config) => {
|
|
321
|
+
const {
|
|
322
|
+
fields,
|
|
323
|
+
...objectConfig
|
|
324
|
+
} = config;
|
|
325
|
+
return defineType({
|
|
326
|
+
title: "Web page metadata (SEO)",
|
|
327
|
+
...objectConfig,
|
|
328
|
+
type: "object",
|
|
329
|
+
fields: [defineField({
|
|
330
|
+
name: "title",
|
|
331
|
+
title: "Title",
|
|
332
|
+
type: "string",
|
|
333
|
+
validation: (rule) => rule.max(70).info("Search engines may truncate this title.")
|
|
334
|
+
}), defineField({
|
|
335
|
+
name: "description",
|
|
336
|
+
title: "Description",
|
|
337
|
+
type: "text",
|
|
338
|
+
validation: (rule) => rule.max(150).info("Search engines may truncate this description.")
|
|
339
|
+
}), defineField({
|
|
340
|
+
name: "ogImage",
|
|
341
|
+
title: "Open Graph image",
|
|
342
|
+
type: "image",
|
|
343
|
+
description: "Landscape 1200x630 (1.91:1)",
|
|
344
|
+
options: {
|
|
345
|
+
hotspot: {
|
|
346
|
+
previews: [{
|
|
347
|
+
title: "Landscape (1.91:1)",
|
|
348
|
+
aspectRatio: 1.91 / 1
|
|
349
|
+
}]
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
validation: (Rule) => Rule.custom((value) => {
|
|
353
|
+
if (!value?.asset?._ref)
|
|
354
|
+
return !0;
|
|
355
|
+
const {
|
|
356
|
+
height,
|
|
357
|
+
width
|
|
358
|
+
} = getImageDimensions(value.asset?._ref);
|
|
359
|
+
return height !== 630 || width !== 1200 ? "Open Graph image must be 1200x630" : !0;
|
|
360
|
+
})
|
|
361
|
+
}), ...fields ?? []]
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}, systemPresets = [linkType, ctaType, seoType, imageType, pageType, richTextType];
|
|
365
|
+
function createPresetsRegistry(config = {}) {
|
|
366
|
+
const registryId = uuid();
|
|
367
|
+
registerRegistry(registryId);
|
|
368
|
+
const seed = {};
|
|
369
|
+
return systemPresets.reduce((registry, preset) => {
|
|
370
|
+
const key = getPresetKey(preset.name);
|
|
371
|
+
return registry[key] = createDefiner({
|
|
372
|
+
registryId,
|
|
373
|
+
preset,
|
|
374
|
+
config,
|
|
375
|
+
registry
|
|
376
|
+
}), registry;
|
|
377
|
+
}, seed);
|
|
378
|
+
}
|
|
379
|
+
function getPresetKey(name) {
|
|
380
|
+
return `define${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
381
|
+
}
|
|
382
|
+
function createRegistryContext({
|
|
383
|
+
registry
|
|
384
|
+
}) {
|
|
385
|
+
return {
|
|
386
|
+
getPreset: (name, presetConfig) => {
|
|
387
|
+
const key = getPresetKey(name), definer = registry[key];
|
|
388
|
+
if (!definer)
|
|
389
|
+
throw new Error(`Cannot resolve preset "${name}". No such preset in this registry.`);
|
|
390
|
+
return definer(presetConfig);
|
|
81
391
|
}
|
|
82
|
-
}
|
|
392
|
+
};
|
|
83
393
|
}
|
|
84
|
-
function
|
|
85
|
-
|
|
86
|
-
|
|
394
|
+
function createDefiner({
|
|
395
|
+
registryId,
|
|
396
|
+
preset,
|
|
397
|
+
config,
|
|
398
|
+
registry
|
|
399
|
+
}) {
|
|
400
|
+
return function(userConfig = {}) {
|
|
401
|
+
recordPresetUsage(registryId, preset.identifier ?? "unnamed");
|
|
402
|
+
const registryContext = createRegistryContext({
|
|
403
|
+
registry
|
|
404
|
+
}), registryDefaults = config[preset.name], mergedConfig = {
|
|
405
|
+
name: preset.name,
|
|
406
|
+
...typeof registryDefaults == "object" && registryDefaults !== null ? registryDefaults : {},
|
|
407
|
+
...userConfig
|
|
408
|
+
}, {
|
|
409
|
+
map,
|
|
410
|
+
...factoryConfig
|
|
411
|
+
} = mergedConfig, schemaType = preset.schemaType(
|
|
412
|
+
// oxlint-disable-next-line no-unsafe-type-assertion -- factoryConfig is the merged user config (minus `map`, with `name` injected); its shape matches the factory's expected parameter at runtime
|
|
413
|
+
factoryConfig,
|
|
414
|
+
registryContext
|
|
415
|
+
);
|
|
416
|
+
return applyMapHooks(addTelemetryComponent(schemaType, registryId), map);
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function applyMapHooks(schemaType, map) {
|
|
420
|
+
if (!map || typeof map != "object") return schemaType;
|
|
421
|
+
const mappedSchemaType = {};
|
|
422
|
+
for (const [configName, configValue] of Object.entries(map))
|
|
423
|
+
typeof configValue == "function" && (mappedSchemaType[configName] = configValue(
|
|
424
|
+
// oxlint-disable-next-line no-unsafe-type-assertion -- map hooks operate on arbitrary schema type properties
|
|
425
|
+
schemaType[configName]
|
|
426
|
+
));
|
|
427
|
+
return {
|
|
428
|
+
...schemaType,
|
|
429
|
+
...mappedSchemaType
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function addTelemetryComponent(schemaType, registryId) {
|
|
433
|
+
const existing = "components" in schemaType ? schemaType.components : void 0, existingInput = existing && "input" in existing && typeof existing.input == "function" ? (
|
|
434
|
+
// oxlint-disable-next-line no-unsafe-type-assertion -- presets only produce object/document schema types, whose input components are assignable to ComponentType<InputProps>
|
|
435
|
+
existing.input
|
|
436
|
+
) : void 0;
|
|
87
437
|
return {
|
|
88
|
-
|
|
438
|
+
...schemaType,
|
|
439
|
+
components: {
|
|
440
|
+
...existing,
|
|
441
|
+
input: (props) => /* @__PURE__ */ jsx(PresetsTelemetryCollector, { ...props, registryId, userInput: existingInput })
|
|
442
|
+
}
|
|
89
443
|
};
|
|
90
444
|
}
|
|
91
445
|
export {
|
|
92
|
-
|
|
93
|
-
linkType,
|
|
94
|
-
presets
|
|
446
|
+
createPresetsRegistry
|
|
95
447
|
};
|
|
96
448
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/composer.ts","../src/presets/link-type/constants.ts","../src/presets/link-type/schema.ts","../src/presets/link-type/index.ts"],"sourcesContent":["import {type PluginOptions, type SchemaTypeDefinition} from 'sanity'\n\nimport type {PresetResult} from './types'\n\nexport function collectTypes(presets: PresetResult[]): SchemaTypeDefinition[] {\n const seen = new Set<string>()\n\n return presets.flatMap((preset) =>\n preset.types.filter((typeDef) => {\n if (seen.has(typeDef.name)) {\n console.warn(\n `[@sanity/presets] Dropped duplicate type \"${typeDef.name}\". Keeping first definition.`,\n )\n return false\n }\n seen.add(typeDef.name)\n return true\n }),\n )\n}\n\nexport function presets(...types: PresetResult[]): PluginOptions {\n return {\n name: '@sanity/presets',\n schema: {types: collectTypes(types)},\n }\n}\n","export const LINK_TYPE_NAME = 'core.presets.link'\n","import {defineField, defineType, type SchemaTypeDefinition} from 'sanity'\n\nimport {LINK_TYPE_NAME} from './constants'\n\nexport function createLinkType(internalTypes: string[]): SchemaTypeDefinition {\n const referenceTargets = internalTypes.map((typeName) => ({type: typeName}))\n\n return defineType({\n name: LINK_TYPE_NAME,\n type: 'object',\n title: 'Link',\n fields: [\n defineField({\n name: 'linkType',\n type: 'string',\n title: 'Link Type',\n initialValue: 'internal',\n options: {\n layout: 'radio',\n list: [\n {title: 'Internal', value: 'internal'},\n {title: 'External', value: 'external'},\n ],\n },\n }),\n defineField({\n name: 'reference',\n type: 'reference',\n title: 'Internal Link',\n to: referenceTargets,\n hidden: ({parent}) => parent?.linkType === 'external',\n }),\n defineField({\n name: 'url',\n type: 'url',\n title: 'URL',\n hidden: ({parent}) => parent?.linkType === 'internal',\n validation: (rule) =>\n rule.uri({\n scheme: ['http', 'https', 'mailto', 'tel'],\n }),\n }),\n defineField({\n name: 'openInNewTab',\n type: 'boolean',\n title: 'Open in New Tab',\n initialValue: false,\n hidden: ({parent}) => parent?.linkType === 'internal',\n }),\n ],\n preview: {\n select: {\n linkType: 'linkType',\n url: 'url',\n referenceTitle: 'reference.title',\n },\n prepare({linkType, url, referenceTitle}) {\n const title = linkType === 'external' ? url || 'No URL' : referenceTitle || 'No reference'\n\n return {\n title,\n subtitle: linkType === 'external' ? 'External link' : 'Internal link',\n }\n },\n },\n })\n}\n","import type {PresetResult} from '../../types'\nimport {createLinkType} from './schema'\n\nexport {LINK_TYPE_NAME} from './constants'\n\nexport interface LinkTypeConfig {\n internalTypes: string[]\n}\n\nexport function linkType(config: LinkTypeConfig): PresetResult {\n if (config.internalTypes.length === 0) {\n throw new Error('[@sanity/presets] linkType requires at least one internalTypes entry.')\n }\n\n return {\n types: [createLinkType(config.internalTypes)],\n }\n}\n"],"names":["collectTypes","presets","seen","Set","flatMap","preset","types","filter","typeDef","has","name","console","warn","add","schema","LINK_TYPE_NAME","createLinkType","internalTypes","referenceTargets","map","typeName","type","defineType","title","fields","defineField","initialValue","options","layout","list","value","to","hidden","parent","linkType","validation","rule","uri","scheme","preview","select","url","referenceTitle","prepare","subtitle","config","length","Error"],"mappings":";AAIO,SAASA,aAAaC,UAAiD;AAC5E,QAAMC,2BAAWC,IAAAA;AAEjB,SAAOF,SAAQG,QAASC,CAAAA,WACtBA,OAAOC,MAAMC,OAAQC,CAAAA,YACfN,KAAKO,IAAID,QAAQE,IAAI,KACvBC,QAAQC,KACN,6CAA6CJ,QAAQE,IAAI,8BAC3D,GACO,OAETR,KAAKW,IAAIL,QAAQE,IAAI,GACd,GACR,CACH;AACF;AAEO,SAAST,WAAWK,OAAsC;AAC/D,SAAO;AAAA,IACLI,MAAM;AAAA,IACNI,QAAQ;AAAA,MAACR,OAAON,aAAaM,KAAK;AAAA,IAAA;AAAA,EAAC;AAEvC;AC1BO,MAAMS,iBAAiB;ACIvB,SAASC,eAAeC,eAA+C;AAC5E,QAAMC,mBAAmBD,cAAcE,IAAKC,CAAAA,cAAc;AAAA,IAACC,MAAMD;AAAAA,EAAAA,EAAU;AAE3E,SAAOE,WAAW;AAAA,IAChBZ,MAAMK;AAAAA,IACNM,MAAM;AAAA,IACNE,OAAO;AAAA,IACPC,QAAQ,CACNC,YAAY;AAAA,MACVf,MAAM;AAAA,MACNW,MAAM;AAAA,MACNE,OAAO;AAAA,MACPG,cAAc;AAAA,MACdC,SAAS;AAAA,QACPC,QAAQ;AAAA,QACRC,MAAM,CACJ;AAAA,UAACN,OAAO;AAAA,UAAYO,OAAO;AAAA,QAAA,GAC3B;AAAA,UAACP,OAAO;AAAA,UAAYO,OAAO;AAAA,QAAA,CAAW;AAAA,MAAA;AAAA,IAE1C,CACD,GACDL,YAAY;AAAA,MACVf,MAAM;AAAA,MACNW,MAAM;AAAA,MACNE,OAAO;AAAA,MACPQ,IAAIb;AAAAA,MACJc,QAAQA,CAAC;AAAA,QAACC;AAAAA,MAAAA,MAAYA,QAAQC,aAAa;AAAA,IAAA,CAC5C,GACDT,YAAY;AAAA,MACVf,MAAM;AAAA,MACNW,MAAM;AAAA,MACNE,OAAO;AAAA,MACPS,QAAQA,CAAC;AAAA,QAACC;AAAAA,MAAAA,MAAYA,QAAQC,aAAa;AAAA,MAC3CC,YAAaC,CAAAA,SACXA,KAAKC,IAAI;AAAA,QACPC,QAAQ,CAAC,QAAQ,SAAS,UAAU,KAAK;AAAA,MAAA,CAC1C;AAAA,IAAA,CACJ,GACDb,YAAY;AAAA,MACVf,MAAM;AAAA,MACNW,MAAM;AAAA,MACNE,OAAO;AAAA,MACPG,cAAc;AAAA,MACdM,QAAQA,CAAC;AAAA,QAACC;AAAAA,MAAAA,MAAYA,QAAQC,aAAa;AAAA,IAAA,CAC5C,CAAC;AAAA,IAEJK,SAAS;AAAA,MACPC,QAAQ;AAAA,QACNN,UAAU;AAAA,QACVO,KAAK;AAAA,QACLC,gBAAgB;AAAA,MAAA;AAAA,MAElBC,QAAQ;AAAA,QAACT,UAAAA;AAAAA,QAAUO;AAAAA,QAAKC;AAAAA,MAAAA,GAAiB;AAGvC,eAAO;AAAA,UACLnB,OAHYW,cAAa,aAAaO,OAAO,WAAWC,kBAAkB;AAAA,UAI1EE,UAAUV,cAAa,aAAa,kBAAkB;AAAA,QAAA;AAAA,MAE1D;AAAA,IAAA;AAAA,EACF,CACD;AACH;ACzDO,SAASA,SAASW,QAAsC;AAC7D,MAAIA,OAAO5B,cAAc6B,WAAW;AAClC,UAAM,IAAIC,MAAM,uEAAuE;AAGzF,SAAO;AAAA,IACLzC,OAAO,CAACU,eAAe6B,OAAO5B,aAAa,CAAC;AAAA,EAAA;AAEhD;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/__telemetry__/presets.telemetry.ts","../src/telemetry.ts","../src/components/PresetsTelemetryCollector.tsx","../src/presets/cta-type/index.ts","../src/presets/image-type/index.ts","../src/presets/link-type/index.ts","../src/presets/page-type/index.ts","../src/presets/rich-text-type/index.ts","../src/presets/seo-type/index.ts","../src/registry.tsx"],"sourcesContent":["import {defineEvent} from '@sanity/telemetry'\n\ninterface PresetsAddedInfo {\n presetNames: string[]\n}\n\nexport const PresetsAdded = defineEvent<PresetsAddedInfo>({\n name: 'Presets Added',\n version: 1,\n description: 'Workspace using presets was accessed',\n})\n","import {PresetsAdded} from './__telemetry__/presets.telemetry'\n\n/**\n * Minimal interface for the subset of TelemetryLogger we need.\n * Avoids forcing callers to satisfy the full generic TelemetryLogger type.\n */\nexport interface TelemetryLog {\n log(event: unknown, data: unknown): void\n}\n\ninterface RegistryRecord {\n id: string\n presets: Set<string>\n logged: boolean\n}\n\nconst registries = new Map<string, RegistryRecord>()\n\nexport function registerRegistry(id: string): void {\n registries.set(id, {id, presets: new Set(), logged: false})\n}\n\nexport function recordPresetUsage(registryId: string, identifier: string): void {\n registries.get(registryId)?.presets.add(identifier)\n}\n\nexport function collectPresetsRegistryTelemetry(registryId: string, telemetry: TelemetryLog): void {\n const record = registries.get(registryId)\n if (!record || record.logged) return\n record.logged = true\n if (record.presets.size > 0) {\n telemetry.log(PresetsAdded, {presetNames: [...record.presets]})\n }\n}\n\n/** @internal */\nexport function resetRegistries(): void {\n registries.clear()\n}\n","import {useTelemetry} from '@sanity/telemetry/react'\nimport {useEffect, type ComponentType} from 'react'\nimport type {InputProps} from 'sanity'\n\nimport {collectPresetsRegistryTelemetry} from '../telemetry'\n\ntype Props = InputProps & {\n registryId: string\n userInput?: ComponentType<InputProps>\n}\n\n/**\n * A transparent input component wrapper that triggers telemetry collection\n * for the presets registry. Renders the user-provided input component if\n * supplied, otherwise the default input component unchanged.\n *\n * Attached to every schema type produced by a define<Type> function via\n * components.input. The first instance to render for a given registry id\n * submits the PresetsAdded telemetry event; subsequent renders are no-ops.\n */\nexport const PresetsTelemetryCollector: ComponentType<Props> = ({\n registryId,\n userInput: UserInput,\n ...props\n}) => {\n const telemetry = useTelemetry()\n\n useEffect(() => {\n collectPresetsRegistryTelemetry(registryId, telemetry)\n }, [registryId, telemetry])\n\n if (UserInput) {\n return <UserInput {...props} />\n }\n\n return props.renderDefault(props)\n}\n","import {defineField, defineType} from 'sanity'\n\nimport {definePresetType} from '../../definePresetType'\n\nexport const ctaType = definePresetType<{}, 'object', 'preview'>({\n name: 'cta',\n identifier: 'core.cta',\n schemaType: (config, registry) => {\n const {fields, ...objectConfig} = config\n\n return defineType({\n title: 'Call to action',\n ...objectConfig,\n type: 'object',\n fields: [\n registry.getPreset('link', {name: 'link', title: 'Link'}),\n defineField({\n name: 'level',\n title: 'Level',\n type: 'number',\n options: {\n layout: 'radio',\n list: [1, 2, 3],\n },\n }),\n ...(fields ?? []),\n ],\n preview: {\n select: {\n linkType: 'link.linkType',\n url: 'link.url',\n referenceTitle: 'link.reference.title',\n referenceName: 'link.reference.name',\n },\n prepare({linkType, url, referenceTitle, referenceName}) {\n const referenceLabel = referenceTitle || referenceName || 'No reference'\n const title = linkType === 'external' ? url || 'No URL' : referenceLabel\n return {title, subtitle: 'Button'}\n },\n },\n })\n },\n})\n","import {defineField, defineType} from 'sanity'\n\nimport {definePresetType} from '../../definePresetType'\n\nexport interface ImageTypeConfig {\n altText?: boolean\n caption?: boolean\n hotspot?: boolean\n}\n\nexport const imageType = definePresetType<ImageTypeConfig, 'object', 'preview'>({\n name: 'image',\n identifier: 'core.image',\n schemaType: (config) => {\n const {altText = true, caption = true, hotspot = true, fields, ...objectConfig} = config\n\n return defineType({\n title: 'Image',\n ...objectConfig,\n type: 'object',\n fields: [\n defineField({\n name: 'image',\n title: 'Image',\n type: 'image',\n options: {\n hotspot,\n },\n }),\n ...(altText\n ? [\n defineField({\n name: 'altText',\n title: 'Alt text',\n type: 'string',\n validation: (rule) => rule.warning('Alt text improves accessibility.'),\n }),\n ]\n : []),\n ...(caption\n ? [\n defineField({\n name: 'caption',\n title: 'Caption',\n type: 'text',\n }),\n ]\n : []),\n ...(fields ?? []),\n ],\n preview: {\n select: {\n title: altText ? 'altText' : caption ? 'caption' : 'image.asset.originalFilename',\n media: 'image',\n },\n },\n })\n },\n})\n","import {defineField, defineType} from 'sanity'\n\nimport {definePresetType} from '../../definePresetType'\n\nexport interface LinkTypeConfig {\n internalTypes?: string[]\n}\n\nexport const linkType = definePresetType<LinkTypeConfig, 'object', 'preview'>({\n name: 'link',\n identifier: 'core.link',\n schemaType: ({internalTypes, fields, ...objectConfig}) => {\n const resolvedInternalTypes = internalTypes ?? []\n const referenceTargets = resolvedInternalTypes.map((type) => ({type}))\n\n return defineType({\n title: 'Link',\n ...objectConfig,\n type: 'object',\n fields: [\n defineField({\n name: 'linkType',\n type: 'string',\n title: 'Link Type',\n initialValue: 'internal',\n options: {\n layout: 'radio',\n list: [\n {title: 'Internal', value: 'internal'},\n {title: 'External', value: 'external'},\n ],\n },\n }),\n defineField({\n name: 'reference',\n type: 'reference',\n title: 'Internal Link',\n to: referenceTargets,\n hidden: ({parent}) => parent?.linkType === 'external',\n }),\n defineField({\n name: 'url',\n type: 'url',\n title: 'URL',\n hidden: ({parent}) => parent?.linkType === 'internal',\n validation: (rule) =>\n rule.uri({\n scheme: ['http', 'https', 'mailto', 'tel'],\n }),\n }),\n defineField({\n name: 'openInNewTab',\n type: 'boolean',\n title: 'Open in New Tab',\n initialValue: false,\n hidden: ({parent}) => parent?.linkType === 'internal',\n }),\n ...(fields ?? []),\n ],\n preview: {\n select: {\n linkType: 'linkType',\n url: 'url',\n referenceTitle: 'reference.title',\n referenceName: 'reference.name',\n },\n prepare({linkType, url, referenceTitle, referenceName}) {\n const referenceLabel = referenceTitle || referenceName || 'No reference'\n const title = linkType === 'external' ? url || 'No URL' : referenceLabel\n\n return {\n title,\n subtitle: linkType === 'external' ? 'External link' : 'Internal link',\n }\n },\n },\n })\n },\n})\n","import {ALL_FIELDS_GROUP, defineArrayMember, defineField, defineType} from 'sanity'\n\nimport {definePresetType} from '../../definePresetType'\n\nexport interface PageTypeConfig {\n pageBuilderBlocks?: string[]\n}\n\nexport const pageType = definePresetType<PageTypeConfig, 'document'>({\n name: 'page',\n identifier: 'core.page',\n schemaType: (config, registry) => {\n const {pageBuilderBlocks, groups, fields, ...documentConfig} = config\n\n return defineType({\n title: 'Page',\n ...documentConfig,\n type: 'document',\n groups: [\n {\n ...ALL_FIELDS_GROUP,\n hidden: true,\n },\n {\n name: 'main',\n title: 'Main',\n default: true,\n },\n {\n name: 'metadata',\n title: 'Metadata',\n },\n ...(groups ?? []),\n ],\n fields: [\n defineField({\n name: 'name',\n title: 'Name',\n type: 'string',\n group: 'main',\n validation: (rule) => rule.required(),\n }),\n defineField({\n name: 'slug',\n title: 'Slug',\n type: 'slug',\n group: 'main',\n options: {\n source: 'name',\n },\n }),\n defineField({\n name: 'content',\n title: 'Content',\n group: 'main',\n type: 'array',\n of: (pageBuilderBlocks ?? []).map((typeName) =>\n defineArrayMember({\n type: typeName,\n }),\n ),\n }),\n registry.getPreset('seo', {\n name: 'seo',\n title: 'SEO',\n group: 'metadata',\n }),\n ...(fields ?? []),\n ],\n })\n },\n})\n","import {defineArrayMember, defineType} from 'sanity'\n\nimport {definePresetType} from '../../definePresetType'\n\nexport interface RichTextObjectsConfig {\n link?: boolean\n image?: boolean\n cta?: boolean\n}\n\nexport interface RichTextTypeConfig {\n /**\n * Toggle the embedded objects (link annotations, image blocks, inline CTAs).\n * Defaults to all enabled. Pass `false` to disable every object, or an\n * object to toggle individual ones (e.g. `{link: false}`).\n *\n * Each object's options (link `internalTypes`, image `altText`, …) are\n * configured on `createPresetsRegistry` and cascade into every rich text\n * field. Use `map.of` for per-field structural changes.\n */\n objects?: boolean | RichTextObjectsConfig\n}\n\nfunction resolveObjects(objects: RichTextTypeConfig['objects']): Required<RichTextObjectsConfig> {\n if (objects === false) return {link: false, image: false, cta: false}\n if (objects === true || objects === undefined) return {link: true, image: true, cta: true}\n const {link = true, image = true, cta = true} = objects\n return {link, image, cta}\n}\n\nexport const richTextType = definePresetType<RichTextTypeConfig, 'array', 'of'>({\n name: 'richText',\n identifier: 'core.richText',\n schemaType: (config, registry) => {\n const {objects, ...arrayConfig} = config\n const {link, image, cta} = resolveObjects(objects)\n\n // The annotation name must be 'link' — Portable Text Editor's built-in link UI keys off this name.\n const linkAnnotation = link\n ? registry.getPreset('link', {name: 'link', title: 'Link'})\n : undefined\n const ctaInline = cta ? registry.getPreset('cta', {name: 'cta', title: 'CTA'}) : undefined\n const imageMember = image\n ? registry.getPreset('image', {name: 'richTextImage', title: 'Image'})\n : undefined\n\n const blockMember = defineArrayMember({\n type: 'block',\n marks: {annotations: linkAnnotation ? [linkAnnotation] : []},\n ...(ctaInline && {of: [ctaInline]}),\n })\n\n return defineType({\n title: 'Rich text',\n ...arrayConfig,\n type: 'array',\n of: imageMember ? [blockMember, imageMember] : [blockMember],\n })\n },\n})\n","import {getImageDimensions} from '@sanity/asset-utils'\nimport {defineField, defineType} from 'sanity'\n\nimport {definePresetType} from '../../definePresetType'\n\nexport const seoType = definePresetType<{}, 'object'>({\n name: 'seo',\n identifier: 'core.seo',\n schemaType: (config) => {\n const {fields, ...objectConfig} = config\n\n return defineType({\n title: 'Web page metadata (SEO)',\n ...objectConfig,\n type: 'object',\n fields: [\n defineField({\n name: 'title',\n title: 'Title',\n type: 'string',\n validation: (rule) => rule.max(70).info('Search engines may truncate this title.'),\n }),\n defineField({\n name: 'description',\n title: 'Description',\n type: 'text',\n validation: (rule) => rule.max(150).info('Search engines may truncate this description.'),\n }),\n defineField({\n name: 'ogImage',\n title: 'Open Graph image',\n type: 'image',\n description: 'Landscape 1200x630 (1.91:1)',\n options: {\n hotspot: {\n previews: [\n {\n title: 'Landscape (1.91:1)',\n aspectRatio: 1.91 / 1,\n },\n ],\n },\n },\n validation: (Rule) =>\n Rule.custom((value) => {\n if (!value?.asset?._ref) {\n return true\n }\n\n const {height, width} = getImageDimensions(value.asset?._ref)\n\n if (height !== 630 || width !== 1200) {\n return 'Open Graph image must be 1200x630'\n }\n\n return true\n }),\n }),\n ...(fields ?? []),\n ],\n })\n },\n})\n","import {uuid} from '@sanity/uuid'\nimport {type ComponentType} from 'react'\nimport type {FieldDefinition, InputProps, SchemaTypeDefinition} from 'sanity'\n\nimport {PresetsTelemetryCollector} from './components/PresetsTelemetryCollector'\nimport type {\n AnyPresetDefinition,\n PresetDefinition,\n RegistryContext,\n UserConfig,\n} from './definePresetType'\nimport {ctaType} from './presets/cta-type'\nimport {imageType, type ImageTypeConfig} from './presets/image-type'\nimport {linkType, type LinkTypeConfig} from './presets/link-type'\nimport {pageType, type PageTypeConfig} from './presets/page-type'\nimport {richTextType} from './presets/rich-text-type'\nimport {seoType} from './presets/seo-type'\nimport {recordPresetUsage, registerRegistry} from './telemetry'\n\nconst systemPresets = [linkType, ctaType, seoType, imageType, pageType, richTextType] as const\n\nexport interface PresetsRegistryConfig {\n link?: LinkTypeConfig\n image?: ImageTypeConfig\n page?: PageTypeConfig\n}\n\ntype DefineFunction<Preset extends AnyPresetDefinition> =\n Preset extends PresetDefinition<infer Context, infer AliasedType, infer LockedProperties>\n ? (\n config?: UserConfig<Context, AliasedType, LockedProperties>,\n ) => SchemaTypeDefinition & FieldDefinition\n : never\n\nexport interface PresetsRegistry {\n defineLink: DefineFunction<typeof linkType>\n defineCta: DefineFunction<typeof ctaType>\n defineSeo: DefineFunction<typeof seoType>\n defineImage: DefineFunction<typeof imageType>\n definePage: DefineFunction<typeof pageType>\n defineRichText: DefineFunction<typeof richTextType>\n}\n\nexport function createPresetsRegistry(config: PresetsRegistryConfig = {}): PresetsRegistry {\n const registryId = uuid()\n registerRegistry(registryId)\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- seeding reduce with an empty object that is populated by each iteration\n const seed = {} as DefinerRecord & PresetsRegistry\n\n return systemPresets.reduce((registry, preset) => {\n const key = getPresetKey(preset.name)\n registry[key] = createDefiner({registryId, preset, config, registry})\n return registry\n }, seed)\n}\n\nexport function getPresetKey(name: string): string {\n return `define${name.charAt(0).toUpperCase()}${name.slice(1)}`\n}\n\ntype Definer = (config?: Record<string, unknown>) => SchemaTypeDefinition & FieldDefinition\ntype DefinerRecord = Record<string, Definer>\n\nfunction createRegistryContext({registry}: {registry: DefinerRecord}): RegistryContext {\n return {\n getPreset: (name, presetConfig) => {\n const key = getPresetKey(name)\n const definer = registry[key]\n if (!definer) {\n throw new Error(`Cannot resolve preset \"${name}\". No such preset in this registry.`)\n }\n return definer(presetConfig)\n },\n }\n}\n\ninterface CreateDefinerOptions {\n registryId: string\n preset: AnyPresetDefinition\n config: PresetsRegistryConfig\n registry: DefinerRecord\n}\n\nfunction createDefiner({registryId, preset, config, registry}: CreateDefinerOptions): Definer {\n return function define(userConfig = {}) {\n recordPresetUsage(registryId, preset.identifier ?? 'unnamed')\n\n const registryContext = createRegistryContext({registry})\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- PresetsRegistryConfig is keyed by preset name; dynamic lookup is safe\n const registryDefaults = (config as Record<string, unknown>)[preset.name]\n const mergedConfig: Record<string, unknown> = {\n name: preset.name,\n ...(typeof registryDefaults === 'object' && registryDefaults !== null\n ? registryDefaults\n : {}),\n ...userConfig,\n }\n\n const {map, ...factoryConfig} = mergedConfig\n\n const schemaType = preset.schemaType(\n // oxlint-disable-next-line no-unsafe-type-assertion -- factoryConfig is the merged user config (minus `map`, with `name` injected); its shape matches the factory's expected parameter at runtime\n factoryConfig as unknown as Parameters<AnyPresetDefinition['schemaType']>[0],\n registryContext,\n )\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- runtime value is a valid field definition\n return applyMapHooks(\n addTelemetryComponent(schemaType, registryId),\n map,\n ) as SchemaTypeDefinition & FieldDefinition\n }\n}\n\nfunction applyMapHooks(schemaType: SchemaTypeDefinition, map: unknown): SchemaTypeDefinition {\n if (!map || typeof map !== 'object') return schemaType\n\n const mappedSchemaType: Record<string, unknown> = {}\n\n for (const [configName, configValue] of Object.entries(map)) {\n if (typeof configValue !== 'function') {\n continue\n }\n\n mappedSchemaType[configName] = configValue(\n // oxlint-disable-next-line no-unsafe-type-assertion -- map hooks operate on arbitrary schema type properties\n schemaType[configName as keyof typeof schemaType],\n )\n }\n\n return {...schemaType, ...mappedSchemaType}\n}\n\nfunction addTelemetryComponent(\n schemaType: SchemaTypeDefinition,\n registryId: string,\n): SchemaTypeDefinition {\n const existing = 'components' in schemaType ? schemaType.components : undefined\n const existingInput =\n existing && 'input' in existing && typeof existing.input === 'function'\n ? // oxlint-disable-next-line no-unsafe-type-assertion -- presets only produce object/document schema types, whose input components are assignable to ComponentType<InputProps>\n (existing.input as ComponentType<InputProps>)\n : undefined\n // oxlint-disable-next-line no-unsafe-type-assertion -- spreading a discriminated union loses the discriminant; the runtime shape is still a valid SchemaTypeDefinition\n return {\n ...schemaType,\n components: {\n ...existing,\n input: (props: InputProps) => (\n <PresetsTelemetryCollector {...props} registryId={registryId} userInput={existingInput} />\n ),\n },\n } as SchemaTypeDefinition\n}\n\n// Re-export for consumers that previously used these types.\nexport type {PresetDefinition, AnyPresetDefinition}\n"],"names":["PresetsAdded","defineEvent","name","version","description","registries","Map","registerRegistry","id","set","presets","Set","logged","recordPresetUsage","registryId","identifier","get","add","collectPresetsRegistryTelemetry","telemetry","record","size","log","presetNames","PresetsTelemetryCollector","t0","$","_c","userInput","UserInput","props","useTelemetry","t1","t2","useEffect","renderDefault","ctaType","schemaType","config","registry","fields","objectConfig","defineType","title","type","getPreset","defineField","options","layout","list","preview","select","linkType","url","referenceTitle","referenceName","prepare","subtitle","imageType","altText","caption","hotspot","validation","rule","warning","media","internalTypes","referenceTargets","map","initialValue","value","to","hidden","parent","uri","scheme","pageType","pageBuilderBlocks","groups","documentConfig","ALL_FIELDS_GROUP","default","group","required","source","of","typeName","defineArrayMember","resolveObjects","objects","link","image","cta","undefined","richTextType","arrayConfig","linkAnnotation","ctaInline","imageMember","blockMember","marks","annotations","seoType","max","info","previews","aspectRatio","Rule","custom","asset","_ref","height","width","getImageDimensions","systemPresets","createPresetsRegistry","uuid","seed","reduce","preset","key","getPresetKey","createDefiner","charAt","toUpperCase","slice","createRegistryContext","presetConfig","definer","Error","userConfig","registryContext","registryDefaults","mergedConfig","factoryConfig","applyMapHooks","addTelemetryComponent","mappedSchemaType","configName","configValue","Object","entries","existing","components","existingInput","input"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/presets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Production ready preset patterns for Sanity Studio",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -26,13 +26,29 @@
|
|
|
26
26
|
".": "./dist/index.js",
|
|
27
27
|
"./package.json": "./package.json"
|
|
28
28
|
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@sanity/asset-utils": "^2.3.0",
|
|
31
|
+
"@sanity/telemetry": "^1.1.0",
|
|
32
|
+
"@sanity/uuid": "^3.0.2"
|
|
33
|
+
},
|
|
29
34
|
"devDependencies": {
|
|
30
|
-
"@sanity/pkg-utils": "^10.4.
|
|
31
|
-
"
|
|
35
|
+
"@sanity/pkg-utils": "^10.4.17",
|
|
36
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
37
|
+
"@testing-library/react": "^16.3.2",
|
|
38
|
+
"@types/node": "^24.12.2",
|
|
39
|
+
"@types/react": "^19.2.14",
|
|
40
|
+
"@types/react-dom": "^19.2.3",
|
|
41
|
+
"jsdom": "^29.0.1",
|
|
42
|
+
"react": "^19.2.5",
|
|
43
|
+
"react-dom": "^19.2.5",
|
|
44
|
+
"sanity": "^5.21.0",
|
|
45
|
+
"styled-components": "^6.4.1",
|
|
32
46
|
"@repo/package.config": "0.0.0",
|
|
33
47
|
"@repo/tsconfig": "0.0.0"
|
|
34
48
|
},
|
|
35
49
|
"peerDependencies": {
|
|
50
|
+
"react": "^19.2",
|
|
51
|
+
"react-dom": "^19.2",
|
|
36
52
|
"sanity": "^5"
|
|
37
53
|
},
|
|
38
54
|
"engines": {
|