@sanity/orderable-document-list 1.5.1 → 2.0.1

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