@vryzel/file-next-ui 0.4.0 → 0.4.1

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 (2) hide show
  1. package/README.md +196 -11
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,39 +1,224 @@
1
1
  # @vryzel/file-next-ui
2
2
 
3
- Ready-to-use file explorer for `@vryzel/file-next`. Tailwind classes. Compose the pieces, or drop in `FileExplorer`.
3
+ Ready-made file explorer for Next.js. Import `FileExplorer`, pass server callbacks, done. Or compose the pieces.
4
4
 
5
5
  ```bash
6
6
  pnpm add @vryzel/file-next-ui
7
7
  ```
8
8
 
9
- Scan the package in `tailwind.config`:
9
+ Scan the package so Tailwind keeps the classes:
10
10
 
11
11
  ```js
12
- content: ["./node_modules/@vryzel/file-next-ui/dist/**/*.{js,mjs}"]
12
+ // tailwind.config.ts
13
+ content: [
14
+ "./app/**/*.{ts,tsx}",
15
+ "./node_modules/@vryzel/file-next-ui/dist/**/*.{js,mjs}",
16
+ ]
13
17
  ```
14
18
 
15
- ## Default explorer
19
+ Your theme must define the usual shadcn CSS variables (`--background`, `--foreground`, `--border`, `--primary`, `--muted`, `--destructive`, `--card`, `--ring`, …).
20
+
21
+ ## Quick path
16
22
 
17
23
  ```tsx
24
+ "use client";
18
25
  import { FileExplorer } from "@vryzel/file-next-ui";
19
26
 
20
27
  <FileExplorer
21
- className="h-[70vh] rounded-[10px] border border-border"
28
+ className="h-[70vh] overflow-hidden rounded-[10px] border border-border bg-card"
22
29
  tenantId="acme"
23
- parentId={null}
30
+ parentId={folderId}
24
31
  listFiles={listFiles}
25
32
  searchFiles={searchFiles}
26
33
  listTrash={listTrash}
27
34
  requestUpload={requestUpload}
28
- actions={actions}
29
- onOpenFolder={setFolder}
35
+ actions={{
36
+ deleteFile,
37
+ moveFile,
38
+ copyFile,
39
+ renameFile,
40
+ createFolder,
41
+ restoreNode,
42
+ createShare,
43
+ }}
44
+ onOpenFolder={(folder) => setFolderId(folder.id)}
45
+ breadcrumbs={crumbs}
46
+ onBreadcrumbNavigate={(seg) => setFolderId(seg.id === "root" ? null : seg.id)}
47
+ />
48
+ ```
49
+
50
+ `listFiles` / `searchFiles` / `listTrash` return:
51
+
52
+ ```ts
53
+ Promise<
54
+ | { ok: true; value: { items: FileNode[]; nextCursor?: string } }
55
+ | { ok: false; error: { code: string; message: string } }
56
+ >
57
+ ```
58
+
59
+ Revive dates if they crossed the server action boundary (`new Date(node.updatedAt)`). `FileExplorer` also revives them.
60
+
61
+ Keep callback identities stable (`useCallback` or module scope).
62
+
63
+ ## Use cases
64
+
65
+ ### 1. Default explorer (batteries)
66
+
67
+ What you get with `FileExplorer`:
68
+
69
+ - List / grid, sort, persisted view (`persistViewKey`)
70
+ - Search, trash, upload (multi-file + OS drop)
71
+ - New folder / rename dialogs (not `window.prompt`)
72
+ - Multi-select, shift-click, ⌘A, copy/paste, drag onto folders
73
+ - Pagination (`limit` 50 + Load more)
74
+ - Quota footer, selection toast, upload queue
75
+
76
+ ```tsx
77
+ <FileExplorer
78
+ persistViewKey="my-app.files.view"
79
+ usedBytes={used}
80
+ quotaBytes={quota}
81
+ refreshKey={refreshKey}
82
+ onPreview={openPreview}
83
+ onDownload={download}
84
+ extraFileAction={{ label: "Create quote", onSelect: (f) => router.push(`/quotes/new?file=${f.id}`) }}
85
+ protectedIds={linkedIds} // cannot move to trash
86
+ labels={{ search: "Buscar", emptyFolder: "Carpeta vacía" }}
87
+ {...props}
88
+ />
89
+ ```
90
+
91
+ ### 2. Uploads that survive navigation
92
+
93
+ Put the provider on a layout. Unmounting the files page will not kill XHR.
94
+
95
+ ```tsx
96
+ // app/(dashboard)/layout.tsx
97
+ import { UploadQueueProvider } from "@vryzel/file-next-ui";
98
+
99
+ <UploadQueueProvider requestUpload={requestUpload} confirmUpload={onUploaded}>
100
+ {children}
101
+ </UploadQueueProvider>
102
+ ```
103
+
104
+ `FileExplorer` uses the nearest provider; if none exists it creates its own.
105
+
106
+ ### 3. Preview dialog
107
+
108
+ ```tsx
109
+ import { FileExplorer, FilePreviewDialog, canPreviewFile } from "@vryzel/file-next-ui";
110
+
111
+ const [preview, setPreview] = useState<{ file: FileNode; src: string } | null>(null);
112
+
113
+ <FileExplorer
114
+ onPreview={async (file) => {
115
+ const src = await signedUrl(file);
116
+ if (canPreviewFile(file)) setPreview({ file, src });
117
+ else window.open(src, "_blank");
118
+ }}
119
+ onDownload={async (file) => window.open(await signedUrl(file), "_blank")}
120
+ />
121
+ <FilePreviewDialog
122
+ file={preview?.file ?? null}
123
+ src={preview?.src ?? ""}
124
+ onClose={() => setPreview(null)}
125
+ onDownload={(file) => void signedUrl(file).then((src) => window.open(src, "_blank"))}
30
126
  />
31
127
  ```
32
128
 
33
- Pass `labels` to override copy. Pass `className` on any piece to restyle.
129
+ `src` is yours (presigned GET). The dialog does not call S3.
130
+
131
+ ### 4. Compose your own shell
132
+
133
+ ```tsx
134
+ import {
135
+ Breadcrumbs,
136
+ ExplorerToolbar,
137
+ ExplorerListView,
138
+ ExplorerGridView,
139
+ EmptyState,
140
+ ErrorState,
141
+ FileIcon,
142
+ } from "@vryzel/file-next-ui";
143
+ import { useFileExplorer } from "@vryzel/file-next-headless";
144
+
145
+ const explorer = useFileExplorer({ listFiles, tenantId, parentId });
146
+
147
+ return (
148
+ <div className="flex h-[70vh] flex-col rounded-[10px] border">
149
+ <Breadcrumbs segments={crumbs} onNavigate={go} className="px-4 py-3" />
150
+ <ExplorerToolbar
151
+ view={explorer.view}
152
+ onViewChange={explorer.setView}
153
+ query={query}
154
+ onQueryChange={setQuery}
155
+ sortKey={sortKey}
156
+ sortDirection={sortDir}
157
+ onSortChange={setSort}
158
+ />
159
+ {explorer.status === "error" ? (
160
+ <ErrorState error={explorer.error!} onRetry={explorer.refetch} />
161
+ ) : explorer.files.length === 0 ? (
162
+ <EmptyState title="Empty folder" description="Drop files here." />
163
+ ) : explorer.view === "list" ? (
164
+ <ExplorerListView files={explorer.files} {...selectionAndDrag} />
165
+ ) : (
166
+ <ExplorerGridView files={explorer.files} {...selectionAndDrag} />
167
+ )}
168
+ </div>
169
+ );
170
+ ```
171
+
172
+ Every piece takes `className`.
34
173
 
35
- Put `UploadQueueProvider` on a layout if uploads should survive unmounting the page.
174
+ ### 5. Copy / i18n
175
+
176
+ ```tsx
177
+ <FileExplorer
178
+ labels={{
179
+ search: "Buscar",
180
+ upload: "Subir",
181
+ newFolder: "Nueva carpeta",
182
+ emptyFolder: "Esta carpeta está vacía",
183
+ moveToTrash: "Mover a la papelera",
184
+ }}
185
+ />
186
+ ```
187
+
188
+ Partial overlay on English defaults. Or wrap several pieces:
189
+
190
+ ```tsx
191
+ import { ExplorerLabelsProvider, defaultLabels } from "@vryzel/file-next-ui";
192
+
193
+ <ExplorerLabelsProvider labels={{ search: "Buscar" }}>
194
+ <ExplorerToolbar ... />
195
+ </ExplorerLabelsProvider>
196
+ ```
197
+
198
+ ### 6. Icons only
199
+
200
+ ```tsx
201
+ import { FileIcon } from "@vryzel/file-next-ui";
202
+ <FileIcon kind={file.kind} mimeType={file.mimeType} className="size-6" />
203
+ ```
36
204
 
37
205
  ## Pieces
38
206
 
39
- `ExplorerToolbar`, `ExplorerListView`, `ExplorerGridView`, `ExplorerContextMenu`, `Breadcrumbs`, `EmptyState`, `ErrorState`, `FileIcon`, `FilePreviewDialog`, `CreateFolderDialog`, `ConfirmDeleteDialog`, `ExplorerSelectionToast`, `ExplorerUploadStatus`.
207
+ | Export | Role |
208
+ |---|---|
209
+ | `FileExplorer` | Default composed explorer |
210
+ | `ExplorerToolbar` | Search, upload, new folder, sort, trash, list/grid |
211
+ | `ExplorerListView` / `ExplorerGridView` | Rows / cards + drag |
212
+ | `ExplorerContextMenu` | Right-click / overflow menu |
213
+ | `Breadcrumbs` | Path |
214
+ | `EmptyState` / `ErrorState` | Empty / error |
215
+ | `FileIcon` | Mime icon |
216
+ | `FilePreviewDialog` | Image/pdf/video/text overlay |
217
+ | `CreateFolderDialog` / `ConfirmDeleteDialog` | Modals |
218
+ | `ExplorerSelectionToast` / `ExplorerClipboardToast` | Multi-select / copy |
219
+ | `UploadQueueProvider` / `ExplorerUploadStatus` | Upload queue |
220
+ | `defaultLabels` | English copy |
221
+
222
+ ## Not this package
223
+
224
+ Server wiring → `@vryzel/file-next`. Hooks without UI → `@vryzel/file-next-headless`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vryzel/file-next-ui",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Ready-to-use file explorer UI for file-next. Tailwind classes, composable pieces, and a default FileExplorer.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -48,8 +48,8 @@
48
48
  "tsup": "^8.3.5",
49
49
  "typescript": "^5.6.3",
50
50
  "vitest": "^2.1.5",
51
- "@vryzel/file-next": "0.4.0",
52
- "@vryzel/file-next-headless": "0.4.0"
51
+ "@vryzel/file-next-headless": "0.4.1",
52
+ "@vryzel/file-next": "0.4.1"
53
53
  },
54
54
  "keywords": [
55
55
  "react",