@depup/sanity 5.17.1-depup.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/LICENSE +21 -0
- package/README.md +57 -0
- package/bin/sanity +209 -0
- package/changes.json +114 -0
- package/lib/_chunks-dts/ActiveWorkspaceMatcherContext.d.ts +16164 -0
- package/lib/_chunks-dts/index.d.ts +780 -0
- package/lib/_chunks-dts/types.d.ts +2765 -0
- package/lib/_chunks-dts/types2.d.ts +656 -0
- package/lib/_chunks-dts/types3.d.ts +303 -0
- package/lib/_chunks-es/BroadcastDisplayedDocument.js +20 -0
- package/lib/_chunks-es/BroadcastDisplayedDocument.js.map +1 -0
- package/lib/_chunks-es/DisplayedDocumentBroadcaster.js +32 -0
- package/lib/_chunks-es/DisplayedDocumentBroadcaster.js.map +1 -0
- package/lib/_chunks-es/LiveQueries.js +339 -0
- package/lib/_chunks-es/LiveQueries.js.map +1 -0
- package/lib/_chunks-es/MenuGroup.js +106 -0
- package/lib/_chunks-es/MenuGroup.js.map +1 -0
- package/lib/_chunks-es/PostMessageDocuments.js +72 -0
- package/lib/_chunks-es/PostMessageDocuments.js.map +1 -0
- package/lib/_chunks-es/PostMessagePerspective.js +23 -0
- package/lib/_chunks-es/PostMessagePerspective.js.map +1 -0
- package/lib/_chunks-es/PostMessagePreviewSnapshots.js +69 -0
- package/lib/_chunks-es/PostMessagePreviewSnapshots.js.map +1 -0
- package/lib/_chunks-es/PostMessageRefreshMutations.js +74 -0
- package/lib/_chunks-es/PostMessageRefreshMutations.js.map +1 -0
- package/lib/_chunks-es/PostMessageSchema.js +502 -0
- package/lib/_chunks-es/PostMessageSchema.js.map +1 -0
- package/lib/_chunks-es/PostMessageTelemetry.js +21 -0
- package/lib/_chunks-es/PostMessageTelemetry.js.map +1 -0
- package/lib/_chunks-es/PresentationToolGrantsCheck.js +3848 -0
- package/lib/_chunks-es/PresentationToolGrantsCheck.js.map +1 -0
- package/lib/_chunks-es/QRCodeSVG.js +692 -0
- package/lib/_chunks-es/QRCodeSVG.js.map +1 -0
- package/lib/_chunks-es/StructureToolProvider.js +2360 -0
- package/lib/_chunks-es/StructureToolProvider.js.map +1 -0
- package/lib/_chunks-es/VideoPlayer.js +22 -0
- package/lib/_chunks-es/VideoPlayer.js.map +1 -0
- package/lib/_chunks-es/ViteDevServerStopped.js +52 -0
- package/lib/_chunks-es/ViteDevServerStopped.js.map +1 -0
- package/lib/_chunks-es/index.js +285 -0
- package/lib/_chunks-es/index.js.map +1 -0
- package/lib/_chunks-es/index2.js +105 -0
- package/lib/_chunks-es/index2.js.map +1 -0
- package/lib/_chunks-es/index3.js +139 -0
- package/lib/_chunks-es/index3.js.map +1 -0
- package/lib/_chunks-es/index4.js +1020 -0
- package/lib/_chunks-es/index4.js.map +1 -0
- package/lib/_chunks-es/pane.js +5 -0
- package/lib/_chunks-es/pane.js.map +1 -0
- package/lib/_chunks-es/pane2.js +5 -0
- package/lib/_chunks-es/pane2.js.map +1 -0
- package/lib/_chunks-es/presentation.js +549 -0
- package/lib/_chunks-es/presentation.js.map +1 -0
- package/lib/_chunks-es/resources.js +303 -0
- package/lib/_chunks-es/resources.js.map +1 -0
- package/lib/_chunks-es/resources2.js +459 -0
- package/lib/_chunks-es/resources2.js.map +1 -0
- package/lib/_chunks-es/resources3.js +281 -0
- package/lib/_chunks-es/resources3.js.map +1 -0
- package/lib/_chunks-es/resources4.js +184 -0
- package/lib/_chunks-es/resources4.js.map +1 -0
- package/lib/_chunks-es/resources5.js +161 -0
- package/lib/_chunks-es/resources5.js.map +1 -0
- package/lib/_chunks-es/resources6.js +141 -0
- package/lib/_chunks-es/resources6.js.map +1 -0
- package/lib/_chunks-es/resources7.js +24 -0
- package/lib/_chunks-es/resources7.js.map +1 -0
- package/lib/_chunks-es/resources8.js +603 -0
- package/lib/_chunks-es/resources8.js.map +1 -0
- package/lib/_chunks-es/resources9.js +126 -0
- package/lib/_chunks-es/resources9.js.map +1 -0
- package/lib/_chunks-es/structureTool.js +13673 -0
- package/lib/_chunks-es/structureTool.js.map +1 -0
- package/lib/_chunks-es/version.js +17 -0
- package/lib/_chunks-es/version.js.map +1 -0
- package/lib/_createContext.d.ts +12 -0
- package/lib/_createContext.js +38 -0
- package/lib/_createContext.js.map +1 -0
- package/lib/_internal.d.ts +9 -0
- package/lib/_internal.js +12 -0
- package/lib/_internal.js.map +1 -0
- package/lib/_singletons.d.ts +951 -0
- package/lib/_singletons.js +284 -0
- package/lib/_singletons.js.map +1 -0
- package/lib/cli.d.ts +3 -0
- package/lib/cli.js +9 -0
- package/lib/cli.js.map +1 -0
- package/lib/desk.d.ts +910 -0
- package/lib/desk.js +71 -0
- package/lib/desk.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +92934 -0
- package/lib/index.js.map +1 -0
- package/lib/media-library.d.ts +85 -0
- package/lib/media-library.js +11 -0
- package/lib/media-library.js.map +1 -0
- package/lib/migrate.d.ts +1 -0
- package/lib/migrate.js +2 -0
- package/lib/migrate.js.map +1 -0
- package/lib/presentation.d.ts +28 -0
- package/lib/presentation.js +10 -0
- package/lib/presentation.js.map +1 -0
- package/lib/router.d.ts +560 -0
- package/lib/router.js +777 -0
- package/lib/router.js.map +1 -0
- package/lib/structure.d.ts +3 -0
- package/lib/structure.js +639 -0
- package/lib/structure.js.map +1 -0
- package/mock-browser-env-stub-loader.mjs +27 -0
- package/package.json +383 -0
- package/static/favicons/apple-touch-icon.png +0 -0
- package/static/favicons/favicon-192.png +0 -0
- package/static/favicons/favicon-512.png +0 -0
- package/static/favicons/favicon-96.png +0 -0
- package/static/favicons/favicon.ico +0 -0
- package/static/favicons/favicon.svg +12 -0
|
@@ -0,0 +1,2360 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { c } from "react/compiler-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { defineLocaleResourceBundle, DEFAULT_STUDIO_CLIENT_OPTIONS, getPublishedId, isRecord, getConfigContextFromSource, useSource, useConfigContextFromSource, useDocumentStore, usePerspective } from "sanity";
|
|
5
|
+
import { StructureToolContext } from "sanity/_singletons";
|
|
6
|
+
import { SortIcon, AddIcon, StackCompactIcon, StackIcon } from "@sanity/icons";
|
|
7
|
+
import camelCase from "lodash-es/camelCase.js";
|
|
8
|
+
import speakingurl from "speakingurl";
|
|
9
|
+
import { isValidElementType } from "react-is";
|
|
10
|
+
import uniqueId from "lodash-es/uniqueId.js";
|
|
11
|
+
import uniq from "lodash-es/uniq.js";
|
|
12
|
+
import kebabCase from "lodash-es/kebabCase.js";
|
|
13
|
+
import { generateHelpUrl } from "./index.js";
|
|
14
|
+
import find from "lodash-es/find.js";
|
|
15
|
+
import startCase from "lodash-es/startCase.js";
|
|
16
|
+
const structureLocaleNamespace = "structure", structureUsEnglishLocaleBundle = defineLocaleResourceBundle({
|
|
17
|
+
locale: "en-US",
|
|
18
|
+
namespace: structureLocaleNamespace,
|
|
19
|
+
resources: () => import("./resources8.js")
|
|
20
|
+
}), IMPLICIT_SCHEMA_TYPE_FIELDS = ["_id", "_type", "_createdAt", "_updatedAt", "_rev"];
|
|
21
|
+
function getOrCreateChildNode(nodes, fieldName, reference) {
|
|
22
|
+
const node = nodes.get(fieldName);
|
|
23
|
+
if (node) return node;
|
|
24
|
+
const createdNode = {
|
|
25
|
+
reference,
|
|
26
|
+
children: /* @__PURE__ */ new Map()
|
|
27
|
+
};
|
|
28
|
+
return nodes.set(fieldName, createdNode), createdNode;
|
|
29
|
+
}
|
|
30
|
+
function joinReferences(nodes, schemaType, path, strict) {
|
|
31
|
+
const [head, ...tail] = path;
|
|
32
|
+
if (!head || !("fields" in schemaType))
|
|
33
|
+
return;
|
|
34
|
+
const schemaField = schemaType.fields.find((field) => field.name === head);
|
|
35
|
+
if (!schemaField) {
|
|
36
|
+
if (!IMPLICIT_SCHEMA_TYPE_FIELDS.includes(head)) {
|
|
37
|
+
const errorMessage = `The current ordering config targeted the nonexistent field "${head}" on schema type "${schemaType.name}". It should be one of ${schemaType.fields.map((field) => field.name).join(", ")}`;
|
|
38
|
+
if (strict)
|
|
39
|
+
throw new Error(errorMessage);
|
|
40
|
+
console.warn(errorMessage);
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (tail.length === 0) {
|
|
45
|
+
nodes.has(head) || nodes.set(head, {
|
|
46
|
+
reference: !1,
|
|
47
|
+
children: /* @__PURE__ */ new Map()
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if ("to" in schemaField.type && schemaField.type.name === "reference") {
|
|
52
|
+
const refTypes = getOrCreateChildNode(nodes, head, !0);
|
|
53
|
+
schemaField.type.to.forEach((refType) => joinReferences(refTypes.children, refType, tail, strict));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const node = getOrCreateChildNode(nodes, head, !1);
|
|
57
|
+
joinReferences(node.children, schemaField.type, tail, strict);
|
|
58
|
+
}
|
|
59
|
+
function createProjection(tree) {
|
|
60
|
+
return [...tree.entries()].map(([fieldName, node]) => {
|
|
61
|
+
if (!node.children || node.children.size === 0)
|
|
62
|
+
return fieldName;
|
|
63
|
+
const childrenProjection = createProjection(node.children);
|
|
64
|
+
return node.reference ? `${fieldName}->{${childrenProjection}}` : `${fieldName}{${childrenProjection}}`;
|
|
65
|
+
}).join(", ");
|
|
66
|
+
}
|
|
67
|
+
function getExtendedProjection(schemaType, orderBy, strict = !1) {
|
|
68
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
69
|
+
return orderBy.forEach((ordering) => {
|
|
70
|
+
joinReferences(nodes, schemaType, ordering.field.split("."), strict);
|
|
71
|
+
}), createProjection(nodes);
|
|
72
|
+
}
|
|
73
|
+
class SerializeError extends Error {
|
|
74
|
+
constructor(message, parentPath, pathSegment, hint) {
|
|
75
|
+
super(message), this.name = "SerializeError";
|
|
76
|
+
const segment = typeof pathSegment > "u" ? "<unknown>" : `${pathSegment}`;
|
|
77
|
+
this.path = (parentPath || []).concat(hint ? `${segment} (${hint})` : segment);
|
|
78
|
+
}
|
|
79
|
+
withHelpUrl(id) {
|
|
80
|
+
return this.helpId = id, this;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const HELP_URL = {
|
|
84
|
+
ID_REQUIRED: "structure-node-id-required",
|
|
85
|
+
TITLE_REQUIRED: "structure-title-required",
|
|
86
|
+
FILTER_REQUIRED: "structure-filter-required",
|
|
87
|
+
INVALID_LIST_ITEM: "structure-invalid-list-item",
|
|
88
|
+
COMPONENT_REQUIRED: "structure-view-component-required",
|
|
89
|
+
DOCUMENT_ID_REQUIRED: "structure-document-id-required",
|
|
90
|
+
DOCUMENT_TYPE_REQUIRED: "structure-document-type-required",
|
|
91
|
+
SCHEMA_TYPE_REQUIRED: "structure-schema-type-required",
|
|
92
|
+
SCHEMA_TYPE_NOT_FOUND: "structure-schema-type-not-found",
|
|
93
|
+
LIST_ITEMS_MUST_BE_ARRAY: "structure-list-items-must-be-array",
|
|
94
|
+
QUERY_PROVIDED_FOR_FILTER: "structure-query-provided-for-filter",
|
|
95
|
+
ACTION_OR_INTENT_REQUIRED: "structure-action-or-intent-required",
|
|
96
|
+
LIST_ITEM_IDS_MUST_BE_UNIQUE: "structure-list-item-ids-must-be-unique",
|
|
97
|
+
ACTION_AND_INTENT_MUTUALLY_EXCLUSIVE: "structure-action-and-intent-mutually-exclusive",
|
|
98
|
+
API_VERSION_REQUIRED_FOR_CUSTOM_FILTER: "structure-api-version-required-for-custom-filter"
|
|
99
|
+
}, ORDER_BY_UPDATED_AT = {
|
|
100
|
+
title: "Last edited",
|
|
101
|
+
i18n: {
|
|
102
|
+
title: {
|
|
103
|
+
key: "menu-items.sort-by.last-edited",
|
|
104
|
+
ns: structureLocaleNamespace
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
name: "lastEditedDesc",
|
|
108
|
+
by: [{
|
|
109
|
+
field: "_updatedAt",
|
|
110
|
+
direction: "desc"
|
|
111
|
+
}]
|
|
112
|
+
}, ORDER_BY_CREATED_AT = {
|
|
113
|
+
title: "Created",
|
|
114
|
+
i18n: {
|
|
115
|
+
title: {
|
|
116
|
+
key: "menu-items.sort-by.created",
|
|
117
|
+
ns: structureLocaleNamespace
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
name: "lastCreatedDesc",
|
|
121
|
+
by: [{
|
|
122
|
+
field: "_createdAt",
|
|
123
|
+
direction: "desc"
|
|
124
|
+
}]
|
|
125
|
+
}, DEFAULT_SELECTED_ORDERING_OPTION = ORDER_BY_UPDATED_AT, DEFAULT_ORDERING_OPTIONS = [
|
|
126
|
+
ORDER_BY_UPDATED_AT,
|
|
127
|
+
// _updatedAt
|
|
128
|
+
ORDER_BY_CREATED_AT
|
|
129
|
+
// _createdAt
|
|
130
|
+
];
|
|
131
|
+
function maybeSerializeMenuItem(item, index, path) {
|
|
132
|
+
return item instanceof MenuItemBuilder ? item.serialize({
|
|
133
|
+
path,
|
|
134
|
+
index
|
|
135
|
+
}) : item;
|
|
136
|
+
}
|
|
137
|
+
class MenuItemBuilder {
|
|
138
|
+
/** menu item option object. See {@link PartialMenuItem} */
|
|
139
|
+
constructor(_context, spec) {
|
|
140
|
+
this._context = _context, this.spec = spec || {};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Set menu item id for tracking selected state.
|
|
144
|
+
* Menu items with the same id will share selected state (like radio buttons).
|
|
145
|
+
* Use with action 'setMenuItemState' to enable automatic selected state tracking.
|
|
146
|
+
* @param id - unique identifier for the menu item
|
|
147
|
+
* @returns menu item builder based on id provided. See {@link MenuItemBuilder}
|
|
148
|
+
*/
|
|
149
|
+
id(id) {
|
|
150
|
+
return this.clone({
|
|
151
|
+
id
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get menu item id
|
|
156
|
+
* @returns menu item id. See {@link PartialMenuItem}
|
|
157
|
+
*/
|
|
158
|
+
getId() {
|
|
159
|
+
return this.spec.id;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Set menu item action
|
|
163
|
+
* @param action - menu item action. See {@link MenuItemActionType}
|
|
164
|
+
* @returns menu item builder based on action provided. See {@link MenuItemBuilder}
|
|
165
|
+
*/
|
|
166
|
+
action(action) {
|
|
167
|
+
return this.clone({
|
|
168
|
+
action
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get menu item action
|
|
173
|
+
* @returns menu item builder action. See {@link PartialMenuItem}
|
|
174
|
+
*/
|
|
175
|
+
getAction() {
|
|
176
|
+
return this.spec.action;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Set menu item intent
|
|
180
|
+
* @param intent - menu item intent. See {@link Intent}
|
|
181
|
+
* @returns menu item builder based on intent provided. See {@link MenuItemBuilder}
|
|
182
|
+
*/
|
|
183
|
+
intent(intent) {
|
|
184
|
+
return this.clone({
|
|
185
|
+
intent
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get menu item intent
|
|
190
|
+
* @returns menu item intent. See {@link PartialMenuItem}
|
|
191
|
+
*/
|
|
192
|
+
getIntent() {
|
|
193
|
+
return this.spec.intent;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Set menu item title
|
|
197
|
+
* @param title - menu item title
|
|
198
|
+
* @returns menu item builder based on title provided. See {@link MenuItemBuilder}
|
|
199
|
+
*/
|
|
200
|
+
title(title) {
|
|
201
|
+
return this.clone({
|
|
202
|
+
title
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get menu item title. Note that the `i18n` configuration will take
|
|
207
|
+
* precedence and this title is left here for compatibility.
|
|
208
|
+
* @returns menu item title
|
|
209
|
+
*/
|
|
210
|
+
getTitle() {
|
|
211
|
+
return this.spec.title;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Set the i18n key and namespace used to populate the localized title.
|
|
215
|
+
* @param i18n - object with i18n key and related namespace
|
|
216
|
+
* @returns menu item builder based on i18n config provided. See {@link MenuItemBuilder}
|
|
217
|
+
*/
|
|
218
|
+
i18n(i18n) {
|
|
219
|
+
return this.clone({
|
|
220
|
+
i18n
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get the i18n key and namespace used to populate the localized title.
|
|
225
|
+
* @returns the i18n key and namespace used to populate the localized title.
|
|
226
|
+
*/
|
|
227
|
+
getI18n() {
|
|
228
|
+
return this.spec.i18n;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Set menu item group
|
|
232
|
+
* @param group - menu item group
|
|
233
|
+
* @returns menu item builder based on group provided. See {@link MenuItemBuilder}
|
|
234
|
+
*/
|
|
235
|
+
group(group) {
|
|
236
|
+
return this.clone({
|
|
237
|
+
group
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get menu item group
|
|
242
|
+
* @returns menu item group. See {@link PartialMenuItem}
|
|
243
|
+
*/
|
|
244
|
+
getGroup() {
|
|
245
|
+
return this.spec.group;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Set menu item icon
|
|
249
|
+
* @param icon - menu item icon
|
|
250
|
+
* @returns menu item builder based on icon provided. See {@link MenuItemBuilder}
|
|
251
|
+
*/
|
|
252
|
+
icon(icon) {
|
|
253
|
+
return this.clone({
|
|
254
|
+
icon
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Get menu item icon
|
|
259
|
+
* @returns menu item icon. See {@link PartialMenuItem}
|
|
260
|
+
*/
|
|
261
|
+
getIcon() {
|
|
262
|
+
return this.spec.icon;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Set menu item parameters
|
|
266
|
+
* @param params - menu item parameters. See {@link MenuItemParamsType}
|
|
267
|
+
* @returns menu item builder based on parameters provided. See {@link MenuItemBuilder}
|
|
268
|
+
*/
|
|
269
|
+
params(params) {
|
|
270
|
+
return this.clone({
|
|
271
|
+
params
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Get meny item parameters
|
|
276
|
+
* @returns menu item parameters. See {@link PartialMenuItem}
|
|
277
|
+
*/
|
|
278
|
+
getParams() {
|
|
279
|
+
return this.spec.params;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Set menu item to show as action
|
|
283
|
+
* @param showAsAction - determine if menu item should show as action
|
|
284
|
+
* @returns menu item builder based on if it should show as action. See {@link MenuItemBuilder}
|
|
285
|
+
*/
|
|
286
|
+
showAsAction(showAsAction = !0) {
|
|
287
|
+
return this.clone({
|
|
288
|
+
showAsAction: !!showAsAction
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Check if menu item should show as action
|
|
293
|
+
* @returns true if menu item should show as action, false if not. See {@link PartialMenuItem}
|
|
294
|
+
*/
|
|
295
|
+
getShowAsAction() {
|
|
296
|
+
return this.spec.showAsAction;
|
|
297
|
+
}
|
|
298
|
+
/** Serialize menu item builder
|
|
299
|
+
* @param options - serialization options. See {@link SerializeOptions}
|
|
300
|
+
* @returns menu item node based on path provided in options. See {@link MenuItem}
|
|
301
|
+
*/
|
|
302
|
+
serialize(options = {
|
|
303
|
+
path: []
|
|
304
|
+
}) {
|
|
305
|
+
const {
|
|
306
|
+
title,
|
|
307
|
+
action,
|
|
308
|
+
intent
|
|
309
|
+
} = this.spec;
|
|
310
|
+
if (!title) {
|
|
311
|
+
const hint = typeof action == "string" ? `action: "${action}"` : void 0;
|
|
312
|
+
throw new SerializeError("`title` is required for menu item", options.path, options.index, hint).withHelpUrl(HELP_URL.TITLE_REQUIRED);
|
|
313
|
+
}
|
|
314
|
+
if (!action && !intent)
|
|
315
|
+
throw new SerializeError(`\`action\` or \`intent\` required for menu item with title ${this.spec.title}`, options.path, options.index, `"${title}"`).withHelpUrl(HELP_URL.ACTION_OR_INTENT_REQUIRED);
|
|
316
|
+
if (intent && action)
|
|
317
|
+
throw new SerializeError("cannot set both `action` AND `intent`", options.path, options.index, `"${title}"`).withHelpUrl(HELP_URL.ACTION_AND_INTENT_MUTUALLY_EXCLUSIVE);
|
|
318
|
+
return {
|
|
319
|
+
...this.spec,
|
|
320
|
+
title
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
/** Clone menu item builder
|
|
324
|
+
* @param withSpec - menu item options. See {@link PartialMenuItem}
|
|
325
|
+
* @returns menu item builder based on context and spec provided. See {@link MenuItemBuilder}
|
|
326
|
+
*/
|
|
327
|
+
clone(withSpec) {
|
|
328
|
+
const builder = new MenuItemBuilder(this._context);
|
|
329
|
+
return builder.spec = {
|
|
330
|
+
...this.spec,
|
|
331
|
+
...withSpec
|
|
332
|
+
}, builder;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function getOrderingMenuItem(context, {
|
|
336
|
+
by,
|
|
337
|
+
title,
|
|
338
|
+
i18n
|
|
339
|
+
}, extendedProjection) {
|
|
340
|
+
let builder = new MenuItemBuilder(context).group("sorting").title(context.i18n.t("default-menu-item.fallback-title", {
|
|
341
|
+
// note this lives in the `studio` bundle because that one is loaded by default
|
|
342
|
+
ns: "studio",
|
|
343
|
+
replace: {
|
|
344
|
+
title
|
|
345
|
+
}
|
|
346
|
+
// replaces the `{{title}}` option
|
|
347
|
+
})).icon(SortIcon).action("setSortOrder").params({
|
|
348
|
+
by,
|
|
349
|
+
extendedProjection
|
|
350
|
+
});
|
|
351
|
+
return i18n && (builder = builder.i18n(i18n)), builder;
|
|
352
|
+
}
|
|
353
|
+
function getOrderingMenuItemsForSchemaType(context, typeName) {
|
|
354
|
+
const {
|
|
355
|
+
schema
|
|
356
|
+
} = context, type = typeof typeName == "string" ? schema.get(typeName) : typeName;
|
|
357
|
+
return !type || !("orderings" in type) ? [] : (type.orderings ? type.orderings.concat(DEFAULT_ORDERING_OPTIONS) : DEFAULT_ORDERING_OPTIONS).map((ordering) => getOrderingMenuItem(context, ordering, getExtendedProjection(type, ordering.by)));
|
|
358
|
+
}
|
|
359
|
+
function maybeSerializeMenuItemGroup(item, index, path) {
|
|
360
|
+
return item instanceof MenuItemGroupBuilder ? item.serialize({
|
|
361
|
+
path,
|
|
362
|
+
index
|
|
363
|
+
}) : item;
|
|
364
|
+
}
|
|
365
|
+
class MenuItemGroupBuilder {
|
|
366
|
+
/** Menu item group ID */
|
|
367
|
+
/** Menu item group title */
|
|
368
|
+
constructor(_context, spec) {
|
|
369
|
+
this._context = _context, this._id = spec ? spec.id : "", this._title = spec ? spec.title : "", this._i18n = spec ? spec.i18n : void 0;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Set menu item group ID
|
|
373
|
+
* @param id - menu item group ID
|
|
374
|
+
* @returns menu item group builder based on ID provided. See {@link MenuItemGroupBuilder}
|
|
375
|
+
*/
|
|
376
|
+
id(id) {
|
|
377
|
+
return new MenuItemGroupBuilder(this._context, {
|
|
378
|
+
id,
|
|
379
|
+
title: this._title,
|
|
380
|
+
i18n: this._i18n
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Get menu item group ID
|
|
385
|
+
* @returns menu item group ID
|
|
386
|
+
*/
|
|
387
|
+
getId() {
|
|
388
|
+
return this._id;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Set menu item group title
|
|
392
|
+
* @param title - menu item group title
|
|
393
|
+
* @returns menu item group builder based on title provided. See {@link MenuItemGroupBuilder}
|
|
394
|
+
*/
|
|
395
|
+
title(title) {
|
|
396
|
+
return new MenuItemGroupBuilder(this._context, {
|
|
397
|
+
title,
|
|
398
|
+
id: this._id,
|
|
399
|
+
i18n: this._i18n
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Get menu item group title
|
|
404
|
+
* @returns menu item group title
|
|
405
|
+
*/
|
|
406
|
+
getTitle() {
|
|
407
|
+
return this._title;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Set the i18n key and namespace used to populate the localized title.
|
|
411
|
+
* @param i18n - object with i18n key and related namespace
|
|
412
|
+
* @returns menu item group builder based on i18n info provided. See {@link MenuItemGroupBuilder}
|
|
413
|
+
*/
|
|
414
|
+
i18n(i18n) {
|
|
415
|
+
return new MenuItemGroupBuilder(this._context, {
|
|
416
|
+
i18n,
|
|
417
|
+
id: this._id,
|
|
418
|
+
title: this._title
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Get the i18n key and namespace used to populate the localized title.
|
|
423
|
+
* @returns the i18n key and namespace used to populate the localized title.
|
|
424
|
+
*/
|
|
425
|
+
getI18n() {
|
|
426
|
+
return this._i18n;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Serialize menu item group builder
|
|
430
|
+
* @param options - serialization options (path). See {@link SerializeOptions}
|
|
431
|
+
* @returns menu item group based on path provided in options. See {@link MenuItemGroup}
|
|
432
|
+
*/
|
|
433
|
+
serialize(options = {
|
|
434
|
+
path: []
|
|
435
|
+
}) {
|
|
436
|
+
if (!this._id)
|
|
437
|
+
throw new SerializeError("`id` is required for a menu item group", options.path, options.index, this._title).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
438
|
+
if (!this._title)
|
|
439
|
+
throw new SerializeError("`title` is required for a menu item group", options.path, this._id).withHelpUrl(HELP_URL.TITLE_REQUIRED);
|
|
440
|
+
return {
|
|
441
|
+
id: this._id,
|
|
442
|
+
title: this._title,
|
|
443
|
+
i18n: this._i18n
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const disallowedPattern = /([^A-Za-z0-9-_.])/;
|
|
448
|
+
function validateId(id, parentPath, pathSegment) {
|
|
449
|
+
if (typeof id != "string")
|
|
450
|
+
throw new SerializeError(`Structure node id must be of type string, got ${typeof id}`, parentPath, pathSegment);
|
|
451
|
+
const [disallowedChar] = id.match(disallowedPattern) || [];
|
|
452
|
+
if (disallowedChar)
|
|
453
|
+
throw new SerializeError(`Structure node id cannot contain character "${disallowedChar}"`, parentPath, pathSegment);
|
|
454
|
+
if (id.startsWith("__edit__"))
|
|
455
|
+
throw new SerializeError("Structure node id cannot start with __edit__", parentPath, pathSegment);
|
|
456
|
+
return id;
|
|
457
|
+
}
|
|
458
|
+
function getStructureNodeId(title, id) {
|
|
459
|
+
if (id)
|
|
460
|
+
return id;
|
|
461
|
+
const camelCased = camelCase(title);
|
|
462
|
+
return disallowedPattern.test(camelCased) ? camelCase(speakingurl(title)) : camelCased;
|
|
463
|
+
}
|
|
464
|
+
class ComponentBuilder {
|
|
465
|
+
/** component builder option object */
|
|
466
|
+
constructor(spec) {
|
|
467
|
+
this.spec = {
|
|
468
|
+
options: {},
|
|
469
|
+
...spec || {}
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
/** Set Component ID
|
|
473
|
+
* @param id - component ID
|
|
474
|
+
* @returns component builder based on ID provided
|
|
475
|
+
*/
|
|
476
|
+
id(id) {
|
|
477
|
+
return this.clone({
|
|
478
|
+
id
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
/** Get ID
|
|
482
|
+
* @returns ID
|
|
483
|
+
*/
|
|
484
|
+
getId() {
|
|
485
|
+
return this.spec.id;
|
|
486
|
+
}
|
|
487
|
+
/** Set Component title
|
|
488
|
+
* @param title - component title
|
|
489
|
+
* @returns component builder based on title provided (and ID)
|
|
490
|
+
*/
|
|
491
|
+
title(title) {
|
|
492
|
+
return this.clone({
|
|
493
|
+
title,
|
|
494
|
+
id: getStructureNodeId(title, this.spec.id)
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
/** Get Component title
|
|
498
|
+
* @returns title
|
|
499
|
+
*/
|
|
500
|
+
getTitle() {
|
|
501
|
+
return this.spec.title;
|
|
502
|
+
}
|
|
503
|
+
/** Set the i18n key and namespace used to populate the localized title.
|
|
504
|
+
* @param i18n - the key and namespaced used to populate the localized title.
|
|
505
|
+
* @returns component builder based on i18n key and ns provided
|
|
506
|
+
*/
|
|
507
|
+
i18n(i18n) {
|
|
508
|
+
return this.clone({
|
|
509
|
+
i18n
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
/** Get i18n key and namespace used to populate the localized title
|
|
513
|
+
* @returns the i18n key and namespace used to populate the localized title
|
|
514
|
+
*/
|
|
515
|
+
getI18n() {
|
|
516
|
+
return this.spec.i18n;
|
|
517
|
+
}
|
|
518
|
+
/** Set Component child
|
|
519
|
+
* @param child - child component
|
|
520
|
+
* @returns component builder based on child component provided
|
|
521
|
+
*/
|
|
522
|
+
child(child) {
|
|
523
|
+
return this.clone({
|
|
524
|
+
child
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
/** Get Component child
|
|
528
|
+
* @returns child component
|
|
529
|
+
*/
|
|
530
|
+
getChild() {
|
|
531
|
+
return this.spec.child;
|
|
532
|
+
}
|
|
533
|
+
/** Set component
|
|
534
|
+
* @param component - user built component
|
|
535
|
+
* @returns component builder based on component provided
|
|
536
|
+
*/
|
|
537
|
+
component(component2) {
|
|
538
|
+
return this.clone({
|
|
539
|
+
component: component2
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
/** Get Component
|
|
543
|
+
* @returns component
|
|
544
|
+
*/
|
|
545
|
+
getComponent() {
|
|
546
|
+
return this.spec.component;
|
|
547
|
+
}
|
|
548
|
+
/** Set Component options
|
|
549
|
+
* @param options - component options
|
|
550
|
+
* @returns component builder based on options provided
|
|
551
|
+
*/
|
|
552
|
+
options(options) {
|
|
553
|
+
return this.clone({
|
|
554
|
+
options
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
/** Get Component options
|
|
558
|
+
* @returns component options
|
|
559
|
+
*/
|
|
560
|
+
getOptions() {
|
|
561
|
+
return this.spec.options || {};
|
|
562
|
+
}
|
|
563
|
+
/** Set Component menu items
|
|
564
|
+
* @param menuItems - component menu items
|
|
565
|
+
* @returns component builder based on menuItems provided
|
|
566
|
+
*/
|
|
567
|
+
menuItems(menuItems) {
|
|
568
|
+
return this.clone({
|
|
569
|
+
menuItems
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
/** Get Component menu items
|
|
573
|
+
* @returns menu items
|
|
574
|
+
*/
|
|
575
|
+
getMenuItems() {
|
|
576
|
+
return this.spec.menuItems;
|
|
577
|
+
}
|
|
578
|
+
/** Set Component menu item groups
|
|
579
|
+
* @param menuItemGroups - component menu item groups
|
|
580
|
+
* @returns component builder based on menuItemGroups provided
|
|
581
|
+
*/
|
|
582
|
+
menuItemGroups(menuItemGroups) {
|
|
583
|
+
return this.clone({
|
|
584
|
+
menuItemGroups
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
/** Get Component menu item groups
|
|
588
|
+
* @returns menu item groups
|
|
589
|
+
*/
|
|
590
|
+
getMenuItemGroups() {
|
|
591
|
+
return this.spec.menuItemGroups;
|
|
592
|
+
}
|
|
593
|
+
canHandleIntent(canHandleIntent) {
|
|
594
|
+
return this.clone({
|
|
595
|
+
canHandleIntent
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
/** Serialize component
|
|
599
|
+
* @param options - serialization options
|
|
600
|
+
* @returns component object based on path provided in options
|
|
601
|
+
*
|
|
602
|
+
*/
|
|
603
|
+
serialize(options = {
|
|
604
|
+
path: []
|
|
605
|
+
}) {
|
|
606
|
+
const {
|
|
607
|
+
id,
|
|
608
|
+
title,
|
|
609
|
+
child,
|
|
610
|
+
options: componentOptions,
|
|
611
|
+
component: component2
|
|
612
|
+
} = this.spec;
|
|
613
|
+
if (!id)
|
|
614
|
+
throw new SerializeError("`id` is required for `component` structure item", options.path, options.index).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
615
|
+
if (!component2)
|
|
616
|
+
throw new SerializeError("`component` is required for `component` structure item", options.path, options.index).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
617
|
+
return {
|
|
618
|
+
id: validateId(id, options.path, options.index),
|
|
619
|
+
title,
|
|
620
|
+
type: "component",
|
|
621
|
+
child,
|
|
622
|
+
component: component2,
|
|
623
|
+
canHandleIntent: this.spec.canHandleIntent,
|
|
624
|
+
options: componentOptions || {},
|
|
625
|
+
menuItems: (this.spec.menuItems || []).map((item, i) => maybeSerializeMenuItem(item, i, options.path)),
|
|
626
|
+
menuItemGroups: (this.spec.menuItemGroups || []).map((item, i) => maybeSerializeMenuItemGroup(item, i, options.path))
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
/** Clone component builder (allows for options overriding)
|
|
630
|
+
* @param withSpec - component builder options
|
|
631
|
+
* @returns cloned builder
|
|
632
|
+
*/
|
|
633
|
+
clone(withSpec) {
|
|
634
|
+
const builder = new ComponentBuilder();
|
|
635
|
+
return builder.spec = {
|
|
636
|
+
...this.spec,
|
|
637
|
+
...withSpec
|
|
638
|
+
}, builder;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
class DividerBuilder {
|
|
642
|
+
constructor(spec) {
|
|
643
|
+
this.spec = {
|
|
644
|
+
id: uniqueId("__divider__"),
|
|
645
|
+
type: "divider",
|
|
646
|
+
...spec
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
/** Set the title of the divider
|
|
650
|
+
* @param title - the title of the divider
|
|
651
|
+
* @returns divider builder based on title provided
|
|
652
|
+
*/
|
|
653
|
+
title(title) {
|
|
654
|
+
return this.clone({
|
|
655
|
+
title
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
/** Get the title of the divider
|
|
659
|
+
* @returns the title of the divider
|
|
660
|
+
*/
|
|
661
|
+
getTitle() {
|
|
662
|
+
return this.spec.title;
|
|
663
|
+
}
|
|
664
|
+
/** Set the i18n key and namespace used to populate the localized title.
|
|
665
|
+
* @param i18n - the key and namespaced used to populate the localized title.
|
|
666
|
+
* @returns divider builder based on i18n key and ns provided
|
|
667
|
+
*/
|
|
668
|
+
i18n(i18n) {
|
|
669
|
+
return this.clone({
|
|
670
|
+
i18n
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
/** Get i18n key and namespace used to populate the localized title
|
|
674
|
+
* @returns the i18n key and namespace used to populate the localized title
|
|
675
|
+
*/
|
|
676
|
+
getI18n() {
|
|
677
|
+
return this.spec.i18n;
|
|
678
|
+
}
|
|
679
|
+
/** Serialize the divider
|
|
680
|
+
* @returns the serialized divider
|
|
681
|
+
*/
|
|
682
|
+
serialize() {
|
|
683
|
+
return {
|
|
684
|
+
...this.spec
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
/** Clone divider builder (allows for options overriding)
|
|
688
|
+
* @param withSpec - divider builder options
|
|
689
|
+
* @returns cloned builder
|
|
690
|
+
*/
|
|
691
|
+
clone(withSpec) {
|
|
692
|
+
const builder = new DividerBuilder();
|
|
693
|
+
return builder.spec = {
|
|
694
|
+
...this.spec,
|
|
695
|
+
...withSpec
|
|
696
|
+
}, builder;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
async function resolveTypeForDocument(getClient, id) {
|
|
700
|
+
return await getClient(DEFAULT_STUDIO_CLIENT_OPTIONS).fetch("*[sanity::versionOf($publishedId)][0]._type", {
|
|
701
|
+
publishedId: getPublishedId(id)
|
|
702
|
+
}, {
|
|
703
|
+
tag: "structure.resolve-type"
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
class GenericViewBuilder {
|
|
707
|
+
/** Generic view option object */
|
|
708
|
+
spec = {};
|
|
709
|
+
/** Set generic view ID
|
|
710
|
+
* @param id - generic view ID
|
|
711
|
+
* @returns generic view builder based on ID provided.
|
|
712
|
+
*/
|
|
713
|
+
id(id) {
|
|
714
|
+
return this.clone({
|
|
715
|
+
id
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
/** Get generic view ID
|
|
719
|
+
* @returns generic view ID
|
|
720
|
+
*/
|
|
721
|
+
getId() {
|
|
722
|
+
return this.spec.id;
|
|
723
|
+
}
|
|
724
|
+
/** Set generic view title
|
|
725
|
+
* @param title - generic view title
|
|
726
|
+
* @returns generic view builder based on title provided and (if provided) its ID.
|
|
727
|
+
*/
|
|
728
|
+
title(title) {
|
|
729
|
+
return this.clone({
|
|
730
|
+
title,
|
|
731
|
+
id: this.spec.id || kebabCase(title)
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
/** Get generic view title
|
|
735
|
+
* @returns generic view title
|
|
736
|
+
*/
|
|
737
|
+
getTitle() {
|
|
738
|
+
return this.spec.title;
|
|
739
|
+
}
|
|
740
|
+
/** Set generic view icon
|
|
741
|
+
* @param icon - generic view icon
|
|
742
|
+
* @returns generic view builder based on icon provided.
|
|
743
|
+
*/
|
|
744
|
+
icon(icon) {
|
|
745
|
+
return this.clone({
|
|
746
|
+
icon
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
/** Get generic view icon
|
|
750
|
+
* @returns generic view icon
|
|
751
|
+
*/
|
|
752
|
+
getIcon() {
|
|
753
|
+
return this.spec.icon;
|
|
754
|
+
}
|
|
755
|
+
/** Serialize generic view
|
|
756
|
+
* @param options - serialization options. See {@link SerializeOptions}
|
|
757
|
+
* @returns generic view object based on path provided in options. See {@link BaseView}
|
|
758
|
+
*/
|
|
759
|
+
serialize(options = {
|
|
760
|
+
path: []
|
|
761
|
+
}) {
|
|
762
|
+
const {
|
|
763
|
+
id,
|
|
764
|
+
title,
|
|
765
|
+
icon
|
|
766
|
+
} = this.spec;
|
|
767
|
+
if (!id)
|
|
768
|
+
throw new SerializeError("`id` is required for view item", options.path, options.index).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
769
|
+
if (!title)
|
|
770
|
+
throw new SerializeError("`title` is required for view item", options.path, options.index).withHelpUrl(HELP_URL.TITLE_REQUIRED);
|
|
771
|
+
return {
|
|
772
|
+
id: validateId(id, options.path, options.index),
|
|
773
|
+
title,
|
|
774
|
+
icon
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
/** Clone generic view builder (allows for options overriding)
|
|
778
|
+
* @param withSpec - Partial generic view builder options. See {@link BaseView}
|
|
779
|
+
* @returns Generic view builder.
|
|
780
|
+
*/
|
|
781
|
+
}
|
|
782
|
+
function isSerializable(view) {
|
|
783
|
+
return typeof view.serialize == "function";
|
|
784
|
+
}
|
|
785
|
+
function maybeSerializeView(item, index, path) {
|
|
786
|
+
return isSerializable(item) ? item.serialize({
|
|
787
|
+
path,
|
|
788
|
+
index
|
|
789
|
+
}) : item;
|
|
790
|
+
}
|
|
791
|
+
const isComponentSpec = (spec) => isRecord(spec) && spec.type === "component";
|
|
792
|
+
class ComponentViewBuilder extends GenericViewBuilder {
|
|
793
|
+
/** Partial Component view option object. See {@link ComponentView} */
|
|
794
|
+
constructor(componentOrSpec) {
|
|
795
|
+
const spec = isComponentSpec(componentOrSpec) ? {
|
|
796
|
+
...componentOrSpec
|
|
797
|
+
} : {
|
|
798
|
+
options: {}
|
|
799
|
+
};
|
|
800
|
+
super(), this.spec = spec;
|
|
801
|
+
const userComponent = typeof componentOrSpec == "function" ? componentOrSpec : this.spec.component;
|
|
802
|
+
userComponent && (this.spec = this.component(userComponent).spec);
|
|
803
|
+
}
|
|
804
|
+
/** Set view Component
|
|
805
|
+
* @param component - component view component. See {@link UserViewComponent}
|
|
806
|
+
* @returns component view builder based on component view provided. See {@link ComponentViewBuilder}
|
|
807
|
+
*/
|
|
808
|
+
component(component2) {
|
|
809
|
+
return this.clone({
|
|
810
|
+
component: component2
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
/** Get view Component
|
|
814
|
+
* @returns Partial component view. See {@link ComponentView}
|
|
815
|
+
*/
|
|
816
|
+
getComponent() {
|
|
817
|
+
return this.spec.component;
|
|
818
|
+
}
|
|
819
|
+
/** Set view Component options
|
|
820
|
+
* @param options - component view options
|
|
821
|
+
* @returns component view builder based on options provided. See {@link ComponentViewBuilder}
|
|
822
|
+
*/
|
|
823
|
+
options(options) {
|
|
824
|
+
return this.clone({
|
|
825
|
+
options
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
/** Get view Component options
|
|
829
|
+
* @returns component view options. See {@link ComponentView}
|
|
830
|
+
*/
|
|
831
|
+
getOptions() {
|
|
832
|
+
return this.spec.options || {};
|
|
833
|
+
}
|
|
834
|
+
/** Serialize view Component
|
|
835
|
+
* @param options - serialization options. See {@link SerializeOptions}
|
|
836
|
+
* @returns component view based on path provided in options. See {@link ComponentView}
|
|
837
|
+
*
|
|
838
|
+
*/
|
|
839
|
+
serialize(options = {
|
|
840
|
+
path: []
|
|
841
|
+
}) {
|
|
842
|
+
const base = super.serialize(options), component2 = this.spec.component;
|
|
843
|
+
if (typeof component2 != "function")
|
|
844
|
+
throw new SerializeError("`component` is required and must be a function for `component()` view item", options.path, options.index).withHelpUrl(HELP_URL.COMPONENT_REQUIRED);
|
|
845
|
+
return {
|
|
846
|
+
...base,
|
|
847
|
+
component: component2,
|
|
848
|
+
options: this.spec.options || {},
|
|
849
|
+
type: "component"
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
/** Clone Component view builder (allows for options overriding)
|
|
853
|
+
* @param withSpec - partial for component view option. See {@link ComponentView}
|
|
854
|
+
* @returns component view builder. See {@link ComponentViewBuilder}
|
|
855
|
+
*/
|
|
856
|
+
clone(withSpec) {
|
|
857
|
+
const builder = new ComponentViewBuilder();
|
|
858
|
+
return builder.spec = {
|
|
859
|
+
...this.spec,
|
|
860
|
+
...withSpec
|
|
861
|
+
}, builder;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
class FormViewBuilder extends GenericViewBuilder {
|
|
865
|
+
/** Document list options. See {@link FormView} */
|
|
866
|
+
constructor(spec) {
|
|
867
|
+
super(), this.spec = {
|
|
868
|
+
id: "editor",
|
|
869
|
+
title: "Editor",
|
|
870
|
+
...spec || {}
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Serialize Form view builder
|
|
875
|
+
* @param options - Serialize options. See {@link SerializeOptions}
|
|
876
|
+
* @returns form view builder based on path provided in options. See {@link FormView}
|
|
877
|
+
*/
|
|
878
|
+
serialize(options = {
|
|
879
|
+
path: []
|
|
880
|
+
}) {
|
|
881
|
+
return {
|
|
882
|
+
...super.serialize(options),
|
|
883
|
+
type: "form"
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Clone Form view builder (allows for options overriding)
|
|
888
|
+
* @param withSpec - Partial form view builder options. See {@link FormView}
|
|
889
|
+
* @returns form view builder. See {@link FormViewBuilder}
|
|
890
|
+
*/
|
|
891
|
+
clone(withSpec) {
|
|
892
|
+
const builder = new FormViewBuilder();
|
|
893
|
+
return builder.spec = {
|
|
894
|
+
...this.spec,
|
|
895
|
+
...withSpec
|
|
896
|
+
}, builder;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
const form = (spec) => new FormViewBuilder(spec), component = (componentOrSpec) => new ComponentViewBuilder(componentOrSpec);
|
|
900
|
+
var views = /* @__PURE__ */ Object.freeze({
|
|
901
|
+
__proto__: null,
|
|
902
|
+
ComponentViewBuilder,
|
|
903
|
+
FormViewBuilder,
|
|
904
|
+
GenericViewBuilder,
|
|
905
|
+
component,
|
|
906
|
+
form,
|
|
907
|
+
maybeSerializeView
|
|
908
|
+
});
|
|
909
|
+
const createDocumentChildResolver = ({
|
|
910
|
+
resolveDocumentNode,
|
|
911
|
+
getClient
|
|
912
|
+
}) => async (itemId, {
|
|
913
|
+
params,
|
|
914
|
+
path
|
|
915
|
+
}) => {
|
|
916
|
+
let type = params.type;
|
|
917
|
+
const parentPath = path.slice(0, path.length - 1), currentSegment = path[path.length - 1];
|
|
918
|
+
if (type || (type = await resolveTypeForDocument(getClient, itemId)), !type)
|
|
919
|
+
throw new SerializeError("Failed to resolve document, and no type provided in parameters.", parentPath, currentSegment);
|
|
920
|
+
return resolveDocumentNode({
|
|
921
|
+
documentId: itemId,
|
|
922
|
+
schemaType: type
|
|
923
|
+
});
|
|
924
|
+
};
|
|
925
|
+
class DocumentBuilder {
|
|
926
|
+
/** Component builder option object See {@link PartialDocumentNode} */
|
|
927
|
+
constructor(_context, spec) {
|
|
928
|
+
this._context = _context, this.spec = spec || {};
|
|
929
|
+
}
|
|
930
|
+
/** Set Document Builder ID
|
|
931
|
+
* @param id - document builder ID
|
|
932
|
+
* @returns document builder based on ID provided. See {@link DocumentBuilder}
|
|
933
|
+
*/
|
|
934
|
+
id(id) {
|
|
935
|
+
return this.clone({
|
|
936
|
+
id
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
/** Get Document Builder ID
|
|
940
|
+
* @returns document ID. See {@link PartialDocumentNode}
|
|
941
|
+
*/
|
|
942
|
+
getId() {
|
|
943
|
+
return this.spec.id;
|
|
944
|
+
}
|
|
945
|
+
/** Set Document title
|
|
946
|
+
* @param title - document title
|
|
947
|
+
* @returns document builder based on title provided (and ID). See {@link DocumentBuilder}
|
|
948
|
+
*/
|
|
949
|
+
title(title) {
|
|
950
|
+
return this.clone({
|
|
951
|
+
title,
|
|
952
|
+
id: getStructureNodeId(title, this.spec.id)
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
/** Get Document title
|
|
956
|
+
* @returns document title. See {@link PartialDocumentNode}
|
|
957
|
+
*/
|
|
958
|
+
getTitle() {
|
|
959
|
+
return this.spec.title;
|
|
960
|
+
}
|
|
961
|
+
/** Set the i18n key and namespace used to populate the localized title.
|
|
962
|
+
* @param i18n - the key and namespaced used to populate the localized title.
|
|
963
|
+
* @returns component builder based on i18n key and ns provided
|
|
964
|
+
*/
|
|
965
|
+
i18n(i18n) {
|
|
966
|
+
return this.clone({
|
|
967
|
+
i18n
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
/** Get i18n key and namespace used to populate the localized title
|
|
971
|
+
* @returns the i18n key and namespace used to populate the localized title
|
|
972
|
+
*/
|
|
973
|
+
getI18n() {
|
|
974
|
+
return this.spec.i18n;
|
|
975
|
+
}
|
|
976
|
+
/** Set Document child
|
|
977
|
+
* @param child - document child
|
|
978
|
+
* @returns document builder based on child provided. See {@link DocumentBuilder}
|
|
979
|
+
*/
|
|
980
|
+
child(child) {
|
|
981
|
+
return this.clone({
|
|
982
|
+
child
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
/** Get Document child
|
|
986
|
+
* @returns document child. See {@link PartialDocumentNode}
|
|
987
|
+
*/
|
|
988
|
+
getChild() {
|
|
989
|
+
return this.spec.child;
|
|
990
|
+
}
|
|
991
|
+
/** Set Document ID
|
|
992
|
+
* @param documentId - document ID
|
|
993
|
+
* @returns document builder with document based on ID provided. See {@link DocumentBuilder}
|
|
994
|
+
*/
|
|
995
|
+
documentId(documentId) {
|
|
996
|
+
const paneId = this.spec.id || documentId;
|
|
997
|
+
return this.clone({
|
|
998
|
+
id: paneId,
|
|
999
|
+
options: {
|
|
1000
|
+
...this.spec.options,
|
|
1001
|
+
id: documentId
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
/** Get Document ID
|
|
1006
|
+
* @returns document ID. See {@link DocumentOptions}
|
|
1007
|
+
*/
|
|
1008
|
+
getDocumentId() {
|
|
1009
|
+
return this.spec.options?.id;
|
|
1010
|
+
}
|
|
1011
|
+
/** Set Document Type
|
|
1012
|
+
* @param documentType - document type
|
|
1013
|
+
* @returns document builder with document based on type provided. See {@link DocumentBuilder}
|
|
1014
|
+
*/
|
|
1015
|
+
schemaType(documentType) {
|
|
1016
|
+
return this.clone({
|
|
1017
|
+
options: {
|
|
1018
|
+
...this.spec.options,
|
|
1019
|
+
type: typeof documentType == "string" ? documentType : documentType.name
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
/** Get Document Type
|
|
1024
|
+
* @returns document type. See {@link DocumentOptions}
|
|
1025
|
+
*/
|
|
1026
|
+
getSchemaType() {
|
|
1027
|
+
return this.spec.options?.type;
|
|
1028
|
+
}
|
|
1029
|
+
/** Set Document Template
|
|
1030
|
+
* @param templateId - document template ID
|
|
1031
|
+
* @param parameters - document template parameters
|
|
1032
|
+
* @returns document builder with document based on template provided. See {@link DocumentBuilder}
|
|
1033
|
+
*/
|
|
1034
|
+
initialValueTemplate(templateId, parameters) {
|
|
1035
|
+
return this.clone({
|
|
1036
|
+
options: {
|
|
1037
|
+
...this.spec.options,
|
|
1038
|
+
template: templateId,
|
|
1039
|
+
templateParameters: parameters
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
/** Get Document Template
|
|
1044
|
+
* @returns document template. See {@link DocumentOptions}
|
|
1045
|
+
*/
|
|
1046
|
+
getInitialValueTemplate() {
|
|
1047
|
+
return this.spec.options?.template;
|
|
1048
|
+
}
|
|
1049
|
+
/** Get Document's initial value Template parameters
|
|
1050
|
+
* @returns document template parameters. See {@link DocumentOptions}
|
|
1051
|
+
*/
|
|
1052
|
+
getInitialValueTemplateParameters() {
|
|
1053
|
+
return this.spec.options?.templateParameters;
|
|
1054
|
+
}
|
|
1055
|
+
/** Set Document views
|
|
1056
|
+
* @param views - document views. See {@link ViewBuilder} and {@link View}
|
|
1057
|
+
* @returns document builder with document based on views provided. See {@link DocumentBuilder}
|
|
1058
|
+
*/
|
|
1059
|
+
views(views2) {
|
|
1060
|
+
return this.clone({
|
|
1061
|
+
views: views2
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
/** Get Document views
|
|
1065
|
+
* @returns document views. See {@link ViewBuilder} and {@link View}
|
|
1066
|
+
*/
|
|
1067
|
+
getViews() {
|
|
1068
|
+
return this.spec.views || [];
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Set the view IDs to open as split panes by default when the document is opened.
|
|
1072
|
+
* Pass an array of view IDs that match the IDs defined in `views()`.
|
|
1073
|
+
* If specified with 2+ valid view IDs, the document will open in split-pane mode.
|
|
1074
|
+
*
|
|
1075
|
+
* @param viewIds - Array of view IDs to open as split panes
|
|
1076
|
+
* @returns document builder with defaultPanes config. See {@link DocumentBuilder}
|
|
1077
|
+
*
|
|
1078
|
+
* @example
|
|
1079
|
+
* ```ts
|
|
1080
|
+
* S.document()
|
|
1081
|
+
* .schemaType('article')
|
|
1082
|
+
* .views([
|
|
1083
|
+
* S.view.form().id('editor'),
|
|
1084
|
+
* S.view.component(PreviewPane).id('preview').title('Preview')
|
|
1085
|
+
* ])
|
|
1086
|
+
* .defaultPanes(['editor', 'preview']) // Opens both as split panes
|
|
1087
|
+
* ```
|
|
1088
|
+
*/
|
|
1089
|
+
defaultPanes(viewIds) {
|
|
1090
|
+
return this.clone({
|
|
1091
|
+
defaultPanes: viewIds
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
/** Serialize Document builder
|
|
1095
|
+
* @param options - serialization options. See {@link SerializeOptions}
|
|
1096
|
+
* @returns document node based on path, index and hint provided in options. See {@link DocumentNode}
|
|
1097
|
+
*/
|
|
1098
|
+
serialize({
|
|
1099
|
+
path = [],
|
|
1100
|
+
index,
|
|
1101
|
+
hint
|
|
1102
|
+
} = {
|
|
1103
|
+
path: []
|
|
1104
|
+
}) {
|
|
1105
|
+
const urlId = path[index || path.length - 1], id = this.spec.id || urlId && `${urlId}` || "", options = {
|
|
1106
|
+
id,
|
|
1107
|
+
type: void 0,
|
|
1108
|
+
template: void 0,
|
|
1109
|
+
templateParameters: void 0,
|
|
1110
|
+
...this.spec.options
|
|
1111
|
+
};
|
|
1112
|
+
if (typeof id != "string" || !id)
|
|
1113
|
+
throw new SerializeError("`id` is required for document nodes", path, index, hint).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
1114
|
+
if (!options || !options.id)
|
|
1115
|
+
throw new SerializeError("document id (`id`) is required for document nodes", path, id, hint).withHelpUrl(HELP_URL.DOCUMENT_ID_REQUIRED);
|
|
1116
|
+
if (!options || !options.type)
|
|
1117
|
+
throw new SerializeError("document type (`schemaType`) is required for document nodes", path, id, hint);
|
|
1118
|
+
const views2 = (this.spec.views && this.spec.views.length > 0 ? this.spec.views : [form()]).map((item, i) => maybeSerializeView(item, i, path)), viewIds = views2.map((view) => view.id), dupes = uniq(viewIds.filter((viewId, i) => viewIds.includes(viewId, i + 1)));
|
|
1119
|
+
if (dupes.length > 0)
|
|
1120
|
+
throw new SerializeError(`document node has views with duplicate IDs: ${dupes.join(", ")}`, path, id, hint);
|
|
1121
|
+
let defaultPanes;
|
|
1122
|
+
if (this.spec.defaultPanes && this.spec.defaultPanes.length > 0) {
|
|
1123
|
+
const validViewIds = this.spec.defaultPanes.filter((windowId) => viewIds.includes(windowId)), invalidViewIds = this.spec.defaultPanes.filter((windowId) => !viewIds.includes(windowId));
|
|
1124
|
+
invalidViewIds.length > 0 && console.warn(`DefaultPanes contains invalid view IDs that don't match any defined views: ${invalidViewIds.join(", ")}. Valid view IDs are: ${viewIds.join(", ")}`), validViewIds.length >= 2 && (defaultPanes = validViewIds);
|
|
1125
|
+
}
|
|
1126
|
+
return {
|
|
1127
|
+
...this.spec,
|
|
1128
|
+
child: this.spec.child || createDocumentChildResolver(this._context),
|
|
1129
|
+
id: validateId(id, path, index),
|
|
1130
|
+
type: "document",
|
|
1131
|
+
options: getDocumentOptions(options),
|
|
1132
|
+
views: views2,
|
|
1133
|
+
defaultPanes
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
/** Clone Document builder
|
|
1137
|
+
* @param withSpec - partial document node specification used to extend the cloned builder. See {@link PartialDocumentNode}
|
|
1138
|
+
* @returns document builder based on context and spec provided. See {@link DocumentBuilder}
|
|
1139
|
+
*/
|
|
1140
|
+
clone(withSpec = {}) {
|
|
1141
|
+
const builder = new DocumentBuilder(this._context), options = {
|
|
1142
|
+
...this.spec.options,
|
|
1143
|
+
...withSpec.options
|
|
1144
|
+
};
|
|
1145
|
+
return builder.spec = {
|
|
1146
|
+
...this.spec,
|
|
1147
|
+
...withSpec,
|
|
1148
|
+
options
|
|
1149
|
+
}, builder;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function getDocumentOptions(spec) {
|
|
1153
|
+
const opts = {
|
|
1154
|
+
id: spec.id || "",
|
|
1155
|
+
type: spec.type || "*"
|
|
1156
|
+
};
|
|
1157
|
+
return spec.template && (opts.template = spec.template), spec.templateParameters && (opts.templateParameters = spec.templateParameters), opts;
|
|
1158
|
+
}
|
|
1159
|
+
function documentFromEditor(context, spec) {
|
|
1160
|
+
let doc = spec?.type ? (
|
|
1161
|
+
// Use user-defined document fragment as base if possible
|
|
1162
|
+
context.resolveDocumentNode({
|
|
1163
|
+
schemaType: spec.type
|
|
1164
|
+
})
|
|
1165
|
+
) : (
|
|
1166
|
+
// Fall back to plain old document builder
|
|
1167
|
+
new DocumentBuilder(context)
|
|
1168
|
+
);
|
|
1169
|
+
if (!spec) return doc;
|
|
1170
|
+
const {
|
|
1171
|
+
id,
|
|
1172
|
+
type,
|
|
1173
|
+
template,
|
|
1174
|
+
templateParameters
|
|
1175
|
+
} = spec.options;
|
|
1176
|
+
return doc = doc.id(spec.id).documentId(id), type && (doc = doc.schemaType(type)), template && (doc = doc.initialValueTemplate(template, templateParameters)), spec.child && (doc = doc.child(spec.child)), doc;
|
|
1177
|
+
}
|
|
1178
|
+
function documentFromEditorWithInitialValue({
|
|
1179
|
+
resolveDocumentNode,
|
|
1180
|
+
templates
|
|
1181
|
+
}, templateId, parameters) {
|
|
1182
|
+
const template = templates.find((t) => t.id === templateId);
|
|
1183
|
+
if (!template)
|
|
1184
|
+
throw new Error(`Template with ID "${templateId}" not defined`);
|
|
1185
|
+
return resolveDocumentNode({
|
|
1186
|
+
schemaType: template.schemaType
|
|
1187
|
+
}).initialValueTemplate(templateId, parameters);
|
|
1188
|
+
}
|
|
1189
|
+
class InitialValueTemplateItemBuilder {
|
|
1190
|
+
/** Initial Value template item option object. See {@link InitialValueTemplateItem} */
|
|
1191
|
+
constructor(_context, spec) {
|
|
1192
|
+
this._context = _context, this.spec = spec || {};
|
|
1193
|
+
}
|
|
1194
|
+
/** Set initial value template item builder ID
|
|
1195
|
+
* @param id - initial value template item ID
|
|
1196
|
+
* @returns initial value template item based on ID provided. See {@link InitialValueTemplateItemBuilder}
|
|
1197
|
+
*/
|
|
1198
|
+
id(id) {
|
|
1199
|
+
return this.clone({
|
|
1200
|
+
id
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
/** Get initial value template item builder ID
|
|
1204
|
+
* @returns initial value template item ID. See {@link InitialValueTemplateItem}
|
|
1205
|
+
*/
|
|
1206
|
+
getId() {
|
|
1207
|
+
return this.spec.id;
|
|
1208
|
+
}
|
|
1209
|
+
/** Set initial value template item title
|
|
1210
|
+
* @param title - initial value template item title
|
|
1211
|
+
* @returns initial value template item based on title provided. See {@link InitialValueTemplateItemBuilder}
|
|
1212
|
+
*/
|
|
1213
|
+
title(title) {
|
|
1214
|
+
return this.clone({
|
|
1215
|
+
title
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
/** Get initial value template item title
|
|
1219
|
+
* @returns initial value template item title. See {@link InitialValueTemplateItem}
|
|
1220
|
+
*/
|
|
1221
|
+
getTitle() {
|
|
1222
|
+
return this.spec.title;
|
|
1223
|
+
}
|
|
1224
|
+
/** Set initial value template item description
|
|
1225
|
+
* @param description - initial value template item description
|
|
1226
|
+
* @returns initial value template item builder based on description provided. See {@link InitialValueTemplateItemBuilder}
|
|
1227
|
+
*/
|
|
1228
|
+
description(description) {
|
|
1229
|
+
return this.clone({
|
|
1230
|
+
description
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
/** Get initial value template item description
|
|
1234
|
+
* @returns initial value template item description. See {@link InitialValueTemplateItem}
|
|
1235
|
+
*/
|
|
1236
|
+
getDescription() {
|
|
1237
|
+
return this.spec.description;
|
|
1238
|
+
}
|
|
1239
|
+
/** Set initial value template ID
|
|
1240
|
+
* @param templateId - initial value template item template ID
|
|
1241
|
+
* @returns initial value template item based builder on template ID provided. See {@link InitialValueTemplateItemBuilder}
|
|
1242
|
+
*/
|
|
1243
|
+
templateId(templateId) {
|
|
1244
|
+
const paneId = this.spec.id || templateId;
|
|
1245
|
+
return this.clone({
|
|
1246
|
+
id: paneId,
|
|
1247
|
+
templateId
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
/** Get initial value template item template ID
|
|
1251
|
+
* @returns initial value template item ID. See {@link InitialValueTemplateItem}
|
|
1252
|
+
*/
|
|
1253
|
+
getTemplateId() {
|
|
1254
|
+
return this.spec.templateId;
|
|
1255
|
+
}
|
|
1256
|
+
/** Get initial value template item template parameters
|
|
1257
|
+
* @param parameters - initial value template item parameters
|
|
1258
|
+
* @returns initial value template item builder based on parameters provided. See {@link InitialValueTemplateItemBuilder}
|
|
1259
|
+
*/
|
|
1260
|
+
parameters(parameters) {
|
|
1261
|
+
return this.clone({
|
|
1262
|
+
parameters
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
/** Get initial value template item template parameters
|
|
1266
|
+
* @returns initial value template item parameters. See {@link InitialValueTemplateItem}
|
|
1267
|
+
*/
|
|
1268
|
+
getParameters() {
|
|
1269
|
+
return this.spec.parameters;
|
|
1270
|
+
}
|
|
1271
|
+
/** Serialize initial value template item
|
|
1272
|
+
* @param options - serialization options. See {@link SerializeOptions}
|
|
1273
|
+
* @returns initial value template item object based on the path, index and hint provided in options. See {@link InitialValueTemplateItem}
|
|
1274
|
+
*/
|
|
1275
|
+
serialize({
|
|
1276
|
+
path = [],
|
|
1277
|
+
index,
|
|
1278
|
+
hint
|
|
1279
|
+
} = {
|
|
1280
|
+
path: []
|
|
1281
|
+
}) {
|
|
1282
|
+
if (typeof this.spec.id != "string" || !this.spec.id)
|
|
1283
|
+
throw new SerializeError("`id` is required for initial value template item nodes", path, index, hint).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
1284
|
+
if (!this.spec.templateId)
|
|
1285
|
+
throw new SerializeError("template id (`templateId`) is required for initial value template item nodes", path, this.spec.id, hint).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
1286
|
+
const template = this._context.templates.find((t) => t.id === this.spec.templateId);
|
|
1287
|
+
if (!template)
|
|
1288
|
+
throw new SerializeError("template id (`templateId`) is required for initial value template item nodes", path, this.spec.id, hint).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
1289
|
+
return {
|
|
1290
|
+
id: this.spec.id,
|
|
1291
|
+
templateId: this.spec.id,
|
|
1292
|
+
schemaType: template.schemaType,
|
|
1293
|
+
type: "initialValueTemplateItem",
|
|
1294
|
+
description: this.spec.description || template.description,
|
|
1295
|
+
title: this.spec.title || template.title,
|
|
1296
|
+
subtitle: this.spec.subtitle,
|
|
1297
|
+
icon: this.spec.icon || template.icon,
|
|
1298
|
+
initialDocumentId: this.spec.initialDocumentId,
|
|
1299
|
+
parameters: this.spec.parameters
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
/** Clone generic view builder (allows for options overriding)
|
|
1303
|
+
* @param withSpec - initial value template item builder options. See {@link InitialValueTemplateItemBuilder}
|
|
1304
|
+
* @returns initial value template item builder based on the context and options provided. See {@link InitialValueTemplateItemBuilder}
|
|
1305
|
+
*/
|
|
1306
|
+
clone(withSpec = {}) {
|
|
1307
|
+
const builder = new InitialValueTemplateItemBuilder(this._context);
|
|
1308
|
+
return builder.spec = {
|
|
1309
|
+
...this.spec,
|
|
1310
|
+
...withSpec
|
|
1311
|
+
}, builder;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
function defaultInitialValueTemplateItems(context) {
|
|
1315
|
+
const {
|
|
1316
|
+
schema,
|
|
1317
|
+
getStructureBuilder,
|
|
1318
|
+
templates
|
|
1319
|
+
} = context, typeNames = schema.getTypeNames();
|
|
1320
|
+
return templates.filter((tpl) => !tpl.parameters?.length).sort((a, b) => typeNames.indexOf(a.schemaType) - typeNames.indexOf(b.schemaType)).map((tpl) => getStructureBuilder().initialValueTemplateItem(tpl.id));
|
|
1321
|
+
}
|
|
1322
|
+
function maybeSerializeInitialValueTemplateItem(item, index, path) {
|
|
1323
|
+
return item instanceof InitialValueTemplateItemBuilder ? item.serialize({
|
|
1324
|
+
path,
|
|
1325
|
+
index
|
|
1326
|
+
}) : item;
|
|
1327
|
+
}
|
|
1328
|
+
function menuItemsFromInitialValueTemplateItems(context, templateItems) {
|
|
1329
|
+
const {
|
|
1330
|
+
schema,
|
|
1331
|
+
templates
|
|
1332
|
+
} = context;
|
|
1333
|
+
return templateItems.map((item) => {
|
|
1334
|
+
const template = templates.find((t) => t.id === item.templateId), title = item.title || template?.title || "Create", params = {};
|
|
1335
|
+
template && template.schemaType && (params.type = template.schemaType), item.templateId && (params.template = item.templateId);
|
|
1336
|
+
const intentParams = item.parameters ? [params, item.parameters] : params, schemaType = template && schema.get(template.schemaType), i18n = item.i18n || template?.i18n;
|
|
1337
|
+
let builder = new MenuItemBuilder(context).title(title).icon(template && template.icon || schemaType?.icon || AddIcon).intent({
|
|
1338
|
+
type: "create",
|
|
1339
|
+
params: intentParams
|
|
1340
|
+
});
|
|
1341
|
+
return i18n && (builder = builder.i18n(i18n)), builder.serialize();
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
const DEFAULT_INTENT_HANDLER = /* @__PURE__ */ Symbol("Document type list canHandleIntent"), defaultIntentChecker = (intentName, params, {
|
|
1345
|
+
pane
|
|
1346
|
+
}) => {
|
|
1347
|
+
const isEdit = intentName === "edit", isCreate = intentName === "create", typedSpec = pane, paneFilter = typedSpec.options?.filter || "", paneParams = typedSpec.options?.params || {}, typeNames = typedSpec.schemaTypeName ? [typedSpec.schemaTypeName] : getTypeNamesFromFilter(paneFilter, paneParams), initialValueTemplates = typedSpec.initialValueTemplates || [];
|
|
1348
|
+
return isCreate && params.template ? initialValueTemplates.some((tpl) => tpl.templateId === params.template) : isEdit && params.id && typeNames.includes(params.type) || isCreate && typeNames.includes(params.type);
|
|
1349
|
+
};
|
|
1350
|
+
defaultIntentChecker.identity = DEFAULT_INTENT_HANDLER;
|
|
1351
|
+
const layoutOptions = ["default", "card", "media", "detail", "block"];
|
|
1352
|
+
function noChildResolver() {
|
|
1353
|
+
}
|
|
1354
|
+
const shallowIntentChecker = (intentName, params, {
|
|
1355
|
+
pane,
|
|
1356
|
+
index
|
|
1357
|
+
}) => index <= 1 && defaultIntentChecker(intentName, params, {
|
|
1358
|
+
pane
|
|
1359
|
+
});
|
|
1360
|
+
class GenericListBuilder {
|
|
1361
|
+
/** Check if initial value templates are set */
|
|
1362
|
+
initialValueTemplatesSpecified = !1;
|
|
1363
|
+
/** Generic list option object */
|
|
1364
|
+
spec = {};
|
|
1365
|
+
/** Set generic list ID
|
|
1366
|
+
* @param id - generic list ID
|
|
1367
|
+
* @returns generic list builder based on ID provided.
|
|
1368
|
+
*/
|
|
1369
|
+
id(id) {
|
|
1370
|
+
return this.clone({
|
|
1371
|
+
id
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
/** Get generic list ID
|
|
1375
|
+
* @returns generic list ID
|
|
1376
|
+
*/
|
|
1377
|
+
getId() {
|
|
1378
|
+
return this.spec.id;
|
|
1379
|
+
}
|
|
1380
|
+
/** Set generic list title
|
|
1381
|
+
* @param title - generic list title
|
|
1382
|
+
* @returns generic list builder based on title and ID provided.
|
|
1383
|
+
*/
|
|
1384
|
+
title(title) {
|
|
1385
|
+
return this.clone({
|
|
1386
|
+
title,
|
|
1387
|
+
id: getStructureNodeId(title, this.spec.id)
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
/** Get generic list title
|
|
1391
|
+
* @returns generic list title
|
|
1392
|
+
*/
|
|
1393
|
+
getTitle() {
|
|
1394
|
+
return this.spec.title;
|
|
1395
|
+
}
|
|
1396
|
+
/** Set the i18n key and namespace used to populate the localized title.
|
|
1397
|
+
* @param i18n - the key and namespaced used to populate the localized title.
|
|
1398
|
+
* @returns component builder based on i18n key and ns provided
|
|
1399
|
+
*/
|
|
1400
|
+
i18n(i18n) {
|
|
1401
|
+
return this.clone({
|
|
1402
|
+
i18n
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1405
|
+
/** Get i18n key and namespace used to populate the localized title
|
|
1406
|
+
* @returns the i18n key and namespace used to populate the localized title
|
|
1407
|
+
*/
|
|
1408
|
+
getI18n() {
|
|
1409
|
+
return this.spec.i18n;
|
|
1410
|
+
}
|
|
1411
|
+
/** Set generic list layout
|
|
1412
|
+
* @param defaultLayout - generic list layout key.
|
|
1413
|
+
* @returns generic list builder based on layout provided.
|
|
1414
|
+
*/
|
|
1415
|
+
defaultLayout(defaultLayout) {
|
|
1416
|
+
return this.clone({
|
|
1417
|
+
defaultLayout
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1420
|
+
/** Get generic list layout
|
|
1421
|
+
* @returns generic list layout
|
|
1422
|
+
*/
|
|
1423
|
+
getDefaultLayout() {
|
|
1424
|
+
return this.spec.defaultLayout;
|
|
1425
|
+
}
|
|
1426
|
+
/** Set generic list menu items
|
|
1427
|
+
* @param menuItems - generic list menu items. See {@link MenuItem} and {@link MenuItemBuilder}
|
|
1428
|
+
* @returns generic list builder based on menu items provided.
|
|
1429
|
+
*/
|
|
1430
|
+
menuItems(menuItems) {
|
|
1431
|
+
return this.clone({
|
|
1432
|
+
menuItems
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
/** Get generic list menu items
|
|
1436
|
+
* @returns generic list menu items
|
|
1437
|
+
*/
|
|
1438
|
+
getMenuItems() {
|
|
1439
|
+
return this.spec.menuItems;
|
|
1440
|
+
}
|
|
1441
|
+
/** Set generic list menu item groups
|
|
1442
|
+
* @param menuItemGroups - generic list menu item groups. See {@link MenuItemGroup} and {@link MenuItemGroupBuilder}
|
|
1443
|
+
* @returns generic list builder based on menu item groups provided.
|
|
1444
|
+
*/
|
|
1445
|
+
menuItemGroups(menuItemGroups) {
|
|
1446
|
+
return this.clone({
|
|
1447
|
+
menuItemGroups
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
/** Get generic list menu item groups
|
|
1451
|
+
* @returns generic list menu item groups
|
|
1452
|
+
*/
|
|
1453
|
+
getMenuItemGroups() {
|
|
1454
|
+
return this.spec.menuItemGroups;
|
|
1455
|
+
}
|
|
1456
|
+
/** Set generic list child
|
|
1457
|
+
* @param child - generic list child. See {@link Child}
|
|
1458
|
+
* @returns generic list builder based on child provided (clone).
|
|
1459
|
+
*/
|
|
1460
|
+
child(child) {
|
|
1461
|
+
return this.clone({
|
|
1462
|
+
child
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
/** Get generic list child
|
|
1466
|
+
* @returns generic list child
|
|
1467
|
+
*/
|
|
1468
|
+
getChild() {
|
|
1469
|
+
return this.spec.child;
|
|
1470
|
+
}
|
|
1471
|
+
/** Set generic list can handle intent
|
|
1472
|
+
* @param canHandleIntent - generic list intent checker. See {@link IntentChecker}
|
|
1473
|
+
* @returns generic list builder based on can handle intent provided.
|
|
1474
|
+
*/
|
|
1475
|
+
canHandleIntent(canHandleIntent) {
|
|
1476
|
+
return this.clone({
|
|
1477
|
+
canHandleIntent
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
/** Get generic list can handle intent
|
|
1481
|
+
* @returns generic list can handle intent
|
|
1482
|
+
*/
|
|
1483
|
+
getCanHandleIntent() {
|
|
1484
|
+
return this.spec.canHandleIntent;
|
|
1485
|
+
}
|
|
1486
|
+
/** Set generic list display options
|
|
1487
|
+
* @param enabled - allow / disallow for showing icons
|
|
1488
|
+
* @returns generic list builder based on display options (showIcons) provided.
|
|
1489
|
+
*/
|
|
1490
|
+
showIcons(enabled = !0) {
|
|
1491
|
+
return this.clone({
|
|
1492
|
+
displayOptions: {
|
|
1493
|
+
...this.spec.displayOptions,
|
|
1494
|
+
showIcons: enabled
|
|
1495
|
+
}
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
/** Get generic list display options
|
|
1499
|
+
* @returns generic list display options (specifically showIcons)
|
|
1500
|
+
*/
|
|
1501
|
+
getShowIcons() {
|
|
1502
|
+
return this.spec.displayOptions ? this.spec.displayOptions.showIcons : void 0;
|
|
1503
|
+
}
|
|
1504
|
+
/** Set generic list initial value templates
|
|
1505
|
+
* @param templates - generic list initial value templates. See {@link InitialValueTemplateItemBuilder}
|
|
1506
|
+
* @returns generic list builder based on templates provided.
|
|
1507
|
+
*/
|
|
1508
|
+
initialValueTemplates(templates) {
|
|
1509
|
+
return this.initialValueTemplatesSpecified = !0, this.clone({
|
|
1510
|
+
initialValueTemplates: Array.isArray(templates) ? templates : [templates]
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
/** Get generic list initial value templates
|
|
1514
|
+
* @returns generic list initial value templates
|
|
1515
|
+
*/
|
|
1516
|
+
getInitialValueTemplates() {
|
|
1517
|
+
return this.spec.initialValueTemplates;
|
|
1518
|
+
}
|
|
1519
|
+
/** Serialize generic list
|
|
1520
|
+
* @param options - serialization options. See {@link SerializeOptions}
|
|
1521
|
+
* @returns generic list object based on path provided in options. See {@link GenericList}
|
|
1522
|
+
*/
|
|
1523
|
+
serialize(options = {
|
|
1524
|
+
path: []
|
|
1525
|
+
}) {
|
|
1526
|
+
const id = this.spec.id || "", path = options.path, defaultLayout = this.spec.defaultLayout;
|
|
1527
|
+
if (defaultLayout && !layoutOptions.includes(defaultLayout))
|
|
1528
|
+
throw new SerializeError(`\`layout\` must be one of ${layoutOptions.map((item) => `"${item}"`).join(", ")}`, path, id || options.index, this.spec.title);
|
|
1529
|
+
const initialValueTemplates = (this.spec.initialValueTemplates || []).map((item, i) => maybeSerializeInitialValueTemplateItem(item, i, path));
|
|
1530
|
+
return {
|
|
1531
|
+
id: validateId(id, options.path, id || options.index),
|
|
1532
|
+
title: this.spec.title,
|
|
1533
|
+
i18n: this.spec.i18n,
|
|
1534
|
+
type: "genericList",
|
|
1535
|
+
defaultLayout,
|
|
1536
|
+
child: this.spec.child || noChildResolver,
|
|
1537
|
+
canHandleIntent: this.spec.canHandleIntent || shallowIntentChecker,
|
|
1538
|
+
displayOptions: this.spec.displayOptions,
|
|
1539
|
+
initialValueTemplates,
|
|
1540
|
+
menuItems: (this.spec.menuItems || []).map((item, i) => maybeSerializeMenuItem(item, i, path)),
|
|
1541
|
+
menuItemGroups: (this.spec.menuItemGroups || []).map((item, i) => maybeSerializeMenuItemGroup(item, i, path))
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
/** Clone generic list builder (allows for options overriding)
|
|
1545
|
+
* @param _withSpec - generic list options.
|
|
1546
|
+
* @returns generic list builder.
|
|
1547
|
+
*/
|
|
1548
|
+
}
|
|
1549
|
+
const validateFilter = (spec, options) => {
|
|
1550
|
+
const filter = spec.options?.filter.trim() || "";
|
|
1551
|
+
if (["*", "{"].includes(filter[0]))
|
|
1552
|
+
throw new SerializeError(`\`filter\` cannot start with \`${filter[0]}\` - looks like you are providing a query, not a filter`, options.path, spec.id, spec.title).withHelpUrl(HELP_URL.QUERY_PROVIDED_FOR_FILTER);
|
|
1553
|
+
return filter;
|
|
1554
|
+
}, createDocumentChildResolverForItem = (context) => (itemId, options) => {
|
|
1555
|
+
const parentItem = options.parent, template = options.params?.template ? context.templates.find((tpl) => tpl.id === options.params.template) : void 0, type = template ? template.schemaType : parentItem.schemaTypeName || resolveTypeForDocument(context.getClient, itemId);
|
|
1556
|
+
return Promise.resolve(type).then((schemaType) => schemaType ? context.resolveDocumentNode({
|
|
1557
|
+
schemaType,
|
|
1558
|
+
documentId: itemId
|
|
1559
|
+
}) : new DocumentBuilder(context).id("editor").documentId(itemId).schemaType(""));
|
|
1560
|
+
};
|
|
1561
|
+
class DocumentListBuilder extends GenericListBuilder {
|
|
1562
|
+
/** Document list options. See {@link PartialDocumentList} */
|
|
1563
|
+
constructor(_context, spec) {
|
|
1564
|
+
super(), this._context = _context, this.spec = spec || {}, this.initialValueTemplatesSpecified = !!spec?.initialValueTemplates;
|
|
1565
|
+
}
|
|
1566
|
+
/** Set API version
|
|
1567
|
+
* @param apiVersion - API version
|
|
1568
|
+
* @returns document list builder based on the options and API version provided. See {@link DocumentListBuilder}
|
|
1569
|
+
*/
|
|
1570
|
+
apiVersion(apiVersion) {
|
|
1571
|
+
return this.clone({
|
|
1572
|
+
options: {
|
|
1573
|
+
...this.spec.options || {
|
|
1574
|
+
filter: ""
|
|
1575
|
+
},
|
|
1576
|
+
apiVersion
|
|
1577
|
+
}
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
/** Get API version
|
|
1581
|
+
* @returns API version
|
|
1582
|
+
*/
|
|
1583
|
+
getApiVersion() {
|
|
1584
|
+
return this.spec.options?.apiVersion;
|
|
1585
|
+
}
|
|
1586
|
+
/** Set Document list filter
|
|
1587
|
+
* @param filter - GROQ-filter used to determine which documents to display. Do not support joins, since they operate on individual documents, and will ignore order-clauses and projections. See {@link https://www.sanity.io/docs/realtime-updates}
|
|
1588
|
+
* @returns document list builder based on the options and filter provided. See {@link DocumentListBuilder}
|
|
1589
|
+
*/
|
|
1590
|
+
filter(filter) {
|
|
1591
|
+
return this.clone({
|
|
1592
|
+
options: {
|
|
1593
|
+
...this.spec.options,
|
|
1594
|
+
filter
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1597
|
+
}
|
|
1598
|
+
/** Get Document list filter
|
|
1599
|
+
* @returns filter
|
|
1600
|
+
*/
|
|
1601
|
+
getFilter() {
|
|
1602
|
+
return this.spec.options?.filter;
|
|
1603
|
+
}
|
|
1604
|
+
/** Set Document list schema type name
|
|
1605
|
+
* @param type - schema type name.
|
|
1606
|
+
* @returns document list builder based on the schema type name provided. See {@link DocumentListBuilder}
|
|
1607
|
+
*/
|
|
1608
|
+
schemaType(type) {
|
|
1609
|
+
const schemaTypeName = typeof type == "string" ? type : type.name;
|
|
1610
|
+
return this.clone({
|
|
1611
|
+
schemaTypeName
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
/** Get Document list schema type name
|
|
1615
|
+
* @returns schema type name
|
|
1616
|
+
*/
|
|
1617
|
+
getSchemaType() {
|
|
1618
|
+
return this.spec.schemaTypeName;
|
|
1619
|
+
}
|
|
1620
|
+
/** Set Document list options' parameters
|
|
1621
|
+
* @param params - parameters
|
|
1622
|
+
* @returns document list builder based on the options provided. See {@link DocumentListBuilder}
|
|
1623
|
+
*/
|
|
1624
|
+
params(params) {
|
|
1625
|
+
return this.clone({
|
|
1626
|
+
options: {
|
|
1627
|
+
...this.spec.options || {
|
|
1628
|
+
filter: ""
|
|
1629
|
+
},
|
|
1630
|
+
params
|
|
1631
|
+
}
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
/** Get Document list options' parameters
|
|
1635
|
+
* @returns options
|
|
1636
|
+
*/
|
|
1637
|
+
getParams() {
|
|
1638
|
+
return this.spec.options?.params;
|
|
1639
|
+
}
|
|
1640
|
+
/** Set Document list default ordering
|
|
1641
|
+
* @param ordering - default sort ordering array. See {@link SortOrderingItem}
|
|
1642
|
+
* @returns document list builder based on ordering provided. See {@link DocumentListBuilder}
|
|
1643
|
+
*/
|
|
1644
|
+
defaultOrdering(ordering) {
|
|
1645
|
+
if (!Array.isArray(ordering))
|
|
1646
|
+
throw new Error("`defaultOrdering` must be an array of order clauses");
|
|
1647
|
+
return this.clone({
|
|
1648
|
+
options: {
|
|
1649
|
+
...this.spec.options || {
|
|
1650
|
+
filter: ""
|
|
1651
|
+
},
|
|
1652
|
+
defaultOrdering: ordering
|
|
1653
|
+
}
|
|
1654
|
+
});
|
|
1655
|
+
}
|
|
1656
|
+
/** Get Document list default ordering
|
|
1657
|
+
* @returns default ordering. See {@link SortOrderingItem}
|
|
1658
|
+
*/
|
|
1659
|
+
getDefaultOrdering() {
|
|
1660
|
+
return this.spec.options?.defaultOrdering;
|
|
1661
|
+
}
|
|
1662
|
+
/** Serialize Document list
|
|
1663
|
+
* @param options - serialization options. See {@link SerializeOptions}
|
|
1664
|
+
* @returns document list object based on path provided in options. See {@link DocumentList}
|
|
1665
|
+
*/
|
|
1666
|
+
serialize(options = {
|
|
1667
|
+
path: []
|
|
1668
|
+
}) {
|
|
1669
|
+
if (typeof this.spec.id != "string" || !this.spec.id)
|
|
1670
|
+
throw new SerializeError("`id` is required for document lists", options.path, options.index, this.spec.title).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
1671
|
+
if (!this.spec.options || !this.spec.options.filter)
|
|
1672
|
+
throw new SerializeError("`filter` is required for document lists", options.path, this.spec.id, this.spec.title).withHelpUrl(HELP_URL.FILTER_REQUIRED);
|
|
1673
|
+
return this.spec.options?.filter !== "_type == $type" && this.spec.options.filter && !this.spec.options.apiVersion && console.warn(`No apiVersion specified for document type list with custom filter: \`${this.spec.options.filter}\`. This will be required in the future. See %s for more info.`, generateHelpUrl(HELP_URL.API_VERSION_REQUIRED_FOR_CUSTOM_FILTER)), {
|
|
1674
|
+
...super.serialize(options),
|
|
1675
|
+
type: "documentList",
|
|
1676
|
+
schemaTypeName: this.spec.schemaTypeName,
|
|
1677
|
+
child: this.spec.child || createDocumentChildResolverForItem(this._context),
|
|
1678
|
+
options: {
|
|
1679
|
+
...this.spec.options,
|
|
1680
|
+
// @todo: make specifying .apiVersion required when using custom (non-simple) filters in v4
|
|
1681
|
+
apiVersion: this.spec.options.apiVersion || DEFAULT_STUDIO_CLIENT_OPTIONS.apiVersion,
|
|
1682
|
+
filter: validateFilter(this.spec, options)
|
|
1683
|
+
}
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
/** Clone Document list builder (allows for options overriding)
|
|
1687
|
+
* @param withSpec - override document list spec. See {@link PartialDocumentList}
|
|
1688
|
+
* @returns document list builder. See {@link DocumentListBuilder}
|
|
1689
|
+
*/
|
|
1690
|
+
clone(withSpec) {
|
|
1691
|
+
const builder = new DocumentListBuilder(this._context);
|
|
1692
|
+
return builder.spec = {
|
|
1693
|
+
...this.spec,
|
|
1694
|
+
...withSpec
|
|
1695
|
+
}, this.initialValueTemplatesSpecified || (builder.spec.initialValueTemplates = inferInitialValueTemplates(this._context, builder.spec)), builder.spec.schemaTypeName || (builder.spec.schemaTypeName = inferTypeName(builder.spec)), builder;
|
|
1696
|
+
}
|
|
1697
|
+
/** Get Document list spec
|
|
1698
|
+
* @returns document list spec. See {@link PartialDocumentList}
|
|
1699
|
+
*/
|
|
1700
|
+
getSpec() {
|
|
1701
|
+
return this.spec;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
function inferInitialValueTemplates(context, spec) {
|
|
1705
|
+
const {
|
|
1706
|
+
document
|
|
1707
|
+
} = context, {
|
|
1708
|
+
schemaTypeName,
|
|
1709
|
+
options
|
|
1710
|
+
} = spec, {
|
|
1711
|
+
filter,
|
|
1712
|
+
params
|
|
1713
|
+
} = options || {
|
|
1714
|
+
filter: "",
|
|
1715
|
+
params: {}
|
|
1716
|
+
}, typeNames = schemaTypeName ? [schemaTypeName] : Array.from(new Set(getTypeNamesFromFilter(filter, params)));
|
|
1717
|
+
if (typeNames.length !== 0)
|
|
1718
|
+
return typeNames.flatMap((schemaType) => document.resolveNewDocumentOptions({
|
|
1719
|
+
type: "structure",
|
|
1720
|
+
schemaType
|
|
1721
|
+
})).map((option) => ({
|
|
1722
|
+
...option,
|
|
1723
|
+
icon: AddIcon
|
|
1724
|
+
}));
|
|
1725
|
+
}
|
|
1726
|
+
function inferTypeName(spec) {
|
|
1727
|
+
const {
|
|
1728
|
+
options
|
|
1729
|
+
} = spec, {
|
|
1730
|
+
filter,
|
|
1731
|
+
params
|
|
1732
|
+
} = options || {
|
|
1733
|
+
filter: "",
|
|
1734
|
+
params: {}
|
|
1735
|
+
}, typeNames = getTypeNamesFromFilter(filter, params);
|
|
1736
|
+
return typeNames.length === 1 ? typeNames[0] : void 0;
|
|
1737
|
+
}
|
|
1738
|
+
function getTypeNamesFromFilter(filter, params = {}) {
|
|
1739
|
+
let typeNames = getTypeNamesFromEqualityFilter(filter, params);
|
|
1740
|
+
return typeNames.length === 0 && (typeNames = getTypeNamesFromInTypesFilter(filter, params)), typeNames;
|
|
1741
|
+
}
|
|
1742
|
+
function getTypeNamesFromEqualityFilter(filter, params = {}) {
|
|
1743
|
+
const pattern = /\b_type\s*==\s*(['"].*?['"]|\$.*?(?:\s|$))|\B(['"].*?['"]|\$.*?(?:\s|$))\s*==\s*_type/g, matches = [];
|
|
1744
|
+
let match;
|
|
1745
|
+
for (; (match = pattern.exec(filter)) !== null; )
|
|
1746
|
+
matches.push(match[1] || match[2]);
|
|
1747
|
+
return matches.map((candidate) => ((candidate[0] === "$" ? params[candidate.slice(1)] : candidate) || "").trim().replace(/^["']|["']$/g, "")).filter(Boolean);
|
|
1748
|
+
}
|
|
1749
|
+
function getTypeNamesFromInTypesFilter(filter, params = {}) {
|
|
1750
|
+
const pattern = /\b_type\s+in\s+\[(.*?)\]/, matches = filter.match(pattern);
|
|
1751
|
+
return matches ? matches[1].split(/,\s*/).map((match) => match.trim().replace(/^["']+|["']+$/g, "")).map((item) => item[0] === "$" ? params[item.slice(1)] : item).filter(Boolean) : [];
|
|
1752
|
+
}
|
|
1753
|
+
const getArgType = (thing) => thing instanceof ListBuilder ? "ListBuilder" : isPromise(thing) ? "Promise" : Array.isArray(thing) ? "array" : typeof thing, isListItem = (item) => item.type === "listItem", defaultCanHandleIntent = (intentName, params, context) => (context.pane.items || []).filter(isDocumentListItem).some((item) => item.schemaType.name === params.type && item._id === params.id) || shallowIntentChecker(intentName, params, context), resolveChildForItem = (itemId, options) => {
|
|
1754
|
+
const target = (options.parent.items.filter(isListItem).find((item) => item.id === itemId) || {
|
|
1755
|
+
child: void 0
|
|
1756
|
+
}).child;
|
|
1757
|
+
return !target || typeof target != "function" ? target : typeof target == "function" ? target(itemId, options) : target;
|
|
1758
|
+
};
|
|
1759
|
+
function maybeSerializeListItem(item, index, path) {
|
|
1760
|
+
if (item instanceof ListItemBuilder)
|
|
1761
|
+
return item.serialize({
|
|
1762
|
+
path,
|
|
1763
|
+
index
|
|
1764
|
+
});
|
|
1765
|
+
if (item instanceof DividerBuilder)
|
|
1766
|
+
return item.serialize();
|
|
1767
|
+
const listItem = item;
|
|
1768
|
+
if (listItem && listItem.type === "divider")
|
|
1769
|
+
return item;
|
|
1770
|
+
if (!listItem || listItem.type !== "listItem") {
|
|
1771
|
+
const gotWhat = listItem && listItem.type || getArgType(listItem), helpText = gotWhat === "array" ? " - did you forget to spread (...moreItems)?" : "";
|
|
1772
|
+
throw new SerializeError(`List items must be of type "listItem", got "${gotWhat}"${helpText}`, path, index).withHelpUrl(HELP_URL.INVALID_LIST_ITEM);
|
|
1773
|
+
}
|
|
1774
|
+
return item;
|
|
1775
|
+
}
|
|
1776
|
+
function isPromise(thing) {
|
|
1777
|
+
return isRecord(thing) && typeof thing.then == "function";
|
|
1778
|
+
}
|
|
1779
|
+
class ListBuilder extends GenericListBuilder {
|
|
1780
|
+
/** buildable list option object. See {@link BuildableList} */
|
|
1781
|
+
constructor(_context, spec) {
|
|
1782
|
+
super(), this._context = _context, this.spec = spec || {}, this.initialValueTemplatesSpecified = !!(spec && spec.initialValueTemplates);
|
|
1783
|
+
}
|
|
1784
|
+
/**
|
|
1785
|
+
* Set list builder based on items provided
|
|
1786
|
+
* @param items - list items. See {@link ListItemBuilder}, {@link ListItem} and {@link Divider}
|
|
1787
|
+
* @returns list builder based on items provided. See {@link ListBuilder}
|
|
1788
|
+
*/
|
|
1789
|
+
items(items) {
|
|
1790
|
+
return this.clone({
|
|
1791
|
+
items
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
/** Get list builder items
|
|
1795
|
+
* @returns list items. See {@link BuildableList}
|
|
1796
|
+
*/
|
|
1797
|
+
getItems() {
|
|
1798
|
+
return this.spec.items;
|
|
1799
|
+
}
|
|
1800
|
+
/** Serialize list builder
|
|
1801
|
+
* @param options - serialization options. See {@link SerializeOptions}
|
|
1802
|
+
* @returns list based on path in options. See {@link List}
|
|
1803
|
+
*/
|
|
1804
|
+
serialize(options = {
|
|
1805
|
+
path: []
|
|
1806
|
+
}) {
|
|
1807
|
+
const id = this.spec.id;
|
|
1808
|
+
if (typeof id != "string" || !id)
|
|
1809
|
+
throw new SerializeError("`id` is required for lists", options.path, options.index).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
1810
|
+
const items = typeof this.spec.items > "u" ? [] : this.spec.items;
|
|
1811
|
+
if (!Array.isArray(items))
|
|
1812
|
+
throw new SerializeError("`items` must be an array of items", options.path, options.index).withHelpUrl(HELP_URL.LIST_ITEMS_MUST_BE_ARRAY);
|
|
1813
|
+
const path = (options.path || []).concat(id), serializedItems = items.map((item, index) => maybeSerializeListItem(item, index, path)), dupes = serializedItems.filter((val, i) => find(serializedItems, {
|
|
1814
|
+
id: val.id
|
|
1815
|
+
}, i + 1));
|
|
1816
|
+
if (dupes.length > 0) {
|
|
1817
|
+
const dupeIds = dupes.map((item) => item.id).slice(0, 5), dupeDesc = dupes.length > 5 ? `${dupeIds.join(", ")}...` : dupeIds.join(", ");
|
|
1818
|
+
throw new SerializeError(`List items with same ID found (${dupeDesc})`, options.path, options.index).withHelpUrl(HELP_URL.LIST_ITEM_IDS_MUST_BE_UNIQUE);
|
|
1819
|
+
}
|
|
1820
|
+
return {
|
|
1821
|
+
...super.serialize(options),
|
|
1822
|
+
type: "list",
|
|
1823
|
+
canHandleIntent: this.spec.canHandleIntent || defaultCanHandleIntent,
|
|
1824
|
+
child: this.spec.child || resolveChildForItem,
|
|
1825
|
+
items: serializedItems
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Clone list builder and return new list builder based on context and spec provided
|
|
1830
|
+
* @param withSpec - list options. See {@link BuildableList}
|
|
1831
|
+
* @returns new list builder based on context and spec provided. See {@link ListBuilder}
|
|
1832
|
+
*/
|
|
1833
|
+
clone(withSpec) {
|
|
1834
|
+
const builder = new ListBuilder(this._context);
|
|
1835
|
+
return builder.spec = {
|
|
1836
|
+
...this.spec,
|
|
1837
|
+
...withSpec
|
|
1838
|
+
}, builder;
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
class ListItemBuilder {
|
|
1842
|
+
/** List item option object. See {@link PartialListItem} */
|
|
1843
|
+
constructor(_context, spec) {
|
|
1844
|
+
this._context = _context, this.spec = spec || {};
|
|
1845
|
+
}
|
|
1846
|
+
/**
|
|
1847
|
+
* Set list item ID
|
|
1848
|
+
* @returns list item builder based on ID provided. See {@link ListItemBuilder}
|
|
1849
|
+
*/
|
|
1850
|
+
id(id) {
|
|
1851
|
+
return this.clone({
|
|
1852
|
+
id
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
/**
|
|
1856
|
+
* Get list item ID
|
|
1857
|
+
* @returns list item ID. See {@link PartialListItem}
|
|
1858
|
+
*/
|
|
1859
|
+
getId() {
|
|
1860
|
+
return this.spec.id;
|
|
1861
|
+
}
|
|
1862
|
+
/**
|
|
1863
|
+
* Set list item title
|
|
1864
|
+
* @returns list item builder based on title provided. See {@link ListItemBuilder}
|
|
1865
|
+
*/
|
|
1866
|
+
title(title) {
|
|
1867
|
+
return this.clone({
|
|
1868
|
+
title,
|
|
1869
|
+
id: getStructureNodeId(title, this.spec.id)
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Get list item title
|
|
1874
|
+
* @returns list item title. See {@link PartialListItem}
|
|
1875
|
+
*/
|
|
1876
|
+
getTitle() {
|
|
1877
|
+
return this.spec.title;
|
|
1878
|
+
}
|
|
1879
|
+
/** Set the i18n key and namespace used to populate the localized title.
|
|
1880
|
+
* @param i18n - the key and namespaced used to populate the localized title.
|
|
1881
|
+
* @returns component builder based on i18n key and ns provided
|
|
1882
|
+
*/
|
|
1883
|
+
i18n(i18n) {
|
|
1884
|
+
return this.clone({
|
|
1885
|
+
i18n
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
/** Get i18n key and namespace used to populate the localized title
|
|
1889
|
+
* @returns the i18n key and namespace used to populate the localized title
|
|
1890
|
+
*/
|
|
1891
|
+
getI18n() {
|
|
1892
|
+
return this.spec.i18n;
|
|
1893
|
+
}
|
|
1894
|
+
/**
|
|
1895
|
+
* Set list item icon
|
|
1896
|
+
* @returns list item builder based on icon provided. See {@link ListItemBuilder}
|
|
1897
|
+
*/
|
|
1898
|
+
icon(icon) {
|
|
1899
|
+
return this.clone({
|
|
1900
|
+
icon
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
/**
|
|
1904
|
+
* Set if list item should show icon
|
|
1905
|
+
* @returns list item builder based on showIcon provided. See {@link ListItemBuilder}
|
|
1906
|
+
*/
|
|
1907
|
+
showIcon(enabled = !0) {
|
|
1908
|
+
return this.clone({
|
|
1909
|
+
displayOptions: {
|
|
1910
|
+
...this.spec.displayOptions,
|
|
1911
|
+
showIcon: enabled
|
|
1912
|
+
}
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
/**
|
|
1916
|
+
* Check if list item should show icon
|
|
1917
|
+
* @returns true if it should show the icon, false if not, undefined if not set
|
|
1918
|
+
*/
|
|
1919
|
+
getShowIcon() {
|
|
1920
|
+
return this.spec.displayOptions ? this.spec.displayOptions.showIcon : void 0;
|
|
1921
|
+
}
|
|
1922
|
+
/**
|
|
1923
|
+
*Get list item icon
|
|
1924
|
+
* @returns list item icon. See {@link PartialListItem}
|
|
1925
|
+
*/
|
|
1926
|
+
getIcon() {
|
|
1927
|
+
return this.spec.icon;
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* Set list item child
|
|
1931
|
+
* @param child - list item child. See {@link UnserializedListItemChild}
|
|
1932
|
+
* @returns list item builder based on child provided. See {@link ListItemBuilder}
|
|
1933
|
+
*/
|
|
1934
|
+
child(child) {
|
|
1935
|
+
return this.clone({
|
|
1936
|
+
child
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1939
|
+
/**
|
|
1940
|
+
* Get list item child
|
|
1941
|
+
* @returns list item child. See {@link PartialListItem}
|
|
1942
|
+
*/
|
|
1943
|
+
getChild() {
|
|
1944
|
+
return this.spec.child;
|
|
1945
|
+
}
|
|
1946
|
+
/**
|
|
1947
|
+
* Set list item schema type
|
|
1948
|
+
* @param schemaType - list item schema type. See {@link SchemaType}
|
|
1949
|
+
* @returns list item builder based on schema type provided. See {@link ListItemBuilder}
|
|
1950
|
+
*/
|
|
1951
|
+
schemaType(schemaType) {
|
|
1952
|
+
return this.clone({
|
|
1953
|
+
schemaType
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
/**
|
|
1957
|
+
* Get list item schema type
|
|
1958
|
+
* @returns list item schema type. See {@link PartialListItem}
|
|
1959
|
+
*/
|
|
1960
|
+
getSchemaType() {
|
|
1961
|
+
const schemaType = this.spec.schemaType;
|
|
1962
|
+
return typeof schemaType == "string" ? this._context.schema.get(schemaType) : this.spec.schemaType;
|
|
1963
|
+
}
|
|
1964
|
+
/** Serialize list item builder
|
|
1965
|
+
* @param options - serialization options. See {@link ListItemSerializeOptions}
|
|
1966
|
+
* @returns list item node based on path provided in options. See {@link ListItem}
|
|
1967
|
+
*/
|
|
1968
|
+
serialize(options = {
|
|
1969
|
+
path: []
|
|
1970
|
+
}) {
|
|
1971
|
+
const {
|
|
1972
|
+
id,
|
|
1973
|
+
title,
|
|
1974
|
+
child
|
|
1975
|
+
} = this.spec;
|
|
1976
|
+
if (typeof id != "string" || !id)
|
|
1977
|
+
throw new SerializeError("`id` is required for list items", options.path, options.index).withHelpUrl(HELP_URL.ID_REQUIRED);
|
|
1978
|
+
if (!options.titleIsOptional && (typeof title != "string" || !title))
|
|
1979
|
+
throw new SerializeError("`title` is required for list items", options.path, id).withHelpUrl(HELP_URL.TITLE_REQUIRED);
|
|
1980
|
+
let schemaType = this.spec.schemaType;
|
|
1981
|
+
if (typeof schemaType == "string") {
|
|
1982
|
+
const type = this._context.schema.get(schemaType);
|
|
1983
|
+
if (!type)
|
|
1984
|
+
throw new SerializeError(`Could not find type "${schemaType}" in schema`, options.path, id).withHelpUrl(HELP_URL.SCHEMA_TYPE_NOT_FOUND);
|
|
1985
|
+
schemaType = type;
|
|
1986
|
+
}
|
|
1987
|
+
const serializeOptions = {
|
|
1988
|
+
path: options.path.concat(id),
|
|
1989
|
+
hint: "child"
|
|
1990
|
+
};
|
|
1991
|
+
let listChild = child instanceof ComponentBuilder || child instanceof DocumentListBuilder || child instanceof DocumentBuilder || child instanceof ListBuilder ? child.serialize(serializeOptions) : child;
|
|
1992
|
+
if (typeof listChild == "function") {
|
|
1993
|
+
const originalChild = listChild;
|
|
1994
|
+
listChild = (itemId, childOptions) => originalChild(itemId, {
|
|
1995
|
+
...childOptions,
|
|
1996
|
+
serializeOptions
|
|
1997
|
+
});
|
|
1998
|
+
}
|
|
1999
|
+
return {
|
|
2000
|
+
...this.spec,
|
|
2001
|
+
id: validateId(id, options.path, options.index),
|
|
2002
|
+
schemaType,
|
|
2003
|
+
child: listChild,
|
|
2004
|
+
title,
|
|
2005
|
+
type: "listItem"
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
2008
|
+
/** Clone list item builder
|
|
2009
|
+
* @param withSpec - partial list item options. See {@link PartialListItem}
|
|
2010
|
+
* @returns list item builder based on context and spec provided. See {@link ListItemBuilder}
|
|
2011
|
+
*/
|
|
2012
|
+
clone(withSpec) {
|
|
2013
|
+
const builder = new ListItemBuilder(this._context);
|
|
2014
|
+
return builder.spec = {
|
|
2015
|
+
...this.spec,
|
|
2016
|
+
...withSpec
|
|
2017
|
+
}, builder;
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
const createDefaultChildResolver = (context, spec) => (documentId) => {
|
|
2021
|
+
const schemaType = spec.schemaType && (typeof spec.schemaType == "string" ? spec.schemaType : spec.schemaType.name);
|
|
2022
|
+
return schemaType ? context.resolveDocumentNode({
|
|
2023
|
+
schemaType,
|
|
2024
|
+
documentId
|
|
2025
|
+
}) : new DocumentBuilder(context).id("documentEditor").documentId(documentId);
|
|
2026
|
+
};
|
|
2027
|
+
class DocumentListItemBuilder extends ListItemBuilder {
|
|
2028
|
+
/** Document list options. See {@link PartialDocumentListItem} */
|
|
2029
|
+
constructor(_context, spec) {
|
|
2030
|
+
super(_context, spec), this._context = _context, this.spec = spec || {};
|
|
2031
|
+
}
|
|
2032
|
+
/**
|
|
2033
|
+
* Serialize document list item
|
|
2034
|
+
* @param options - serialization options. See {@link SerializeOptions}
|
|
2035
|
+
* @returns document list item object based on path provided in options. See {@link DocumentListItem}
|
|
2036
|
+
*/
|
|
2037
|
+
serialize(options = {
|
|
2038
|
+
path: []
|
|
2039
|
+
}) {
|
|
2040
|
+
const spec = super.serialize({
|
|
2041
|
+
...options,
|
|
2042
|
+
titleIsOptional: !0
|
|
2043
|
+
});
|
|
2044
|
+
if (!spec.schemaType)
|
|
2045
|
+
throw new SerializeError("`schemaType` is required for document list items", options.path, options.index).withHelpUrl(HELP_URL.SCHEMA_TYPE_REQUIRED);
|
|
2046
|
+
const child = spec.child || createDefaultChildResolver(this._context, spec);
|
|
2047
|
+
return {
|
|
2048
|
+
...spec,
|
|
2049
|
+
child,
|
|
2050
|
+
schemaType: spec.schemaType,
|
|
2051
|
+
_id: spec.id
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
/** Clone Document list item builder (allows for options overriding)
|
|
2055
|
+
* @param withSpec - Document list item builder options. See {@link PartialDocumentListItem}
|
|
2056
|
+
* @returns document list item builder. See {@link DocumentListItemBuilder}
|
|
2057
|
+
*/
|
|
2058
|
+
clone(withSpec) {
|
|
2059
|
+
const builder = new DocumentListItemBuilder(this._context);
|
|
2060
|
+
return builder.spec = {
|
|
2061
|
+
...this.spec,
|
|
2062
|
+
...withSpec
|
|
2063
|
+
}, builder;
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
function isDocumentListItem(item) {
|
|
2067
|
+
return isRecord(item) && typeof item.schemaType < "u" && typeof item._id == "string";
|
|
2068
|
+
}
|
|
2069
|
+
class DocumentTypeListBuilder extends DocumentListBuilder {
|
|
2070
|
+
/** Document list options. See {@link PartialDocumentList} */
|
|
2071
|
+
constructor(_context, spec) {
|
|
2072
|
+
super(_context), this._context = _context, this.spec = spec || {};
|
|
2073
|
+
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Set Document type list child
|
|
2076
|
+
* @param child - Child component. See {@link Child}
|
|
2077
|
+
* @returns document type list builder based on child component provided without default intent handler. See {@link DocumentTypeListBuilder}
|
|
2078
|
+
*/
|
|
2079
|
+
child(child) {
|
|
2080
|
+
return this.cloneWithoutDefaultIntentHandler({
|
|
2081
|
+
child
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2084
|
+
/** Clone Document type list builder (allows for options overriding)
|
|
2085
|
+
* @param withSpec - Document type list builder options. See {@link PartialDocumentList}
|
|
2086
|
+
* @returns document type list builder. See {@link DocumentTypeListBuilder}
|
|
2087
|
+
*/
|
|
2088
|
+
clone(withSpec) {
|
|
2089
|
+
const parent = super.clone(withSpec), builder = new DocumentTypeListBuilder(this._context);
|
|
2090
|
+
return builder.spec = {
|
|
2091
|
+
...this.spec,
|
|
2092
|
+
...parent.getSpec(),
|
|
2093
|
+
...withSpec
|
|
2094
|
+
}, builder;
|
|
2095
|
+
}
|
|
2096
|
+
/** Clone Document type list builder (allows for options overriding) and remove default intent handler
|
|
2097
|
+
* @param withSpec - Document type list builder options. See {@link PartialDocumentList}
|
|
2098
|
+
* @returns document type list builder without default intent handler. See {@link DocumentTypeListBuilder}
|
|
2099
|
+
*/
|
|
2100
|
+
cloneWithoutDefaultIntentHandler(withSpec) {
|
|
2101
|
+
const parent = super.clone(withSpec), builder = new DocumentTypeListBuilder(this._context), canHandleIntent = this.spec.canHandleIntent, override = canHandleIntent && canHandleIntent.identity === DEFAULT_INTENT_HANDLER ? {
|
|
2102
|
+
canHandleIntent: void 0
|
|
2103
|
+
} : {};
|
|
2104
|
+
return builder.spec = {
|
|
2105
|
+
...parent.getSpec(),
|
|
2106
|
+
...this.spec,
|
|
2107
|
+
...withSpec,
|
|
2108
|
+
...override
|
|
2109
|
+
}, builder;
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
const BUNDLED_DOC_TYPES = ["sanity.imageAsset", "sanity.fileAsset"];
|
|
2113
|
+
function isBundledDocType(typeName) {
|
|
2114
|
+
return BUNDLED_DOC_TYPES.includes(typeName);
|
|
2115
|
+
}
|
|
2116
|
+
function isDocumentType(schemaType) {
|
|
2117
|
+
return schemaType.type?.name === "document";
|
|
2118
|
+
}
|
|
2119
|
+
function isList(collection) {
|
|
2120
|
+
return collection.type === "list";
|
|
2121
|
+
}
|
|
2122
|
+
function getDocumentTypes({
|
|
2123
|
+
schema
|
|
2124
|
+
}) {
|
|
2125
|
+
return schema.getTypeNames().filter((n) => {
|
|
2126
|
+
const schemaType = schema.get(n);
|
|
2127
|
+
return schemaType && isDocumentType(schemaType);
|
|
2128
|
+
}).filter((n) => !isBundledDocType(n));
|
|
2129
|
+
}
|
|
2130
|
+
function getDocumentTypeListItems(context) {
|
|
2131
|
+
return getDocumentTypes(context).map((typeName) => getDocumentTypeListItem(context, typeName));
|
|
2132
|
+
}
|
|
2133
|
+
function getDocumentTypeListItem(context, typeName) {
|
|
2134
|
+
const {
|
|
2135
|
+
schema
|
|
2136
|
+
} = context, type = schema.get(typeName);
|
|
2137
|
+
if (!type)
|
|
2138
|
+
throw new Error(`Schema type with name "${typeName}" not found`);
|
|
2139
|
+
const title = type.title || startCase(typeName);
|
|
2140
|
+
return new ListItemBuilder(context).id(typeName).title(title).schemaType(type).child((id, childContext) => {
|
|
2141
|
+
const parent = childContext.parent, parentItem = isList(parent) ? parent.items.find((item) => item.id === id) : null;
|
|
2142
|
+
let list = getDocumentTypeList(context, typeName);
|
|
2143
|
+
return parentItem && parentItem.title && (list = list.title(parentItem.title)), list;
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
function getDocumentTypeList(context, typeNameOrSpec) {
|
|
2147
|
+
const {
|
|
2148
|
+
schema,
|
|
2149
|
+
resolveDocumentNode
|
|
2150
|
+
} = context, schemaType = typeof typeNameOrSpec == "string" ? typeNameOrSpec : typeNameOrSpec.schemaType, typeName = typeof schemaType == "string" ? schemaType : schemaType.name, spec = typeof typeNameOrSpec == "string" ? {} : typeNameOrSpec, type = schema.get(typeName);
|
|
2151
|
+
if (!type)
|
|
2152
|
+
throw new Error(`Schema type with name "${typeName}" not found`);
|
|
2153
|
+
const title = type.title || startCase(typeName);
|
|
2154
|
+
return new DocumentTypeListBuilder(context).id(spec.id || typeName).title(spec.title || title).filter("_type == $type").params({
|
|
2155
|
+
type: typeName
|
|
2156
|
+
}).schemaType(type).defaultOrdering(DEFAULT_SELECTED_ORDERING_OPTION.by).menuItemGroups(spec.menuItemGroups || [{
|
|
2157
|
+
id: "sorting",
|
|
2158
|
+
title: "Sort",
|
|
2159
|
+
i18n: {
|
|
2160
|
+
title: {
|
|
2161
|
+
key: "menu-item-groups.actions-group",
|
|
2162
|
+
ns: structureLocaleNamespace
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
}, {
|
|
2166
|
+
id: "layout",
|
|
2167
|
+
title: "Layout",
|
|
2168
|
+
i18n: {
|
|
2169
|
+
title: {
|
|
2170
|
+
key: "menu-item-groups.layout-group",
|
|
2171
|
+
ns: structureLocaleNamespace
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
}, {
|
|
2175
|
+
id: "actions",
|
|
2176
|
+
title: "Actions",
|
|
2177
|
+
i18n: {
|
|
2178
|
+
title: {
|
|
2179
|
+
key: "menu-item-groups.sorting-group",
|
|
2180
|
+
ns: structureLocaleNamespace
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
}]).child(spec.child || ((documentId) => resolveDocumentNode({
|
|
2184
|
+
schemaType: typeName,
|
|
2185
|
+
documentId
|
|
2186
|
+
}))).canHandleIntent(spec.canHandleIntent || defaultIntentChecker).menuItems(spec.menuItems || [
|
|
2187
|
+
// Create new (from action button) will be added in serialization step of GenericList
|
|
2188
|
+
// Sort by <Y>
|
|
2189
|
+
...getOrderingMenuItemsForSchemaType(context, type),
|
|
2190
|
+
// Display as <Z>
|
|
2191
|
+
new MenuItemBuilder(context).group("layout").i18n({
|
|
2192
|
+
title: {
|
|
2193
|
+
key: "menu-items.layout.compact-view",
|
|
2194
|
+
ns: structureLocaleNamespace
|
|
2195
|
+
}
|
|
2196
|
+
}).title("Compact view").icon(StackCompactIcon).action("setLayout").params({
|
|
2197
|
+
layout: "default"
|
|
2198
|
+
}),
|
|
2199
|
+
new MenuItemBuilder(context).group("layout").i18n({
|
|
2200
|
+
title: {
|
|
2201
|
+
key: "menu-items.layout.detailed-view",
|
|
2202
|
+
ns: structureLocaleNamespace
|
|
2203
|
+
}
|
|
2204
|
+
}).title("Detailed view").icon(StackIcon).action("setLayout").params({
|
|
2205
|
+
layout: "detail"
|
|
2206
|
+
})
|
|
2207
|
+
// Create new (from menu) will be added in serialization step of GenericList
|
|
2208
|
+
]);
|
|
2209
|
+
}
|
|
2210
|
+
function hasIcon(schemaType) {
|
|
2211
|
+
return !schemaType || typeof schemaType == "string" ? !1 : !!schemaType.icon;
|
|
2212
|
+
}
|
|
2213
|
+
function getDefaultStructure(context) {
|
|
2214
|
+
const items = getDocumentTypeListItems(context);
|
|
2215
|
+
return new ListBuilder(context).id("__root__").title("Content").i18n({
|
|
2216
|
+
title: {
|
|
2217
|
+
key: "default-definition.content-title",
|
|
2218
|
+
ns: structureLocaleNamespace
|
|
2219
|
+
}
|
|
2220
|
+
}).items(items).showIcons(items.some((item) => hasIcon(item.getSchemaType())));
|
|
2221
|
+
}
|
|
2222
|
+
function createStructureBuilder({
|
|
2223
|
+
defaultDocumentNode,
|
|
2224
|
+
source,
|
|
2225
|
+
perspectiveStack
|
|
2226
|
+
}) {
|
|
2227
|
+
const configContext = getConfigContextFromSource(source), context = {
|
|
2228
|
+
...source,
|
|
2229
|
+
getStructureBuilder: () => structureBuilder,
|
|
2230
|
+
resolveDocumentNode: (options) => {
|
|
2231
|
+
let builder = defaultDocumentNode?.(structureBuilder, {
|
|
2232
|
+
...options,
|
|
2233
|
+
...configContext
|
|
2234
|
+
}) || new DocumentBuilder(context);
|
|
2235
|
+
return builder.getId() || (builder = builder.id("documentEditor")), options.documentId && (builder = builder.documentId(getPublishedId(options.documentId))), builder.schemaType(options.schemaType);
|
|
2236
|
+
},
|
|
2237
|
+
perspectiveStack
|
|
2238
|
+
}, structureBuilder = {
|
|
2239
|
+
defaults: () => getDefaultStructure(context),
|
|
2240
|
+
documentTypeList: (...args) => getDocumentTypeList(context, ...args),
|
|
2241
|
+
documentTypeListItem: (...args) => getDocumentTypeListItem(context, ...args),
|
|
2242
|
+
documentTypeListItems: (...args) => getDocumentTypeListItems(context, ...args),
|
|
2243
|
+
document: (...args) => new DocumentBuilder(context, ...args),
|
|
2244
|
+
documentWithInitialValueTemplate: (...args) => documentFromEditorWithInitialValue(context, ...args),
|
|
2245
|
+
defaultDocument: context.resolveDocumentNode,
|
|
2246
|
+
list: (...args) => new ListBuilder(context, ...args),
|
|
2247
|
+
listItem: (...args) => new ListItemBuilder(context, ...args),
|
|
2248
|
+
menuItem: (...args) => new MenuItemBuilder(context, ...args),
|
|
2249
|
+
menuItemGroup: (...args) => new MenuItemGroupBuilder(context, ...args),
|
|
2250
|
+
menuItemsFromInitialValueTemplateItems: (...args) => menuItemsFromInitialValueTemplateItems(context, ...args),
|
|
2251
|
+
documentList: (...args) => new DocumentListBuilder(context, ...args),
|
|
2252
|
+
documentListItem: (...args) => new DocumentListItemBuilder(context, ...args),
|
|
2253
|
+
orderingMenuItem: (...args) => getOrderingMenuItem(context, ...args),
|
|
2254
|
+
orderingMenuItemsForType: (...args) => getOrderingMenuItemsForSchemaType(context, ...args),
|
|
2255
|
+
editor: (...args) => documentFromEditor(context, ...args),
|
|
2256
|
+
defaultInitialValueTemplateItems: (...args) => defaultInitialValueTemplateItems(context, ...args),
|
|
2257
|
+
initialValueTemplateItem: (templateId, parameters) => new InitialValueTemplateItemBuilder(context, {
|
|
2258
|
+
id: templateId,
|
|
2259
|
+
parameters,
|
|
2260
|
+
templateId
|
|
2261
|
+
}),
|
|
2262
|
+
component: (spec) => isValidElementType(spec) ? new ComponentBuilder().component(spec) : new ComponentBuilder(spec),
|
|
2263
|
+
divider: (spec) => new DividerBuilder(spec),
|
|
2264
|
+
view: views,
|
|
2265
|
+
context
|
|
2266
|
+
};
|
|
2267
|
+
return structureBuilder;
|
|
2268
|
+
}
|
|
2269
|
+
function StructureToolProvider(t0) {
|
|
2270
|
+
const $ = c(26), {
|
|
2271
|
+
defaultDocumentNode,
|
|
2272
|
+
structure: resolveStructure,
|
|
2273
|
+
children
|
|
2274
|
+
} = t0, [layoutCollapsed, setLayoutCollapsed] = useState(!1), source = useSource(), configContext = useConfigContextFromSource(source), documentStore = useDocumentStore(), {
|
|
2275
|
+
perspectiveStack
|
|
2276
|
+
} = usePerspective();
|
|
2277
|
+
let t1;
|
|
2278
|
+
$[0] !== defaultDocumentNode || $[1] !== perspectiveStack || $[2] !== source ? (t1 = createStructureBuilder({
|
|
2279
|
+
defaultDocumentNode,
|
|
2280
|
+
source,
|
|
2281
|
+
perspectiveStack
|
|
2282
|
+
}), $[0] = defaultDocumentNode, $[1] = perspectiveStack, $[2] = source, $[3] = t1) : t1 = $[3];
|
|
2283
|
+
const S = t1;
|
|
2284
|
+
let t2;
|
|
2285
|
+
bb0: {
|
|
2286
|
+
if (resolveStructure) {
|
|
2287
|
+
let t33;
|
|
2288
|
+
$[4] !== S || $[5] !== configContext || $[6] !== documentStore || $[7] !== perspectiveStack || $[8] !== resolveStructure ? (t33 = resolveStructure(S, {
|
|
2289
|
+
...configContext,
|
|
2290
|
+
documentStore,
|
|
2291
|
+
perspectiveStack
|
|
2292
|
+
}), $[4] = S, $[5] = configContext, $[6] = documentStore, $[7] = perspectiveStack, $[8] = resolveStructure, $[9] = t33) : t33 = $[9], t2 = t33;
|
|
2293
|
+
break bb0;
|
|
2294
|
+
}
|
|
2295
|
+
let t32;
|
|
2296
|
+
$[10] !== S ? (t32 = S.defaults(), $[10] = S, $[11] = t32) : t32 = $[11], t2 = t32;
|
|
2297
|
+
}
|
|
2298
|
+
const rootPaneNode = t2, t3 = !layoutCollapsed, t4 = !layoutCollapsed, t5 = !layoutCollapsed, t6 = !layoutCollapsed;
|
|
2299
|
+
let t7;
|
|
2300
|
+
$[12] !== layoutCollapsed || $[13] !== t3 || $[14] !== t4 || $[15] !== t5 || $[16] !== t6 ? (t7 = {
|
|
2301
|
+
backButton: layoutCollapsed,
|
|
2302
|
+
resizablePanes: t3,
|
|
2303
|
+
reviewChanges: t4,
|
|
2304
|
+
splitPanes: t5,
|
|
2305
|
+
splitViews: t6
|
|
2306
|
+
}, $[12] = layoutCollapsed, $[13] = t3, $[14] = t4, $[15] = t5, $[16] = t6, $[17] = t7) : t7 = $[17];
|
|
2307
|
+
const features = t7;
|
|
2308
|
+
let t8;
|
|
2309
|
+
$[18] !== S.context || $[19] !== features || $[20] !== layoutCollapsed || $[21] !== rootPaneNode ? (t8 = {
|
|
2310
|
+
features,
|
|
2311
|
+
layoutCollapsed,
|
|
2312
|
+
setLayoutCollapsed,
|
|
2313
|
+
rootPaneNode,
|
|
2314
|
+
structureContext: S.context
|
|
2315
|
+
}, $[18] = S.context, $[19] = features, $[20] = layoutCollapsed, $[21] = rootPaneNode, $[22] = t8) : t8 = $[22];
|
|
2316
|
+
const structureTool = t8;
|
|
2317
|
+
let t9;
|
|
2318
|
+
return $[23] !== children || $[24] !== structureTool ? (t9 = /* @__PURE__ */ jsx(StructureToolContext.Provider, { value: structureTool, children }), $[23] = children, $[24] = structureTool, $[25] = t9) : t9 = $[25], t9;
|
|
2319
|
+
}
|
|
2320
|
+
export {
|
|
2321
|
+
ComponentBuilder,
|
|
2322
|
+
ComponentViewBuilder,
|
|
2323
|
+
DEFAULT_INTENT_HANDLER,
|
|
2324
|
+
DocumentBuilder,
|
|
2325
|
+
DocumentListBuilder,
|
|
2326
|
+
DocumentListItemBuilder,
|
|
2327
|
+
DocumentTypeListBuilder,
|
|
2328
|
+
FormViewBuilder,
|
|
2329
|
+
GenericListBuilder,
|
|
2330
|
+
GenericViewBuilder,
|
|
2331
|
+
HELP_URL,
|
|
2332
|
+
InitialValueTemplateItemBuilder,
|
|
2333
|
+
ListBuilder,
|
|
2334
|
+
ListItemBuilder,
|
|
2335
|
+
MenuItemBuilder,
|
|
2336
|
+
MenuItemGroupBuilder,
|
|
2337
|
+
SerializeError,
|
|
2338
|
+
StructureToolProvider,
|
|
2339
|
+
component,
|
|
2340
|
+
createStructureBuilder,
|
|
2341
|
+
defaultInitialValueTemplateItems,
|
|
2342
|
+
defaultIntentChecker,
|
|
2343
|
+
documentFromEditor,
|
|
2344
|
+
documentFromEditorWithInitialValue,
|
|
2345
|
+
form,
|
|
2346
|
+
getExtendedProjection,
|
|
2347
|
+
getOrderingMenuItem,
|
|
2348
|
+
getOrderingMenuItemsForSchemaType,
|
|
2349
|
+
getTypeNamesFromFilter,
|
|
2350
|
+
isDocumentListItem,
|
|
2351
|
+
maybeSerializeInitialValueTemplateItem,
|
|
2352
|
+
maybeSerializeMenuItem,
|
|
2353
|
+
maybeSerializeMenuItemGroup,
|
|
2354
|
+
maybeSerializeView,
|
|
2355
|
+
menuItemsFromInitialValueTemplateItems,
|
|
2356
|
+
shallowIntentChecker,
|
|
2357
|
+
structureLocaleNamespace,
|
|
2358
|
+
structureUsEnglishLocaleBundle
|
|
2359
|
+
};
|
|
2360
|
+
//# sourceMappingURL=StructureToolProvider.js.map
|