UNPKG

@sanity/visual-editing

Version:

[![npm stat](https://img.shields.io/npm/dm/@sanity/visual-editing.svg?style=flat-square)](https://npm-stat.com/charts.html?package=@sanity/visual-editing) [![npm version](https://img.shields.io/npm/v/@sanity/visual-editing.svg?style=flat-square)](https://

329 lines (328 loc) 11.4 kB
import { c } from "react-compiler-runtime"; import { getDraftId, getPublishedId } from "@sanity/client/csm"; import { createIfNotExists, patch, at, insert, truncate } from "@sanity/mutate"; import { isMaybePreviewIframe, isMaybePreviewWindow } from "@sanity/presentation-comlink"; import { isEmptyActor, listeners, actor, emptyActor } from "./context.js"; import { useSyncExternalStore } from "react"; import getRandomValues from "get-random-values-esm"; const reKeySegment$1 = /_key\s*==\s*['"](.*)['"]/, reIndexTuple = /^\d*:\d*$/; function isIndexSegment(segment) { return typeof segment == "number" || typeof segment == "string" && /^\[\d+\]$/.test(segment); } function isKeySegment(segment) { return typeof segment == "string" ? reKeySegment$1.test(segment.trim()) : typeof segment == "object" && "_key" in segment; } function isIndexTuple(segment) { if (typeof segment == "string" && reIndexTuple.test(segment)) return !0; if (!Array.isArray(segment) || segment.length !== 2) return !1; const [from, to] = segment; return (typeof from == "number" || from === "") && (typeof to == "number" || to === ""); } const rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g, reKeySegment = /_key\s*==\s*['"](.*)['"]/; function get(obj, path, defaultVal) { const select = typeof path == "string" ? fromString(path) : path; if (!Array.isArray(select)) throw new Error("Path must be an array or a string"); let acc = obj; for (let i = 0; i < select.length; i++) { const segment = select[i]; if (isIndexSegment(segment)) { if (!Array.isArray(acc)) return defaultVal; acc = acc[segment]; } if (isKeySegment(segment)) { if (!Array.isArray(acc)) return defaultVal; acc = acc.find((item) => item._key === segment._key); } if (typeof segment == "string" && (acc = typeof acc == "object" && acc !== null ? acc[segment] : void 0), typeof acc > "u") return defaultVal; } return acc; } function fromString(path) { if (typeof path != "string") throw new Error("Path is not a string"); const segments = path.match(rePropName); if (!segments) throw new Error("Invalid path string"); return segments.map(normalizePathSegment); } function normalizePathSegment(segment) { return isIndexSegment(segment) ? normalizeIndexSegment(segment) : isKeySegment(segment) ? normalizeKeySegment(segment) : isIndexTuple(segment) ? normalizeIndexTupleSegment(segment) : segment; } function normalizeIndexSegment(segment) { return Number(segment.replace(/[^\d]/g, "")); } function normalizeKeySegment(segment) { return { _key: segment.match(reKeySegment)[1] }; } function normalizeIndexTupleSegment(segment) { const [from, to] = segment.split(":").map((seg) => seg === "" ? seg : Number(seg)); return [from, to]; } function useOptimisticActor() { return useSyncExternalStore(_temp, _temp2, _temp3); } function _temp3() { return emptyActor; } function _temp2() { return actor; } function _temp(listener) { return listeners.add(listener), () => listeners.delete(listener); } function useOptimisticActorReady() { const actor2 = useOptimisticActor(); let t0; return t0 = !isEmptyActor(actor2), t0; } function debounce(fn, timeout) { let timer; return (...args) => { clearTimeout(timer), timer = setTimeout(() => { fn.apply(fn, args); }, timeout); }; } function getDocumentsAndSnapshot(id, actor2) { const inFrame = isMaybePreviewIframe(), inPopUp = isMaybePreviewWindow(); if (isEmptyActor(actor2) || !inFrame && !inPopUp) throw new Error("The `useDocuments` hook cannot be used in this context"); const draftId = getDraftId(id), publishedId = getPublishedId(id), documents = actor2.getSnapshot().context?.documents, draftDoc = documents?.[draftId], publishedDoc = documents?.[publishedId], doc = draftDoc || publishedDoc; if (!doc) throw new Error(`Document "${id}" not found`); const snapshot = draftDoc.getSnapshot().context?.local || publishedDoc.getSnapshot().context?.local, snapshotPromise = new Promise((resolve) => { if (snapshot) resolve(snapshot); else { const subscriber = doc.on("ready", (event) => { const { snapshot: snapshot2 } = event; resolve(snapshot2 || null), subscriber.unsubscribe(); }); } }); return { draftDoc, draftId, getSnapshot: () => snapshotPromise, publishedDoc, publishedId, /** * @deprecated - use `getSnapshot` instead */ get snapshot() { if (!snapshot) throw new Error(`Snapshot for document "${id}" not found`); return snapshot; } }; } function createDocumentCommit(id, actor2) { return () => { const { draftDoc } = getDocumentsAndSnapshot(id, actor2); draftDoc.send({ type: "submit" }); }; } function createDocumentGet(id, actor2) { return (path) => { const { snapshot } = getDocumentsAndSnapshot(id, actor2); return path ? get(snapshot, path) : snapshot; }; } function createDocumentGetSnapshot(id, actor2) { const { getSnapshot } = getDocumentsAndSnapshot(id, actor2); return getSnapshot; } function createDocumentPatch(id, actor2) { return async (patches, options) => { const result = getDocumentsAndSnapshot(id, actor2), { draftDoc, draftId, getSnapshot, publishedId } = result, { commit = !0 } = options || {}, resolvedPatches = await (typeof patches == "function" ? patches({ draftId, publishedId, /** * @deprecated - use `getSnapshot` instead */ get snapshot() { return result.snapshot; }, getSnapshot }) : patches), _snapshot = await getSnapshot(); if (!_snapshot) throw new Error(`Snapshot for document "${id}" not found`); draftDoc.send({ type: "mutate", mutations: [ // Attempt to create the draft document, it might not exist if the // snapshot was from the published document createIfNotExists({ ..._snapshot, _id: draftId }), // Patch the draft document with the resolved patches patch(draftId, resolvedPatches) ] }), commit && (typeof commit == "object" && "debounce" in commit ? debounce(() => draftDoc.send({ type: "submit" }), commit.debounce)() : draftDoc.send({ type: "submit" })); }; } function useDocuments() { const $ = c(7), actor2 = useOptimisticActor(); let t0; $[0] !== actor2 ? (t0 = (documentId) => ({ id: documentId, commit: createDocumentCommit(documentId, actor2), get: createDocumentGet(documentId, actor2), getSnapshot: createDocumentGetSnapshot(documentId, actor2), patch: createDocumentPatch(documentId, actor2) }), $[0] = actor2, $[1] = t0) : t0 = $[1]; const getDocument = t0; let t1; $[2] !== actor2 ? (t1 = (id, mutations, options) => { const { draftDoc } = getDocumentsAndSnapshot(id, actor2), { commit: t22 } = options || {}, commit = t22 === void 0 ? !0 : t22; draftDoc.send({ type: "mutate", mutations }), commit && (typeof commit == "object" && "debounce" in commit ? debounce(() => draftDoc.send({ type: "submit" }), commit.debounce)() : draftDoc.send({ type: "submit" })); }, $[2] = actor2, $[3] = t1) : t1 = $[3]; const mutateDocument = t1; let t2; return $[4] !== getDocument || $[5] !== mutateDocument ? (t2 = { getDocument, mutateDocument }, $[4] = getDocument, $[5] = mutateDocument, $[6] = t2) : t2 = $[6], t2; } function whatwgRNG(length = 16) { const rnds8 = new Uint8Array(length); return getRandomValues(rnds8), rnds8; } const getByteHexTable = /* @__PURE__ */ (() => { let table; return () => { if (table) return table; table = []; for (let i = 0; i < 256; ++i) table[i] = (i + 256).toString(16).slice(1); return table; }; })(); function randomKey(length) { const table = getByteHexTable(); return whatwgRNG(length).reduce((str, n) => str + table[n], "").slice(0, length); } function getArrayItemKeyAndParentPath(pathOrNode) { const elementPath = typeof pathOrNode == "string" ? pathOrNode : pathOrNode.path, lastDotIndex = elementPath.lastIndexOf("."), lastPathItem = elementPath.substring(lastDotIndex + 1, elementPath.length); if (!lastPathItem.indexOf("[")) throw new Error("Invalid path: not an array"); const lastArrayIndex = elementPath.lastIndexOf("["), path = elementPath.substring(0, lastArrayIndex); let key, hasExplicitKey; if (lastPathItem.includes("_key")) { const startIndex = lastPathItem.indexOf('"') + 1, endIndex = lastPathItem.indexOf('"', startIndex); key = lastPathItem.substring(startIndex, endIndex), hasExplicitKey = !0; } else { const startIndex = lastPathItem.indexOf("[") + 1, endIndex = lastPathItem.indexOf("]", startIndex); key = lastPathItem.substring(startIndex, endIndex), hasExplicitKey = !1; } if (!path || !key) throw new Error("Invalid path"); return { path, key, hasExplicitKey }; } function getArrayDuplicatePatches(node, snapshot, position = "after") { const { path: arrayPath, key: itemKey } = getArrayItemKeyAndParentPath(node), duplicate = { ...get(snapshot, node.path), _key: randomKey() }; return [at(arrayPath, insert(duplicate, position, { _key: itemKey }))]; } function getArrayRemovePatches(node, snapshot) { const { path: arrayPath, key: itemKey } = getArrayItemKeyAndParentPath(node), currentIndex = get(snapshot, arrayPath).findIndex((item) => item._key === itemKey); return [at(arrayPath, truncate(currentIndex, currentIndex + 1))]; } function getArrayInsertPatches(node, insertType, position) { const { path: arrayPath, key: itemKey } = getArrayItemKeyAndParentPath(node), insertKey = randomKey(); return [at(arrayPath, insert([{ _type: insertType, _key: insertKey }], position, { _key: itemKey }))]; } async function getArrayMovePatches(node, doc, moveTo) { if (!node.type) throw new Error("Node type is missing"); const { path: arrayPath, key: itemKey } = getArrayItemKeyAndParentPath(node), snapshot = await doc.getSnapshot(), array = get(snapshot, arrayPath), item = get(snapshot, node.path), currentIndex = array.findIndex((item2) => item2._key === itemKey); let nextIndex = -1, position = "before"; if (moveTo === "first") { if (currentIndex === 0) return []; nextIndex = 0, position = "before"; } else if (moveTo === "last") { if (currentIndex === array.length - 1) return []; nextIndex = -1, position = "after"; } else if (moveTo === "next") { if (currentIndex === array.length - 1) return []; nextIndex = currentIndex, position = "after"; } else if (moveTo === "previous") { if (currentIndex === 0) return []; nextIndex = currentIndex - 1, position = "before"; } return [at(arrayPath, truncate(currentIndex, currentIndex + 1)), at(arrayPath, insert(item, position, nextIndex))]; } export { get, getArrayDuplicatePatches, getArrayInsertPatches, getArrayItemKeyAndParentPath, getArrayMovePatches, getArrayRemovePatches, useDocuments, useOptimisticActor, useOptimisticActorReady }; //# sourceMappingURL=mutations.js.map