sanity-plugin-media

6.6.06.6.1
dist/index.js
~dist/index.jsModified
+45−26
Index: package/dist/index.js
===================================================================
--- package/dist/index.js
+++ package/dist/index.js
@@ -15,11 +15,11 @@
 import { bufferTime, catchError, concatMap, debounceTime, delay, filter, first, map, mergeMap, switchMap, takeUntil as takeUntil$1, withLatestFrom } from "rxjs/operators";
 import { uuid } from "@sanity/uuid";
 import pluralize from "pluralize";
 import { createGlobalStyle, css, styled } from "styled-components";
+import { zodResolver } from "@hookform/resolvers/zod";
 import { Controller, useForm, useFormState } from "react-hook-form";
 import * as z from "zod";
-import { zodResolver } from "@hookform/resolvers/zod";
 import { DownloadIcon } from "@sanity/icons/Download";
 import { format } from "date-fns/format";
 import filesize from "filesize";
 import { ClipboardIcon } from "@sanity/icons/Clipboard";
@@ -529,12 +529,40 @@
 	return iif(() => !!throttled, source.pipe(delay(3e3), mergeMap((v) => Math.random() > .5 ? throwError(() => ({
 		message: "Test error",
 		statusCode: 500
 	})) : of(v))), source);
+}, LOCALIZED_TEXT_FIELDS = /* @__PURE__ */ new Set([
+	"altText",
+	"creditLine",
+	"description",
+	"title"
+]), TEXT_SEARCH_FIELDS = [
+	"_id",
+	"altText",
+	"assetId",
+	"creditLine",
+	"description",
+	"originalFilename",
+	"title",
+	"url"
+], groqString = (value) => JSON.stringify(value), localizedFieldPaths = (field, localeIds) => {
+	if (!localeIds?.length || !LOCALIZED_TEXT_FIELDS.has(field)) return [];
+	let seen = /* @__PURE__ */ new Set(), paths = [];
+	for (let localeId of localeIds) localeId && !seen.has(localeId) && (seen.add(localeId), paths.push(`${field}[${groqString(localeId)}]`));
+	return paths;
+}, textSearchFieldList = (localeIds) => TEXT_SEARCH_FIELDS.flatMap((field) => [field, ...localizedFieldPaths(field, localeIds)]).join(", "), localizedFieldPresent = (field, paths) => `((string(${field}) == ${field} && defined(${field})) || ${paths.map((path) => `defined(${path})`).join(" || ")})`, stringFacetFragment = (field, operatorType, value, localeIds) => {
+	let paths = localizedFieldPaths(field, localeIds);
+	if (paths.length === 0) return operators[operatorType].fn(value, field);
+	if (operatorType === "includes" || operatorType === "doesNotInclude") return operators[operatorType].fn(value, `[${field}, ${paths.join(", ")}]`);
+	if (operatorType === "empty" || operatorType === "notEmpty") {
+		let present = localizedFieldPresent(field, paths);
+		return operatorType === "empty" ? `!(${present})` : present;
+	}
+	return operators[operatorType].fn(value, field);
 }, buildExcludeTagsFragment = (excludeTagSlugs) => {
 	let serializedExcludeTagSlugs = excludeTagSlugs?.length ? JSON.stringify(excludeTagSlugs) : void 0;
 	return serializedExcludeTagSlugs ? groq`!(defined(opt.media.tags) && count(opt.media.tags[@._ref in *[_type == "${TAG_DOCUMENT_NAME}" && name.current in ${serializedExcludeTagSlugs}]._id]) > 0)` : void 0;
-}, buildExcludeMediaLibraryFragment = (showMediaLibraryAssets) => showMediaLibraryAssets ? void 0 : groq`(!defined(source.name) || source.name != "${"sanity-media-library"}") && (!defined(media._ref) || !string::startsWith(media._ref, "${"media-library:"}"))`, constructFilter = ({ assetTypes, currentFolderId, excludeTagSlugs, searchFacets, searchQuery, showMediaLibraryAssets = !0 }) => {
+}, buildExcludeMediaLibraryFragment = (showMediaLibraryAssets) => showMediaLibraryAssets ? void 0 : groq`(!defined(source.name) || source.name != "${"sanity-media-library"}") && (!defined(media._ref) || !string::startsWith(media._ref, "${"media-library:"}"))`, constructFilter = ({ assetTypes, currentFolderId, excludeTagSlugs, localeIds, searchFacets, searchQuery, showMediaLibraryAssets = !0 }) => {
 	let documentAssetTypes = assetTypes.map((type) => `sanity.${type}Asset`), baseFilter = groq`
     _type in ${JSON.stringify(documentAssetTypes)} && !(_id in path("drafts.**"))
   `, excludeTagsFragment = buildExcludeTagsFragment(excludeTagSlugs), excludeMediaLibraryFragment = buildExcludeMediaLibraryFragment(showMediaLibraryAssets), searchFacetFragments = searchFacets.reduce((acc, facet) => {
 		if (facet.type === "number") {
@@ -549,18 +577,18 @@
 			let { field, operatorType, options, value } = facet, operator = operators[operatorType], currentOptionValue = options?.find((l) => l.name === value)?.value, fragment = operator.fn(currentOptionValue, field);
 			fragment && acc.push(fragment);
 		}
 		if (facet.type === "string") {
-			let { field, operatorType, value } = facet, fragment = operators[operatorType].fn(value, field);
+			let { field, operatorType, value } = facet, fragment = stringFacetFragment(field, operatorType, value, localeIds);
 			fragment && acc.push(fragment);
 		}
 		return acc;
 	}, []), folderFilter = currentFolderId ? `opt.media.folder._ref == ${JSON.stringify(currentFolderId)}` : void 0;
 	return [
 		baseFilter,
 		...excludeMediaLibraryFragment ? [excludeMediaLibraryFragment] : [],
 		...excludeTagsFragment ? [excludeTagsFragment] : [],
-		...searchQuery ? [groq`[_id, altText, assetId, creditLine, description, originalFilename, title, url] match ${groqWildcardMatch(searchQuery.trim())}`] : [],
+		...searchQuery ? [groq`[${textSearchFieldList(localeIds)}] match ${groqWildcardMatch(searchQuery.trim())}`] : [],
 		...folderFilter ? [folderFilter] : [],
 		...searchFacetFragments
 	].join(" && ");
 };
@@ -1206,8 +1234,9 @@
 	let pageSize = state.assets.pageSize, start = action.payload.pageIndex * pageSize, end = start + pageSize, documentId = state?.selected.document?._id, documentAssetIds = state?.selected?.documentAssetIds, constructedFilter = constructFilter({
 		assetTypes: state.assets.assetTypes,
 		currentFolderId: state.folders.currentFolderId,
 		excludeTagSlugs: state.assets.excludeTagSlugs,
+		localeIds: state.assets.localeIds,
 		searchFacets: state.search.facets,
 		searchQuery: state.search.query,
 		showMediaLibraryAssets: state.assets.showMediaLibraryAssets
 	}), params = {
@@ -1855,26 +1884,26 @@
 function localizedStringSchema(locales) {
 	if (!locales || locales.length === 0) return z.string().trim().optional();
 	let shape = {};
 	for (let locale of locales) shape[locale.id] = z.string().trim().optional();
-	return z.object(shape).passthrough();
+	return z.object(shape).loose();
 }
 const tagOptionSchema = z.object({
-	label: z.string().trim().min(1, { message: "Label cannot be empty" }),
-	value: z.string().trim().min(1, { message: "Value cannot be empty" })
+	label: z.string().trim().min(1, { error: "Label cannot be empty" }),
+	value: z.string().trim().min(1, { error: "Value cannot be empty" })
 });
 function getAssetFormSchema(locales) {
 	return z.object({
 		altText: localizedStringSchema(locales),
 		creditLine: localizedStringSchema(locales),
 		description: localizedStringSchema(locales),
 		opt: z.object({ media: z.object({ tags: z.array(tagOptionSchema).nullable() }) }),
-		originalFilename: z.string().trim().min(1, { message: "Filename cannot be empty" }),
+		originalFilename: z.string().trim().min(1, { error: "Filename cannot be empty" }),
 		title: localizedStringSchema(locales)
 	});
 }
 getAssetFormSchema();
-const tagFormSchema = z.object({ name: z.string().min(1, { message: "Name cannot be empty" }) }), folderFormSchema = z.object({ name: z.string().trim().min(1, { message: "Name cannot be empty" }) });
+const tagFormSchema = z.object({ name: z.string().min(1, { error: "Name cannot be empty" }) }), folderFormSchema = z.object({ name: z.string().trim().min(1, { error: "Name cannot be empty" }) });
 function getUniqueDocuments(documents) {
 	let draftIds = documents.reduce((acc, doc) => doc._id.startsWith("drafts.") ? acc.concat(doc._id.slice(7)) : acc, []);
 	return documents.filter((doc) => !draftIds.includes(doc._id));
 }
@@ -1883,20 +1912,9 @@
 	return urlParams.append("fit", "max"), urlParams.append("w", imgW.toString()), imgH && urlParams.append("h", imgH.toString()), `${asset.url}?${urlParams.toString()}`;
 }, sanitizeFormData = (formData) => Object.keys(formData).reduce((acc, key) => {
 	let val = formData[key];
 	return acc[key] = typeof val == "object" && val && val.constructor !== Array ? sanitizeFormData(val) : val === "" || val === void 0 || val?.length === 0 ? null : typeof val == "string" && val ? formData[key].trim() : formData[key], acc;
-}, {}), isFileAsset = (asset) => asset._type === "sanity.fileAsset", isImageAsset = (asset) => asset._type === "sanity.imageAsset";
-/**
-* `@hookform/resolvers/zod` resolves its own `zod` typings through dependency
-* hoisting, which in this monorepo lands on zod v4, while this plugin authors its
-* form schemas with zod v3. The resolver accepts v3 schema instances correctly at
-* runtime, so this thin wrapper only bridges the type-only v3/v4 mismatch. The
-* react-hook-form field types stay fully checked at the call sites.
-*/
-function zodFormResolver(schema) {
-	return zodResolver(schema);
-}
-const getAssetResolution = (asset) => `${asset.metadata.dimensions.width}x${asset.metadata.dimensions.height}px`;
+}, {}), isFileAsset = (asset) => asset._type === "sanity.fileAsset", isImageAsset = (asset) => asset._type === "sanity.imageAsset", getAssetResolution = (asset) => `${asset.metadata.dimensions.width}x${asset.metadata.dimensions.height}px`;
 function usePortalPopoverProps() {
 	let $ = c(2), portal = usePortal(), t0;
 	return $[0] === portal.element ? t0 = $[1] : (t0 = {
 		animate: !0,
@@ -2871,9 +2889,9 @@
 	}, $[10] = assetTagOptions, $[11] = locales, $[12] = t7) : t7 = $[12];
 	let generateDefaultValues = t7, t8 = assetItem?.asset, t9;
 	$[13] !== generateDefaultValues || $[14] !== t8 ? (t9 = generateDefaultValues(t8), $[13] = generateDefaultValues, $[14] = t8, $[15] = t9) : t9 = $[15];
 	let t10;
-	$[16] === locales ? t10 = $[17] : (t10 = zodFormResolver(getAssetFormSchema(locales)), $[16] = locales, $[17] = t10);
+	$[16] === locales ? t10 = $[17] : (t10 = zodResolver(getAssetFormSchema(locales)), $[16] = locales, $[17] = t10);
 	let t11;
 	$[18] !== t10 || $[19] !== t9 ? (t11 = {
 		defaultValues: t9,
 		mode: "onChange",
@@ -3800,8 +3818,9 @@
 	let { assets } = action.payload, documentIds = assets.map((asset) => asset._id), constructedFilter = constructFilter({
 		assetTypes: state.assets.assetTypes,
 		currentFolderId: state.folders.currentFolderId,
 		excludeTagSlugs: state.assets.excludeTagSlugs,
+		localeIds: state.assets.localeIds,
 		searchFacets: state.search.facets,
 		searchQuery: state.search.query,
 		showMediaLibraryAssets: state.assets.showMediaLibraryAssets
 	}), query = groq`
@@ -4267,9 +4286,9 @@
 	let t3;
 	$[3] === Symbol.for("react.memo_cache_sentinel") ? (t3 = {
 		defaultValues: t2,
 		mode: "onChange",
-		resolver: zodFormResolver(folderFormSchema)
+		resolver: zodResolver(folderFormSchema)
 	}, $[3] = t3) : t3 = $[3];
 	let { formState: t4, handleSubmit, register, setError } = useForm(t3), { errors, isDirty, isValid } = t4, t5;
 	$[4] === dispatch ? t5 = $[5] : (t5 = () => {
 		dispatch(dialogActions.clear());
@@ -4527,9 +4546,9 @@
 	$[4] === folderPath ? t3 = $[5] : (t3 = folderPath.includes("/") ? folderPath.slice(0, folderPath.lastIndexOf("/")) : null, $[4] = folderPath, $[5] = t3);
 	let parentPath = t3, t4;
 	$[6] === currentName ? t4 = $[7] : (t4 = { name: currentName }, $[6] = currentName, $[7] = t4);
 	let t5;
-	$[8] === Symbol.for("react.memo_cache_sentinel") ? (t5 = zodFormResolver(folderFormSchema), $[8] = t5) : t5 = $[8];
+	$[8] === Symbol.for("react.memo_cache_sentinel") ? (t5 = zodResolver(folderFormSchema), $[8] = t5) : t5 = $[8];
 	let t6;
 	$[9] === t4 ? t6 = $[10] : (t6 = {
 		defaultValues: t4,
 		mode: "onChange",
@@ -5645,9 +5664,9 @@
 	let t2;
 	$[1] === Symbol.for("react.memo_cache_sentinel") ? (t2 = {
 		defaultValues: t1,
 		mode: "onChange",
-		resolver: zodFormResolver(tagFormSchema)
+		resolver: zodResolver(tagFormSchema)
 	}, $[1] = t2) : t2 = $[1];
 	let { formState: t3, handleSubmit, register, setError } = useForm(t2), { errors, isDirty, isValid } = t3, formUpdating = creating, t4;
 	$[2] === dispatch ? t4 = $[3] : (t4 = () => {
 		dispatch(dialogActions.clear());
@@ -5722,9 +5741,9 @@
 	$[0] === tagId ? t1 = $[1] : (t1 = (state) => selectTagById(state, String(tagId)), $[0] = tagId, $[1] = t1);
 	let tagItem = useTypedSelector(t1), [tagSnapshot, setTagSnapshot] = useState(tagItem?.tag), currentTag = tagItem ? tagItem?.tag : tagSnapshot, generateDefaultValues = _temp$24, t2 = tagItem?.tag, t3;
 	$[2] === t2 ? t3 = $[3] : (t3 = generateDefaultValues(t2), $[2] = t2, $[3] = t3);
 	let t4;
-	$[4] === Symbol.for("react.memo_cache_sentinel") ? (t4 = zodFormResolver(tagFormSchema), $[4] = t4) : t4 = $[4];
+	$[4] === Symbol.for("react.memo_cache_sentinel") ? (t4 = zodResolver(tagFormSchema), $[4] = t4) : t4 = $[4];
 	let t5;
 	$[5] === t3 ? t5 = $[6] : (t5 = {
 		defaultValues: t3,
 		mode: "onChange",