@bison-lab/payload-blocks 2.0.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 +163 -0
- package/dist/cx-BKHSv3xT.mjs +17 -0
- package/dist/cx-BKHSv3xT.mjs.map +1 -0
- package/dist/index.d.mts +344 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +677 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react.d.mts +53 -0
- package/dist/react.d.mts.map +1 -0
- package/dist/react.mjs +370 -0
- package/dist/react.mjs.map +1 -0
- package/dist/rich-text.d.mts +24 -0
- package/dist/rich-text.d.mts.map +1 -0
- package/dist/rich-text.mjs +31 -0
- package/dist/rich-text.mjs.map +1 -0
- package/dist/types-BvRvDCDT.d.mts +307 -0
- package/dist/types-BvRvDCDT.d.mts.map +1 -0
- package/package.json +81 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
//#region src/fields/image.ts
|
|
2
|
+
/**
|
|
3
|
+
* A single image from the site's upload collection, for any block with a
|
|
4
|
+
* picture in it.
|
|
5
|
+
*
|
|
6
|
+
* Optional unless the block says otherwise: `imageField({ name: 'portrait',
|
|
7
|
+
* required: true })`. `admin` is replaced, not merged, so a block that passes
|
|
8
|
+
* its own description writes the whole thing.
|
|
9
|
+
*/
|
|
10
|
+
function imageField(overrides = {}) {
|
|
11
|
+
return {
|
|
12
|
+
name: "image",
|
|
13
|
+
type: "upload",
|
|
14
|
+
relationTo: "media",
|
|
15
|
+
...overrides.required ? {} : { admin: { description: "Optional." } },
|
|
16
|
+
...overrides
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/fields/link.ts
|
|
21
|
+
/**
|
|
22
|
+
* The three fields a call to action is made of, unwrapped.
|
|
23
|
+
*
|
|
24
|
+
* `href` is plain text rather than a relationship to a `pages` row: a block in
|
|
25
|
+
* this package has to work on a site whose page collection is named something
|
|
26
|
+
* else, or which links out more often than in. Resolving an internal reference
|
|
27
|
+
* is the site's job.
|
|
28
|
+
*
|
|
29
|
+
* `newTab` drives `target="_blank"` *and* the matching `rel`, which is why no
|
|
30
|
+
* renderer takes one without the other.
|
|
31
|
+
*/
|
|
32
|
+
function linkFields({ required = false, labelFieldLabel = "Label" } = {}) {
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
name: "label",
|
|
36
|
+
type: "text",
|
|
37
|
+
label: labelFieldLabel,
|
|
38
|
+
required
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "href",
|
|
42
|
+
type: "text",
|
|
43
|
+
required,
|
|
44
|
+
admin: { description: "A site path (\"/contact\") or a full URL (\"https://example.com\")." }
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "newTab",
|
|
48
|
+
type: "checkbox",
|
|
49
|
+
label: "Open in a new tab",
|
|
50
|
+
defaultValue: false
|
|
51
|
+
}
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
/** `linkFields()` as one named group, for a block with a single CTA. */
|
|
55
|
+
function linkField({ name = "link", label, admin, ...rest } = {}) {
|
|
56
|
+
return {
|
|
57
|
+
name,
|
|
58
|
+
type: "group",
|
|
59
|
+
fields: linkFields(rest),
|
|
60
|
+
...label === void 0 ? {} : { label },
|
|
61
|
+
...admin === void 0 ? {} : { admin }
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/blocks/hero/config.ts
|
|
66
|
+
/**
|
|
67
|
+
* The band a page opens with.
|
|
68
|
+
*
|
|
69
|
+
* Unlike every other block here this one has no `@bison-lab/ui` counterpart:
|
|
70
|
+
* a hero is where a site's brand is loudest, and the shipped renderer is
|
|
71
|
+
* deliberately plain markup so a site can swap in its own by overriding this
|
|
72
|
+
* one registry entry. The *fields* are the shared part — that is what makes a
|
|
73
|
+
* page portable between sites.
|
|
74
|
+
*/
|
|
75
|
+
const HeroBlock = {
|
|
76
|
+
slug: "hero",
|
|
77
|
+
interfaceName: "HeroBlock",
|
|
78
|
+
labels: {
|
|
79
|
+
singular: "Hero",
|
|
80
|
+
plural: "Heroes"
|
|
81
|
+
},
|
|
82
|
+
fields: [
|
|
83
|
+
{
|
|
84
|
+
name: "eyebrow",
|
|
85
|
+
type: "text",
|
|
86
|
+
admin: { description: "Small label above the heading. Optional." }
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "heading",
|
|
90
|
+
type: "text",
|
|
91
|
+
required: true
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "body",
|
|
95
|
+
type: "textarea"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "tone",
|
|
99
|
+
type: "select",
|
|
100
|
+
defaultValue: "sweep",
|
|
101
|
+
options: [
|
|
102
|
+
{
|
|
103
|
+
label: "Sweep (brand gradient)",
|
|
104
|
+
value: "sweep"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
label: "Dark (flat brand band)",
|
|
108
|
+
value: "dark"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
label: "Light (page background)",
|
|
112
|
+
value: "light"
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
admin: { description: "How the band is painted. Sites map these to their own surfaces." }
|
|
116
|
+
},
|
|
117
|
+
imageField({ admin: { description: "Optional background or lead image." } }),
|
|
118
|
+
{
|
|
119
|
+
name: "links",
|
|
120
|
+
type: "array",
|
|
121
|
+
maxRows: 2,
|
|
122
|
+
labels: {
|
|
123
|
+
singular: "Call to action",
|
|
124
|
+
plural: "Calls to action"
|
|
125
|
+
},
|
|
126
|
+
fields: linkFields({ required: true })
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
};
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region src/blocks/rich-text/config.ts
|
|
132
|
+
/** A prose section: one Lexical document at reading measure. */
|
|
133
|
+
const RichTextBlock = {
|
|
134
|
+
slug: "richText",
|
|
135
|
+
interfaceName: "RichTextBlock",
|
|
136
|
+
labels: {
|
|
137
|
+
singular: "Rich Text",
|
|
138
|
+
plural: "Rich Text"
|
|
139
|
+
},
|
|
140
|
+
fields: [{
|
|
141
|
+
name: "content",
|
|
142
|
+
type: "richText",
|
|
143
|
+
required: true
|
|
144
|
+
}]
|
|
145
|
+
};
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/blocks/showcase-panels/config.ts
|
|
148
|
+
/** Expanding panels, one per service or product line. */
|
|
149
|
+
const ShowcasePanelsBlock = {
|
|
150
|
+
slug: "showcasePanels",
|
|
151
|
+
interfaceName: "ShowcasePanelsBlock",
|
|
152
|
+
labels: {
|
|
153
|
+
singular: "Showcase Panels",
|
|
154
|
+
plural: "Showcase Panels"
|
|
155
|
+
},
|
|
156
|
+
fields: [
|
|
157
|
+
{
|
|
158
|
+
name: "items",
|
|
159
|
+
type: "array",
|
|
160
|
+
required: true,
|
|
161
|
+
minRows: 3,
|
|
162
|
+
maxRows: 6,
|
|
163
|
+
labels: {
|
|
164
|
+
singular: "Panel",
|
|
165
|
+
plural: "Panels"
|
|
166
|
+
},
|
|
167
|
+
fields: [
|
|
168
|
+
{
|
|
169
|
+
name: "title",
|
|
170
|
+
type: "text",
|
|
171
|
+
required: true
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: "summary",
|
|
175
|
+
type: "textarea",
|
|
176
|
+
required: true,
|
|
177
|
+
admin: { description: "Revealed when the panel expands." }
|
|
178
|
+
},
|
|
179
|
+
imageField({ required: true }),
|
|
180
|
+
{
|
|
181
|
+
name: "href",
|
|
182
|
+
type: "text",
|
|
183
|
+
admin: { description: "Optional \"read more\" destination for this panel." }
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: "numeral",
|
|
187
|
+
type: "text",
|
|
188
|
+
admin: { description: "Overrides the spine numeral (\"01\", \"II\"). Leave empty to number automatically." }
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: "spineVariant",
|
|
194
|
+
type: "select",
|
|
195
|
+
defaultValue: "numbered",
|
|
196
|
+
options: [
|
|
197
|
+
{
|
|
198
|
+
label: "Numbered (01, 02)",
|
|
199
|
+
value: "numbered"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
label: "Volume (I, II)",
|
|
203
|
+
value: "volume"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
label: "Minimal (no numeral)",
|
|
207
|
+
value: "minimal"
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: "watermark",
|
|
213
|
+
type: "text",
|
|
214
|
+
admin: { description: "Faint mark behind the panels, e.g. a brand word." }
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: "defaultActiveIndex",
|
|
218
|
+
type: "number",
|
|
219
|
+
defaultValue: 0,
|
|
220
|
+
min: 0,
|
|
221
|
+
admin: { description: "Which panel is open on load, counting from 0." }
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: "ariaLabel",
|
|
225
|
+
type: "text",
|
|
226
|
+
admin: { description: "Names the region for screen readers. Defaults to \"Showcase panels\"." }
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: "labels",
|
|
230
|
+
type: "group",
|
|
231
|
+
admin: { description: "Overrides for the panel state text." },
|
|
232
|
+
fields: [{
|
|
233
|
+
name: "selected",
|
|
234
|
+
type: "text"
|
|
235
|
+
}, {
|
|
236
|
+
name: "preview",
|
|
237
|
+
type: "text"
|
|
238
|
+
}]
|
|
239
|
+
}
|
|
240
|
+
]
|
|
241
|
+
};
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region src/blocks/process-steps/config.ts
|
|
244
|
+
/** An ordered walkthrough that advances on its own. */
|
|
245
|
+
const ProcessStepsBlock = {
|
|
246
|
+
slug: "processSteps",
|
|
247
|
+
interfaceName: "ProcessStepsBlock",
|
|
248
|
+
labels: {
|
|
249
|
+
singular: "Process Steps",
|
|
250
|
+
plural: "Process Steps"
|
|
251
|
+
},
|
|
252
|
+
fields: [
|
|
253
|
+
{
|
|
254
|
+
name: "items",
|
|
255
|
+
type: "array",
|
|
256
|
+
required: true,
|
|
257
|
+
minRows: 3,
|
|
258
|
+
maxRows: 6,
|
|
259
|
+
labels: {
|
|
260
|
+
singular: "Step",
|
|
261
|
+
plural: "Steps"
|
|
262
|
+
},
|
|
263
|
+
fields: [
|
|
264
|
+
{
|
|
265
|
+
name: "title",
|
|
266
|
+
type: "text",
|
|
267
|
+
required: true
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: "description",
|
|
271
|
+
type: "textarea",
|
|
272
|
+
required: true
|
|
273
|
+
},
|
|
274
|
+
imageField({ required: true }),
|
|
275
|
+
{
|
|
276
|
+
name: "step",
|
|
277
|
+
type: "number",
|
|
278
|
+
min: 1,
|
|
279
|
+
admin: { description: "Overrides the displayed number. Leave empty to number by position." }
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: "autoAdvance",
|
|
285
|
+
type: "checkbox",
|
|
286
|
+
defaultValue: true,
|
|
287
|
+
admin: { description: "Advance on a timer. Always off for visitors who prefer reduced motion." }
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
name: "autoAdvanceDuration",
|
|
291
|
+
type: "number",
|
|
292
|
+
defaultValue: 6e3,
|
|
293
|
+
min: 1e3,
|
|
294
|
+
admin: { description: "Milliseconds each step holds before advancing." }
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: "pauseOnHover",
|
|
298
|
+
type: "checkbox",
|
|
299
|
+
defaultValue: true
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
name: "defaultActiveIndex",
|
|
303
|
+
type: "number",
|
|
304
|
+
defaultValue: 0,
|
|
305
|
+
min: 0,
|
|
306
|
+
admin: { description: "Which step is active on load, counting from 0." }
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
name: "ariaLabel",
|
|
310
|
+
type: "text",
|
|
311
|
+
admin: { description: "Names the region for screen readers. Defaults to \"Process steps\"." }
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
name: "labels",
|
|
315
|
+
type: "group",
|
|
316
|
+
admin: { description: "Overrides for the play/pause control text." },
|
|
317
|
+
fields: [{
|
|
318
|
+
name: "pause",
|
|
319
|
+
type: "text"
|
|
320
|
+
}, {
|
|
321
|
+
name: "resume",
|
|
322
|
+
type: "text"
|
|
323
|
+
}]
|
|
324
|
+
}
|
|
325
|
+
]
|
|
326
|
+
};
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region src/fields/heading.ts
|
|
329
|
+
/**
|
|
330
|
+
* The eyebrow / title / description trio every marketing band opens with.
|
|
331
|
+
*
|
|
332
|
+
* They are three top-level fields rather than a group: editors read a section
|
|
333
|
+
* heading as the first thing in the block, and burying it one collapse deep
|
|
334
|
+
* puts the least-optional copy behind a click. The field names match the
|
|
335
|
+
* `@bison-lab/ui` prop names so the renderers stay a pass-through.
|
|
336
|
+
*/
|
|
337
|
+
function headingFields({ required = true, eyebrowDescription = "Small label above the heading. Leave empty to hide the row." } = {}) {
|
|
338
|
+
return [
|
|
339
|
+
{
|
|
340
|
+
name: "eyebrow",
|
|
341
|
+
type: "text",
|
|
342
|
+
admin: { description: eyebrowDescription }
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
name: "title",
|
|
346
|
+
type: "text",
|
|
347
|
+
required
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
name: "description",
|
|
351
|
+
type: "textarea"
|
|
352
|
+
}
|
|
353
|
+
];
|
|
354
|
+
}
|
|
355
|
+
//#endregion
|
|
356
|
+
//#region src/blocks/faq-columns/config.ts
|
|
357
|
+
/** A sticky intro beside a column of questions. */
|
|
358
|
+
const FaqColumnsBlock = {
|
|
359
|
+
slug: "faqColumns",
|
|
360
|
+
interfaceName: "FaqColumnsBlock",
|
|
361
|
+
labels: {
|
|
362
|
+
singular: "FAQ Columns",
|
|
363
|
+
plural: "FAQ Columns"
|
|
364
|
+
},
|
|
365
|
+
fields: [
|
|
366
|
+
...headingFields(),
|
|
367
|
+
{
|
|
368
|
+
name: "items",
|
|
369
|
+
type: "array",
|
|
370
|
+
required: true,
|
|
371
|
+
minRows: 1,
|
|
372
|
+
labels: {
|
|
373
|
+
singular: "Question",
|
|
374
|
+
plural: "Questions"
|
|
375
|
+
},
|
|
376
|
+
fields: [{
|
|
377
|
+
name: "question",
|
|
378
|
+
type: "text",
|
|
379
|
+
required: true
|
|
380
|
+
}, {
|
|
381
|
+
name: "answer",
|
|
382
|
+
type: "textarea",
|
|
383
|
+
required: true
|
|
384
|
+
}]
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
name: "cta",
|
|
388
|
+
type: "group",
|
|
389
|
+
label: "Call to action",
|
|
390
|
+
admin: { description: "Shown under the intro. Leave the link empty to hide it." },
|
|
391
|
+
fields: [
|
|
392
|
+
{
|
|
393
|
+
name: "title",
|
|
394
|
+
type: "text",
|
|
395
|
+
admin: { description: "Lead-in line, e.g. \"Still have questions?\"." }
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
name: "linkText",
|
|
399
|
+
type: "text"
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
name: "href",
|
|
403
|
+
type: "text"
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
name: "newTab",
|
|
407
|
+
type: "checkbox",
|
|
408
|
+
label: "Open in a new tab",
|
|
409
|
+
defaultValue: false
|
|
410
|
+
}
|
|
411
|
+
]
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
name: "sticky",
|
|
415
|
+
type: "checkbox",
|
|
416
|
+
defaultValue: true,
|
|
417
|
+
admin: { description: "Pin the intro column while the answers scroll." }
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: "type",
|
|
421
|
+
type: "select",
|
|
422
|
+
defaultValue: "single",
|
|
423
|
+
options: [{
|
|
424
|
+
label: "One answer open at a time",
|
|
425
|
+
value: "single"
|
|
426
|
+
}, {
|
|
427
|
+
label: "Several answers open at once",
|
|
428
|
+
value: "multiple"
|
|
429
|
+
}]
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
name: "collapsible",
|
|
433
|
+
type: "checkbox",
|
|
434
|
+
defaultValue: true,
|
|
435
|
+
admin: { description: "Allow the open answer to be closed again. Single mode only." }
|
|
436
|
+
}
|
|
437
|
+
]
|
|
438
|
+
};
|
|
439
|
+
//#endregion
|
|
440
|
+
//#region src/blocks/testimonial-masonry/config.ts
|
|
441
|
+
/** Quotes in a masonry grid, clipped behind a fade once there are enough. */
|
|
442
|
+
const TestimonialMasonryBlock = {
|
|
443
|
+
slug: "testimonialMasonry",
|
|
444
|
+
interfaceName: "TestimonialMasonryBlock",
|
|
445
|
+
labels: {
|
|
446
|
+
singular: "Testimonial Masonry",
|
|
447
|
+
plural: "Testimonial Masonry"
|
|
448
|
+
},
|
|
449
|
+
fields: [
|
|
450
|
+
...headingFields(),
|
|
451
|
+
{
|
|
452
|
+
name: "items",
|
|
453
|
+
type: "array",
|
|
454
|
+
required: true,
|
|
455
|
+
minRows: 1,
|
|
456
|
+
labels: {
|
|
457
|
+
singular: "Testimonial",
|
|
458
|
+
plural: "Testimonials"
|
|
459
|
+
},
|
|
460
|
+
fields: [{
|
|
461
|
+
name: "content",
|
|
462
|
+
type: "textarea",
|
|
463
|
+
required: true,
|
|
464
|
+
label: "Quote"
|
|
465
|
+
}, {
|
|
466
|
+
name: "author",
|
|
467
|
+
type: "group",
|
|
468
|
+
fields: [
|
|
469
|
+
{
|
|
470
|
+
name: "name",
|
|
471
|
+
type: "text",
|
|
472
|
+
required: true
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
name: "title",
|
|
476
|
+
type: "text",
|
|
477
|
+
admin: { description: "Role or organisation, e.g. \"Orthopaedic surgeon\"." }
|
|
478
|
+
},
|
|
479
|
+
imageField({
|
|
480
|
+
name: "avatar",
|
|
481
|
+
admin: { description: "Optional. Initials from the name are used when empty." }
|
|
482
|
+
})
|
|
483
|
+
]
|
|
484
|
+
}]
|
|
485
|
+
},
|
|
486
|
+
linkField({
|
|
487
|
+
label: "Link",
|
|
488
|
+
admin: { description: "Shown under the fade, once there are enough quotes to clip." }
|
|
489
|
+
}),
|
|
490
|
+
{
|
|
491
|
+
name: "minItemsForFade",
|
|
492
|
+
type: "number",
|
|
493
|
+
defaultValue: 7,
|
|
494
|
+
min: 1,
|
|
495
|
+
admin: { description: "How many quotes before the grid clips and the bottom fade appears." }
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
name: "maxVisibleRows",
|
|
499
|
+
type: "number",
|
|
500
|
+
min: 1,
|
|
501
|
+
admin: { description: "Rows shown before the fade. Optional." }
|
|
502
|
+
}
|
|
503
|
+
]
|
|
504
|
+
};
|
|
505
|
+
//#endregion
|
|
506
|
+
//#region src/blocks/nap/config.ts
|
|
507
|
+
/**
|
|
508
|
+
* Name, address, phone — the block local SEO is graded on.
|
|
509
|
+
*
|
|
510
|
+
* The `e164` phone number is a separate field from the displayed one because
|
|
511
|
+
* `NapBlock` uses it, and only it, for the `tel:` href and the JSON-LD
|
|
512
|
+
* `telephone`. A prettified string can never silently become an unreachable
|
|
513
|
+
* link.
|
|
514
|
+
*/
|
|
515
|
+
const NapBlock = {
|
|
516
|
+
slug: "nap",
|
|
517
|
+
interfaceName: "NapBlock",
|
|
518
|
+
labels: {
|
|
519
|
+
singular: "Name, Address, Phone",
|
|
520
|
+
plural: "Name, Address, Phone"
|
|
521
|
+
},
|
|
522
|
+
fields: [
|
|
523
|
+
{
|
|
524
|
+
name: "businessName",
|
|
525
|
+
type: "text",
|
|
526
|
+
required: true,
|
|
527
|
+
label: "Business name"
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
name: "businessType",
|
|
531
|
+
type: "text",
|
|
532
|
+
required: true,
|
|
533
|
+
defaultValue: "LocalBusiness",
|
|
534
|
+
admin: { description: "schema.org type, e.g. \"MedicalBusiness\", \"Chiropractor\", \"LocalBusiness\"." }
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
name: "address",
|
|
538
|
+
type: "group",
|
|
539
|
+
fields: [
|
|
540
|
+
{
|
|
541
|
+
name: "streetAddress",
|
|
542
|
+
type: "text",
|
|
543
|
+
required: true
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
name: "addressLocality",
|
|
547
|
+
type: "text",
|
|
548
|
+
required: true,
|
|
549
|
+
label: "City"
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
name: "addressRegion",
|
|
553
|
+
type: "text",
|
|
554
|
+
required: true,
|
|
555
|
+
label: "State or region"
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
name: "postalCode",
|
|
559
|
+
type: "text",
|
|
560
|
+
required: true
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
name: "addressCountry",
|
|
564
|
+
type: "text",
|
|
565
|
+
defaultValue: "US",
|
|
566
|
+
admin: { description: "ISO 3166-1 alpha-2, e.g. US." }
|
|
567
|
+
}
|
|
568
|
+
]
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
name: "departments",
|
|
572
|
+
type: "array",
|
|
573
|
+
required: true,
|
|
574
|
+
minRows: 1,
|
|
575
|
+
labels: {
|
|
576
|
+
singular: "Department",
|
|
577
|
+
plural: "Departments"
|
|
578
|
+
},
|
|
579
|
+
admin: { description: "A single-location business has one entry, usually named after the business." },
|
|
580
|
+
fields: [
|
|
581
|
+
{
|
|
582
|
+
name: "name",
|
|
583
|
+
type: "text",
|
|
584
|
+
required: true
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
name: "departmentType",
|
|
588
|
+
type: "text",
|
|
589
|
+
admin: { description: "schema.org type for this department. Falls back to the business type." }
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
name: "phoneE164",
|
|
593
|
+
type: "text",
|
|
594
|
+
required: true,
|
|
595
|
+
label: "Phone (E.164)",
|
|
596
|
+
admin: { description: "Dialable form, e.g. \"+15551234567\". This is what the tel: link and the structured data use." }
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
name: "phoneDisplay",
|
|
600
|
+
type: "text",
|
|
601
|
+
label: "Phone (as displayed)",
|
|
602
|
+
admin: { description: "Optional. US numbers are formatted automatically when this is empty." }
|
|
603
|
+
}
|
|
604
|
+
]
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
name: "url",
|
|
608
|
+
type: "text",
|
|
609
|
+
admin: { description: "Canonical URL for the business. Optional." }
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
name: "showName",
|
|
613
|
+
type: "checkbox",
|
|
614
|
+
defaultValue: true,
|
|
615
|
+
admin: { description: "Turn off when a heading above the block already names the business." }
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
name: "headingLevel",
|
|
619
|
+
type: "select",
|
|
620
|
+
defaultValue: "h2",
|
|
621
|
+
options: [
|
|
622
|
+
{
|
|
623
|
+
label: "H2",
|
|
624
|
+
value: "h2"
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
label: "H3",
|
|
628
|
+
value: "h3"
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
label: "H4",
|
|
632
|
+
value: "h4"
|
|
633
|
+
}
|
|
634
|
+
],
|
|
635
|
+
admin: { description: "Keeps the page's heading order intact." }
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
name: "emitJsonLd",
|
|
639
|
+
type: "checkbox",
|
|
640
|
+
defaultValue: true,
|
|
641
|
+
label: "Emit structured data",
|
|
642
|
+
admin: { description: "Adds a schema.org LocalBusiness script. Turn off if the page emits its own." }
|
|
643
|
+
}
|
|
644
|
+
]
|
|
645
|
+
};
|
|
646
|
+
//#endregion
|
|
647
|
+
//#region src/media.ts
|
|
648
|
+
function isMediaDoc(value) {
|
|
649
|
+
return typeof value === "object" && value !== null;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Narrows an upload value to something renderable, or `undefined`.
|
|
653
|
+
*
|
|
654
|
+
* `undefined` covers three cases a renderer must treat identically: the field
|
|
655
|
+
* is empty, `depth: 0` left it as a bare id, or the document exists but has no
|
|
656
|
+
* `url` yet (an upload mid-flight). A renderer that gets `undefined` omits the
|
|
657
|
+
* image rather than emitting a broken `<img>`.
|
|
658
|
+
*
|
|
659
|
+
* `alt` is always a string: the media collection requires it, but a draft saved
|
|
660
|
+
* before that validation ran can still reach a renderer, and an `alt` of
|
|
661
|
+
* `undefined` would silently drop the attribute entirely.
|
|
662
|
+
*/
|
|
663
|
+
function resolveMedia(value) {
|
|
664
|
+
if (!isMediaDoc(value)) return void 0;
|
|
665
|
+
const { url, alt, width, height } = value;
|
|
666
|
+
if (typeof url !== "string" || url.length === 0) return void 0;
|
|
667
|
+
return {
|
|
668
|
+
src: url,
|
|
669
|
+
alt: typeof alt === "string" ? alt : "",
|
|
670
|
+
...typeof width === "number" ? { width } : {},
|
|
671
|
+
...typeof height === "number" ? { height } : {}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
//#endregion
|
|
675
|
+
export { FaqColumnsBlock, HeroBlock, NapBlock, ProcessStepsBlock, RichTextBlock, ShowcasePanelsBlock, TestimonialMasonryBlock, headingFields, imageField, linkField, linkFields, resolveMedia };
|
|
676
|
+
|
|
677
|
+
//# sourceMappingURL=index.mjs.map
|