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