@scaleflex/asset-picker 0.2.11 → 0.2.12
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 +195 -11
- package/dist/{asset-picker-BvXr_8iN.cjs → asset-picker-CMsm4Ewp.cjs} +51 -51
- package/dist/{asset-picker-Cd9cgAZ6.js → asset-picker-DCcLalcQ.js} +2 -1
- package/dist/define.cjs +1 -1
- package/dist/define.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -2
- package/dist/react.cjs +1 -1
- package/dist/react.d.ts +82 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +75 -31
- package/dist/types/asset.types.d.ts +6 -1
- package/dist/types/asset.types.d.ts.map +1 -1
- package/dist/utils/asset-helpers.d.ts +80 -0
- package/dist/utils/asset-helpers.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
- [Public Methods](#public-methods)
|
|
45
45
|
- [Events](#events)
|
|
46
46
|
- [React API](#react-api)
|
|
47
|
+
- [Provider + Hook](#provider--hook-recommended)
|
|
48
|
+
- [Asset Utilities](#asset-utilities)
|
|
47
49
|
- [Theming](#theming)
|
|
48
50
|
- [Brand Color](#brand-color)
|
|
49
51
|
- [CSS Custom Properties](#css-custom-properties)
|
|
@@ -112,8 +114,8 @@ pnpm add @scaleflex/asset-picker
|
|
|
112
114
|
|
|
113
115
|
| Export path | Description |
|
|
114
116
|
|---|---|
|
|
115
|
-
| `@scaleflex/asset-picker` | `AssetPicker` class + all TypeScript types |
|
|
116
|
-
| `@scaleflex/asset-picker/react` | React wrapper component |
|
|
117
|
+
| `@scaleflex/asset-picker` | `AssetPicker` class + all TypeScript types + asset utility functions |
|
|
118
|
+
| `@scaleflex/asset-picker/react` | React wrapper component + `AssetPickerProvider` + `useAssetPicker` hook |
|
|
117
119
|
| `@scaleflex/asset-picker/define` | Side-effect import — registers `<sfx-asset-picker>` custom element |
|
|
118
120
|
|
|
119
121
|
Both ESM (`import`) and CJS (`require`) builds are provided.
|
|
@@ -248,7 +250,13 @@ Use when your application already has a SASS key — e.g. inside the Scaleflex H
|
|
|
248
250
|
| `rememberLastTab` | `boolean` | `false` | Persist the last active tab (assets/folders) and restore on next open |
|
|
249
251
|
| `defaultFilters` | `FiltersInput` | `undefined` | Filters pre-applied on open. User can modify/remove |
|
|
250
252
|
| `forcedFilters` | `FiltersInput` | `undefined` | Filters always active. Shown as locked chips the user cannot remove |
|
|
251
|
-
| `
|
|
253
|
+
| `displayMode` | `'modal' \| 'inline'` | `'modal'` | `'modal'` renders as a dialog overlay, `'inline'` renders in page flow |
|
|
254
|
+
| `gridSize` | `'normal' \| 'large'` | `'normal'` | Grid card density: `'normal'` (4 cols at ~1200px) or `'large'` (3 cols) |
|
|
255
|
+
| `stickyFilters` | `boolean` | `false` | Make the toolbar and filters bar sticky while scrolling content |
|
|
256
|
+
| `folderSelection` | `boolean` | `true` | Allow selecting folders via checkboxes |
|
|
257
|
+
| `folderSelectionMode` | `'folder' \| 'assets'` | `'folder'` | `'folder'` returns Folder objects; `'assets'` fetches folder contents and returns only Assets |
|
|
258
|
+
| `uploader` | `UploaderIntegrationConfig` | `undefined` | Enable integrated uploader. Adds an "Upload" button and drop zone. Requires `@scaleflex/uploader` |
|
|
259
|
+
| `onSelect` | `(assets: Asset[], folders?: Folder[]) => void` | `undefined` | Callback when assets are selected |
|
|
252
260
|
| `onCancel` | `() => void` | `undefined` | Callback when the picker is cancelled |
|
|
253
261
|
|
|
254
262
|
#### Sort fields
|
|
@@ -327,7 +335,7 @@ All events bubble and cross shadow DOM boundaries (`composed: true`).
|
|
|
327
335
|
| Event | Detail | Description |
|
|
328
336
|
|---|---|---|
|
|
329
337
|
| `ap-select` | `{ assets: Asset[] }` | Fired when the user confirms their selection |
|
|
330
|
-
| `ap-cancel` | `{ reason: 'backdrop' \| 'escape' \| 'button'
|
|
338
|
+
| `ap-cancel` | `{ reason: 'backdrop' \| 'escape' \| 'button' }` | Fired when the picker is closed without selecting |
|
|
331
339
|
| `ap-open` | `{ timestamp: number }` | Fired when the picker opens successfully |
|
|
332
340
|
| `ap-error` | `{ error: Error, context: string }` | Fired on initialisation or runtime errors |
|
|
333
341
|
|
|
@@ -362,7 +370,8 @@ import { AssetPicker, type AssetPickerRef, type AssetPickerProps } from '@scalef
|
|
|
362
370
|
|---|---|---|
|
|
363
371
|
| `config` | `AssetPickerConfig` | Configuration object (see [Config Options](#config-options)) |
|
|
364
372
|
| `open` | `boolean` | Controlled open state |
|
|
365
|
-
| `onSelect` | `(assets: Asset[]) => void` | Selection callback |
|
|
373
|
+
| `onSelect` | `(assets: Asset[], folders?: Folder[]) => void` | Selection callback (assets + optional folders) |
|
|
374
|
+
| `onSelectWithFolders` | `(result: { assets: Asset[]; folders: Folder[] }) => void` | Alternative callback that always includes folders |
|
|
366
375
|
| `onCancel` | `() => void` | Cancel callback |
|
|
367
376
|
| `className` | `string` | CSS class for the wrapper |
|
|
368
377
|
| `style` | `CSSProperties` | Inline styles for the wrapper |
|
|
@@ -399,6 +408,163 @@ const ref = useRef<AssetPickerRef>(null);
|
|
|
399
408
|
<AssetPicker ref={ref} config={config} onSelect={handleSelect} />
|
|
400
409
|
```
|
|
401
410
|
|
|
411
|
+
### Provider + Hook (recommended)
|
|
412
|
+
|
|
413
|
+
For apps that open the picker from many places, use `AssetPickerProvider` + `useAssetPicker()` to avoid managing open/close state yourself. One picker instance is mounted at the root and shared across the tree.
|
|
414
|
+
|
|
415
|
+
#### Setup
|
|
416
|
+
|
|
417
|
+
```tsx
|
|
418
|
+
import { AssetPickerProvider } from '@scaleflex/asset-picker/react';
|
|
419
|
+
|
|
420
|
+
function App() {
|
|
421
|
+
return (
|
|
422
|
+
<AssetPickerProvider
|
|
423
|
+
config={{
|
|
424
|
+
auth: {
|
|
425
|
+
mode: 'sassKey',
|
|
426
|
+
sassKey: 'YOUR_SASS_KEY',
|
|
427
|
+
projectToken: 'YOUR_TOKEN',
|
|
428
|
+
},
|
|
429
|
+
}}
|
|
430
|
+
>
|
|
431
|
+
<Dashboard />
|
|
432
|
+
</AssetPickerProvider>
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
#### Promise mode
|
|
438
|
+
|
|
439
|
+
```tsx
|
|
440
|
+
import { useAssetPicker } from '@scaleflex/asset-picker/react';
|
|
441
|
+
|
|
442
|
+
function ImageSelector() {
|
|
443
|
+
const picker = useAssetPicker();
|
|
444
|
+
|
|
445
|
+
const handleClick = async () => {
|
|
446
|
+
try {
|
|
447
|
+
const assets = await picker.open({ multiSelect: true });
|
|
448
|
+
console.log('Selected:', assets);
|
|
449
|
+
} catch {
|
|
450
|
+
console.log('User cancelled');
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
return <button onClick={handleClick}>Choose images</button>;
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
The promise resolves with the selected `Asset[]` on confirm, and rejects with `'cancelled'` when the user closes without selecting. Note: promise mode returns only assets — use callback mode with `onSelect(assets, folders)` if you need folder data.
|
|
459
|
+
|
|
460
|
+
#### Callback mode
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
function VideoSelector() {
|
|
464
|
+
const picker = useAssetPicker();
|
|
465
|
+
|
|
466
|
+
return (
|
|
467
|
+
<button
|
|
468
|
+
onClick={() =>
|
|
469
|
+
picker.open({
|
|
470
|
+
forcedFilters: { type: { values: ['video'] } },
|
|
471
|
+
onSelect: (assets) => console.log(assets),
|
|
472
|
+
onCancel: () => console.log('Cancelled'),
|
|
473
|
+
})
|
|
474
|
+
}
|
|
475
|
+
>
|
|
476
|
+
Choose video
|
|
477
|
+
</button>
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
#### Config overrides
|
|
483
|
+
|
|
484
|
+
Any `AssetPickerConfig` property passed to `open()` is merged with (and overrides) the base config from the provider:
|
|
485
|
+
|
|
486
|
+
```tsx
|
|
487
|
+
// Base config has multiSelect: false
|
|
488
|
+
// This call overrides it to true and adds a forced filter
|
|
489
|
+
const assets = await picker.open({
|
|
490
|
+
multiSelect: true,
|
|
491
|
+
forcedFilters: { type: { values: ['image'] } },
|
|
492
|
+
});
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
#### Hook return type
|
|
496
|
+
|
|
497
|
+
```ts
|
|
498
|
+
interface UseAssetPickerReturn {
|
|
499
|
+
open(overrides?: OpenOptions): Promise<Asset[]>;
|
|
500
|
+
close(): void;
|
|
501
|
+
isOpen: boolean;
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## Asset Utilities
|
|
508
|
+
|
|
509
|
+
Pure helper functions for working with `Asset` objects. Exported from the main entry point — no React required.
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
import {
|
|
513
|
+
getAltText,
|
|
514
|
+
getCdnUrl,
|
|
515
|
+
getAssetWidth,
|
|
516
|
+
getAssetHeight,
|
|
517
|
+
getAssetDimensions,
|
|
518
|
+
isTranscoded,
|
|
519
|
+
getTranscodedUrl,
|
|
520
|
+
getBestVideoUrl,
|
|
521
|
+
isVideo,
|
|
522
|
+
isImage,
|
|
523
|
+
isAudio,
|
|
524
|
+
} from '@scaleflex/asset-picker';
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Type checks
|
|
528
|
+
|
|
529
|
+
| Function | Returns | Description |
|
|
530
|
+
|---|---|---|
|
|
531
|
+
| `isImage(asset)` | `boolean` | `true` if `asset.type` starts with `"image"` |
|
|
532
|
+
| `isVideo(asset)` | `boolean` | `true` if `asset.type` starts with `"video"` |
|
|
533
|
+
| `isAudio(asset)` | `boolean` | `true` if `asset.type` starts with `"audio"` |
|
|
534
|
+
|
|
535
|
+
### URLs
|
|
536
|
+
|
|
537
|
+
| Function | Returns | Description |
|
|
538
|
+
|---|---|---|
|
|
539
|
+
| `getCdnUrl(asset)` | `string` | CDN URL, falling back to public URL, then `""` |
|
|
540
|
+
| `getBestVideoUrl(asset)` | `string` | Transcoded HLS URL > CDN URL > public URL |
|
|
541
|
+
| `getTranscodedUrl(asset)` | `string \| null` | HLS manifest URL, or `null` if not transcoded |
|
|
542
|
+
|
|
543
|
+
### Alt text
|
|
544
|
+
|
|
545
|
+
```ts
|
|
546
|
+
const alt = getAltText(asset); // uses first available language
|
|
547
|
+
const alt = getAltText(asset, 'fr'); // prefers French title
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
Resolution priority: `meta.alt` > `meta.title` (string or localized `Record<string, string>`) > filename without extension.
|
|
551
|
+
|
|
552
|
+
### Dimensions
|
|
553
|
+
|
|
554
|
+
| Function | Returns | Description |
|
|
555
|
+
|---|---|---|
|
|
556
|
+
| `getAssetWidth(asset)` | `number` | Width in px (`0` if unknown). Works for images and videos. |
|
|
557
|
+
| `getAssetHeight(asset)` | `number` | Height in px (`0` if unknown). Works for images and videos. |
|
|
558
|
+
| `getAssetDimensions(asset)` | `{ width, height }` | Both dimensions as an object. |
|
|
559
|
+
|
|
560
|
+
### Video transcoding
|
|
561
|
+
|
|
562
|
+
| Function | Returns | Description |
|
|
563
|
+
|---|---|---|
|
|
564
|
+
| `isTranscoded(asset)` | `boolean` | Whether the asset has a transcoded HLS version |
|
|
565
|
+
| `getTranscodedUrl(asset)` | `string \| null` | The HLS manifest URL, or `null` |
|
|
566
|
+
| `getBestVideoUrl(asset)` | `string` | Best playback URL (transcoded > CDN > public) |
|
|
567
|
+
|
|
402
568
|
---
|
|
403
569
|
|
|
404
570
|
## Theming
|
|
@@ -635,24 +801,36 @@ interface Asset {
|
|
|
635
801
|
};
|
|
636
802
|
created_at: string; // ISO timestamp
|
|
637
803
|
modified_at: string; // ISO timestamp
|
|
638
|
-
tags: Record<string,
|
|
804
|
+
tags: Record<string, Array<{ label: string; sid: string }>>
|
|
805
|
+
| Record<string, { label: string; sid: string }>
|
|
806
|
+
| string[];
|
|
639
807
|
labels: string[];
|
|
640
808
|
meta: {
|
|
641
|
-
title?: string
|
|
809
|
+
title?: string | Record<string, string>; // plain or localized by language code
|
|
642
810
|
description?: string;
|
|
643
811
|
alt?: string;
|
|
644
812
|
[key: string]: unknown;
|
|
645
813
|
};
|
|
646
814
|
info: {
|
|
815
|
+
img_type?: string; // Image format (e.g. "jpeg", "png")
|
|
647
816
|
img_w?: number; // Image width (px)
|
|
648
817
|
img_h?: number; // Image height (px)
|
|
649
|
-
duration?: number; //
|
|
818
|
+
duration?: number; // Audio duration (seconds)
|
|
819
|
+
video_duration?: number; // Video duration (seconds)
|
|
650
820
|
video_w?: number; // Video width (px)
|
|
651
821
|
video_h?: number; // Video height (px)
|
|
652
822
|
thumbnail?: string; // Thumbnail URL
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
823
|
+
preview?: string; // Preview URL
|
|
824
|
+
video_thumbnail?: string; // Video poster image URL
|
|
825
|
+
video_gif?: string; // Animated GIF preview URL
|
|
826
|
+
image_thumbnail?: string; // Image thumbnail URL
|
|
827
|
+
main_colors?: string[]; // Dominant colours (names)
|
|
828
|
+
main_colors_hex?: string[]; // Dominant colours (hex)
|
|
829
|
+
dominant_color?: string; // Most dominant colour (name)
|
|
830
|
+
dominant_color_hex?: string; // Most dominant colour (hex)
|
|
831
|
+
color_space?: string; // Colour space (e.g. "sRGB")
|
|
832
|
+
metadata?: Record<string, unknown>; // Embedded metadata (EXIF, IPTC, etc.)
|
|
833
|
+
playlists?: Array<{ playlists: string[]; resolution?: string }>; // HLS transcoded playlists
|
|
656
834
|
};
|
|
657
835
|
folder?: {
|
|
658
836
|
uuid: string;
|
|
@@ -673,8 +851,10 @@ interface Folder {
|
|
|
673
851
|
uuid: string;
|
|
674
852
|
name: string;
|
|
675
853
|
path: string;
|
|
854
|
+
owner?: string;
|
|
676
855
|
created_at: string;
|
|
677
856
|
modified_at?: string;
|
|
857
|
+
updated_at?: string;
|
|
678
858
|
count?: {
|
|
679
859
|
files_recursive?: number;
|
|
680
860
|
files_direct?: number;
|
|
@@ -682,6 +862,10 @@ interface Folder {
|
|
|
682
862
|
size?: {
|
|
683
863
|
total_recursive_bytes?: number;
|
|
684
864
|
};
|
|
865
|
+
visibility?: {
|
|
866
|
+
in_cdn?: { actual: string; set: string };
|
|
867
|
+
in_dam?: { actual: string; set: string };
|
|
868
|
+
};
|
|
685
869
|
}
|
|
686
870
|
```
|
|
687
871
|
|