sanity-plugin-media 4.1.1 → 4.3.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/LICENSE +1 -1
- package/README.md +107 -3
- package/dist/index.d.mts +227 -56
- package/dist/index.d.ts +227 -56
- package/dist/index.js +473 -184
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +476 -187
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -2
- package/src/__tests__/fixtures/createEpicTestStore.ts +27 -0
- package/src/__tests__/fixtures/listenMock.ts +9 -0
- package/src/__tests__/fixtures/mockSanityClient.ts +84 -0
- package/src/__tests__/fixtures/renderWithProviders.tsx +54 -0
- package/src/__tests__/fixtures/rootState.ts +27 -0
- package/src/__tests__/fixtures/withinDialog.ts +28 -0
- package/src/components/AutoTagInputWrapper/index.tsx +82 -0
- package/src/components/Browser/Browser.test.tsx +44 -0
- package/src/components/Browser/index.tsx +12 -69
- package/src/components/Browser/useBrowserInit.ts +126 -0
- package/src/components/CardAsset/CardAsset.test.tsx +322 -0
- package/src/components/DialogAssetEdit/Details.tsx +123 -44
- package/src/components/DialogAssetEdit/DialogAssetEdit.test.tsx +215 -0
- package/src/components/DialogAssetEdit/index.tsx +138 -30
- package/src/components/DialogTagCreate/DialogTagCreate.test.tsx +120 -0
- package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +164 -0
- package/src/components/FormBuilderTool/FormBuilderTool.test.tsx +62 -0
- package/src/components/FormBuilderTool/index.tsx +1 -1
- package/src/components/UploadDropzone/UploadDropzone.test.tsx +39 -0
- package/src/contexts/ToolOptionsContext.tsx +9 -3
- package/src/formSchema/index.test.ts +55 -0
- package/src/formSchema/index.ts +28 -12
- package/src/hooks/useVersionedClient.ts +1 -1
- package/src/index.ts +4 -1
- package/src/modules/assets/deleteAndUpdateEpics.test.ts +86 -0
- package/src/modules/assets/fetchEpic.test.ts +72 -0
- package/src/modules/assets/reducer.test.ts +90 -0
- package/src/modules/assets/tagsAndListenerEpics.test.ts +205 -0
- package/src/modules/dialog/epics.test.ts +167 -0
- package/src/modules/dialog/reducer.test.ts +184 -0
- package/src/modules/notifications/epics.test.ts +373 -0
- package/src/modules/notifications/index.ts +24 -4
- package/src/modules/notifications/reducer.test.ts +53 -0
- package/src/modules/search/index.test.ts +35 -0
- package/src/modules/selectors.test.ts +20 -0
- package/src/modules/tags/epics.test.ts +95 -0
- package/src/modules/tags/index.test.ts +41 -0
- package/src/modules/uploads/epics.test.ts +108 -0
- package/src/modules/uploads/index.test.ts +58 -0
- package/src/operators/checkTagName.test.ts +28 -0
- package/src/types/index.ts +25 -7
- package/src/utils/applyMediaTags.ts +86 -0
- package/src/utils/blocksToText.test.ts +42 -0
- package/src/utils/constructFilter.test.ts +119 -0
- package/src/utils/generatePreviewBlobUrl.test.ts +69 -0
- package/src/utils/getAssetResolution.test.ts +12 -0
- package/src/utils/getDocumentAssetIds.test.ts +49 -0
- package/src/utils/getSchemeColor.test.ts +11 -0
- package/src/utils/getTagSelectOptions.test.ts +43 -0
- package/src/utils/getUniqueDocuments.test.ts +25 -0
- package/src/utils/imageDprUrl.test.ts +45 -0
- package/src/utils/isSupportedAssetType.test.ts +15 -0
- package/src/utils/mediaField.ts +72 -0
- package/src/utils/sanitizeFormData.test.ts +58 -0
- package/src/utils/typeGuards.test.ts +17 -0
- package/src/utils/uploadSanityAsset.test.ts +28 -0
- package/src/utils/withMaxConcurrency.test.ts +42 -0
package/dist/index.mjs
CHANGED
|
@@ -3,16 +3,16 @@ import { useClient, useColorSchemeValue, useSchema, Preview, useDocumentStore, W
|
|
|
3
3
|
import { ThLargeIcon, ThListIcon, SortIcon, CloseIcon, SelectIcon, AddIcon, SearchIcon, PlugIcon, ClipboardIcon, DownloadIcon, ChevronDownIcon, ErrorOutlineIcon, WarningOutlineIcon, EditIcon, ArrowUpIcon, ArrowDownIcon, TrashIcon, ComposeIcon, Icon, UploadIcon, WarningFilledIcon, CheckmarkCircleIcon, ChevronUpIcon, ImageIcon } from "@sanity/icons";
|
|
4
4
|
import { Inline, Button, usePortal, MenuButton, Menu as Menu$2, MenuItem, MenuDivider, Box, studioTheme, rem, Flex, Label, Text, TextInput, Card, MenuGroup, useMediaIndex, Tooltip, Switch, Popover, Stack, Dialog as Dialog$1, TextArea, TabList, Tab, TabPanel, Container as Container$2, Spinner, Checkbox, Grid, useToast, PortalProvider, useLayer, Portal } from "@sanity/ui";
|
|
5
5
|
import { useRef, useCallback, useEffect, createContext, useContext, useMemo, useState, forwardRef, memo, Component } from "react";
|
|
6
|
-
import
|
|
6
|
+
import { css, createGlobalStyle, styled } from "styled-components";
|
|
7
7
|
import { useSelector, useDispatch, Provider } from "react-redux";
|
|
8
8
|
import { createAction, createSlice, isAnyOf, createSelector, combineReducers, configureStore } from "@reduxjs/toolkit";
|
|
9
|
-
import
|
|
9
|
+
import pluralize from "pluralize";
|
|
10
10
|
import { ofType, combineEpics, createEpicMiddleware } from "redux-observable";
|
|
11
11
|
import { iif, throwError, of, from, EMPTY, Subject, Observable, merge, empty } from "rxjs";
|
|
12
12
|
import { delay, mergeMap, filter, withLatestFrom, catchError, switchMap, bufferTime, debounceTime, first, map, takeUntil } from "rxjs/operators";
|
|
13
|
+
import groq from "groq";
|
|
14
|
+
import { nanoid } from "nanoid";
|
|
13
15
|
import { uuid } from "@sanity/uuid";
|
|
14
|
-
import { css, createGlobalStyle, styled } from "styled-components";
|
|
15
|
-
import pluralize from "pluralize";
|
|
16
16
|
import { useNProgress } from "@tanem/react-nprogress";
|
|
17
17
|
import { hues, white } from "@sanity/color";
|
|
18
18
|
import Select, { components } from "react-select";
|
|
@@ -176,7 +176,71 @@ const useKeyPress = (hotkey, onPress) => {
|
|
|
176
176
|
return useEffect(() => (window.addEventListener("keydown", downHandler), window.addEventListener("keyup", upHandler), () => {
|
|
177
177
|
window.removeEventListener("keydown", downHandler), window.removeEventListener("keyup", upHandler);
|
|
178
178
|
}), [downHandler, upHandler]), keyPressed;
|
|
179
|
-
},
|
|
179
|
+
}, AssetSourceDispatchContext = createContext(void 0), AssetBrowserDispatchProvider = (props) => {
|
|
180
|
+
const { children, onSelect } = props, contextValue = {
|
|
181
|
+
onSelect
|
|
182
|
+
};
|
|
183
|
+
return /* @__PURE__ */ jsx(AssetSourceDispatchContext.Provider, { value: contextValue, children });
|
|
184
|
+
}, useAssetSourceActions = () => {
|
|
185
|
+
const context = useContext(AssetSourceDispatchContext);
|
|
186
|
+
if (context === void 0)
|
|
187
|
+
throw new Error("useAssetSourceActions must be used within an AssetSourceDispatchProvider");
|
|
188
|
+
return context;
|
|
189
|
+
}, useVersionedClient = () => useClient({ apiVersion: "2025-10-02" }), customScrollbar = css`
|
|
190
|
+
::-webkit-scrollbar {
|
|
191
|
+
width: 14px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
::-webkit-scrollbar-thumb {
|
|
195
|
+
border-radius: 10px;
|
|
196
|
+
border: 4px solid rgba(0, 0, 0, 0);
|
|
197
|
+
background: var(--card-border-color);
|
|
198
|
+
background-clip: padding-box;
|
|
199
|
+
|
|
200
|
+
&:hover {
|
|
201
|
+
background: var(--card-muted-fg-color);
|
|
202
|
+
background-clip: padding-box;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
`, GlobalStyle = createGlobalStyle`
|
|
206
|
+
.media__custom-scrollbar {
|
|
207
|
+
${customScrollbar}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// @sanity/ui overrides
|
|
211
|
+
|
|
212
|
+
// Custom scrollbar on Box (used in Dialogs)
|
|
213
|
+
div[data-ui="Box"] {
|
|
214
|
+
${customScrollbar}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Dialog background color
|
|
218
|
+
div[data-ui="Dialog"] {
|
|
219
|
+
background-color: rgba(15, 17, 18, 0.9);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
`, useTypedSelector = useSelector, ORDER_DICTIONARY = {
|
|
223
|
+
_createdAt: {
|
|
224
|
+
asc: "Last created: Oldest first",
|
|
225
|
+
desc: "Last created: Newest first"
|
|
226
|
+
},
|
|
227
|
+
_updatedAt: {
|
|
228
|
+
asc: "Last updated: Oldest first",
|
|
229
|
+
desc: "Last updated: Newest first"
|
|
230
|
+
},
|
|
231
|
+
mimeType: {
|
|
232
|
+
asc: "MIME type: A to Z",
|
|
233
|
+
desc: "MIME type: Z to A"
|
|
234
|
+
},
|
|
235
|
+
originalFilename: {
|
|
236
|
+
asc: "File name: A to Z",
|
|
237
|
+
desc: "File name: Z to A"
|
|
238
|
+
},
|
|
239
|
+
size: {
|
|
240
|
+
asc: "File size: Smallest first",
|
|
241
|
+
desc: "File size: Largest first"
|
|
242
|
+
}
|
|
243
|
+
}, getOrderTitle = (field, direction) => ORDER_DICTIONARY[field][direction], divider = { type: "divider" }, inputs = {
|
|
180
244
|
altText: {
|
|
181
245
|
assetTypes: ["file", "image"],
|
|
182
246
|
field: "altText",
|
|
@@ -539,38 +603,7 @@ const useKeyPress = (hotkey, onPress) => {
|
|
|
539
603
|
], GRID_TEMPLATE_COLUMNS = {
|
|
540
604
|
SMALL: "3rem 100px auto 1.5rem",
|
|
541
605
|
LARGE: "3rem 100px auto 5.5rem 5.5rem 3.5rem 8.5rem 4.75rem 2rem"
|
|
542
|
-
}, PANEL_HEIGHT = 32, TAG_DOCUMENT_NAME = "media.tag", TAGS_PANEL_WIDTH = 250,
|
|
543
|
-
const { children, onSelect } = props, contextValue = {
|
|
544
|
-
onSelect
|
|
545
|
-
};
|
|
546
|
-
return /* @__PURE__ */ jsx(AssetSourceDispatchContext.Provider, { value: contextValue, children });
|
|
547
|
-
}, useAssetSourceActions = () => {
|
|
548
|
-
const context = useContext(AssetSourceDispatchContext);
|
|
549
|
-
if (context === void 0)
|
|
550
|
-
throw new Error("useAssetSourceActions must be used within an AssetSourceDispatchProvider");
|
|
551
|
-
return context;
|
|
552
|
-
}, useVersionedClient = () => useClient({ apiVersion: "2022-10-01" }), ORDER_DICTIONARY = {
|
|
553
|
-
_createdAt: {
|
|
554
|
-
asc: "Last created: Oldest first",
|
|
555
|
-
desc: "Last created: Newest first"
|
|
556
|
-
},
|
|
557
|
-
_updatedAt: {
|
|
558
|
-
asc: "Last updated: Oldest first",
|
|
559
|
-
desc: "Last updated: Newest first"
|
|
560
|
-
},
|
|
561
|
-
mimeType: {
|
|
562
|
-
asc: "MIME type: A to Z",
|
|
563
|
-
desc: "MIME type: Z to A"
|
|
564
|
-
},
|
|
565
|
-
originalFilename: {
|
|
566
|
-
asc: "File name: A to Z",
|
|
567
|
-
desc: "File name: Z to A"
|
|
568
|
-
},
|
|
569
|
-
size: {
|
|
570
|
-
asc: "File size: Smallest first",
|
|
571
|
-
desc: "File size: Largest first"
|
|
572
|
-
}
|
|
573
|
-
}, getOrderTitle = (field, direction) => ORDER_DICTIONARY[field][direction], debugThrottle = (throttled) => function(source) {
|
|
606
|
+
}, PANEL_HEIGHT = 32, TAG_DOCUMENT_NAME = "media.tag", TAGS_PANEL_WIDTH = 250, debugThrottle = (throttled) => function(source) {
|
|
574
607
|
return iif(
|
|
575
608
|
() => !!throttled,
|
|
576
609
|
source.pipe(
|
|
@@ -1614,40 +1647,7 @@ const UPLOADS_ACTIONS = {
|
|
|
1614
1647
|
(assetsPicked) => assetsPicked.length
|
|
1615
1648
|
), assetsActions = { ...assetsSlice.actions };
|
|
1616
1649
|
var assetsReducer = assetsSlice.reducer;
|
|
1617
|
-
const
|
|
1618
|
-
::-webkit-scrollbar {
|
|
1619
|
-
width: 14px;
|
|
1620
|
-
}
|
|
1621
|
-
|
|
1622
|
-
::-webkit-scrollbar-thumb {
|
|
1623
|
-
border-radius: 10px;
|
|
1624
|
-
border: 4px solid rgba(0, 0, 0, 0);
|
|
1625
|
-
background: var(--card-border-color);
|
|
1626
|
-
background-clip: padding-box;
|
|
1627
|
-
|
|
1628
|
-
&:hover {
|
|
1629
|
-
background: var(--card-muted-fg-color);
|
|
1630
|
-
background-clip: padding-box;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
`, GlobalStyle = createGlobalStyle`
|
|
1634
|
-
.media__custom-scrollbar {
|
|
1635
|
-
${customScrollbar}
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
// @sanity/ui overrides
|
|
1639
|
-
|
|
1640
|
-
// Custom scrollbar on Box (used in Dialogs)
|
|
1641
|
-
div[data-ui="Box"] {
|
|
1642
|
-
${customScrollbar}
|
|
1643
|
-
}
|
|
1644
|
-
|
|
1645
|
-
// Dialog background color
|
|
1646
|
-
div[data-ui="Dialog"] {
|
|
1647
|
-
background-color: rgba(15, 17, 18, 0.9);
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
`, useTypedSelector = useSelector, initialState$4 = {
|
|
1650
|
+
const initialState$4 = {
|
|
1651
1651
|
items: []
|
|
1652
1652
|
}, dialogSlice = createSlice({
|
|
1653
1653
|
name: "dialog",
|
|
@@ -2368,18 +2368,22 @@ const Container$1 = styled(Box)(({ $scheme, theme }) => css`
|
|
|
2368
2368
|
components: {
|
|
2369
2369
|
details: options?.components?.details
|
|
2370
2370
|
},
|
|
2371
|
+
createTagsOnUpload: options?.createTagsOnUpload ?? !0,
|
|
2371
2372
|
creditLine: {
|
|
2372
2373
|
enabled: options?.creditLine?.enabled || !1,
|
|
2373
2374
|
excludeSources: creditLineExcludeSources
|
|
2374
2375
|
},
|
|
2375
|
-
directUploads: options?.directUploads ?? !0
|
|
2376
|
+
directUploads: options?.directUploads ?? !0,
|
|
2377
|
+
locales: options?.locales
|
|
2376
2378
|
};
|
|
2377
2379
|
}, [
|
|
2378
2380
|
options?.creditLine?.enabled,
|
|
2379
2381
|
options?.components,
|
|
2382
|
+
options?.createTagsOnUpload,
|
|
2380
2383
|
options?.creditLine?.excludeSources,
|
|
2381
2384
|
options?.maximumUploadSize,
|
|
2382
|
-
options?.directUploads
|
|
2385
|
+
options?.directUploads,
|
|
2386
|
+
options?.locales
|
|
2383
2387
|
]);
|
|
2384
2388
|
return /* @__PURE__ */ jsx(ToolOptionsContext.Provider, { value, children });
|
|
2385
2389
|
}, useToolOptions = () => {
|
|
@@ -2658,21 +2662,35 @@ const DebugControls = () => {
|
|
|
2658
2662
|
] })
|
|
2659
2663
|
}
|
|
2660
2664
|
) : null;
|
|
2661
|
-
}
|
|
2665
|
+
};
|
|
2666
|
+
function localizedStringSchema(locales) {
|
|
2667
|
+
if (!locales || locales.length === 0)
|
|
2668
|
+
return z.string().trim().optional();
|
|
2669
|
+
const shape = {};
|
|
2670
|
+
for (const locale of locales)
|
|
2671
|
+
shape[locale.id] = z.string().trim().optional();
|
|
2672
|
+
return z.object(shape).passthrough();
|
|
2673
|
+
}
|
|
2674
|
+
const tagOptionSchema = z.object({
|
|
2662
2675
|
label: z.string().trim().min(1, { message: "Label cannot be empty" }),
|
|
2663
2676
|
value: z.string().trim().min(1, { message: "Value cannot be empty" })
|
|
2664
|
-
})
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2677
|
+
});
|
|
2678
|
+
function getAssetFormSchema(locales) {
|
|
2679
|
+
return z.object({
|
|
2680
|
+
altText: localizedStringSchema(locales),
|
|
2681
|
+
creditLine: localizedStringSchema(locales),
|
|
2682
|
+
description: localizedStringSchema(locales),
|
|
2683
|
+
opt: z.object({
|
|
2684
|
+
media: z.object({
|
|
2685
|
+
tags: z.array(tagOptionSchema).nullable()
|
|
2686
|
+
})
|
|
2687
|
+
}),
|
|
2688
|
+
originalFilename: z.string().trim().min(1, { message: "Filename cannot be empty" }),
|
|
2689
|
+
title: localizedStringSchema(locales)
|
|
2690
|
+
});
|
|
2691
|
+
}
|
|
2692
|
+
getAssetFormSchema();
|
|
2693
|
+
const tagFormSchema = z.object({
|
|
2676
2694
|
name: z.string().min(1, { message: "Name cannot be empty" })
|
|
2677
2695
|
});
|
|
2678
2696
|
function getUniqueDocuments(documents) {
|
|
@@ -3107,6 +3125,11 @@ const imageDprUrl = (asset, options) => {
|
|
|
3107
3125
|
)
|
|
3108
3126
|
] });
|
|
3109
3127
|
});
|
|
3128
|
+
function toStringField(value) {
|
|
3129
|
+
if (typeof value == "string") return value;
|
|
3130
|
+
if (typeof value == "object" && value !== null)
|
|
3131
|
+
return Object.values(value).find((v) => v) || void 0;
|
|
3132
|
+
}
|
|
3110
3133
|
function Details({
|
|
3111
3134
|
formUpdating,
|
|
3112
3135
|
handleCreateTag,
|
|
@@ -3116,8 +3139,10 @@ function Details({
|
|
|
3116
3139
|
allTagOptions,
|
|
3117
3140
|
assetTagOptions,
|
|
3118
3141
|
currentAsset,
|
|
3119
|
-
creditLine
|
|
3142
|
+
creditLine,
|
|
3143
|
+
locales
|
|
3120
3144
|
}) {
|
|
3145
|
+
const hasLocales = locales && locales.length > 0, [activeLocaleTab, setActiveLocaleTab] = useState(0);
|
|
3121
3146
|
return /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
3122
3147
|
/* @__PURE__ */ jsx(
|
|
3123
3148
|
FormFieldInputTags,
|
|
@@ -3144,51 +3169,117 @@ function Details({
|
|
|
3144
3169
|
value: currentAsset?.originalFilename
|
|
3145
3170
|
}
|
|
3146
3171
|
),
|
|
3147
|
-
/* @__PURE__ */ jsx(
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3172
|
+
hasLocales ? /* @__PURE__ */ jsx(Card, { marginTop: 2, shadow: 1, padding: 3, radius: 1, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
3173
|
+
/* @__PURE__ */ jsx(TabList, { space: 2, children: locales.map((locale, idx) => /* @__PURE__ */ jsx(
|
|
3174
|
+
Tab,
|
|
3175
|
+
{
|
|
3176
|
+
id: `locale-tab-${locale.id}`,
|
|
3177
|
+
"aria-controls": `locale-panel-${locale.id}`,
|
|
3178
|
+
selected: activeLocaleTab === idx,
|
|
3179
|
+
onClick: () => setActiveLocaleTab(idx),
|
|
3180
|
+
label: locale.title
|
|
3181
|
+
},
|
|
3182
|
+
locale.id
|
|
3183
|
+
)) }),
|
|
3184
|
+
locales.map((locale, idx) => /* @__PURE__ */ jsx(
|
|
3185
|
+
TabPanel,
|
|
3186
|
+
{
|
|
3187
|
+
id: `locale-panel-${locale.id}`,
|
|
3188
|
+
"aria-labelledby": `locale-tab-${locale.id}`,
|
|
3189
|
+
hidden: activeLocaleTab !== idx,
|
|
3190
|
+
children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
3191
|
+
/* @__PURE__ */ jsx(
|
|
3192
|
+
FormFieldInputText,
|
|
3193
|
+
{
|
|
3194
|
+
...register(`title.${locale.id}`),
|
|
3195
|
+
disabled: formUpdating,
|
|
3196
|
+
error: errors?.title?.[locale.id]?.message,
|
|
3197
|
+
label: "Title",
|
|
3198
|
+
name: `title.${locale.id}`
|
|
3199
|
+
}
|
|
3200
|
+
),
|
|
3201
|
+
/* @__PURE__ */ jsx(
|
|
3202
|
+
FormFieldInputText,
|
|
3203
|
+
{
|
|
3204
|
+
...register(`altText.${locale.id}`),
|
|
3205
|
+
disabled: formUpdating,
|
|
3206
|
+
error: errors?.altText?.[locale.id]?.message,
|
|
3207
|
+
label: "Alt Text",
|
|
3208
|
+
name: `altText.${locale.id}`
|
|
3209
|
+
}
|
|
3210
|
+
),
|
|
3211
|
+
/* @__PURE__ */ jsx(
|
|
3212
|
+
FormFieldInputTextarea,
|
|
3213
|
+
{
|
|
3214
|
+
...register(`description.${locale.id}`),
|
|
3215
|
+
disabled: formUpdating,
|
|
3216
|
+
error: errors?.description?.[locale.id]?.message,
|
|
3217
|
+
label: "Description",
|
|
3218
|
+
name: `description.${locale.id}`,
|
|
3219
|
+
rows: 5
|
|
3220
|
+
}
|
|
3221
|
+
),
|
|
3222
|
+
creditLine?.enabled && /* @__PURE__ */ jsx(
|
|
3223
|
+
FormFieldInputText,
|
|
3224
|
+
{
|
|
3225
|
+
...register(`creditLine.${locale.id}`),
|
|
3226
|
+
error: errors?.creditLine?.[locale.id]?.message,
|
|
3227
|
+
label: "Credit",
|
|
3228
|
+
name: `creditLine.${locale.id}`,
|
|
3229
|
+
disabled: formUpdating || creditLine?.excludeSources?.includes(currentAsset?.source?.name)
|
|
3230
|
+
}
|
|
3231
|
+
)
|
|
3232
|
+
] })
|
|
3233
|
+
},
|
|
3234
|
+
locale.id
|
|
3235
|
+
))
|
|
3236
|
+
] }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3237
|
+
/* @__PURE__ */ jsx(
|
|
3238
|
+
FormFieldInputText,
|
|
3239
|
+
{
|
|
3240
|
+
...register("title"),
|
|
3241
|
+
disabled: formUpdating,
|
|
3242
|
+
error: errors?.title?.message,
|
|
3243
|
+
label: "Title",
|
|
3244
|
+
name: "title",
|
|
3245
|
+
value: toStringField(currentAsset?.title)
|
|
3246
|
+
}
|
|
3247
|
+
),
|
|
3248
|
+
/* @__PURE__ */ jsx(
|
|
3249
|
+
FormFieldInputText,
|
|
3250
|
+
{
|
|
3251
|
+
...register("altText"),
|
|
3252
|
+
disabled: formUpdating,
|
|
3253
|
+
error: errors?.altText?.message,
|
|
3254
|
+
label: "Alt Text",
|
|
3255
|
+
name: "altText",
|
|
3256
|
+
value: toStringField(currentAsset?.altText)
|
|
3257
|
+
}
|
|
3258
|
+
),
|
|
3259
|
+
/* @__PURE__ */ jsx(
|
|
3260
|
+
FormFieldInputTextarea,
|
|
3261
|
+
{
|
|
3262
|
+
...register("description"),
|
|
3263
|
+
disabled: formUpdating,
|
|
3264
|
+
error: errors?.description?.message,
|
|
3265
|
+
label: "Description",
|
|
3266
|
+
name: "description",
|
|
3267
|
+
rows: 5,
|
|
3268
|
+
value: toStringField(currentAsset?.description)
|
|
3269
|
+
}
|
|
3270
|
+
),
|
|
3271
|
+
creditLine?.enabled && /* @__PURE__ */ jsx(
|
|
3272
|
+
FormFieldInputText,
|
|
3273
|
+
{
|
|
3274
|
+
...register("creditLine"),
|
|
3275
|
+
error: errors?.creditLine?.message,
|
|
3276
|
+
label: "Credit",
|
|
3277
|
+
name: "creditLine",
|
|
3278
|
+
value: toStringField(currentAsset?.creditLine),
|
|
3279
|
+
disabled: formUpdating || creditLine?.excludeSources?.includes(currentAsset?.source?.name)
|
|
3280
|
+
}
|
|
3281
|
+
)
|
|
3282
|
+
] })
|
|
3192
3283
|
] });
|
|
3193
3284
|
}
|
|
3194
3285
|
function renderDefaultDetails(props) {
|
|
@@ -3198,16 +3289,37 @@ const DialogAssetEdit = (props) => {
|
|
|
3198
3289
|
const {
|
|
3199
3290
|
children,
|
|
3200
3291
|
dialog: { assetId, id, lastCreatedTag, lastRemovedTagIds }
|
|
3201
|
-
} = props, client = useVersionedClient(), scheme = useColorSchemeValue(), documentStore = useDocumentStore(), dispatch = useDispatch(), assetItem = useTypedSelector((state) => selectAssetById(state, String(assetId))), tags = useTypedSelector(selectTags), assetUpdatedPrev = useRef(void 0), [assetSnapshot, setAssetSnapshot] = useState(assetItem?.asset), [tabSection, setTabSection] = useState("details"), currentAsset = assetItem ? assetItem?.asset : assetSnapshot, allTagOptions = getTagSelectOptions(tags), assetTagOptions = useTypedSelector(selectTagSelectOptions(currentAsset)), { creditLine, components: { details: CustomDetails } = {} } = useToolOptions(), generateDefaultValues = useCallback(
|
|
3202
|
-
(asset) =>
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3292
|
+
} = props, client = useVersionedClient(), scheme = useColorSchemeValue(), documentStore = useDocumentStore(), dispatch = useDispatch(), assetItem = useTypedSelector((state) => selectAssetById(state, String(assetId))), tags = useTypedSelector(selectTags), assetUpdatedPrev = useRef(void 0), [assetSnapshot, setAssetSnapshot] = useState(assetItem?.asset), [tabSection, setTabSection] = useState("details"), currentAsset = assetItem ? assetItem?.asset : assetSnapshot, allTagOptions = getTagSelectOptions(tags), assetTagOptions = useTypedSelector(selectTagSelectOptions(currentAsset)), { creditLine, components: { details: CustomDetails } = {}, locales } = useToolOptions(), generateDefaultValues = useCallback(
|
|
3293
|
+
(asset) => {
|
|
3294
|
+
if (locales && locales.length > 0) {
|
|
3295
|
+
const makeLocaleObj = (field) => {
|
|
3296
|
+
const obj = {};
|
|
3297
|
+
for (let i = 0; i < locales.length; i++) {
|
|
3298
|
+
const locale = locales[i];
|
|
3299
|
+
typeof field == "object" && field && field[locale.id] ? obj[locale.id] = field[locale.id] : typeof field == "string" ? obj[locale.id] = i === 0 ? field : "" : obj[locale.id] = "";
|
|
3300
|
+
}
|
|
3301
|
+
return obj;
|
|
3302
|
+
};
|
|
3303
|
+
return {
|
|
3304
|
+
altText: makeLocaleObj(asset?.altText),
|
|
3305
|
+
creditLine: makeLocaleObj(asset?.creditLine),
|
|
3306
|
+
description: makeLocaleObj(asset?.description),
|
|
3307
|
+
originalFilename: asset?.originalFilename || "",
|
|
3308
|
+
opt: { media: { tags: assetTagOptions } },
|
|
3309
|
+
title: makeLocaleObj(asset?.title)
|
|
3310
|
+
};
|
|
3311
|
+
}
|
|
3312
|
+
const flattenField = (field) => typeof field == "string" ? field : typeof field == "object" && field !== null && Object.values(field).find((v) => v) || "";
|
|
3313
|
+
return {
|
|
3314
|
+
altText: flattenField(asset?.altText),
|
|
3315
|
+
creditLine: flattenField(asset?.creditLine),
|
|
3316
|
+
description: flattenField(asset?.description),
|
|
3317
|
+
originalFilename: asset?.originalFilename || "",
|
|
3318
|
+
opt: { media: { tags: assetTagOptions } },
|
|
3319
|
+
title: flattenField(asset?.title)
|
|
3320
|
+
};
|
|
3321
|
+
},
|
|
3322
|
+
[assetTagOptions, locales]
|
|
3211
3323
|
), {
|
|
3212
3324
|
control,
|
|
3213
3325
|
// Read the formState before render to subscribe the form state through Proxy
|
|
@@ -3220,7 +3332,7 @@ const DialogAssetEdit = (props) => {
|
|
|
3220
3332
|
} = useForm({
|
|
3221
3333
|
defaultValues: generateDefaultValues(assetItem?.asset),
|
|
3222
3334
|
mode: "onChange",
|
|
3223
|
-
resolver: zodResolver(
|
|
3335
|
+
resolver: zodResolver(getAssetFormSchema(locales))
|
|
3224
3336
|
}), formUpdating = !assetItem || assetItem?.updating, handleClose = useCallback(() => {
|
|
3225
3337
|
dispatch(dialogActions.remove({ id }));
|
|
3226
3338
|
}, [dispatch, id]), handleDelete = useCallback(() => {
|
|
@@ -3243,7 +3355,39 @@ const DialogAssetEdit = (props) => {
|
|
|
3243
3355
|
);
|
|
3244
3356
|
},
|
|
3245
3357
|
[currentAsset?._id, dispatch]
|
|
3246
|
-
),
|
|
3358
|
+
), hasOrphanedLocales = useMemo(() => {
|
|
3359
|
+
if (!currentAsset) return !1;
|
|
3360
|
+
const isLocaleObj = (v) => typeof v == "object" && v !== null && !Array.isArray(v), fields = [
|
|
3361
|
+
currentAsset.title,
|
|
3362
|
+
currentAsset.altText,
|
|
3363
|
+
currentAsset.description,
|
|
3364
|
+
...currentAsset._type === "sanity.imageAsset" ? [currentAsset.creditLine] : []
|
|
3365
|
+
];
|
|
3366
|
+
if (!fields.some((f) => isLocaleObj(f))) return !1;
|
|
3367
|
+
if (!locales || locales.length === 0) return !0;
|
|
3368
|
+
const configuredIds = new Set(locales.map((l) => l.id));
|
|
3369
|
+
return fields.some((f) => isLocaleObj(f) ? Object.keys(f).some((k) => !configuredIds.has(k)) : !1);
|
|
3370
|
+
}, [currentAsset, locales]), handleCleanupLocales = useCallback(async () => {
|
|
3371
|
+
if (!currentAsset) return;
|
|
3372
|
+
const cleanField = (field) => {
|
|
3373
|
+
if (typeof field != "object" || field === null || Array.isArray(field)) return field;
|
|
3374
|
+
const obj = field;
|
|
3375
|
+
if (!locales || locales.length === 0)
|
|
3376
|
+
return Object.keys(obj).sort().map((k) => obj[k]).find((v) => v) || "";
|
|
3377
|
+
const configuredIds = new Set(locales.map((l) => l.id)), cleaned = {};
|
|
3378
|
+
for (const [key, val] of Object.entries(obj))
|
|
3379
|
+
configuredIds.has(key) && (cleaned[key] = val);
|
|
3380
|
+
return cleaned;
|
|
3381
|
+
};
|
|
3382
|
+
await client.patch(currentAsset._id).set({
|
|
3383
|
+
title: cleanField(currentAsset.title),
|
|
3384
|
+
altText: cleanField(currentAsset.altText),
|
|
3385
|
+
description: cleanField(currentAsset.description),
|
|
3386
|
+
...currentAsset._type === "sanity.imageAsset" && {
|
|
3387
|
+
creditLine: cleanField(currentAsset.creditLine)
|
|
3388
|
+
}
|
|
3389
|
+
}).commit();
|
|
3390
|
+
}, [client, currentAsset, locales]), onSubmit = useCallback(
|
|
3247
3391
|
(formData) => {
|
|
3248
3392
|
if (!assetItem?.asset)
|
|
3249
3393
|
return;
|
|
@@ -3291,27 +3435,42 @@ const DialogAssetEdit = (props) => {
|
|
|
3291
3435
|
}, [getValues, lastRemovedTagIds, setValue]), useEffect(() => {
|
|
3292
3436
|
assetUpdatedPrev.current !== assetItem?.asset._updatedAt && reset(generateDefaultValues(assetItem?.asset)), assetUpdatedPrev.current = assetItem?.asset._updatedAt;
|
|
3293
3437
|
}, [assetItem?.asset, generateDefaultValues, reset]);
|
|
3294
|
-
const Footer = () => /* @__PURE__ */ jsx(Box, { padding: 3, children: /* @__PURE__ */ jsxs(
|
|
3295
|
-
/* @__PURE__ */ jsx(
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3438
|
+
const Footer = () => /* @__PURE__ */ jsx(Box, { padding: 3, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
3439
|
+
hasOrphanedLocales && /* @__PURE__ */ jsx(Card, { padding: 3, radius: 2, shadow: 1, tone: "caution", children: /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "space-between", gap: 3, children: [
|
|
3440
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: "This asset has localized fields that are no longer configured. Clean them up to avoid validation errors." }),
|
|
3441
|
+
/* @__PURE__ */ jsx(
|
|
3442
|
+
Button,
|
|
3443
|
+
{
|
|
3444
|
+
fontSize: 1,
|
|
3445
|
+
mode: "ghost",
|
|
3446
|
+
onClick: handleCleanupLocales,
|
|
3447
|
+
text: "Cleanup localized fields",
|
|
3448
|
+
tone: "caution"
|
|
3449
|
+
}
|
|
3450
|
+
)
|
|
3451
|
+
] }) }),
|
|
3452
|
+
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", children: [
|
|
3453
|
+
/* @__PURE__ */ jsx(
|
|
3454
|
+
Button,
|
|
3455
|
+
{
|
|
3456
|
+
disabled: formUpdating,
|
|
3457
|
+
fontSize: 1,
|
|
3458
|
+
mode: "bleed",
|
|
3459
|
+
onClick: handleDelete,
|
|
3460
|
+
text: "Delete",
|
|
3461
|
+
tone: "critical"
|
|
3462
|
+
}
|
|
3463
|
+
),
|
|
3464
|
+
/* @__PURE__ */ jsx(
|
|
3465
|
+
FormSubmitButton,
|
|
3466
|
+
{
|
|
3467
|
+
disabled: formUpdating || !isDirty || !isValid || hasOrphanedLocales,
|
|
3468
|
+
isValid,
|
|
3469
|
+
lastUpdated: currentAsset?._updatedAt,
|
|
3470
|
+
onClick: handleSubmit(onSubmit)
|
|
3471
|
+
}
|
|
3472
|
+
)
|
|
3473
|
+
] })
|
|
3315
3474
|
] }) });
|
|
3316
3475
|
if (!currentAsset)
|
|
3317
3476
|
return null;
|
|
@@ -3325,7 +3484,8 @@ const DialogAssetEdit = (props) => {
|
|
|
3325
3484
|
allTagOptions,
|
|
3326
3485
|
handleCreateTag,
|
|
3327
3486
|
currentAsset,
|
|
3328
|
-
creditLine
|
|
3487
|
+
creditLine,
|
|
3488
|
+
locales
|
|
3329
3489
|
};
|
|
3330
3490
|
return /* @__PURE__ */ jsxs(
|
|
3331
3491
|
Dialog,
|
|
@@ -5109,6 +5269,9 @@ const TableRowUpload = (props) => {
|
|
|
5109
5269
|
reducers: {}
|
|
5110
5270
|
});
|
|
5111
5271
|
var selectedReducer = selectedSlice.reducer;
|
|
5272
|
+
function messageFromGenericErrorPayload(payload) {
|
|
5273
|
+
return !payload || typeof payload != "object" ? "Unknown error" : "error" in payload && payload.error && typeof payload.error == "object" && payload.error !== null && "message" in payload.error ? String(payload.error.message) : "message" in payload && typeof payload.message == "string" ? String(payload.message) : "Unknown error";
|
|
5274
|
+
}
|
|
5112
5275
|
const initialState = {
|
|
5113
5276
|
items: []
|
|
5114
5277
|
}, notificationsSlice = createSlice({
|
|
@@ -5195,11 +5358,11 @@ const initialState = {
|
|
|
5195
5358
|
uploadsActions.uploadError.type
|
|
5196
5359
|
),
|
|
5197
5360
|
mergeMap((action) => {
|
|
5198
|
-
const
|
|
5361
|
+
const title = `An error occurred: ${messageFromGenericErrorPayload(action.payload)}`;
|
|
5199
5362
|
return of(
|
|
5200
5363
|
notificationsSlice.actions.add({
|
|
5201
5364
|
status: "error",
|
|
5202
|
-
title
|
|
5365
|
+
title
|
|
5203
5366
|
})
|
|
5204
5367
|
);
|
|
5205
5368
|
})
|
|
@@ -5447,24 +5610,81 @@ const UploadDropzone = (props) => {
|
|
|
5447
5610
|
isDragActive && /* @__PURE__ */ jsx(DragActiveContainer, { children: /* @__PURE__ */ jsx(Flex, { direction: "column", justify: "center", style: { color: white.hex }, children: /* @__PURE__ */ jsx(Text, { size: 3, style: { color: "inherit" }, children: "Drop files to upload" }) }) }),
|
|
5448
5611
|
children
|
|
5449
5612
|
] }) });
|
|
5450
|
-
}
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
const
|
|
5613
|
+
};
|
|
5614
|
+
function getMediaTagNames(schemaType) {
|
|
5615
|
+
const mediaTags = schemaType?.options?.mediaTags;
|
|
5616
|
+
if (!mediaTags?.length) return [];
|
|
5617
|
+
const unique = new Set(
|
|
5618
|
+
mediaTags.map((t) => t?.trim()).filter((t) => !!t?.length)
|
|
5619
|
+
);
|
|
5620
|
+
return Array.from(unique);
|
|
5621
|
+
}
|
|
5622
|
+
function createAssetHandler(dispatch) {
|
|
5623
|
+
return (update) => {
|
|
5624
|
+
const { documentId, result, transition } = update;
|
|
5625
|
+
switch (transition) {
|
|
5626
|
+
case "appear":
|
|
5627
|
+
dispatch(assetsActions.listenerCreateQueue({ asset: result }));
|
|
5628
|
+
break;
|
|
5629
|
+
case "disappear":
|
|
5630
|
+
dispatch(assetsActions.listenerDeleteQueue({ assetId: documentId }));
|
|
5631
|
+
break;
|
|
5632
|
+
case "update":
|
|
5633
|
+
dispatch(assetsActions.listenerUpdateQueue({ asset: result }));
|
|
5634
|
+
break;
|
|
5635
|
+
}
|
|
5636
|
+
};
|
|
5637
|
+
}
|
|
5638
|
+
function createTagHandler(dispatch) {
|
|
5639
|
+
return (update) => {
|
|
5640
|
+
const { documentId, result, transition } = update;
|
|
5641
|
+
switch (transition) {
|
|
5642
|
+
case "appear":
|
|
5643
|
+
dispatch(tagsActions.listenerCreateQueue({ tag: result }));
|
|
5644
|
+
break;
|
|
5645
|
+
case "disappear":
|
|
5646
|
+
dispatch(tagsActions.listenerDeleteQueue({ tagId: documentId }));
|
|
5647
|
+
break;
|
|
5648
|
+
case "update":
|
|
5649
|
+
dispatch(tagsActions.listenerUpdateQueue({ tag: result }));
|
|
5650
|
+
break;
|
|
5651
|
+
}
|
|
5652
|
+
};
|
|
5653
|
+
}
|
|
5654
|
+
function useBrowserInit(client, schemaType) {
|
|
5655
|
+
const dispatch = useDispatch(), tagsByIds = useSelector((state) => state.tags.byIds), tagsFetchCount = useSelector((state) => state.tags.fetchCount), tagNames = getMediaTagNames(schemaType), hasMediaTags = tagNames.length > 0;
|
|
5656
|
+
useEffect(() => {
|
|
5657
|
+
hasMediaTags || dispatch(searchActions.facetsClear()), dispatch(tagsActions.fetchRequest());
|
|
5658
|
+
const assetSubscription = client.listen(
|
|
5462
5659
|
groq`*[_type in ["sanity.fileAsset", "sanity.imageAsset"] && !(_id in path("drafts.**"))]`
|
|
5463
|
-
).subscribe(
|
|
5660
|
+
).subscribe(createAssetHandler(dispatch)), tagSubscription = client.listen(groq`*[_type == "${TAG_DOCUMENT_NAME}" && !(_id in path("drafts.**"))]`).subscribe(createTagHandler(dispatch));
|
|
5464
5661
|
return () => {
|
|
5465
|
-
|
|
5662
|
+
assetSubscription.unsubscribe(), tagSubscription.unsubscribe();
|
|
5466
5663
|
};
|
|
5467
|
-
}, [client, dispatch]),
|
|
5664
|
+
}, [client, dispatch, hasMediaTags]), useEffect(() => {
|
|
5665
|
+
if (!hasMediaTags || tagsFetchCount < 0) return;
|
|
5666
|
+
const tagFacetInput = inputs.tag;
|
|
5667
|
+
if (tagFacetInput.type !== "searchable") return;
|
|
5668
|
+
const resolvedTags = tagNames.map((name) => Object.values(tagsByIds).find((item) => item.tag.name.current === name)).filter((item) => !!item);
|
|
5669
|
+
dispatch(searchActions.facetsClear());
|
|
5670
|
+
for (const tagItem of resolvedTags)
|
|
5671
|
+
dispatch(
|
|
5672
|
+
searchActions.facetsAdd({
|
|
5673
|
+
facet: {
|
|
5674
|
+
...tagFacetInput,
|
|
5675
|
+
operatorType: "references",
|
|
5676
|
+
value: { label: tagItem.tag.name.current, value: tagItem.tag._id }
|
|
5677
|
+
}
|
|
5678
|
+
})
|
|
5679
|
+
);
|
|
5680
|
+
}, [tagsFetchCount, hasMediaTags]);
|
|
5681
|
+
}
|
|
5682
|
+
const BrowserContent = ({
|
|
5683
|
+
onClose,
|
|
5684
|
+
schemaType
|
|
5685
|
+
}) => {
|
|
5686
|
+
const client = useVersionedClient(), [portalElement, setPortalElement] = useState(null);
|
|
5687
|
+
return useBrowserInit(client, schemaType), /* @__PURE__ */ jsx(PortalProvider, { element: portalElement, children: /* @__PURE__ */ jsxs(UploadDropzone, { children: [
|
|
5468
5688
|
/* @__PURE__ */ jsx(Dialogs, {}),
|
|
5469
5689
|
/* @__PURE__ */ jsx(Notifications, {}),
|
|
5470
5690
|
/* @__PURE__ */ jsx(Card, { display: "flex", height: "fill", ref: setPortalElement, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", flex: 1, children: [
|
|
@@ -5491,7 +5711,7 @@ const UploadDropzone = (props) => {
|
|
|
5491
5711
|
selectedAssets: props?.selectedAssets,
|
|
5492
5712
|
children: /* @__PURE__ */ jsxs(AssetBrowserDispatchProvider, { onSelect: props?.onSelect, children: [
|
|
5493
5713
|
/* @__PURE__ */ jsx(GlobalStyle, {}),
|
|
5494
|
-
/* @__PURE__ */ jsx(BrowserContent, { onClose: props?.onClose })
|
|
5714
|
+
/* @__PURE__ */ jsx(BrowserContent, { onClose: props?.onClose, schemaType: props?.schemaType })
|
|
5495
5715
|
] })
|
|
5496
5716
|
}
|
|
5497
5717
|
);
|
|
@@ -5518,7 +5738,7 @@ const UploadDropzone = (props) => {
|
|
|
5518
5738
|
width: "100%",
|
|
5519
5739
|
zIndex
|
|
5520
5740
|
},
|
|
5521
|
-
children: /* @__PURE__ */ jsx(Browser, { document: currentDocument, ...props })
|
|
5741
|
+
children: /* @__PURE__ */ jsx(Browser, { document: currentDocument, schemaType: props.schemaType, ...props })
|
|
5522
5742
|
}
|
|
5523
5743
|
) }) });
|
|
5524
5744
|
}, useRootPortalElement = () => {
|
|
@@ -5583,9 +5803,78 @@ const plugin = {
|
|
|
5583
5803
|
types: [mediaTag]
|
|
5584
5804
|
},
|
|
5585
5805
|
tools: (prev) => [...prev, tool]
|
|
5586
|
-
}));
|
|
5806
|
+
})), pendingByAsset = /* @__PURE__ */ new Map();
|
|
5807
|
+
function applyMediaTags(options) {
|
|
5808
|
+
const { assetId } = options, chain = (pendingByAsset.get(assetId) ?? Promise.resolve()).then(
|
|
5809
|
+
() => doApplyMediaTags(options)
|
|
5810
|
+
), cleanup = chain.catch(() => {
|
|
5811
|
+
}).finally(() => {
|
|
5812
|
+
pendingByAsset.get(assetId) === cleanup && pendingByAsset.delete(assetId);
|
|
5813
|
+
});
|
|
5814
|
+
return pendingByAsset.set(assetId, cleanup), chain;
|
|
5815
|
+
}
|
|
5816
|
+
async function doApplyMediaTags({
|
|
5817
|
+
client,
|
|
5818
|
+
assetId,
|
|
5819
|
+
mediaTags,
|
|
5820
|
+
createTagsOnUpload = !0
|
|
5821
|
+
}) {
|
|
5822
|
+
if (!mediaTags || mediaTags.length === 0) return;
|
|
5823
|
+
const validTags = (await Promise.all(
|
|
5824
|
+
mediaTags.map(async (tagName) => await client.fetch(
|
|
5825
|
+
groq`*[_type == "${TAG_DOCUMENT_NAME}" && name.current == $tagName][0]`,
|
|
5826
|
+
{ tagName }
|
|
5827
|
+
) || (createTagsOnUpload ? await client.create({
|
|
5828
|
+
_type: TAG_DOCUMENT_NAME,
|
|
5829
|
+
name: { _type: "slug", current: tagName }
|
|
5830
|
+
}) : null))
|
|
5831
|
+
)).filter((tag) => tag !== null);
|
|
5832
|
+
if (validTags.length === 0) return;
|
|
5833
|
+
const existing = await client.fetch(
|
|
5834
|
+
groq`*[_id == $assetId][0]{'tagIds': opt.media.tags[]._ref}`,
|
|
5835
|
+
{ assetId },
|
|
5836
|
+
{ useCdn: !1 }
|
|
5837
|
+
// bypass CDN cache so we see the latest committed tag refs
|
|
5838
|
+
), existingIds = new Set(existing?.tagIds ?? []), tagReferences = validTags.filter((tag) => !existingIds.has(tag._id)).map((tag) => ({
|
|
5839
|
+
_key: nanoid(),
|
|
5840
|
+
_ref: tag._id,
|
|
5841
|
+
_type: "reference",
|
|
5842
|
+
_weak: !0
|
|
5843
|
+
}));
|
|
5844
|
+
tagReferences.length !== 0 && await client.patch(assetId).setIfMissing({ opt: {} }).setIfMissing({ "opt.media": {} }).setIfMissing({ "opt.media.tags": [] }).append("opt.media.tags", tagReferences).commit();
|
|
5845
|
+
}
|
|
5846
|
+
function AutoTagInput(props) {
|
|
5847
|
+
const { renderDefault, schemaType, value, mediaTags: mediaTagsProp } = props, toast = useToast(), mediaTags = mediaTagsProp ?? schemaType?.options?.mediaTags, client = useVersionedClient(), { createTagsOnUpload } = useToolOptions(), prevAssetRef = useRef(void 0), isInitialMount = useRef(!0), currentAssetRef = value?.asset?._ref;
|
|
5848
|
+
return useEffect(() => {
|
|
5849
|
+
if (isInitialMount.current) {
|
|
5850
|
+
isInitialMount.current = !1, prevAssetRef.current = currentAssetRef;
|
|
5851
|
+
return;
|
|
5852
|
+
}
|
|
5853
|
+
const previousRef = prevAssetRef.current;
|
|
5854
|
+
prevAssetRef.current = currentAssetRef, !(!mediaTags?.length || !currentAssetRef || currentAssetRef === previousRef) && applyMediaTags({
|
|
5855
|
+
client,
|
|
5856
|
+
assetId: currentAssetRef,
|
|
5857
|
+
mediaTags,
|
|
5858
|
+
createTagsOnUpload
|
|
5859
|
+
}).catch((err) => {
|
|
5860
|
+
console.error("[sanity-plugin-media] Failed to apply auto-tags:", err);
|
|
5861
|
+
const label = mediaTags.length === 1 ? "tag" : "tags";
|
|
5862
|
+
toast.push({ closable: !0, status: "error", title: `Failed to apply the media ${label} ${mediaTags.join(", ")}` });
|
|
5863
|
+
});
|
|
5864
|
+
}, [currentAssetRef, mediaTags, client, createTagsOnUpload]), renderDefault(props);
|
|
5865
|
+
}
|
|
5866
|
+
function mediaField(config) {
|
|
5867
|
+
const { mediaTags, options, components: components2, ...rest } = config;
|
|
5868
|
+
return {
|
|
5869
|
+
...rest,
|
|
5870
|
+
options: { ...options, mediaTags },
|
|
5871
|
+
components: { ...components2, input: AutoTagInput }
|
|
5872
|
+
};
|
|
5873
|
+
}
|
|
5587
5874
|
export {
|
|
5875
|
+
AutoTagInput,
|
|
5588
5876
|
media,
|
|
5589
|
-
mediaAssetSource
|
|
5877
|
+
mediaAssetSource,
|
|
5878
|
+
mediaField
|
|
5590
5879
|
};
|
|
5591
5880
|
//# sourceMappingURL=index.mjs.map
|