@plugable-io/react 0.0.2 → 0.0.3

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
@@ -238,6 +238,37 @@ function ImageGallery() {
238
238
  }
239
239
  ```
240
240
 
241
+ ### Ordering Files
242
+
243
+ ```tsx
244
+ function SortedFileList() {
245
+ const [orderBy, setOrderBy] = useState<'created_at' | 'name' | 'byte_size'>('created_at');
246
+ const [orderDirection, setOrderDirection] = useState<'asc' | 'desc'>('desc');
247
+
248
+ const { files, isLoading } = useFiles({
249
+ orderBy,
250
+ orderDirection,
251
+ perPage: 20,
252
+ });
253
+
254
+ return (
255
+ <div>
256
+ <select value={orderBy} onChange={(e) => setOrderBy(e.target.value as any)}>
257
+ <option value="created_at">Date</option>
258
+ <option value="name">Name</option>
259
+ <option value="byte_size">Size</option>
260
+ </select>
261
+ <button onClick={() => setOrderDirection(orderDirection === 'asc' ? 'desc' : 'asc')}>
262
+ {orderDirection === 'asc' ? '↑' : '↓'}
263
+ </button>
264
+ {files.map((file) => (
265
+ <div key={file.id}>{file.name}</div>
266
+ ))}
267
+ </div>
268
+ );
269
+ }
270
+ ```
271
+
241
272
  ### Manual Loading
242
273
 
243
274
  ```tsx
@@ -268,6 +299,8 @@ function LazyFileList() {
268
299
  | `perPage` | `number` | `20` | Files per page |
269
300
  | `startPage` | `number` | `1` | Initial page number |
270
301
  | `autoLoad` | `boolean` | `true` | Fetch on mount |
302
+ | `orderBy` | `'created_at' \| 'name' \| 'byte_size'` | `'created_at'` | Field to order by |
303
+ | `orderDirection` | `'asc' \| 'desc'` | `'desc'` | Sort direction |
271
304
 
272
305
  ### Return Value
273
306
 
package/dist/index.d.mts CHANGED
@@ -104,6 +104,8 @@ interface UseFilesOptions {
104
104
  perPage?: number;
105
105
  mediaType?: string;
106
106
  autoLoad?: boolean;
107
+ orderBy?: 'created_at' | 'name' | 'byte_size';
108
+ orderDirection?: 'asc' | 'desc';
107
109
  }
108
110
  interface UseFilesResult {
109
111
  files: FileObject[];
@@ -118,6 +120,6 @@ interface UseFilesResult {
118
120
  setPage: (page: number) => void;
119
121
  refresh: () => Promise<void>;
120
122
  }
121
- declare function useFiles({ metadata, startPage, perPage, mediaType, autoLoad, }?: UseFilesOptions): UseFilesResult;
123
+ declare function useFiles({ metadata, startPage, perPage, mediaType, autoLoad, orderBy, orderDirection, }?: UseFilesOptions): UseFilesResult;
122
124
 
123
125
  export { type AuthProvider, Dropzone, type DropzoneProps, type DropzoneRenderProps, FileImage, type FileImageProps, FileList, type FileListProps, type FileListRenderProps, FilePreview, type FilePreviewProps, PlugableProvider, type PlugableProviderProps, type UseFilesOptions, type UseFilesResult, clearImageCache, useFiles, usePlugable };
package/dist/index.d.ts CHANGED
@@ -104,6 +104,8 @@ interface UseFilesOptions {
104
104
  perPage?: number;
105
105
  mediaType?: string;
106
106
  autoLoad?: boolean;
107
+ orderBy?: 'created_at' | 'name' | 'byte_size';
108
+ orderDirection?: 'asc' | 'desc';
107
109
  }
108
110
  interface UseFilesResult {
109
111
  files: FileObject[];
@@ -118,6 +120,6 @@ interface UseFilesResult {
118
120
  setPage: (page: number) => void;
119
121
  refresh: () => Promise<void>;
120
122
  }
121
- declare function useFiles({ metadata, startPage, perPage, mediaType, autoLoad, }?: UseFilesOptions): UseFilesResult;
123
+ declare function useFiles({ metadata, startPage, perPage, mediaType, autoLoad, orderBy, orderDirection, }?: UseFilesOptions): UseFilesResult;
122
124
 
123
125
  export { type AuthProvider, Dropzone, type DropzoneProps, type DropzoneRenderProps, FileImage, type FileImageProps, FileList, type FileListProps, type FileListRenderProps, FilePreview, type FilePreviewProps, PlugableProvider, type PlugableProviderProps, type UseFilesOptions, type UseFilesResult, clearImageCache, useFiles, usePlugable };
package/dist/index.js CHANGED
@@ -369,7 +369,9 @@ function useFiles({
369
369
  startPage = 1,
370
370
  perPage = 20,
371
371
  mediaType,
372
- autoLoad = true
372
+ autoLoad = true,
373
+ orderBy,
374
+ orderDirection
373
375
  } = {}) {
374
376
  const { client, on } = usePlugable();
375
377
  const [files, setFiles] = (0, import_react3.useState)([]);
@@ -378,6 +380,15 @@ function useFiles({
378
380
  const [hasNext, setHasNext] = (0, import_react3.useState)(false);
379
381
  const metadataKey = JSON.stringify(metadata);
380
382
  const stableMetadata = (0, import_react3.useMemo)(() => metadata, [metadataKey]);
383
+ const loadedParamsRef = (0, import_react3.useRef)(null);
384
+ const paramsKeyWithPage = (0, import_react3.useMemo)(() => JSON.stringify({
385
+ metadata: stableMetadata,
386
+ mediaType,
387
+ perPage,
388
+ orderBy,
389
+ orderDirection,
390
+ page
391
+ }), [stableMetadata, mediaType, perPage, orderBy, orderDirection, page]);
381
392
  const fetchFiles = (0, import_react3.useCallback)(async (pageNum) => {
382
393
  setIsLoading(true);
383
394
  try {
@@ -386,11 +397,22 @@ function useFiles({
386
397
  media_type: mediaType,
387
398
  page: pageNum,
388
399
  per_page: perPage,
389
- with_download_url: true
400
+ with_download_url: true,
401
+ order_by: orderBy,
402
+ order_direction: orderDirection
390
403
  };
391
404
  const response = await client.list(options);
392
405
  setFiles(response.files);
393
406
  setHasNext(response.paging.has_next_page);
407
+ const currentParamsKey = JSON.stringify({
408
+ metadata: stableMetadata,
409
+ mediaType,
410
+ perPage,
411
+ orderBy,
412
+ orderDirection,
413
+ page: pageNum
414
+ });
415
+ loadedParamsRef.current = currentParamsKey;
394
416
  } catch (err) {
395
417
  console.error("Failed to load files:", err);
396
418
  setFiles([]);
@@ -398,12 +420,14 @@ function useFiles({
398
420
  } finally {
399
421
  setIsLoading(false);
400
422
  }
401
- }, [client, stableMetadata, mediaType, perPage]);
423
+ }, [client, stableMetadata, mediaType, perPage, orderBy, orderDirection]);
402
424
  (0, import_react3.useEffect)(() => {
403
- if (autoLoad) {
425
+ const hasLoadedForParams = loadedParamsRef.current === paramsKeyWithPage;
426
+ const shouldLoad = autoLoad || !hasLoadedForParams && files.length === 0 && !isLoading;
427
+ if (shouldLoad) {
404
428
  fetchFiles(page);
405
429
  }
406
- }, [fetchFiles, page, autoLoad]);
430
+ }, [fetchFiles, page, autoLoad, paramsKeyWithPage, isLoading]);
407
431
  (0, import_react3.useEffect)(() => {
408
432
  const unsubscribe = on("file.uploaded", () => {
409
433
  fetchFiles(page);
package/dist/index.mjs CHANGED
@@ -320,13 +320,15 @@ function Dropzone({
320
320
  }
321
321
 
322
322
  // src/hooks/useFiles.ts
323
- import { useState as useState2, useCallback as useCallback3, useEffect, useMemo as useMemo2 } from "react";
323
+ import { useState as useState2, useCallback as useCallback3, useEffect, useMemo as useMemo2, useRef as useRef2 } from "react";
324
324
  function useFiles({
325
325
  metadata,
326
326
  startPage = 1,
327
327
  perPage = 20,
328
328
  mediaType,
329
- autoLoad = true
329
+ autoLoad = true,
330
+ orderBy,
331
+ orderDirection
330
332
  } = {}) {
331
333
  const { client, on } = usePlugable();
332
334
  const [files, setFiles] = useState2([]);
@@ -335,6 +337,15 @@ function useFiles({
335
337
  const [hasNext, setHasNext] = useState2(false);
336
338
  const metadataKey = JSON.stringify(metadata);
337
339
  const stableMetadata = useMemo2(() => metadata, [metadataKey]);
340
+ const loadedParamsRef = useRef2(null);
341
+ const paramsKeyWithPage = useMemo2(() => JSON.stringify({
342
+ metadata: stableMetadata,
343
+ mediaType,
344
+ perPage,
345
+ orderBy,
346
+ orderDirection,
347
+ page
348
+ }), [stableMetadata, mediaType, perPage, orderBy, orderDirection, page]);
338
349
  const fetchFiles = useCallback3(async (pageNum) => {
339
350
  setIsLoading(true);
340
351
  try {
@@ -343,11 +354,22 @@ function useFiles({
343
354
  media_type: mediaType,
344
355
  page: pageNum,
345
356
  per_page: perPage,
346
- with_download_url: true
357
+ with_download_url: true,
358
+ order_by: orderBy,
359
+ order_direction: orderDirection
347
360
  };
348
361
  const response = await client.list(options);
349
362
  setFiles(response.files);
350
363
  setHasNext(response.paging.has_next_page);
364
+ const currentParamsKey = JSON.stringify({
365
+ metadata: stableMetadata,
366
+ mediaType,
367
+ perPage,
368
+ orderBy,
369
+ orderDirection,
370
+ page: pageNum
371
+ });
372
+ loadedParamsRef.current = currentParamsKey;
351
373
  } catch (err) {
352
374
  console.error("Failed to load files:", err);
353
375
  setFiles([]);
@@ -355,12 +377,14 @@ function useFiles({
355
377
  } finally {
356
378
  setIsLoading(false);
357
379
  }
358
- }, [client, stableMetadata, mediaType, perPage]);
380
+ }, [client, stableMetadata, mediaType, perPage, orderBy, orderDirection]);
359
381
  useEffect(() => {
360
- if (autoLoad) {
382
+ const hasLoadedForParams = loadedParamsRef.current === paramsKeyWithPage;
383
+ const shouldLoad = autoLoad || !hasLoadedForParams && files.length === 0 && !isLoading;
384
+ if (shouldLoad) {
361
385
  fetchFiles(page);
362
386
  }
363
- }, [fetchFiles, page, autoLoad]);
387
+ }, [fetchFiles, page, autoLoad, paramsKeyWithPage, isLoading]);
364
388
  useEffect(() => {
365
389
  const unsubscribe = on("file.uploaded", () => {
366
390
  fetchFiles(page);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plugable-io/react",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "React components and hooks for Plugable File Management API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -43,7 +43,7 @@
43
43
  "react-dom": ">=16.8.0"
44
44
  },
45
45
  "dependencies": {
46
- "@plugable-io/js": "^0.0.8"
46
+ "@plugable-io/js": "^0.0.9"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/node": "^20.0.0",