@calmlens/sdk 0.16.3 → 0.18.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.
Files changed (114) hide show
  1. package/README.md +425 -181
  2. package/bin/calmlens.js +16016 -0
  3. package/bin/package.json +1 -0
  4. package/cjs/BrowserUpload-BT091eOB.d.ts +11 -0
  5. package/cjs/BrowserUpload-CQwXEGFv.js +10 -0
  6. package/cjs/CalmLensAppClient-CHQGu-Do.js +89 -0
  7. package/cjs/CalmLensAppClient-CV_K26Ce.d.ts +40 -0
  8. package/cjs/CalmLensConnection-B8Bu2j3y.js +659 -0
  9. package/cjs/CalmLensServerClient-C5o2A8MW.js +645 -0
  10. package/cjs/CalmLensServerClient-JtP687a3.d.ts +235 -0
  11. package/cjs/CalmLensTypes-9Vt16pc7.d.ts +40400 -0
  12. package/cjs/Classification-94kSYWZw-CMnQKW13.d.ts +5873 -0
  13. package/cjs/CryptoUtils-B_x8lMIx-YBW1-bvL.js +42 -0
  14. package/cjs/FileIcons-Ob003MdS.js +175 -0
  15. package/cjs/Jurisdiction-FusEXb4U-zVs21tDv.js +91 -0
  16. package/cjs/ModerationContext-9lGm-Mna-CcmbRnOy.d.ts +67 -0
  17. package/cjs/ModerationContextLimits-DelWfmiJ.js +1311 -0
  18. package/cjs/ReactUpload-CAyCsyG6.d.ts +17 -0
  19. package/cjs/ReactUpload-Cfg5JYUq.js +54 -0
  20. package/cjs/TestTriggers-By07LR31-CmK0yTyR.d.ts +271 -0
  21. package/cjs/TestTriggers-DTc_iMJF-BjMPq4_3.js +1327 -0
  22. package/cjs/UploadController-BGO1eyzb.js +618 -0
  23. package/{esm/index-C9Xw1aid.d.ts → cjs/WebhookPayload-2aL31v0J.d.ts} +131 -155
  24. package/cjs/app.d.ts +7 -44
  25. package/cjs/app.js +11 -89
  26. package/cjs/elements.d.ts +88 -0
  27. package/cjs/elements.js +555 -0
  28. package/cjs/file-icons.d.ts +67 -0
  29. package/cjs/file-icons.js +10 -0
  30. package/cjs/index-CI4BzN4W.d.ts +252 -0
  31. package/cjs/index.d.ts +6 -4
  32. package/cjs/index.js +9 -4
  33. package/cjs/react-native.d.ts +56 -0
  34. package/cjs/react-native.js +495 -0
  35. package/cjs/react.d.ts +30 -0
  36. package/cjs/react.js +370 -0
  37. package/cjs/server.d.ts +12 -191
  38. package/cjs/server.js +18 -378
  39. package/cjs/test-inputs.d.ts +2 -2
  40. package/cjs/test-inputs.js +9 -264
  41. package/cjs/testing.d.ts +285 -190
  42. package/cjs/testing.js +2393 -1203
  43. package/cjs/ui-CC1GOoMg.js +583 -0
  44. package/cjs/ui-wIiMfqMB.d.ts +526 -0
  45. package/cjs/ui.d.ts +2 -0
  46. package/cjs/ui.js +27 -0
  47. package/cjs/vue.d.ts +490 -0
  48. package/cjs/vue.js +419 -0
  49. package/esm/BrowserUpload-BT091eOB.d.ts +11 -0
  50. package/esm/BrowserUpload-D2xBWqhm.js +5 -0
  51. package/esm/CalmLensAppClient-CV_K26Ce.d.ts +40 -0
  52. package/esm/CalmLensAppClient-DuFas_dW.js +84 -0
  53. package/esm/CalmLensConnection-MxwwLXdl.js +582 -0
  54. package/esm/CalmLensServerClient-D80_mKpW.js +586 -0
  55. package/esm/CalmLensServerClient-JtP687a3.d.ts +235 -0
  56. package/esm/CalmLensTypes-9Vt16pc7.d.ts +40400 -0
  57. package/esm/Classification-94kSYWZw-CMnQKW13.d.ts +5873 -0
  58. package/esm/CryptoUtils-B_x8lMIx-DhuWGzqn.js +25 -0
  59. package/esm/FileIcons-M6dzjFxd.js +128 -0
  60. package/esm/Jurisdiction-FusEXb4U-1ov6m5yE.js +46 -0
  61. package/esm/ModerationContext-9lGm-Mna-CcmbRnOy.d.ts +67 -0
  62. package/esm/ModerationContextLimits-BaX2QnU8.js +1114 -0
  63. package/esm/ReactUpload-CAyCsyG6.d.ts +17 -0
  64. package/esm/ReactUpload-CL2XC8WS.js +37 -0
  65. package/esm/TestTriggers-By07LR31-CmK0yTyR.d.ts +271 -0
  66. package/esm/TestTriggers-DTc_iMJF-HfB533Gx.js +1267 -0
  67. package/esm/UploadController-qjoYGCwx.js +589 -0
  68. package/{cjs/index-C9Xw1aid.d.ts → esm/WebhookPayload-2aL31v0J.d.ts} +131 -155
  69. package/esm/app.d.ts +7 -44
  70. package/esm/app.js +3 -86
  71. package/esm/elements.d.ts +88 -0
  72. package/esm/elements.js +528 -0
  73. package/esm/file-icons.d.ts +67 -0
  74. package/esm/file-icons.js +1 -0
  75. package/esm/index-CI4BzN4W.d.ts +252 -0
  76. package/esm/index.d.ts +6 -4
  77. package/esm/index.js +1 -1
  78. package/esm/react-native.d.ts +56 -0
  79. package/esm/react-native.js +467 -0
  80. package/esm/react.d.ts +30 -0
  81. package/esm/react.js +343 -0
  82. package/esm/server.d.ts +12 -191
  83. package/esm/server.js +3 -369
  84. package/esm/styles.css +147 -0
  85. package/esm/svelte/CalmLensMedia.svelte +134 -0
  86. package/esm/svelte/CalmLensUploader.svelte +175 -0
  87. package/esm/svelte/Icon.svelte +7 -0
  88. package/esm/svelte/index.d.ts +37 -0
  89. package/esm/svelte/index.js +6 -0
  90. package/esm/test-inputs.d.ts +2 -2
  91. package/esm/test-inputs.js +1 -256
  92. package/esm/testing.d.ts +285 -190
  93. package/esm/testing.js +2329 -1122
  94. package/esm/ui-CCY3yXFn.js +458 -0
  95. package/esm/ui-wIiMfqMB.d.ts +526 -0
  96. package/esm/ui.d.ts +2 -0
  97. package/esm/ui.js +3 -0
  98. package/esm/vue.d.ts +490 -0
  99. package/esm/vue.js +392 -0
  100. package/package.json +118 -13
  101. package/cjs/CalmLensConnection-BNUHp_AQ.js +0 -234
  102. package/cjs/CalmLensUtils-o171ownK.js +0 -699
  103. package/cjs/CalmLensVersion-DwhgxQK5.js +0 -480
  104. package/cjs/CalmLensWebhooks-BKrq30Yp.js +0 -201
  105. package/cjs/Classification-BNhgwGEm-DmA9VEuE.d.ts +0 -4806
  106. package/cjs/TestTriggers-CRKtulyp-vrzEq2wm.d.ts +0 -44
  107. package/cjs/WebhookPayload-CJoIkGBD.d.ts +0 -11753
  108. package/esm/CalmLensConnection-XTqmlwzG.js +0 -193
  109. package/esm/CalmLensUtils-DsF8Aa_x.js +0 -574
  110. package/esm/CalmLensVersion-DcifRKsx.js +0 -415
  111. package/esm/CalmLensWebhooks-BvGyk5d3.js +0 -148
  112. package/esm/Classification-BNhgwGEm-DmA9VEuE.d.ts +0 -4806
  113. package/esm/TestTriggers-CRKtulyp-vrzEq2wm.d.ts +0 -44
  114. package/esm/WebhookPayload-CJoIkGBD.d.ts +0 -11753
@@ -0,0 +1,526 @@
1
+ import { Dt as ViewerClaims, k as CdnTransform, m as AssetModerationStatus, w as CalmLensAppClientOptions } from "./CalmLensTypes-9Vt16pc7.js";
2
+ import { t as CalmLensAppClient } from "./CalmLensAppClient-CV_K26Ce.js";
3
+ /**
4
+ * The parts of an asset, as the API or a webhook returns it, that the media component reads.
5
+ * Assets from `CalmLensServerClient` fit as they are.
6
+ */
7
+ interface MediaAsset {
8
+ id: string;
9
+ projectId: string;
10
+ type?: string | null;
11
+ classification?: {
12
+ moderation?: {
13
+ status?: AssetModerationStatus | null;
14
+ regions?: {
15
+ region: string;
16
+ action: string;
17
+ }[];
18
+ } | null;
19
+ } | null;
20
+ content?: {
21
+ status?: string | null;
22
+ image?: {
23
+ thumbhash?: string | null;
24
+ averageColor?: string | null;
25
+ width?: number | null;
26
+ height?: number | null;
27
+ } | null;
28
+ } | null;
29
+ }
30
+ /** Which asset to show: an asset from the API, or its project and ID. */
31
+ type MediaSource = {
32
+ /**
33
+ * An asset from the API. It supplies the project, ID, moderation status, media type and
34
+ * stored preview (placeholder, average colour and size); props you pass win over it.
35
+ */
36
+ asset: MediaAsset;
37
+ projectId?: string;
38
+ assetId?: string;
39
+ } | {
40
+ asset?: undefined;
41
+ projectId: string /** The asset ID, or its `externalId`. */;
42
+ assetId: string;
43
+ };
44
+ type MediaOptions = MediaSource & MediaSettings;
45
+ interface MediaSettings {
46
+ /** Optional customer assertions. Defaults to connection country and age confirmation false. */
47
+ viewerClaims?: ViewerClaims;
48
+ /** The asset's stored moderation status. Defaults to `allowed`. */
49
+ status?: AssetModerationStatus;
50
+ /**
51
+ * Whether CalmLens has removed the asset's content, from its `content.status`. Removed content
52
+ * shows the unavailable notice and requests nothing. Set from `asset` when you pass one.
53
+ */
54
+ contentRemoved?: boolean;
55
+ /** `image` (default), `video` or `audio`. */
56
+ type?: "image" | "video" | "audio";
57
+ /**
58
+ * `rendered` (default), which the CDN serves in the best format the browser accepts and where
59
+ * lenses and transforms apply, or `original`, the exact uploaded file. Video and audio always
60
+ * play the original.
61
+ */
62
+ resource?: "original" | "rendered";
63
+ /** A named lens, such as `avatar`. */
64
+ lens?: string;
65
+ /** A transform applied after the lens, as a selector string or structured steps. */
66
+ transform?: CdnTransform;
67
+ /** Widths to offer in `srcset`, so browsers fetch the smallest that fits `sizes`. */
68
+ widths?: number[];
69
+ /**
70
+ * A signed URL from your server, used as-is instead of a CDN URL built here, for private
71
+ * assets. Include any viewer claims when creating the signed URL.
72
+ */
73
+ url?: string;
74
+ /** Show the blurred placeholder while the media loads. Defaults to `true`. */
75
+ placeholder?: boolean;
76
+ /**
77
+ * The asset's `content.image.thumbhash`, if your app stores it. The placeholder is then
78
+ * drawn in the browser instead of requested from the CDN.
79
+ */
80
+ placeholderHash?: string;
81
+ /** Your own placeholder image URL, used when there is no `placeholderHash`. */
82
+ placeholderUrl?: string;
83
+ /** The CDN base URL, for local development. */
84
+ cdnBaseUrl?: string;
85
+ }
86
+ type MediaState = {
87
+ kind: "unavailable";
88
+ reason?: "regional";
89
+ } | {
90
+ kind: "gated";
91
+ placeholderUrl?: string;
92
+ } | {
93
+ kind: "image";
94
+ src: string;
95
+ srcSet?: string;
96
+ /** One URL per width in `widths`, smallest first, for apps that pick their own. */
97
+ sources?: MediaImageSource[];
98
+ placeholderUrl?: string;
99
+ } | {
100
+ kind: "video";
101
+ src: string;
102
+ placeholderUrl?: string;
103
+ } | {
104
+ kind: "audio";
105
+ src: string;
106
+ };
107
+ /** An image at one of the widths in `widths`. */
108
+ interface MediaImageSource {
109
+ src: string;
110
+ width: number;
111
+ }
112
+ /**
113
+ * The image URL to load for a box `displayWidth` pixels wide: the smallest width that covers it,
114
+ * or the largest when none does. Without `widths`, or before the box is measured, the image's own
115
+ * `src`. React Native, which has no `srcset`, calls this with its measured size.
116
+ */
117
+ declare const pickMediaSource: (state: Extract<MediaState, {
118
+ kind: "image";
119
+ }>, displayWidth: number | undefined) => string;
120
+ /**
121
+ * What the media component should render for an asset: the image with its responsive widths,
122
+ * the video or audio, a gated placeholder for an age-restricted asset the viewer can't see, or
123
+ * nothing for blocked and purged assets. Every framework's component renders this.
124
+ */
125
+ /** The display props an asset can supply, which media components read alongside the options. */
126
+ type AssetDisplay = {
127
+ width?: number;
128
+ height?: number;
129
+ averageColor?: string;
130
+ };
131
+ /**
132
+ * Fills the props left unset from `asset`, if there is one: the project and ID, its moderation
133
+ * status, `video` or `audio` for those asset types, and its stored preview's ThumbHash, average
134
+ * colour and size. Every framework's media component calls this before rendering.
135
+ */
136
+ declare const resolveMediaProps: <T extends MediaOptions & AssetDisplay>(props: T) => T & {
137
+ projectId: string;
138
+ assetId: string;
139
+ };
140
+ declare const getMediaState: (options: MediaOptions) => MediaState;
141
+ /**
142
+ * Where a file is in the upload: picked and waiting for `start()` (with `autoUpload: false`),
143
+ * waiting its turn, sending bytes, being moderated, or finished.
144
+ */
145
+ type UploadStage = "selected" | "queued" | "uploading" | "checking" | "complete" | "failed";
146
+ /**
147
+ * A file to upload: a browser `File`, or a file on a phone, such as a `File` from
148
+ * `expo-file-system`. Anything with a name, MIME type, size and bytes works.
149
+ */
150
+ interface UploadFile {
151
+ readonly name: string;
152
+ readonly type: string;
153
+ readonly size: number;
154
+ /** The file's local URI on a phone, such as `file:///…`, used for the image preview. */
155
+ readonly uri?: string;
156
+ /** Reads the file's bytes when its upload starts. */
157
+ arrayBuffer(): Promise<ArrayBuffer>;
158
+ }
159
+ /** One file the uploader has picked, as the components render it. */
160
+ interface UploadItem<F extends UploadFile = UploadFile> {
161
+ /** A local ID for the file in this uploader, not the asset ID. */
162
+ readonly key: string;
163
+ readonly file: F;
164
+ readonly stage: UploadStage;
165
+ /** Sent bytes as a fraction from 0 to 1 while uploading, `null` when unknown. */
166
+ readonly progress: number | null;
167
+ /**
168
+ * A local preview of an image file while it's checked: an object URL in browsers, or the file's
169
+ * own URI on a phone.
170
+ */
171
+ readonly previewUrl?: string;
172
+ readonly assetId?: string;
173
+ /** The moderation status, when the upload preset shows decisions to the uploader. */
174
+ readonly status?: AssetModerationStatus;
175
+ /**
176
+ * Why the file failed: a `CalmLensError` code, or `file/not-accepted` and `file/too-large` when
177
+ * the uploader refused the file before sending it.
178
+ */
179
+ readonly errorCode?: string;
180
+ }
181
+ /** A finished upload that wasn't blocked, which your app saves with its record. */
182
+ interface CalmLensUpload<F extends UploadFile = UploadFile> {
183
+ assetId: string;
184
+ /** `undefined` when the upload preset doesn't show decisions to the uploader. */
185
+ status?: AssetModerationStatus;
186
+ file: F;
187
+ }
188
+ interface UploadSnapshot<F extends UploadFile = UploadFile> {
189
+ readonly items: readonly UploadItem<F>[];
190
+ /** Whether any file is still waiting, uploading or being checked. */
191
+ readonly busy: boolean;
192
+ }
193
+ /** The part of `CalmLensAppClient` the uploader uses, which `MockCalmLensAppClient` also has. */
194
+ interface UploadClient {
195
+ assets: Pick<CalmLensAppClient["assets"], "create" | "retrieve">;
196
+ }
197
+ /** What a custom `upload` function returns for each file. */
198
+ interface CustomUploadResult {
199
+ assetId: string;
200
+ /** The moderation status, if your API returns it. */
201
+ status?: AssetModerationStatus;
202
+ }
203
+ interface CustomUploadContext {
204
+ /** Aborted when the uploader cancels or removes the file. */
205
+ signal: AbortSignal;
206
+ /** Reports sent bytes, for the progress bar. `createProgressFetch` reports them for you. */
207
+ onProgress: (sentBytes: number, totalBytes: number) => void;
208
+ }
209
+ interface UploadControllerOptions<F extends UploadFile = UploadFile> {
210
+ /** The upload preset the files upload through. Not needed with `upload`. */
211
+ uploadPresetId?: string;
212
+ /**
213
+ * Uploads each file your own way instead of through an upload preset, for example through your
214
+ * app's API, which creates the asset with its API key. The uploader still shows progress, the
215
+ * decision and errors: throw a `CalmLensError` to show its code's message.
216
+ */
217
+ upload?: (file: F, context: CustomUploadContext) => Promise<CustomUploadResult>;
218
+ /**
219
+ * Checks a pending upload made with `upload`, returning its current moderation status. Without
220
+ * it, a pending upload finishes as pending.
221
+ */
222
+ checkStatus?: (assetId: string, context: {
223
+ signal: AbortSignal;
224
+ }) => Promise<AssetModerationStatus | undefined>;
225
+ /**
226
+ * The upload token, or a function that returns a fresh one for each file. Leave it out for
227
+ * presets that anyone can upload to.
228
+ */
229
+ token?: string | ((file: F) => string | Promise<string>);
230
+ /**
231
+ * An endpoint on your server that returns `{ token }` for each file. It receives a `POST` with
232
+ * the file's `{ name, type, size }` as JSON. Use `token` instead for anything more custom.
233
+ */
234
+ tokenUrl?: string;
235
+ /** File types to accept, as in an `<input accept>`: `image/*`, `.png`, `video/mp4`. */
236
+ accept?: string;
237
+ /** The largest file to accept, in bytes. Your preset's own limit still applies. */
238
+ maxFileSize?: number;
239
+ /**
240
+ * Upload files as soon as they're picked. Defaults to `true`. With `false`, picked files wait in
241
+ * the `selected` stage until you call `start()`, for example when a form is submitted.
242
+ */
243
+ autoUpload?: boolean;
244
+ /** Accept more than one file. Defaults to `false`; a new file then replaces the last one. */
245
+ multiple?: boolean;
246
+ /** The most files kept at once when `multiple` is on. Defaults to 10. */
247
+ maxFiles?: number;
248
+ /** How many files upload at the same time. Defaults to 3. */
249
+ concurrency?: number;
250
+ /**
251
+ * How long to keep checking for a moderation decision, in milliseconds. Defaults to 15
252
+ * seconds; anything still pending after that is settled by your server's webhook.
253
+ */
254
+ decisionTimeoutMs?: number;
255
+ /** The CalmLens API base URL, for local development. */
256
+ baseUrl?: string;
257
+ /**
258
+ * Creates the client for each upload. Defaults to `CalmLensAppClient`; tests can return a
259
+ * `MockCalmLensAppClient` from `calmlens/testing` instead.
260
+ */
261
+ createClient?: (options: CalmLensAppClientOptions) => UploadClient;
262
+ /**
263
+ * Called for each finished upload that wasn't blocked or purged, and again with the new status
264
+ * when `retry` checks one that was still pending.
265
+ */
266
+ onUploaded?: (upload: CalmLensUpload<F>) => void;
267
+ /** Called when moderation blocks or purges a file. */
268
+ onRejected?: (item: UploadItem<F>) => void;
269
+ /** Called when a file couldn't be uploaded. */
270
+ onFailed?: (item: UploadItem<F>) => void;
271
+ /** Called when the uploader removes a file, including a finished upload. */
272
+ onRemoved?: (item: UploadItem<F>) => void;
273
+ }
274
+ /** Whether a file matches an `accept` list such as `image/*,.pdf`. */
275
+ declare const isFileAccepted: (file: Pick<UploadFile, "name" | "type">, accept?: string) => boolean;
276
+ /**
277
+ * Uploads files through an upload preset and tracks each one until it has a moderation
278
+ * decision. It holds no UI: the React, Vue, Svelte and web components render its snapshot, and
279
+ * you can render your own with `subscribe`, which also makes it a Svelte store.
280
+ */
281
+ declare class UploadController<F extends UploadFile = UploadFile> {
282
+ #private;
283
+ constructor(options: UploadControllerOptions<F>);
284
+ /** The current options. */
285
+ get options(): Readonly<UploadControllerOptions<F>>;
286
+ /** Replaces the options, for example when a component's props change. */
287
+ setOptions(options: UploadControllerOptions<F>): void;
288
+ getSnapshot: () => UploadSnapshot<F>;
289
+ /**
290
+ * Calls `listener` with the current snapshot now and after every change, and returns a
291
+ * function that stops. This is the Svelte store contract, and works with React's
292
+ * `useSyncExternalStore`.
293
+ */
294
+ subscribe: (listener: (snapshot: UploadSnapshot<F>) => void) => (() => void);
295
+ /**
296
+ * Adds files from a file input, a drop, a paste or a phone's picker, and starts uploading them,
297
+ * or keeps them `selected` with `autoUpload: false`.
298
+ */
299
+ addFiles(files: Iterable<F> | ArrayLike<F>): void;
300
+ /** Uploads every `selected` file, for an uploader with `autoUpload: false`. */
301
+ start(): void;
302
+ /**
303
+ * Tries a failed file again: an upload that finished but couldn't be checked is checked again,
304
+ * anything else is uploaded again. A finished upload still `pending` is checked again too.
305
+ */
306
+ retry(key: string): void;
307
+ /**
308
+ * Stops a queued or running file and keeps it in the list as failed with `sdk/cancelled`, so
309
+ * `retry` can upload it again. Finished files are left as they are.
310
+ */
311
+ cancel(key: string): void;
312
+ /** Cancels a file's upload if it's running and removes it from the list. */
313
+ remove(key: string): void;
314
+ /** Cancels every upload and empties the list, without calling `onRemoved`. */
315
+ clear(): void;
316
+ }
317
+ declare const createUploadController: <F extends UploadFile = UploadFile>(options: UploadControllerOptions<F>) => UploadController<F>;
318
+ /**
319
+ * The text the components show. Pass `messages` to any component to replace some or all of it,
320
+ * for example to translate it. Keys other than the named ones are error codes, so you can give
321
+ * any `CalmLensError` code its own message.
322
+ */
323
+ interface CalmLensMessages {
324
+ dropzoneTitle: string;
325
+ dropzoneTitleDragging: string;
326
+ /** The picker button when the uploader takes one file. */
327
+ chooseFile: string;
328
+ /** The picker button with `multiple`. */
329
+ chooseFiles: string;
330
+ /** Replaces the picked file when the uploader takes one file. */
331
+ chooseAnother: string;
332
+ /** `{size}` is replaced with the largest accepted size, such as `20 MB`. */
333
+ maxFileSizeHint: string;
334
+ /** Under a file waiting for `start()`. Empty by default, so the row shows only its size. */
335
+ selected: string;
336
+ queued: string;
337
+ uploading: string;
338
+ checking: string;
339
+ /** Finished, when the upload preset doesn't show decisions to the uploader. */
340
+ submitted: string;
341
+ pending: string;
342
+ allowed: string;
343
+ limited: string;
344
+ "age-restricted": string;
345
+ blocked: string;
346
+ purged: string;
347
+ failed: string;
348
+ "file/not-accepted": string;
349
+ "file/too-large": string;
350
+ retry: string;
351
+ /** `{name}` is replaced with the file name. */
352
+ remove: string;
353
+ /** `{name}` is replaced with the file name. */
354
+ cancel: string;
355
+ sensitiveTitle: string;
356
+ sensitiveBody: string;
357
+ reveal: string;
358
+ unavailable: string;
359
+ /** A viewer-specific regional block reported by the asset API. */
360
+ regionalUnavailable: string;
361
+ [errorCode: string]: string;
362
+ }
363
+ declare const DEFAULT_MESSAGES: CalmLensMessages;
364
+ declare const resolveMessages: (overrides?: Partial<CalmLensMessages>) => CalmLensMessages;
365
+ /** The unavailable notice every media binding shows for the same resolved state. */
366
+ declare const getMediaUnavailableMessage: (state: MediaState, messages: CalmLensMessages) => string;
367
+ /** Fills `{name}`-style placeholders. */
368
+ declare const formatMessage: (message: string, values: Record<string, string>) => string;
369
+ /** The message for a file's current state. */
370
+ declare const getUploadItemMessage: (item: UploadItem, messages: CalmLensMessages) => string;
371
+ /** How a finished file turned out, for styling: `accepted`, `restricted` or `rejected`. */
372
+ declare const getUploadItemOutcome: (item: UploadItem) => "accepted" | "restricted" | "rejected" | undefined;
373
+ /** A byte count for people, such as `1.2 MB`. */
374
+ declare const formatBytes: (bytes: number) => string;
375
+ /** Everything a file's row shows, worked out once for every framework's uploader. */
376
+ interface UploadItemView {
377
+ message: string;
378
+ outcome?: "accepted" | "restricted" | "rejected";
379
+ busy: boolean;
380
+ /** Sent bytes from 0 to 100, or `undefined` for an indeterminate bar while checking. */
381
+ progressPercent?: number;
382
+ canRetry: boolean;
383
+ /** The remove button's accessible name: cancel while the file is busy. */
384
+ removeLabel: string;
385
+ /** The file-type icon shown when there is no image preview, as SVG markup. */
386
+ fileIcon: string;
387
+ size: string;
388
+ }
389
+ declare const describeUploadItem: (item: UploadItem, messages: CalmLensMessages) => UploadItemView;
390
+ /** The hint under the drop zone's title, or `undefined` without a size limit. */
391
+ declare const getDropzoneHint: (messages: CalmLensMessages, maxFileSize?: number) => string | undefined;
392
+ /** What an uploader shows around its file list, worked out once for every framework. */
393
+ interface UploaderView {
394
+ /**
395
+ * Whether to show the drop zone. An uploader that takes one file swaps it for the file's row,
396
+ * with a button to choose another, once a file is picked.
397
+ */
398
+ showDropzone: boolean;
399
+ chooseLabel: string;
400
+ hint?: string;
401
+ }
402
+ declare const describeUploader: (snapshot: UploadSnapshot, options: Pick<UploadControllerOptions, "multiple" | "maxFileSize">, messages: CalmLensMessages) => UploaderView;
403
+ /** Props every framework's uploader takes, on top of the upload options. */
404
+ interface UploaderDisplayOptions<F extends UploadFile = UploadFile> {
405
+ disabled?: boolean;
406
+ /** Opens the camera on phones: `user` for the front camera, `environment` for the back. */
407
+ capture?: "user" | "environment";
408
+ /** Replaces some or all of the text the uploader shows. */
409
+ messages?: Partial<CalmLensMessages>;
410
+ /**
411
+ * Shows this upload queue instead of creating one, such as `useCalmLensUpload`'s `controller`,
412
+ * so your app can read the picked files and call `start()`. The upload options then come from
413
+ * the controller, and the uploader leaves its uploads running when it unmounts.
414
+ */
415
+ controller?: UploadController<F>;
416
+ }
417
+ type UploaderProps<F extends UploadFile = UploadFile> = UploadControllerOptions<F> & UploaderDisplayOptions<F>;
418
+ /** Props every framework's media component takes, on top of the media options. */
419
+ interface MediaDisplayOptions {
420
+ /** Describes the image. Leave it empty only for decorative images. */
421
+ alt?: string;
422
+ /** Width divided by height, which you store with the upload, so the box keeps its size. */
423
+ aspectRatio?: number;
424
+ /** The intrinsic width, used with `height` for the aspect ratio and the image attributes. */
425
+ width?: number;
426
+ height?: number;
427
+ /** The `sizes` attribute for `widths`, such as `(min-width: 768px) 50vw, 100vw`. */
428
+ sizes?: string;
429
+ /** The asset's `content.image.averageColor`, shown behind the media while it loads. */
430
+ averageColor?: string;
431
+ /** How the media fills its box: `cover` (default) or `contain`. */
432
+ fit?: "cover" | "contain";
433
+ /** The CSS `object-position`, such as `top` or `30% 50%`. */
434
+ position?: string;
435
+ /** Load the image only when it nears the viewport. Defaults to `true`. */
436
+ lazy?: boolean;
437
+ fetchPriority?: "high" | "low" | "auto";
438
+ /** Video and audio controls. Defaults to `true`. */
439
+ controls?: boolean;
440
+ messages?: Partial<CalmLensMessages>;
441
+ /**
442
+ * Called when the viewer presses the reveal button on age-restricted media. Run your app's own
443
+ * check, then render again with `ageConfirmed`. Without it, the notice has no button.
444
+ */
445
+ onReveal?: () => void;
446
+ }
447
+ type MediaProps = MediaOptions & MediaDisplayOptions;
448
+ /** The aspect ratio a media component's box keeps, if it knows one. */
449
+ declare const getMediaAspectRatio: ({ aspectRatio, width, height }: MediaDisplayOptions) => number | undefined;
450
+ /** A key that changes whenever a media component must load something new. */
451
+ declare const getMediaLoadKey: (state: MediaState) => string;
452
+ /** Path data for the components' 24×24 stroke icons, so every framework draws the same ones. */
453
+ declare const ICONS: {
454
+ readonly upload: "M12 16V4m0 0L7 9m5-5 5 5M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2";
455
+ readonly remove: "M18 6 6 18M6 6l12 12";
456
+ readonly retry: "M20 11a8 8 0 1 0-2.3 5.7M20 4v7h-7";
457
+ readonly unavailable: "M3 3l18 18M10.6 10.6a2 2 0 0 0 2.8 2.8M9.9 5.1A9.8 9.8 0 0 1 12 5c5 0 9 5 10 7a17 17 0 0 1-3.3 4.2M6.6 6.6C4.4 8 2.8 10.4 2 12c1 2 5 7 10 7a9.6 9.6 0 0 0 5.4-1.6";
458
+ };
459
+ type IconName = keyof typeof ICONS;
460
+ /** Attributes shared by every icon's `<svg>`. */
461
+ declare const ICON_ATTRIBUTES: {
462
+ readonly width: "18";
463
+ readonly height: "18";
464
+ readonly viewBox: "0 0 24 24";
465
+ readonly fill: "none";
466
+ readonly stroke: "currentColor";
467
+ readonly "stroke-width": "2";
468
+ readonly "stroke-linecap": "round";
469
+ readonly "stroke-linejoin": "round";
470
+ readonly "aria-hidden": "true";
471
+ };
472
+ /**
473
+ * A `fetch` that reports how many bytes of the request body have been sent, which `fetch` itself
474
+ * can't do. It sends through `XMLHttpRequest`, so the upload components pass it to
475
+ * `CalmLensAppClient` as `uploadFetch`. Without `XMLHttpRequest` it falls back to `fetch` and
476
+ * reports nothing.
477
+ */
478
+ declare const createProgressFetch: (onProgress: (sentBytes: number, totalBytes: number) => void) => ((input: RequestInfo | URL, init?: RequestInit) => Promise<Response>);
479
+ /**
480
+ * The components' stylesheet, also shipped as `calmlens/styles.css`. The React components
481
+ * render it themselves (React hoists it into the head, on the server too); with Vue, Svelte or
482
+ * the web components, import or link `calmlens/styles.css` once. Nothing is added to the page
483
+ * at runtime. Theme it with the `--calmlens-*` custom properties, or leave it out and style the
484
+ * `calmlens-*` classes yourself.
485
+ */
486
+ declare const CALMLENS_STYLES: string;
487
+ /**
488
+ * The components' colours and corner radius. The stylesheet uses them as its `--calmlens-*`
489
+ * defaults, and the React Native components take them as `theme`.
490
+ */
491
+ interface CalmLensTheme {
492
+ accent: string;
493
+ /** Text on the accent colour. */
494
+ accentText: string;
495
+ /** Corner radius of the drop zone, file rows and media, in pixels. */
496
+ radius: number;
497
+ /** Body text. The stylesheet inherits it from the page instead. */
498
+ text: string;
499
+ /** Secondary text, such as a file's size. Defaults to `text` at 72%. */
500
+ muted: string;
501
+ /** Borders and the progress track. Defaults to `text` at 18%. */
502
+ border: string;
503
+ /** The drop zone's fill. Defaults to `text` at 4%. */
504
+ surface: string;
505
+ /** The file rows' fill. Defaults to none, so rows show what's behind them. */
506
+ background: string;
507
+ success: string;
508
+ warning: string;
509
+ danger: string;
510
+ }
511
+ declare const CALMLENS_THEME: {
512
+ readonly accent: "#635bff";
513
+ readonly accentText: "#fff";
514
+ readonly radius: 12;
515
+ readonly text: "#1f2328";
516
+ readonly background: "transparent";
517
+ readonly success: "#12a26f";
518
+ readonly warning: "#e8a317";
519
+ readonly danger: "#e5484d";
520
+ };
521
+ /**
522
+ * The full theme from your overrides, mixing the muted, border and surface colours from `text`
523
+ * as the stylesheet mixes them from the page's text colour.
524
+ */
525
+ declare const resolveTheme: (overrides?: Partial<CalmLensTheme>) => CalmLensTheme;
526
+ export { CustomUploadResult as A, MediaAsset as B, getDropzoneHint as C, resolveMessages as D, getUploadItemOutcome as E, UploadItem as F, MediaState as G, MediaOptions as H, UploadSnapshot as I, resolveMediaProps as J, getMediaState as K, UploadStage as L, UploadController as M, UploadControllerOptions as N, CalmLensUpload as O, UploadFile as P, createUploadController as R, formatMessage as S, getUploadItemMessage as T, MediaSettings as U, MediaImageSource as V, MediaSource as W, UploadItemView as _, createProgressFetch as a, describeUploader as b, IconName as c, UploaderDisplayOptions as d, UploaderProps as f, DEFAULT_MESSAGES as g, CalmLensMessages as h, CALMLENS_STYLES as i, UploadClient as j, CustomUploadContext as k, MediaDisplayOptions as l, getMediaLoadKey as m, CalmLensTheme as n, ICONS as o, getMediaAspectRatio as p, pickMediaSource as q, resolveTheme as r, ICON_ATTRIBUTES as s, CALMLENS_THEME as t, MediaProps as u, UploaderView as v, getMediaUnavailableMessage as w, formatBytes as x, describeUploadItem as y, isFileAccepted as z };
package/esm/ui.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import { A as CustomUploadResult, B as MediaAsset, C as getDropzoneHint, D as resolveMessages, E as getUploadItemOutcome, F as UploadItem, G as MediaState, H as MediaOptions, I as UploadSnapshot, J as resolveMediaProps, K as getMediaState, L as UploadStage, M as UploadController, N as UploadControllerOptions, O as CalmLensUpload, P as UploadFile, R as createUploadController, S as formatMessage, T as getUploadItemMessage, U as MediaSettings, V as MediaImageSource, W as MediaSource, _ as UploadItemView, a as createProgressFetch, b as describeUploader, c as IconName, d as UploaderDisplayOptions, f as UploaderProps, g as DEFAULT_MESSAGES, h as CalmLensMessages, i as CALMLENS_STYLES, j as UploadClient, k as CustomUploadContext, l as MediaDisplayOptions, m as getMediaLoadKey, n as CalmLensTheme, o as ICONS, p as getMediaAspectRatio, q as pickMediaSource, r as resolveTheme, s as ICON_ATTRIBUTES, t as CALMLENS_THEME, u as MediaProps, v as UploaderView, w as getMediaUnavailableMessage, x as formatBytes, y as describeUploadItem, z as isFileAccepted } from "./ui-wIiMfqMB.js";
2
+ export { CALMLENS_STYLES, CALMLENS_THEME, type CalmLensMessages, type CalmLensTheme, type CalmLensUpload, type CustomUploadContext, type CustomUploadResult, DEFAULT_MESSAGES, ICONS, ICON_ATTRIBUTES, type IconName, type MediaAsset, type MediaDisplayOptions, type MediaImageSource, type MediaOptions, type MediaProps, type MediaSettings, type MediaSource, type MediaState, type UploadClient, UploadController, type UploadControllerOptions, type UploadFile, type UploadItem, type UploadItemView, type UploadSnapshot, type UploadStage, type UploaderDisplayOptions, type UploaderProps, type UploaderView, createProgressFetch, createUploadController, describeUploadItem, describeUploader, formatBytes, formatMessage, getDropzoneHint, getMediaAspectRatio, getMediaLoadKey, getMediaState, getMediaUnavailableMessage, getUploadItemMessage, getUploadItemOutcome, isFileAccepted, pickMediaSource, resolveMediaProps, resolveMessages, resolveTheme };
package/esm/ui.js ADDED
@@ -0,0 +1,3 @@
1
+ import { _ as getMediaState, a as getMediaAspectRatio, b as ICONS, c as describeUploadItem, d as formatMessage, f as getDropzoneHint, g as resolveMessages, h as getUploadItemOutcome, i as resolveTheme, l as describeUploader, m as getUploadItemMessage, o as getMediaLoadKey, p as getMediaUnavailableMessage, r as CALMLENS_THEME, s as DEFAULT_MESSAGES, t as CALMLENS_STYLES, u as formatBytes, v as pickMediaSource, x as ICON_ATTRIBUTES, y as resolveMediaProps } from "./ui-CCY3yXFn.js";
2
+ import { i as createProgressFetch, n as createUploadController, r as isFileAccepted, t as UploadController } from "./UploadController-qjoYGCwx.js";
3
+ export { CALMLENS_STYLES, CALMLENS_THEME, DEFAULT_MESSAGES, ICONS, ICON_ATTRIBUTES, UploadController, createProgressFetch, createUploadController, describeUploadItem, describeUploader, formatBytes, formatMessage, getDropzoneHint, getMediaAspectRatio, getMediaLoadKey, getMediaState, getMediaUnavailableMessage, getUploadItemMessage, getUploadItemOutcome, isFileAccepted, pickMediaSource, resolveMediaProps, resolveMessages, resolveTheme };