@electrolux-oss/sanity-plugin-media 5.0.1 → 5.1.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/README.md CHANGED
@@ -223,7 +223,18 @@ The plugin adds an **Edit Media** option to the asset menu of image and file fie
223
223
 
224
224
  ### Link the plugin to a local studio
225
225
 
226
- **Step 1: Set up the plugin for local development**
226
+ **Step 1: Install the studio's dependencies**
227
+
228
+ In your studio project directory, run:
229
+
230
+ ```zsh
231
+ npm install
232
+ ```
233
+
234
+ This installs the published version of the plugin, so its own dependencies end up in the
235
+ studio's `node_modules`.
236
+
237
+ **Step 2: Publish the plugin to yalc and watch for changes**
227
238
 
228
239
  In the plugin directory, run:
229
240
 
@@ -234,29 +245,33 @@ npm run link-watch
234
245
  This will:
235
246
 
236
247
  - Build your plugin automatically whenever code changes
237
- - Publish the package to a local yalc repository
248
+ - Publish the package to a local yalc repository and push it to linked studios
238
249
 
239
- **Step 2: Link the plugin to your studio**
250
+ **Step 3: Link the plugin to your studio**
240
251
 
241
252
  In your studio project directory, run:
242
253
 
243
254
  ```zsh
244
- npx yalc add @electrolux-oss/sanity-plugin-media && npm install
255
+ npx yalc link @electrolux-oss/sanity-plugin-media
245
256
  ```
246
257
 
247
- **Step 3: Verify the setup**
258
+ **Step 4: Verify the setup**
248
259
 
249
- Check your studio's `package.json` - you should see:
260
+ `node_modules/@electrolux-oss/sanity-plugin-media` is now a symlink to
261
+ `.yalc/@electrolux-oss/sanity-plugin-media`, and the studio's `package.json` is unchanged:
250
262
 
251
- ```json
252
- "@electrolux-oss/sanity-plugin-media": "file:.yalc/@electrolux-oss/sanity-plugin-media"
263
+ ```zsh
264
+ ls -l node_modules/@electrolux-oss/
265
+ git diff package.json # no change
253
266
  ```
254
267
 
255
- Now you can use the local version of the plugin:
268
+ Don't run `npm install` in the studio while linked: it replaces the link with the published
269
+ version. Run `npx yalc link @electrolux-oss/sanity-plugin-media` again if you did. To stop,
270
+ run `npx yalc remove @electrolux-oss/sanity-plugin-media && npm install`.
256
271
 
257
- ```typescript
258
- import { media } from '@electrolux-oss/sanity-plugin-media'
259
- ```
272
+ Avoid `yalc add` here. It writes `file:.yalc/…` into the studio's `package.json`, and with
273
+ `link-watch` every rebuild replaces the plugin with a copy that can't resolve the plugin's own
274
+ dependencies.
260
275
 
261
276
  ### Making changes
262
277
 
@@ -268,12 +283,46 @@ serves the old build.
268
283
 
269
284
  ```zsh
270
285
  npm run typecheck # tsc --noEmit
271
- npm run lint # ESLint
272
- npm run build # also fails on type errors
286
+ npm run lint # oxlint, type-aware; warnings count as errors
287
+ npm run format # oxfmt
288
+ npm run build # plugin-kit verify-package, then pkg-utils
273
289
  ```
274
290
 
275
291
  This plugin has no automated tests yet.
276
292
 
293
+ `npm run build` doesn't type-check (pkg-utils 13 generates types without checking them), so
294
+ run `typecheck` or `lint` to catch type errors.
295
+
296
+ ### Formatting
297
+
298
+ The plugin is formatted with [oxfmt](https://oxc.rs/docs/guide/usage/formatter.html), using
299
+ plugin-kit's preset with the repository's previous Prettier settings on top (see
300
+ `oxfmt.config.ts`). To format on save in VS Code, install the
301
+ [Oxc extension](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode) and make it
302
+ the default formatter for this workspace; a global Prettier formatter would undo oxfmt's
303
+ import and `package.json` sorting.
304
+
305
+ ### Publishing
306
+
307
+ Releases are published with pnpm, while development uses npm:
308
+
309
+ ```zsh
310
+ npm run publish:next:dry-run # what would ship
311
+ npm run publish:next # publish behind the next tag
312
+ ```
313
+
314
+ pnpm is a pinned devDependency, so `npm ci` installs it. Don't use `npm publish`.
315
+
316
+ pkg-utils writes a `source` condition into `exports` for local development and a
317
+ `source`-less `publishConfig.exports` for the published package. pnpm applies
318
+ `publishConfig` when it packs the package; npm doesn't, and would publish an export that points
319
+ at `src/`, which isn't shipped. To check what the packed `package.json` exports:
320
+
321
+ ```zsh
322
+ D=$(mktemp -d) && npx pnpm pack --pack-destination "$D" >/dev/null && tar xzf "$D"/*.tgz -C "$D" && node -p "JSON.stringify(require('$D/package/package.json').exports)"
323
+ # -> {".":"./dist/index.js","./package.json":"./package.json"}, no "source"
324
+ ```
325
+
277
326
  ## Breaking changes
278
327
 
279
328
  ### **v4 → v5**
package/dist/index.d.ts CHANGED
@@ -1,221 +1,158 @@
1
- import { AssetSourceComponentProps } from 'sanity'
2
- import type { ComponentType } from 'react'
3
- import type { Control } from 'react-hook-form'
4
- import type { FieldDefinitionBase } from 'sanity'
5
- import type { FieldErrors } from 'react-hook-form'
6
- import type { FileDefinition } from 'sanity'
7
- import { ForwardRefExoticComponent } from 'react'
8
- import type { ImageDefinition } from 'sanity'
9
- import type { InputProps } from 'sanity'
10
- import { JSX } from 'react'
11
- import { Plugin as Plugin_2 } from 'sanity'
12
- import { RefAttributes } from 'react'
13
- import type { SanityAssetDocument } from '@sanity/client'
14
- import type { SanityImageAssetDocument } from '@sanity/client'
15
- import { SVGProps } from 'react'
16
- import type { UseFormRegister } from 'react-hook-form'
17
- import type { WidenInitialValue } from 'sanity'
18
- import type { WidenValidation } from 'sanity'
19
- import * as z from 'zod'
20
-
21
- declare type Asset = FileAsset | ImageAsset
22
-
23
- declare type AssetFormData = z.infer<AssetFormSchemaObject>
24
-
25
- declare type AssetFormSchemaObject = ReturnType<typeof createAssetFormSchema>
26
-
27
- /**
28
- * Image / file input that tags the selected or uploaded asset with `mediaTags`.
29
- *
30
- * Tags come from the `mediaTags` prop, falling back to `options.mediaTags` on the field
31
- * (which also pre-filters the media browser). Only changes made after mount are tagged,
32
- * so opening a document never patches its existing assets.
33
- */
34
- export declare function AutoTagInput(props: AutoTagInputProps): JSX
35
-
36
- export declare type AutoTagInputProps = InputProps & {
37
- mediaTags?: string[]
38
- }
39
-
40
- declare const createAssetFormSchema: (
41
- languages: MediaToolOptions['languages'],
42
- validateAltTexts?: boolean
43
- ) => z.ZodObject<
44
- {
45
- altText: z.ZodOptional<z.ZodString>
46
- altTexts: z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodNullable<z.ZodString>>>
47
- creditLine: z.ZodOptional<z.ZodString>
48
- description: z.ZodOptional<z.ZodString>
49
- opt: z.ZodObject<
50
- {
51
- media: z.ZodObject<
52
- {
53
- tags: z.ZodNullable<
54
- z.ZodArray<
55
- z.ZodObject<
56
- {
57
- label: z.ZodString
58
- value: z.ZodString
59
- },
60
- z.core.$strip
61
- >
62
- >
63
- >
64
- },
65
- z.core.$strip
66
- >
67
- },
68
- z.core.$strip
69
- >
70
- originalFilename: z.ZodString
71
- title: z.ZodOptional<z.ZodString>
72
- },
73
- z.core.$strip
74
- >
75
-
76
- declare type CustomFields = {
77
- altText?: string
78
- altTexts?: Record<string, string>
79
- description?: string
80
- opt?: {
81
- media?: {
82
- tags?: SanityReference[]
83
- uploadedBy?: Uploader | string
84
- }
85
- }
86
- title?: string
87
- }
88
-
89
- declare type DetailsProps = {
90
- formUpdating: boolean
91
- handleCreateTag: (title: string) => void
92
- control: Control<AssetFormData>
93
- errors: FieldErrors<AssetFormData>
94
- register: UseFormRegister<AssetFormData>
95
- allTagOptions: TagSelectOption[]
96
- assetTagOptions: TagSelectOption[] | null
97
- currentAsset: Asset
1
+ import { ComponentType, JSX } from "react";
2
+ import { FieldDefinitionBase, FileDefinition, ImageDefinition, InputProps, WidenInitialValue, WidenValidation } from "sanity";
3
+ import * as z from "zod";
4
+ import "react-redux";
5
+ import "@reduxjs/toolkit";
6
+ import "redux-observable";
7
+ import { Control, FieldErrors, UseFormRegister } from "react-hook-form";
8
+ import { SanityAssetDocument, SanityImageAssetDocument } from "@sanity/client";
9
+ declare const tagOptionSchema: z.ZodObject<{
10
+ label: z.ZodString;
11
+ value: z.ZodString;
12
+ }, z.core.$strip>;
13
+ declare const createAssetFormSchema: (languages: MediaToolOptions["languages"], validateAltTexts?: boolean) => z.ZodObject<{
14
+ altText: z.ZodOptional<z.ZodString>;
15
+ altTexts: z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodNullable<z.ZodString>>>;
16
+ creditLine: z.ZodOptional<z.ZodString>;
17
+ description: z.ZodOptional<z.ZodString>;
18
+ opt: z.ZodObject<{
19
+ media: z.ZodObject<{
20
+ tags: z.ZodNullable<z.ZodArray<z.ZodObject<{
21
+ label: z.ZodString;
22
+ value: z.ZodString;
23
+ }, z.core.$strip>>>;
24
+ }, z.core.$strip>;
25
+ }, z.core.$strip>;
26
+ originalFilename: z.ZodString;
27
+ title: z.ZodOptional<z.ZodString>;
28
+ }, z.core.$strip>;
29
+ type AssetFormSchemaObject = ReturnType<typeof createAssetFormSchema>;
30
+ type DetailsProps = {
31
+ formUpdating: boolean;
32
+ handleCreateTag: (title: string) => void;
33
+ control: Control<AssetFormData>;
34
+ errors: FieldErrors<AssetFormData>;
35
+ register: UseFormRegister<AssetFormData>;
36
+ allTagOptions: TagSelectOption[];
37
+ assetTagOptions: TagSelectOption[] | null;
38
+ currentAsset: Asset;
98
39
  creditLine?: {
99
- enabled: boolean
100
- excludeSources?: string | string[] | undefined
101
- }
102
- }
103
-
104
- declare type FileAsset = SanityAssetDocument &
105
- CustomFields & {
106
- _type: 'sanity.fileAsset'
107
- }
108
-
109
- declare type ImageAsset = SanityImageAssetDocument &
110
- CustomFields & {
111
- _type: 'sanity.imageAsset'
112
- creditLine?: string
40
+ enabled: boolean;
41
+ excludeSources?: string | string[] | undefined;
42
+ };
43
+ };
44
+ declare global {
45
+ interface SymbolConstructor {
46
+ readonly observable: symbol;
113
47
  }
114
-
115
- export declare const media: Plugin_2<void | MediaToolOptions>
116
-
117
- export declare const mediaAssetSource: {
118
- component: (props: AssetSourceComponentProps) => JSX
119
- uploadMode: 'component'
120
- icon: ForwardRefExoticComponent<
121
- Omit<SVGProps<SVGSVGElement>, 'ref'> & RefAttributes<SVGSVGElement>
122
- >
123
- name: string
124
- title: string
125
48
  }
126
-
127
- /**
128
- * Defines an image or file field whose selected / uploaded assets are tagged with `mediaTags`.
129
- *
130
- * `mediaTags` is copied to `options.mediaTags` (which pre-filters the media browser) and
131
- * {@link AutoTagInput} is set as the input component.
132
- *
133
- * ```ts
134
- * mediaField({ name: 'image', type: 'image', mediaTags: ['product'] })
135
- * ```
136
- */
137
- export declare function mediaField(
138
- config: MediaFieldConfig<ImageDefinition>
139
- ): MediaFieldResult<ImageDefinition>
140
-
141
- export declare function mediaField(
142
- config: MediaFieldConfig<FileDefinition>
143
- ): MediaFieldResult<FileDefinition>
144
-
145
- declare type MediaFieldConfig<T extends ImageDefinition | FileDefinition> = Omit<T, 'options'> &
146
- FieldDefinitionBase & {
147
- name: string
148
- mediaTags: string[]
149
- options?: T['options']
150
- }
151
-
152
- declare type MediaFieldResult<T extends ImageDefinition | FileDefinition> = Omit<T, 'options'> &
153
- FieldDefinitionBase & {
154
- options?: T['options'] & {
155
- mediaTags: string[]
156
- }
157
- components: {
158
- input: typeof AutoTagInput
159
- }
160
- } & WidenValidation &
161
- WidenInitialValue
162
-
163
- export declare type MediaToolOptions = {
49
+ type MediaToolOptions = {
164
50
  languages: {
165
- code: string
166
- title: string
167
- default?: boolean
168
- }[]
169
- maximumUploadSize?: number
170
- createTagsOnUpload?: boolean
51
+ code: string;
52
+ title: string;
53
+ default?: boolean;
54
+ }[];
55
+ maximumUploadSize?: number;
56
+ createTagsOnUpload?: boolean;
171
57
  components?: {
172
- details?: ComponentType<
173
- DetailsProps & {
174
- renderDefaultDetails: (props: DetailsProps) => JSX.Element
175
- }
176
- >
177
- }
58
+ details?: ComponentType<DetailsProps & {
59
+ renderDefaultDetails: (props: DetailsProps) => JSX.Element;
60
+ }>;
61
+ };
178
62
  creditLine: {
179
- enabled: boolean
180
- excludeSources?: string | string[]
181
- }
182
- directUploads?: boolean
183
- uploadMenu?: boolean
63
+ enabled: boolean;
64
+ excludeSources?: string | string[];
65
+ };
66
+ directUploads?: boolean;
67
+ uploadMenu?: boolean;
184
68
  /**
185
69
  * Tag slugs (`media.tag` `name.current`) whose assets are hidden from the Media browser and
186
70
  * asset picker, along with the tags themselves in the tag panel and tag search facet.
187
71
  * The asset edit dialog still lists every tag.
188
72
  */
189
- excludeTags?: string[]
190
- }
191
-
192
- declare type SanityReference = {
193
- _ref: string
194
- _type: 'reference'
195
- _weak?: boolean
196
- }
197
-
198
- declare const tagOptionSchema: z.ZodObject<
199
- {
200
- label: z.ZodString
201
- value: z.ZodString
202
- },
203
- z.core.$strip
204
- >
205
-
206
- declare type TagSelectOption = z.infer<typeof tagOptionSchema>
207
-
208
- declare type Uploader = {
209
- id: string
73
+ excludeTags?: string[];
74
+ };
75
+ type Uploader = {
76
+ id: string;
210
77
  /** Only set by earlier builds; the name is now looked up on demand. */
211
- name?: string
212
- }
213
-
214
- export {}
215
-
78
+ name?: string;
79
+ };
80
+ type CustomFields = {
81
+ altText?: string;
82
+ altTexts?: Record<string, string>;
83
+ description?: string;
84
+ opt?: {
85
+ media?: {
86
+ tags?: SanityReference[];
87
+ uploadedBy?: Uploader | string;
88
+ };
89
+ };
90
+ title?: string;
91
+ };
92
+ type Asset = FileAsset | ImageAsset;
93
+ type AssetFormData = z.infer<AssetFormSchemaObject>;
94
+ type FileAsset = SanityAssetDocument & CustomFields & {
95
+ _type: 'sanity.fileAsset';
96
+ };
97
+ type ImageAsset = SanityImageAssetDocument & CustomFields & {
98
+ _type: 'sanity.imageAsset';
99
+ creditLine?: string;
100
+ };
101
+ type SanityReference = {
102
+ _ref: string;
103
+ _type: 'reference';
104
+ _weak?: boolean;
105
+ };
106
+ type TagSelectOption = z.infer<typeof tagOptionSchema>;
216
107
  declare module 'sanity' {
217
108
  interface FileOptions {
218
109
  /** Tags applied by `AutoTagInput` / `mediaField`, also used to pre-filter the media browser. */
219
- mediaTags?: string[]
110
+ mediaTags?: string[];
220
111
  }
221
112
  }
113
+ export declare const mediaAssetSource: {
114
+ component: (props: import("sanity").AssetSourceComponentProps) => import("react/jsx-runtime").JSX.Element;
115
+ uploadMode: "component";
116
+ icon: import("react").ForwardRefExoticComponent<Omit<import("react").SVGProps<SVGSVGElement>, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
117
+ name: string;
118
+ title: string;
119
+ };
120
+ export declare const media: import("sanity").Plugin<void | MediaToolOptions>;
121
+ type AutoTagInputProps = InputProps & {
122
+ mediaTags?: string[];
123
+ };
124
+ /**
125
+ * Image / file input that tags the selected or uploaded asset with `mediaTags`.
126
+ *
127
+ * Tags come from the `mediaTags` prop, falling back to `options.mediaTags` on the field
128
+ * (which also pre-filters the media browser). Only changes made after mount are tagged,
129
+ * so opening a document never patches its existing assets.
130
+ */
131
+ export declare function AutoTagInput(props: AutoTagInputProps): import("react").JSX.Element;
132
+ type MediaFieldConfig<T extends ImageDefinition | FileDefinition> = Omit<T, 'options'> & FieldDefinitionBase & {
133
+ name: string;
134
+ mediaTags: string[];
135
+ options?: T['options'];
136
+ };
137
+ type MediaFieldResult<T extends ImageDefinition | FileDefinition> = Omit<T, 'options'> & FieldDefinitionBase & {
138
+ options?: T['options'] & {
139
+ mediaTags: string[];
140
+ };
141
+ components: {
142
+ input: typeof AutoTagInput;
143
+ };
144
+ } & WidenValidation & WidenInitialValue;
145
+ /**
146
+ * Defines an image or file field whose selected / uploaded assets are tagged with `mediaTags`.
147
+ *
148
+ * `mediaTags` is copied to `options.mediaTags` (which pre-filters the media browser) and
149
+ * {@link AutoTagInput} is set as the input component.
150
+ *
151
+ * ```ts
152
+ * mediaField({ name: 'image', type: 'image', mediaTags: ['product'] })
153
+ * ```
154
+ */
155
+ export declare function mediaField(config: MediaFieldConfig<ImageDefinition>): MediaFieldResult<ImageDefinition>;
156
+ export declare function mediaField(config: MediaFieldConfig<FileDefinition>): MediaFieldResult<FileDefinition>;
157
+ export type { AutoTagInputProps, MediaToolOptions };
158
+ //# sourceMappingURL=index.d.ts.map