@sanity/orderable-document-list 1.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs DELETED
@@ -1,581 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var sanity = require("sanity"), lexorank = require("lexorank"), icons = require("@sanity/icons"), jsxRuntime = require("react/jsx-runtime"), react = require("react"), ui = require("@sanity/ui"), sanityPluginUtils = require("sanity-plugin-utils"), dnd = require("@hello-pangea/dnd"), structure = require("sanity/structure");
4
- const ORDER_FIELD_NAME = "orderRank", API_VERSION = "v2025-06-27";
5
- function parseOrderRank(value, fallback) {
6
- if (typeof value != "string")
7
- return console.warn("[orderable-document-list] Invalid orderRank value (expected string):", value), fallback;
8
- try {
9
- return lexorank.LexoRank.parse(value);
10
- } catch (err) {
11
- return console.warn(
12
- "[orderable-document-list] Failed to parse orderRank value:",
13
- value,
14
- "Error:",
15
- err instanceof Error ? err.message : String(err)
16
- ), fallback;
17
- }
18
- }
19
- function initialRank(compareRankValue = "", newItemPosition = "after") {
20
- const compareRank = parseOrderRank(compareRankValue, lexorank.LexoRank.min());
21
- return (newItemPosition === "before" ? compareRank.genPrev().genPrev() : compareRank.genNext().genNext()).toString();
22
- }
23
- const orderRankField = (config) => {
24
- if (!config?.type)
25
- throw new Error(
26
- `
27
- type must be provided.
28
- Example: orderRankField({type: 'category'})
29
- `
30
- );
31
- const { type, newItemPosition = "after", ...rest } = config;
32
- return sanity.defineField({
33
- title: "Order Rank",
34
- readOnly: !0,
35
- hidden: !0,
36
- ...rest,
37
- name: ORDER_FIELD_NAME,
38
- type: "string",
39
- initialValue: async (p, { getClient }) => {
40
- const direction = newItemPosition === "before" ? "asc" : "desc", lastDocOrderRank = await getClient({ apiVersion: API_VERSION }).fetch(
41
- `*[_type == $type]|order(@[$order] ${direction})[0][$order]`,
42
- { type, order: ORDER_FIELD_NAME },
43
- { tag: "orderable-document-list.last-doc-order-rank" }
44
- );
45
- return initialRank(lastDocOrderRank, newItemPosition);
46
- }
47
- });
48
- }, orderRankOrdering = {
49
- title: "Ordered",
50
- name: "ordered",
51
- by: [{ field: ORDER_FIELD_NAME, direction: "asc" }]
52
- }, OrderableContext = react.createContext({});
53
- function Document({
54
- doc,
55
- increment,
56
- entities,
57
- index,
58
- isFirst,
59
- isLast,
60
- dragBadge
61
- }) {
62
- const { showIncrements } = react.useContext(OrderableContext), schema = sanity.useSchema(), router = structure.usePaneRouter(), versionsInfo = sanity.useDocumentVersionInfo(doc._id), { ChildLink, groupIndex, routerPanesState } = router, currentDoc = routerPanesState[groupIndex + 1]?.[0]?.id || !1, pressed = currentDoc === doc._id || currentDoc === doc._id.replace("drafts.", ""), selected = pressed && routerPanesState.length === groupIndex + 2, Link = react.useMemo(
63
- () => function(linkProps) {
64
- return /* @__PURE__ */ jsxRuntime.jsx(ChildLink, { ...linkProps, childId: doc._id });
65
- },
66
- [ChildLink, doc._id]
67
- ), tooltip = /* @__PURE__ */ jsxRuntime.jsx(
68
- sanity.DocumentStatus,
69
- {
70
- draft: versionsInfo.draft,
71
- published: versionsInfo.published,
72
- versions: versionsInfo.versions
73
- }
74
- );
75
- return /* @__PURE__ */ jsxRuntime.jsx(
76
- sanity.PreviewCard,
77
- {
78
- __unstable_focusRing: !0,
79
- as: Link,
80
- "data-as": "a",
81
- "data-ui": "PaneItem",
82
- radius: 2,
83
- pressed,
84
- selected,
85
- sizing: "border",
86
- tabIndex: -1,
87
- tone: "inherit",
88
- width: "100%",
89
- flex: 1,
90
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", children: [
91
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingX: 2, style: { flexShrink: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 2, children: /* @__PURE__ */ jsxRuntime.jsx(icons.DragHandleIcon, { cursor: "grab" }) }) }),
92
- showIncrements && /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { style: { flexShrink: 0 }, align: "center", gap: 1, paddingRight: 1, children: [
93
- /* @__PURE__ */ jsxRuntime.jsx(
94
- ui.Button,
95
- {
96
- padding: 2,
97
- mode: "ghost",
98
- onClick: () => increment(index, index + -1, doc._id, entities),
99
- disabled: isFirst,
100
- icon: icons.ChevronUpIcon
101
- }
102
- ),
103
- /* @__PURE__ */ jsxRuntime.jsx(
104
- ui.Button,
105
- {
106
- padding: 2,
107
- mode: "ghost",
108
- disabled: isLast,
109
- onClick: () => increment(index, index + 1, doc._id, entities),
110
- icon: icons.ChevronDownIcon
111
- }
112
- )
113
- ] }),
114
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: { width: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { flex: 1, align: "center", justify: "space-between", paddingRight: 3, children: [
115
- /* @__PURE__ */ jsxRuntime.jsx(
116
- sanity.Preview,
117
- {
118
- layout: "default",
119
- value: doc,
120
- schemaType: schema.get(doc._type)
121
- }
122
- ),
123
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { content: tooltip, portal: !0, placement: "right", boundaryElement: null, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(
124
- sanity.DocumentStatusIndicator,
125
- {
126
- draft: versionsInfo.draft,
127
- published: versionsInfo.published,
128
- versions: versionsInfo.versions
129
- }
130
- ) }) })
131
- ] }) }),
132
- dragBadge && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { tone: "default", marginRight: 4, radius: 5, children: /* @__PURE__ */ jsxRuntime.jsx(ui.AvatarCounter, { count: dragBadge }) })
133
- ] })
134
- }
135
- );
136
- }
137
- function lexicographicalSort(a, b) {
138
- return !a[ORDER_FIELD_NAME] || !b[ORDER_FIELD_NAME] ? 0 : a[ORDER_FIELD_NAME] < b[ORDER_FIELD_NAME] ? -1 : a[ORDER_FIELD_NAME] > b[ORDER_FIELD_NAME] ? 1 : 0;
139
- }
140
- const reorderDocuments = ({
141
- entities,
142
- selectedIds,
143
- source,
144
- destination
145
- }) => {
146
- const startIndex = source.index, endIndex = destination.index, isMovingUp = startIndex > endIndex, selectedItems = entities.filter((item) => selectedIds.includes(item._id)), message = [
147
- "Moved",
148
- selectedItems.length === 1 ? "1 document" : `${selectedItems.length} documents`,
149
- isMovingUp ? "up" : "down",
150
- "from position",
151
- `${startIndex + 1} to ${endIndex + 1}`
152
- ].join(" "), { all, selected } = entities.reduce(
153
- (acc, cur, curIndex) => {
154
- if (selectedIds.includes(cur._id))
155
- return { all: acc.all, selected: acc.selected };
156
- if (curIndex === endIndex) {
157
- const prevIndex = curIndex - 1, prevRank = parseOrderRank(entities[prevIndex]?.[ORDER_FIELD_NAME], lexorank.LexoRank.min()), curRank = parseOrderRank(entities[curIndex][ORDER_FIELD_NAME], lexorank.LexoRank.min()), nextIndex = curIndex + 1, nextRank = parseOrderRank(entities[nextIndex]?.[ORDER_FIELD_NAME], lexorank.LexoRank.max());
158
- let betweenRank = isMovingUp ? prevRank.between(curRank) : curRank.between(nextRank);
159
- for (let selectedIndex = 0; selectedIndex < selectedItems.length; selectedIndex += 1)
160
- selectedItems[selectedIndex][ORDER_FIELD_NAME] = betweenRank.toString(), betweenRank = isMovingUp ? betweenRank.between(curRank) : betweenRank.between(nextRank);
161
- return {
162
- // The `all` array gets sorted by order field later anyway
163
- // so that this probably isn't necessary ¯\_(ツ)_/¯
164
- all: isMovingUp ? [...acc.all, ...selectedItems, cur] : [...acc.all, cur, ...selectedItems],
165
- selected: selectedItems
166
- };
167
- }
168
- return { all: [...acc.all, cur], selected: acc.selected };
169
- },
170
- { all: [], selected: [] }
171
- ), patches = selected.flatMap((doc) => {
172
- const docPatches = [
173
- [
174
- doc._id,
175
- {
176
- set: {
177
- [ORDER_FIELD_NAME]: doc[ORDER_FIELD_NAME]
178
- }
179
- }
180
- ]
181
- ];
182
- return doc._id.startsWith("drafts.") && doc.hasPublished && docPatches.push([
183
- doc._id.replace("drafts.", ""),
184
- {
185
- set: {
186
- [ORDER_FIELD_NAME]: doc[ORDER_FIELD_NAME]
187
- }
188
- }
189
- ]), docPatches;
190
- });
191
- return { newOrder: all.sort(lexicographicalSort), patches, message };
192
- };
193
- function useSanityClient() {
194
- const { perspectiveStack } = sanity.usePerspective();
195
- return sanity.useClient({ apiVersion: API_VERSION }).withConfig({ perspective: perspectiveStack });
196
- }
197
- const getItemStyle = (draggableStyle, itemIsUpdating) => ({
198
- userSelect: "none",
199
- transition: "opacity 500ms ease-in-out",
200
- opacity: itemIsUpdating ? 0.2 : 1,
201
- pointerEvents: itemIsUpdating ? "none" : void 0,
202
- ...draggableStyle
203
- }), cardTone = (settings) => {
204
- const { isDuplicate, isGhosting, isDragging, isSelected } = settings;
205
- if (isGhosting) return "transparent";
206
- if (isDragging || isSelected) return "primary";
207
- if (isDuplicate) return "caution";
208
- };
209
- function DraggableList({ data, listIsUpdating, setListIsUpdating }) {
210
- const toast = ui.useToast(), router = structure.usePaneRouter(), { groupIndex, routerPanesState } = router, currentDoc = routerPanesState[groupIndex + 1]?.[0]?.id || !1, [orderedData, setOrderedData] = react.useState(data);
211
- react.useEffect(() => {
212
- listIsUpdating || setOrderedData(data);
213
- }, [data]);
214
- const [draggingId, setDraggingId] = react.useState(""), [selectedIds, setSelectedIds] = react.useState(currentDoc ? [currentDoc] : []), clearSelected = react.useCallback(() => setSelectedIds([]), [setSelectedIds]), handleSelect = react.useCallback(
215
- (clickedId, index, nativeEvent) => {
216
- const isSelected = selectedIds.includes(clickedId), selectMultiple = nativeEvent.shiftKey, selectAdditional = navigator.appVersion.indexOf("Win") !== -1 ? nativeEvent.ctrlKey : nativeEvent.metaKey;
217
- let updatedIds = [];
218
- if (!selectMultiple && !selectAdditional)
219
- return setSelectedIds([clickedId]);
220
- if (selectMultiple && nativeEvent.preventDefault(), selectMultiple && !isSelected) {
221
- const lastSelectedId = selectedIds[selectedIds.length - 1], lastSelectedIndex = orderedData.findIndex((item) => item._id === lastSelectedId), firstSelected = index < lastSelectedIndex ? index : lastSelectedIndex, lastSelected = index > lastSelectedIndex ? index : lastSelectedIndex, betweenIds = orderedData.filter((item, itemIndex) => itemIndex > firstSelected && itemIndex < lastSelected).map((item) => item._id);
222
- updatedIds = [...selectedIds, ...betweenIds, clickedId];
223
- } else isSelected ? updatedIds = selectedIds.filter((id) => id !== clickedId) : updatedIds = [...selectedIds, clickedId];
224
- return setSelectedIds(updatedIds);
225
- },
226
- [setSelectedIds, orderedData, selectedIds]
227
- ), client = useSanityClient(), transactPatches = react.useCallback(
228
- async (patches, message) => {
229
- const transaction = client.transaction();
230
- patches.forEach(([docId, ops]) => transaction.patch(docId, ops));
231
- try {
232
- const updated = await transaction.commit({
233
- visibility: "async",
234
- tag: "orderable-document-list.reorder"
235
- });
236
- clearSelected(), setDraggingId(""), setListIsUpdating(!1), toast.push({
237
- title: `${updated.results.length === 1 ? "1 document" : `${updated.results.length} documents`} reordered`,
238
- status: "success",
239
- description: message
240
- });
241
- } catch {
242
- setDraggingId(""), setListIsUpdating(!1), toast.push({
243
- title: "Reordering failed",
244
- status: "error"
245
- });
246
- }
247
- },
248
- [client, setDraggingId, clearSelected, setListIsUpdating, toast]
249
- ), handleDragEnd = react.useCallback(
250
- (result, entities) => {
251
- setDraggingId("");
252
- const { source, destination, draggableId } = result ?? {};
253
- if (source?.index === destination?.index || !entities?.length || !draggableId) return;
254
- const effectedIds = selectedIds?.length ? selectedIds : [draggableId];
255
- if (!effectedIds?.length) return;
256
- setListIsUpdating(!0), setSelectedIds(effectedIds);
257
- const { newOrder, patches, message } = reorderDocuments({
258
- entities,
259
- selectedIds: effectedIds,
260
- source,
261
- destination
262
- });
263
- newOrder?.length && setOrderedData(newOrder), patches?.length && transactPatches(patches, message);
264
- },
265
- [selectedIds, setDraggingId, setSelectedIds, transactPatches, setListIsUpdating]
266
- ), handleDragStart = react.useCallback(
267
- (start) => {
268
- const id = start.draggableId;
269
- selectedIds.includes(id) || clearSelected(), setDraggingId(id);
270
- },
271
- [selectedIds, clearSelected, setDraggingId]
272
- ), incrementIndex = react.useCallback(
273
- (shiftFrom, shiftTo, id, entities) => handleDragEnd({
274
- draggableId: id,
275
- source: { index: shiftFrom },
276
- destination: { index: shiftTo }
277
- }, entities),
278
- [handleDragEnd]
279
- ), onWindowKeyDown = react.useCallback(
280
- (event) => {
281
- event.key === "Escape" && clearSelected();
282
- },
283
- [clearSelected]
284
- );
285
- react.useEffect(() => (window.addEventListener("keydown", onWindowKeyDown), () => {
286
- window.removeEventListener("keydown", onWindowKeyDown);
287
- }), [onWindowKeyDown]);
288
- const duplicateOrders = react.useMemo(() => {
289
- if (!orderedData.length) return [];
290
- const orderField = orderedData.map((item) => item[ORDER_FIELD_NAME]);
291
- return orderField.filter((item, index) => orderField.indexOf(item) !== index);
292
- }, [orderedData]), onDragEnd = react.useCallback(
293
- (result) => handleDragEnd(result, orderedData),
294
- [orderedData, handleDragEnd]
295
- );
296
- return /* @__PURE__ */ jsxRuntime.jsx(dnd.DragDropContext, { onDragStart: handleDragStart, onDragEnd, children: /* @__PURE__ */ jsxRuntime.jsx(dnd.Droppable, { droppableId: "documentSortZone", children: (provided) => /* @__PURE__ */ jsxRuntime.jsxs("div", { ...provided.droppableProps, ref: provided.innerRef, children: [
297
- orderedData.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
298
- dnd.Draggable,
299
- {
300
- draggableId: item._id,
301
- index,
302
- children: (innerProvided, innerSnapshot) => {
303
- const isSelected = selectedIds.includes(item._id), isDragging = innerSnapshot.isDragging, isGhosting = !!(!isDragging && draggingId && isSelected), isUpdating = listIsUpdating && isSelected, isDisabled = !item[ORDER_FIELD_NAME], isDuplicate = duplicateOrders.includes(item[ORDER_FIELD_NAME]), tone = cardTone({ isDuplicate, isGhosting, isDragging, isSelected }), selectedCount = selectedIds.length, dragBadge = isDragging && selectedCount > 1 ? selectedCount : !1;
304
- return /* @__PURE__ */ jsxRuntime.jsx(
305
- "div",
306
- {
307
- ref: innerProvided.innerRef,
308
- ...innerProvided.draggableProps,
309
- ...innerProvided.dragHandleProps,
310
- style: isDisabled ? { opacity: 0.2, pointerEvents: "none" } : getItemStyle(innerProvided.draggableProps.style, isUpdating),
311
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingBottom: 1, children: /* @__PURE__ */ jsxRuntime.jsx(
312
- ui.Card,
313
- {
314
- tone,
315
- shadow: isDragging ? 2 : void 0,
316
- radius: 2,
317
- onClick: (e) => handleSelect(item._id, index, e.nativeEvent),
318
- children: /* @__PURE__ */ jsxRuntime.jsx(
319
- Document,
320
- {
321
- doc: item,
322
- entities: orderedData,
323
- increment: incrementIndex,
324
- index,
325
- isFirst: index === 0,
326
- isLast: index === orderedData.length - 1,
327
- dragBadge
328
- }
329
- )
330
- }
331
- ) })
332
- }
333
- );
334
- }
335
- },
336
- `${item._id}-${item[ORDER_FIELD_NAME]}`
337
- )),
338
- provided.placeholder
339
- ] }) }) });
340
- }
341
- const DEFAULT_PARAMS = {};
342
- function getDocumentQuery({
343
- type,
344
- filter,
345
- params = DEFAULT_PARAMS,
346
- currentVersion
347
- }) {
348
- let perspectiveFilter = null;
349
- currentVersion === "published" ? perspectiveFilter = '!(_id in path("drafts.**")) && !(_id in path("versions.**"))' : currentVersion === "drafts" ? perspectiveFilter = `
350
- (_id in path("drafts.**") || (!(_id in path("drafts.**")) && !(_id in path("versions.**"))))
351
- ` : perspectiveFilter = '(sanity::partOfRelease($currentVersion) || (!(_id in path("drafts.**")) && !(_id in path("versions.**"))) || (_id in path("drafts.**")))';
352
- const querySelect = `*[_type == $type ${perspectiveFilter ? `&& ${perspectiveFilter}` : ""}${filter ? `&& ${filter}` : ""}]`, queryOrder = "|order(@[$order] asc)", queryFields = `{_id, _type, ${ORDER_FIELD_NAME}}`, query = `${querySelect}${queryOrder}${queryFields}`, queryParams = {
353
- ...params,
354
- type,
355
- order: ORDER_FIELD_NAME,
356
- ...currentVersion && { currentVersion }
357
- };
358
- return { query, queryParams };
359
- }
360
- const isVersionForCurrentPerspective = (document, perspectiveName, publishedId) => document._id && sanity.isVersionId(document._id) && sanity.getVersionFromId(document._id) === perspectiveName && sanity.getPublishedId(document._id) === publishedId, getFilteredDedupedDocs = (documents, perspectiveName) => {
361
- const flatDocuments = documents.flat();
362
- return flatDocuments.reduce((acc, cur) => {
363
- if (!cur._id)
364
- return acc;
365
- if (sanity.isVersionId(cur._id)) {
366
- const isCorrectVersion = sanity.getVersionFromId(cur._id) === perspectiveName;
367
- return perspectiveName && perspectiveName !== "drafts" && perspectiveName !== "published" && isCorrectVersion ? [...acc, cur] : acc;
368
- }
369
- if (perspectiveName === "published")
370
- return sanity.isPublishedId(cur._id) ? [...acc, cur] : acc;
371
- if (!sanity.isDraftId(cur._id)) {
372
- const publishedId = sanity.getPublishedId(cur._id), countNrPublished = JSON.stringify(flatDocuments).match(`/${publishedId}/g`), hasMatchingVersion = perspectiveName && perspectiveName !== "drafts" && perspectiveName !== "published" ? flatDocuments.some(
373
- (doc) => isVersionForCurrentPerspective(doc, perspectiveName, publishedId)
374
- ) : !1, hasDraft = flatDocuments.some((doc) => doc._id === `drafts.${cur._id}`);
375
- return hasMatchingVersion || hasDraft || countNrPublished ? acc : [...acc, cur];
376
- }
377
- if (perspectiveName && perspectiveName !== "drafts" && perspectiveName !== "published") {
378
- const baseId = sanity.getPublishedId(cur._id);
379
- if (flatDocuments.some(
380
- (doc) => isVersionForCurrentPerspective(doc, perspectiveName, baseId)
381
- ))
382
- return acc;
383
- }
384
- return cur.hasPublished = flatDocuments.some((doc) => doc._id === cur._id.replace("drafts.", "")), [...acc, cur];
385
- }, []);
386
- };
387
- function DocumentListQuery(props) {
388
- const [listIsUpdating, setListIsUpdating] = react.useState(!1), [data, setData] = react.useState([]), { query, queryParams } = getDocumentQuery(props), {
389
- data: _queryData,
390
- loading,
391
- error
392
- } = sanityPluginUtils.useListeningQuery(query, {
393
- params: queryParams,
394
- initialValue: []
395
- }), queryData = _queryData;
396
- react.useEffect(() => {
397
- if (queryData) {
398
- const filteredDocuments = getFilteredDedupedDocs(queryData, props.currentVersion);
399
- setData(filteredDocuments);
400
- } else
401
- setData([]);
402
- }, [queryData]);
403
- const unorderedDataCount = react.useMemo(
404
- () => data?.length ? data.filter((doc) => !doc[ORDER_FIELD_NAME]).length : 0,
405
- [data]
406
- );
407
- return loading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { style: { width: "100%", height: "100%" }, align: "center", justify: "center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {}) }) : error ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 2, children: /* @__PURE__ */ jsxRuntime.jsx(sanityPluginUtils.Feedback, { tone: "critical", title: "There was an error", description: "Please try again later" }) }) : !data || data?.length == 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", direction: "column", height: "fill", justify: "center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { width: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingX: 4, paddingY: 5, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { align: "center", muted: !0, children: "No documents of this type" }) }) }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 1, style: { overflow: "auto", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { padding: 2, children: [
408
- unorderedDataCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
409
- sanityPluginUtils.Feedback,
410
- {
411
- tone: "caution",
412
- description: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
413
- unorderedDataCount,
414
- "/",
415
- data?.length,
416
- " documents have no order. Select",
417
- " ",
418
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Reset Order" }),
419
- " from the menu above to fix."
420
- ] })
421
- }
422
- ) }),
423
- /* @__PURE__ */ jsxRuntime.jsx(
424
- DraggableList,
425
- {
426
- data,
427
- listIsUpdating,
428
- setListIsUpdating
429
- }
430
- )
431
- ] }) });
432
- }
433
- function DocumentListWrapper({
434
- type,
435
- showIncrements,
436
- resetOrderTransaction,
437
- filter,
438
- params,
439
- currentVersion
440
- }) {
441
- const toast = ui.useToast(), schema = sanity.useSchema();
442
- react.useEffect(() => {
443
- resetOrderTransaction?.title && resetOrderTransaction?.status && toast.push(resetOrderTransaction);
444
- }, [resetOrderTransaction, toast]);
445
- const schemaIsInvalid = react.useMemo(() => {
446
- if (!type)
447
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
448
- "No ",
449
- /* @__PURE__ */ jsxRuntime.jsx("code", { children: "type" }),
450
- " was configured"
451
- ] });
452
- const typeSchema = schema.get(type);
453
- return typeSchema ? !("fields" in typeSchema) || !typeSchema.fields.some((field) => field?.name === ORDER_FIELD_NAME) ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
454
- "Schema ",
455
- /* @__PURE__ */ jsxRuntime.jsx("code", { children: type }),
456
- " must have an ",
457
- /* @__PURE__ */ jsxRuntime.jsx("code", { children: ORDER_FIELD_NAME }),
458
- " field of type",
459
- " ",
460
- /* @__PURE__ */ jsxRuntime.jsx("code", { children: "string" })
461
- ] }) : "fields" in typeSchema && typeSchema.fields.some(
462
- (field) => field?.name === ORDER_FIELD_NAME && field?.type?.name !== "string"
463
- ) ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
464
- /* @__PURE__ */ jsxRuntime.jsx("code", { children: ORDER_FIELD_NAME }),
465
- " field on Schema ",
466
- /* @__PURE__ */ jsxRuntime.jsx("code", { children: type }),
467
- " must be",
468
- " ",
469
- /* @__PURE__ */ jsxRuntime.jsx("code", { children: "string" }),
470
- " type"
471
- ] }) : "" : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
472
- "Schema ",
473
- /* @__PURE__ */ jsxRuntime.jsx("code", { children: type }),
474
- " not found"
475
- ] });
476
- }, [type, schema]);
477
- return schemaIsInvalid ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 2, children: /* @__PURE__ */ jsxRuntime.jsx(sanityPluginUtils.Feedback, { description: schemaIsInvalid, tone: "caution" }) }) : /* @__PURE__ */ jsxRuntime.jsx(OrderableContext.Provider, { value: { showIncrements }, children: /* @__PURE__ */ jsxRuntime.jsx(
478
- DocumentListQuery,
479
- {
480
- type,
481
- filter,
482
- params,
483
- currentVersion
484
- }
485
- ) });
486
- }
487
- async function resetOrder(params) {
488
- const { client, currentVersion, ...queryProps } = params, { query, queryParams } = getDocumentQuery({ ...queryProps, currentVersion }), documents = await client.fetch(query, queryParams, {
489
- tag: "orderable-document-list.reset-order"
490
- });
491
- if (documents.length === 0)
492
- return null;
493
- let aLexoRank = lexorank.LexoRank.min();
494
- return documents.map((doc) => doc._id).reduce((trx, documentId) => (aLexoRank = aLexoRank.genNext().genNext(), trx.patch(documentId, {
495
- set: { [ORDER_FIELD_NAME]: aLexoRank.toString() }
496
- })), client.transaction()).commit({
497
- visibility: "async",
498
- tag: "orderable-document-list.reset-order"
499
- });
500
- }
501
- class OrderableDocumentList extends react.Component {
502
- constructor(props) {
503
- super(props), this.state = {
504
- showIncrements: !1,
505
- resetOrderTransaction: {}
506
- };
507
- }
508
- actionHandlers = {
509
- showIncrements: () => {
510
- this.setState((state) => ({
511
- showIncrements: !state.showIncrements
512
- }));
513
- },
514
- resetOrder: async () => {
515
- this.setState(() => ({
516
- resetOrderTransaction: {
517
- status: "info",
518
- title: "Reordering started...",
519
- closable: !0
520
- }
521
- }));
522
- const update = await resetOrder(this.props.options), reorderWasSuccessful = update?.results?.length;
523
- this.setState(() => ({
524
- resetOrderTransaction: {
525
- status: reorderWasSuccessful ? "success" : "info",
526
- title: reorderWasSuccessful ? `Reordered ${update.results.length === 1 ? "Document" : "Documents"}` : "Reordering failed",
527
- closable: !0
528
- }
529
- }));
530
- }
531
- };
532
- render() {
533
- const type = this?.props?.options?.type;
534
- return type ? /* @__PURE__ */ jsxRuntime.jsx(
535
- DocumentListWrapper,
536
- {
537
- filter: this?.props?.options?.filter,
538
- params: this?.props?.options?.params,
539
- type,
540
- showIncrements: this.state.showIncrements,
541
- resetOrderTransaction: this.state.resetOrderTransaction,
542
- currentVersion: this?.props?.options?.currentVersion
543
- }
544
- ) : null;
545
- }
546
- }
547
- function orderableDocumentListDeskItem(config) {
548
- if (!config?.type || !config.context || !config.S)
549
- throw new Error(`
550
- type, context and S (StructureBuilder) must be provided.
551
- context and S are available when configuring structure.
552
- Example: orderableDocumentListDeskItem({type: 'category'})
553
- `);
554
- const { type, filter, menuItems = [], createIntent, params, title, icon, id, context, S } = config, { schema, getClient } = context, perspectiveStack = context.perspectiveStack || [], client = getClient({ apiVersion: API_VERSION }), currentVersion = perspectiveStack[0], listTitle = title ?? `Orderable ${type}`, listId = id ?? `orderable-${type}`, listIcon = icon ?? icons.SortIcon, typeTitle = schema.get(type)?.title ?? type;
555
- return createIntent !== !1 && menuItems.push(
556
- S.menuItem().title(`Create new ${typeTitle}`).intent({ type: "create", params: { type } }).serialize()
557
- ), S.listItem().title(listTitle).id(listId).icon(listIcon).schemaType(type).child(
558
- Object.assign(
559
- S.documentTypeList(type).canHandleIntent(() => !!createIntent).serialize(),
560
- {
561
- // Prevents the component from re-rendering when switching documents
562
- __preserveInstance: !0,
563
- // Prevents the component from NOT re-rendering when switching listItems
564
- key: listId,
565
- type: "component",
566
- component: OrderableDocumentList,
567
- options: { type, filter, params, client, currentVersion },
568
- menuItems: [
569
- ...menuItems,
570
- S.menuItem().title("Reset Order").icon(icons.GenerateIcon).action("resetOrder").serialize(),
571
- S.menuItem().title("Toggle Increments").icon(icons.SortIcon).action("showIncrements").serialize()
572
- ]
573
- }
574
- )
575
- ).serialize();
576
- }
577
- exports.OrderableDocumentList = OrderableDocumentList;
578
- exports.orderRankField = orderRankField;
579
- exports.orderRankOrdering = orderRankOrdering;
580
- exports.orderableDocumentListDeskItem = orderableDocumentListDeskItem;
581
- //# sourceMappingURL=index.cjs.map