@scaleflex/uploader 0.2.1 → 0.2.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.
Files changed (33) hide show
  1. package/.claude/skills/integrate-uploader/SKILL.md +458 -0
  2. package/README.md +30 -0
  3. package/dist/components/drop-zone.d.ts +1 -0
  4. package/dist/components/drop-zone.d.ts.map +1 -1
  5. package/dist/components/file-item.d.ts +1 -0
  6. package/dist/components/file-item.d.ts.map +1 -1
  7. package/dist/components/file-list.d.ts +13 -0
  8. package/dist/components/file-list.d.ts.map +1 -1
  9. package/dist/components/success-card.d.ts +4 -0
  10. package/dist/components/success-card.d.ts.map +1 -1
  11. package/dist/define.cjs +1 -1
  12. package/dist/define.js +1 -1
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/{provider-browser-ixqCA0XP.js → provider-browser-CMbbN8PZ.js} +1 -1
  16. package/dist/{provider-browser-yW3pZFSP.cjs → provider-browser-DbjyF_Ou.cjs} +1 -1
  17. package/dist/react.cjs +1 -1
  18. package/dist/react.d.ts +12 -0
  19. package/dist/react.d.ts.map +1 -1
  20. package/dist/react.js +95 -60
  21. package/dist/{search-provider-browser-B5ZWGUl8.js → search-provider-browser-9oZjABnB.js} +1 -1
  22. package/dist/{search-provider-browser-BrKVwGf_.cjs → search-provider-browser-KQs6JI8u.cjs} +1 -1
  23. package/dist/{sfx-uploader-CU9IwNC7.js → sfx-uploader-DTfESjzm.js} +3765 -2475
  24. package/dist/sfx-uploader-DXyLpoIJ.cjs +4407 -0
  25. package/dist/sfx-uploader.d.ts +39 -4
  26. package/dist/sfx-uploader.d.ts.map +1 -1
  27. package/dist/store/store.types.d.ts +2 -0
  28. package/dist/store/store.types.d.ts.map +1 -1
  29. package/dist/test-utils.d.ts.map +1 -1
  30. package/dist/utils/file-utils.d.ts +2 -0
  31. package/dist/utils/file-utils.d.ts.map +1 -1
  32. package/package.json +2 -1
  33. package/dist/sfx-uploader-ziRTzw0k.cjs +0 -3298
@@ -0,0 +1,458 @@
1
+ ---
2
+ name: integrate-uploader
3
+ description: Integrate @scaleflex/uploader into any project — install, configure auth,
4
+ wire events, theme, and add restrictions. Works with vanilla JS, React, Vue, Angular, Svelte.
5
+ user_invocable: true
6
+ metadata:
7
+ category: integration
8
+ tags:
9
+ - scaleflex
10
+ - uploader
11
+ - file-upload
12
+ - web-component
13
+ status: ready
14
+ version: 1
15
+ ---
16
+
17
+ # Scaleflex Uploader Integration Skill
18
+
19
+ ## When to Use
20
+
21
+ - User says "add uploader", "integrate uploader", "file upload widget", "upload component"
22
+ - User wants to let users upload files to Scaleflex VXP / Filerobot
23
+ - User asks how to use `@scaleflex/uploader` in their project
24
+
25
+ ## Step 1 — Detect the Target Framework
26
+
27
+ Read the project's `package.json` to determine:
28
+ - **React** (18+): use the React wrapper (`@scaleflex/uploader/react`)
29
+ - **Vue / Angular / Svelte / vanilla JS**: use the Web Component (`@scaleflex/uploader/define`)
30
+
31
+ ## Step 2 — Install
32
+
33
+ ```bash
34
+ npm install @scaleflex/uploader
35
+ ```
36
+
37
+ `lit` is bundled — no extra peer deps for vanilla JS / Vue / Angular / Svelte.
38
+ For React, `react` and `react-dom` (v18+) must already be installed (they're optional peer deps).
39
+
40
+ ### CDN (no bundler)
41
+
42
+ ```html
43
+ <script src="https://scaleflex.cloudimg.io/v7/plugins/scaleflex/uploader/0.2.1/sfx-uploader.min.js"></script>
44
+ ```
45
+
46
+ This registers `<sfx-uploader>` and all sub-components automatically. Replace `0.2.1` with the desired version.
47
+
48
+ ## Step 3 — Add the Uploader
49
+
50
+ ### Vanilla JS / Web Component
51
+
52
+ ```js
53
+ import '@scaleflex/uploader/define';
54
+
55
+ const uploader = document.querySelector('sfx-uploader')
56
+ || document.createElement('sfx-uploader');
57
+ document.body.appendChild(uploader);
58
+
59
+ uploader.config = {
60
+ auth: {
61
+ mode: 'security-template',
62
+ container: 'YOUR_CONTAINER',
63
+ securityTemplateId: 'SECU_YOUR_TEMPLATE_ID',
64
+ },
65
+ };
66
+
67
+ uploader.addEventListener('sfx-all-complete', (e) => {
68
+ const { successful, failed } = e.detail;
69
+ console.log('Uploaded:', successful.map(f => f.response.file.url.cdn));
70
+ });
71
+
72
+ uploader.open();
73
+ ```
74
+
75
+ ### React
76
+
77
+ ```tsx
78
+ import { useRef } from 'react';
79
+ import { Uploader, type UploaderRef } from '@scaleflex/uploader/react';
80
+
81
+ function MyComponent() {
82
+ const uploaderRef = useRef<UploaderRef>(null);
83
+
84
+ return (
85
+ <>
86
+ <button onClick={() => uploaderRef.current?.open()}>Upload files</button>
87
+ <Uploader
88
+ ref={uploaderRef}
89
+ config={{
90
+ auth: {
91
+ mode: 'security-template' as const,
92
+ container: 'YOUR_CONTAINER',
93
+ securityTemplateId: 'SECU_YOUR_TEMPLATE_ID',
94
+ },
95
+ }}
96
+ onUploadComplete={(file, response) => {
97
+ console.log('Uploaded:', response.file.url.cdn);
98
+ }}
99
+ onAllComplete={(successful, failed) => {
100
+ console.log(`Done: ${successful.length} ok, ${failed.length} failed`);
101
+ }}
102
+ />
103
+ </>
104
+ );
105
+ }
106
+ ```
107
+
108
+ **React controlled mode** (open state managed by parent):
109
+
110
+ ```tsx
111
+ const [isOpen, setIsOpen] = useState(false);
112
+
113
+ <Uploader
114
+ config={config}
115
+ open={isOpen}
116
+ onAllComplete={(successful) => { handleFiles(successful); setIsOpen(false); }}
117
+ onCancel={() => setIsOpen(false)}
118
+ />
119
+ ```
120
+
121
+ ### Vue
122
+
123
+ ```vue
124
+ <template>
125
+ <sfx-uploader ref="uploader"></sfx-uploader>
126
+ <button @click="openUploader">Upload files</button>
127
+ </template>
128
+
129
+ <script setup>
130
+ import '@scaleflex/uploader/define';
131
+ import { ref, onMounted } from 'vue';
132
+
133
+ const uploader = ref(null);
134
+
135
+ onMounted(() => {
136
+ const el = uploader.value;
137
+ el.config = {
138
+ auth: {
139
+ mode: 'security-template',
140
+ container: 'YOUR_CONTAINER',
141
+ securityTemplateId: 'SECU_YOUR_TEMPLATE_ID',
142
+ },
143
+ };
144
+
145
+ el.addEventListener('sfx-all-complete', (e) => {
146
+ console.log('Uploaded:', e.detail.successful);
147
+ });
148
+ });
149
+
150
+ function openUploader() {
151
+ uploader.value?.open();
152
+ }
153
+ </script>
154
+ ```
155
+
156
+ ## Step 4 — Authentication
157
+
158
+ Ask the user which auth mode they need:
159
+
160
+ ### Security template (recommended for client-side)
161
+
162
+ The uploader auto-exchanges the template ID for a SASS key on init. Safer for client-side code.
163
+
164
+ ```ts
165
+ auth: {
166
+ mode: 'security-template',
167
+ container: string, // Scaleflex container name
168
+ securityTemplateId: string, // From Scaleflex dashboard (SECU_...)
169
+ airboxPuid?: string, // Optional: airbox user ID
170
+ }
171
+ ```
172
+
173
+ ### SASS key (direct)
174
+
175
+ Use when you already have a SASS key (e.g. from your backend or inside Scaleflex Hub).
176
+
177
+ ```ts
178
+ auth: {
179
+ mode: 'sass-key',
180
+ container: string,
181
+ sassKey: string, // X-Filerobot-Key value
182
+ airboxPuid?: string,
183
+ }
184
+ ```
185
+
186
+ ## Step 5 — Configure (Optional)
187
+
188
+ All options beyond `auth` are optional. Add only what the user needs:
189
+
190
+ ```ts
191
+ uploader.config = {
192
+ auth: { /* ... */ },
193
+
194
+ // Upload target
195
+ targetFolder: '/user-uploads/', // Filerobot folder path (default: '/')
196
+
197
+ // Display
198
+ mode: 'modal', // 'modal' (default) or 'inline'
199
+ headerButton: 'close', // 'none' | 'close' | 'back'
200
+ // modal default: 'close'
201
+ // inline default: 'none'
202
+ // 'back': for wizard/step flows
203
+ sourcesLayout: 'pills', // 'pills' (default) or 'cards'
204
+
205
+ // Upload behavior
206
+ concurrency: 3, // Max concurrent uploads (default: 3)
207
+ autoProceed: false, // Auto-start upload on file add (default: false)
208
+
209
+ // File restrictions
210
+ restrictions: {
211
+ maxFileSize: 10 * 1024 * 1024, // 10 MB per file
212
+ maxTotalFilesSize: 500 * 1024 * 1024, // 500 MB total
213
+ maxNumberOfFiles: 50,
214
+ minNumberOfFiles: 1,
215
+ allowedFileTypes: ['image/*', 'video/*', 'application/pdf'],
216
+ blockedFileTypes: ['application/exe'],
217
+ },
218
+
219
+ // Cloud connectors (Google Drive, Dropbox, etc.)
220
+ connectors: {
221
+ companionUrl: 'https://eu-on-24001.connector.filerobot.com',
222
+ providers: ['google-drive', 'dropbox', 'onedrive', 'box'],
223
+ },
224
+
225
+ // UI options
226
+ showFillMetadata: false, // Show "Fill Metadata" button (default: false)
227
+ clearOnClose: true, // Clear files on modal close (default: true)
228
+ clearOnComplete: true, // Clear files on "Done" action (default: true)
229
+ rejectedFileAutoRemoveDelay: 4000, // ms before auto-removing rejected files
230
+ // Set to 0 or false to disable
231
+ };
232
+ ```
233
+
234
+ ## Events Reference
235
+
236
+ All events bubble and cross Shadow DOM (`composed: true`):
237
+
238
+ | Event | Detail | When |
239
+ |---|---|---|
240
+ | `sfx-file-added` | `{ file: UploadFile }` | File added to queue |
241
+ | `sfx-file-removed` | `{ file: UploadFile }` | File removed from queue |
242
+ | `sfx-file-rejected` | `{ file: UploadFile, reason: string }` | File rejected by restrictions |
243
+ | `sfx-upload-started` | `{ files: UploadFile[] }` | Upload batch started |
244
+ | `sfx-upload-progress` | `{ file: UploadFile, progress: number, speed: number }` | Per-file progress update |
245
+ | `sfx-upload-complete` | `{ file: UploadFile, response: UploadResponse }` | Single file uploaded |
246
+ | `sfx-upload-error` | `{ file: UploadFile, error: Error }` | Single file failed |
247
+ | `sfx-upload-retry` | `{ file: UploadFile, attempt: number }` | File being retried |
248
+ | `sfx-all-complete` | `{ successful: UploadFile[], failed: UploadFile[] }` | All files finished |
249
+ | `sfx-total-progress` | `{ percentage: number, speed: number, eta: number }` | Aggregate progress |
250
+ | `sfx-before-upload` | `{ files: UploadFile[] }` | Before upload starts (cancelable) |
251
+ | `sfx-open` | `{}` | Uploader opened |
252
+ | `sfx-close` | `{}` | Uploader closed |
253
+ | `sfx-cancel` | `{}` | Upload cancelled |
254
+ | `sfx-fill-metadata` | `{ files: UploadFile[] }` | "Fill Metadata" button clicked |
255
+
256
+ ## Public Methods
257
+
258
+ | Method | Returns | Description |
259
+ |---|---|---|
260
+ | `open()` | `void` | Open the modal |
261
+ | `close()` | `void` | Close the modal (respects `clearOnClose`) |
262
+ | `upload()` | `void` | Start uploading all queued files |
263
+ | `addFiles(files: File[])` | `void` | Programmatically add files |
264
+ | `resumeUpload(files?: UploadFile[])` | `void` | Resume paused upload with optional metadata updates |
265
+ | `cancelUpload()` | `void` | Cancel active uploads |
266
+ | `getFiles()` | `UploadFile[]` | Get snapshot of all files |
267
+ | `getFile(fileId)` | `UploadFile \| undefined` | Get single file by ID |
268
+ | `updateFileMeta(fileId, meta?, tags?)` | `void` | Update metadata on a queued file |
269
+ | `updateFilesMeta(updates)` | `void` | Batch update metadata |
270
+
271
+ ## Config Callbacks (Web Component)
272
+
273
+ For Web Component usage, callbacks can be passed via `config.callbacks`:
274
+
275
+ ```ts
276
+ uploader.config = {
277
+ auth: { /* ... */ },
278
+ callbacks: {
279
+ onFileAdded: (file) => { /* ... */ },
280
+ onAllComplete: (successful, failed) => { /* ... */ },
281
+ onBeforeUpload: (files) => {
282
+ // Return false to cancel the upload
283
+ return true;
284
+ },
285
+ onFillMetadata: (files) => {
286
+ // Called when "Fill Metadata" button is clicked
287
+ },
288
+ onFilePreview: (file) => {
289
+ // Called when a file preview is clicked
290
+ },
291
+ // ... all other callbacks from the Events table
292
+ },
293
+ };
294
+ ```
295
+
296
+ `onBeforeUpload`, `onFillMetadata`, and `onFilePreview` are only available via `config.callbacks` (not as React props).
297
+
298
+ ## React Wrapper Props
299
+
300
+ ```ts
301
+ interface UploaderProps {
302
+ config: UploaderConfig; // Required
303
+ open?: boolean; // Controlled open state
304
+
305
+ // All event callbacks (mirror DOM events)
306
+ onFileAdded?: (file: UploadFile) => void;
307
+ onFileRemoved?: (file: UploadFile) => void;
308
+ onFileRejected?: (file: UploadFile, reason: string) => void;
309
+ onUploadStarted?: (files: UploadFile[]) => void;
310
+ onUploadProgress?: (file: UploadFile, progress: number, speed: number) => void;
311
+ onUploadComplete?: (file: UploadFile, response: UploadResponse) => void;
312
+ onUploadError?: (file: UploadFile, error: Error) => void;
313
+ onUploadRetry?: (file: UploadFile, attempt: number) => void;
314
+ onAllComplete?: (successful: UploadFile[], failed: UploadFile[]) => void;
315
+ onTotalProgress?: (percentage: number, speed: number, eta: number) => void;
316
+ onOpen?: () => void;
317
+ onClose?: () => void;
318
+ onCancel?: () => void;
319
+
320
+ className?: string;
321
+ style?: CSSProperties;
322
+ }
323
+ ```
324
+
325
+ React ref exposes: `open()`, `close()`, `upload()`, `addFiles()`, `resumeUpload()`, `cancelUpload()`, and `element` (direct Web Component access).
326
+
327
+ ## UploadResponse Shape
328
+
329
+ ```ts
330
+ interface UploadResponse {
331
+ status: 'success' | 'error';
332
+ file: {
333
+ uuid: string;
334
+ name: string;
335
+ extension: string;
336
+ type: string;
337
+ size: number;
338
+ url: { public: string; cdn: string };
339
+ meta: Record<string, unknown>;
340
+ tags: string[];
341
+ info: { img_w?: number; img_h?: number };
342
+ created_at: string;
343
+ modified_at: string;
344
+ };
345
+ msg?: string;
346
+ }
347
+ ```
348
+
349
+ ## Theming
350
+
351
+ Override CSS custom properties on the element or any ancestor. All use `--sfx-up-` prefix:
352
+
353
+ ```css
354
+ sfx-uploader {
355
+ /* Colors */
356
+ --sfx-up-primary: #2563eb;
357
+ --sfx-up-primary-hover: #1d4ed8;
358
+ --sfx-up-primary-bg: #eff6ff;
359
+ --sfx-up-success: #16a34a;
360
+ --sfx-up-error: #dc2626;
361
+
362
+ /* Text */
363
+ --sfx-up-text: #1e293b;
364
+ --sfx-up-text-secondary: #475569;
365
+ --sfx-up-text-muted: #94a3b8;
366
+
367
+ /* Background & borders */
368
+ --sfx-up-bg: #ffffff;
369
+ --sfx-up-surface: #f8fafc;
370
+ --sfx-up-border: #e8edf5;
371
+ --sfx-up-backdrop: rgba(0, 0, 0, 0.45);
372
+
373
+ /* Typography & shape */
374
+ --sfx-up-font: 'Inter', system-ui, sans-serif;
375
+ --sfx-up-radius: 16px;
376
+ --sfx-up-max-height: 88vh;
377
+ }
378
+ ```
379
+
380
+ ## Cloud Connectors
381
+
382
+ Supported providers:
383
+
384
+ | Provider ID | Service |
385
+ |---|---|
386
+ | `'google-drive'` | Google Drive |
387
+ | `'dropbox'` | Dropbox |
388
+ | `'onedrive'` | Microsoft OneDrive |
389
+ | `'box'` | Box |
390
+ | `'instagram'` | Instagram |
391
+ | `'facebook'` | Facebook |
392
+ | `'unsplash'` | Unsplash (search-based) |
393
+
394
+ ## Common Patterns
395
+
396
+ ### Image-only uploader
397
+
398
+ ```ts
399
+ config = {
400
+ auth: { /* ... */ },
401
+ restrictions: {
402
+ allowedFileTypes: ['image/*'],
403
+ maxFileSize: 5 * 1024 * 1024,
404
+ },
405
+ autoProceed: true,
406
+ };
407
+ ```
408
+
409
+ ### Inline mode (embedded in page)
410
+
411
+ ```ts
412
+ config = {
413
+ auth: { /* ... */ },
414
+ mode: 'inline',
415
+ };
416
+ ```
417
+
418
+ ### Step/wizard flow (modal with back button)
419
+
420
+ ```ts
421
+ config = {
422
+ auth: { /* ... */ },
423
+ mode: 'modal',
424
+ headerButton: 'back',
425
+ clearOnClose: false, // preserve files across open/close
426
+ };
427
+ ```
428
+
429
+ ### With cloud connectors
430
+
431
+ ```ts
432
+ config = {
433
+ auth: { /* ... */ },
434
+ connectors: {
435
+ companionUrl: 'https://eu-on-24001.connector.filerobot.com',
436
+ providers: ['google-drive', 'dropbox'],
437
+ },
438
+ };
439
+ ```
440
+
441
+ ### Intercept before upload (metadata dialog)
442
+
443
+ ```js
444
+ uploader.addEventListener('sfx-before-upload', (e) => {
445
+ e.preventDefault(); // pause upload
446
+ showMetadataDialog(e.detail.files).then((updatedFiles) => {
447
+ uploader.resumeUpload(updatedFiles);
448
+ });
449
+ });
450
+ ```
451
+
452
+ ## Troubleshooting
453
+
454
+ - **"customElements is not defined"** — SSR environment. The React wrapper handles this automatically. For vanilla JS, guard the import: `if (typeof customElements !== 'undefined') import('@scaleflex/uploader/define');`
455
+ - **Styles not showing** — The component uses Shadow DOM; external CSS won't penetrate. Use `--sfx-up-*` CSS custom properties for theming.
456
+ - **Auth errors** — Check that the security template ID or SASS key is valid and the container name matches.
457
+ - **`open()` does nothing** — `config` must be set before calling `open()`. Ensure `auth` is provided.
458
+ - **Files rejected silently** — Check `restrictions` config. Listen to `sfx-file-rejected` for the reason.
package/README.md CHANGED
@@ -47,6 +47,12 @@
47
47
  npm install @scaleflex/uploader
48
48
  ```
49
49
 
50
+ Or use the CDN for a no-bundler setup:
51
+
52
+ ```html
53
+ <script src="https://scaleflex.cloudimg.io/v7/plugins/scaleflex/uploader/0.2.1/sfx-uploader.min.js"></script>
54
+ ```
55
+
50
56
  ## Quick start
51
57
 
52
58
  ### Web Component
@@ -114,6 +120,30 @@ function App() {
114
120
  | Firefox | 100+ |
115
121
  | Safari | 15.4+ |
116
122
 
123
+ ## Claude Code Integration
124
+
125
+ If you use [Claude Code](https://docs.anthropic.com/en/docs/claude-code), this package ships with a ready-made skill that helps Claude add the uploader to your project — detecting your framework, wiring auth, events, theming, and restrictions automatically.
126
+
127
+ **Per-project** (recommended — share with your team via version control):
128
+
129
+ ```bash
130
+ mkdir -p .claude/skills/integrate-uploader
131
+ cp node_modules/@scaleflex/uploader/.claude/skills/integrate-uploader/SKILL.md \
132
+ .claude/skills/integrate-uploader/SKILL.md
133
+ ```
134
+
135
+ Commit the `.claude/skills/` directory to version control. The skill is now available to everyone on the team.
136
+
137
+ **Per-user** (available across all your projects):
138
+
139
+ ```bash
140
+ mkdir -p ~/.claude/skills/integrate-uploader
141
+ cp node_modules/@scaleflex/uploader/.claude/skills/integrate-uploader/SKILL.md \
142
+ ~/.claude/skills/integrate-uploader/SKILL.md
143
+ ```
144
+
145
+ Then type `/integrate-uploader` in Claude Code and it will walk you through the full integration — install, config, events, and theming — tailored to your stack (React, Vue, vanilla JS, etc.).
146
+
117
147
  ## Documentation
118
148
 
119
149
  See the full documentation and interactive examples at **[scaleflex.github.io/uploader](https://scaleflex.github.io/uploader/)**.
@@ -35,6 +35,7 @@ export declare class SfxDropZone extends LitElement {
35
35
  private _onScrollOrResize;
36
36
  private _updateVisiblePills;
37
37
  connectedCallback(): void;
38
+ updated(changed: Map<string, unknown>): void;
38
39
  disconnectedCallback(): void;
39
40
  private _renderPill;
40
41
  private _renderCard;
@@ -1 +1 @@
1
- {"version":3,"file":"drop-zone.d.ts","sourceRoot":"","sources":["../../src/components/drop-zone.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAKrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKhD,qBAAa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,MAAM,0BAyxBX;IAE0C,OAAO,UAAS;IACE,gBAAgB,UAAS;IAC3D,MAAM,SAAM;IACb,OAAO,EAAE,SAAS,EAAE,CAAM;IACI,aAAa,EAAE,OAAO,GAAG,OAAO,CAAW;IAE3F,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAiB;IAE7B,OAAO,CAAC,SAAS,CAAe;IACrB,SAAS,EAAG,gBAAgB,CAAC;IAE1D,OAAO,CAAC,YAAY,CAAK;IAEzB,0CAA0C;IAC1C,MAAM;IAMN,OAAO,CAAC,YAAY,CAMlB;IAEF,OAAO,CAAC,WAAW,CAEjB;IAEF,OAAO,CAAC,YAAY,CAOlB;IAEF,OAAO,CAAC,OAAO,CAUb;IAIF,OAAO,CAAC,QAAQ,CAad;IAEF,OAAO,CAAC,UAAU,CAKhB;IAEF,OAAO,CAAC,aAAa,CAQnB;IAIF,OAAO,CAAC,QAAQ,CAkBd;IAEF,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,WAAW;IAQnB,qFAAqF;IACrF,OAAO,CAAC,iBAAiB;IAkCzB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,WAAW,CAEjB;IAEF,OAAO,CAAC,aAAa,CAInB;IAEF,OAAO,CAAC,YAAY,CAA8C;IAElE,OAAO,CAAC,iBAAiB,CAMvB;IAEF,OAAO,CAAC,mBAAmB;IAqB3B,iBAAiB;IAUjB,oBAAoB;IAUpB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,mBAAmB;IA4B3B,MAAM;CAwGP"}
1
+ {"version":3,"file":"drop-zone.d.ts","sourceRoot":"","sources":["../../src/components/drop-zone.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAKrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKhD,qBAAa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,MAAM,0BA8wBX;IAE0C,OAAO,UAAS;IACE,gBAAgB,UAAS;IAC3D,MAAM,SAAM;IACb,OAAO,EAAE,SAAS,EAAE,CAAM;IACI,aAAa,EAAE,OAAO,GAAG,OAAO,CAAW;IAE3F,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAiB;IAE7B,OAAO,CAAC,SAAS,CAAe;IACrB,SAAS,EAAG,gBAAgB,CAAC;IAE1D,OAAO,CAAC,YAAY,CAAK;IAEzB,0CAA0C;IAC1C,MAAM;IAMN,OAAO,CAAC,YAAY,CAMlB;IAEF,OAAO,CAAC,WAAW,CAEjB;IAEF,OAAO,CAAC,YAAY,CAOlB;IAEF,OAAO,CAAC,OAAO,CAUb;IAIF,OAAO,CAAC,QAAQ,CAad;IAEF,OAAO,CAAC,UAAU,CAKhB;IAEF,OAAO,CAAC,aAAa,CAQnB;IAIF,OAAO,CAAC,QAAQ,CAkBd;IAEF,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,WAAW;IAQnB,qFAAqF;IACrF,OAAO,CAAC,iBAAiB;IAkCzB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,WAAW,CAEjB;IAEF,OAAO,CAAC,aAAa,CAInB;IAEF,OAAO,CAAC,YAAY,CAA8C;IAElE,OAAO,CAAC,iBAAiB,CAMvB;IAEF,OAAO,CAAC,mBAAmB;IAqB3B,iBAAiB;IAUjB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAMrC,oBAAoB;IAUpB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,mBAAmB;IA2B3B,MAAM;CAuGP"}
@@ -7,6 +7,7 @@ export declare class SfxFileItem extends LitElement {
7
7
  private _retry;
8
8
  private _preview;
9
9
  render(): typeof nothing | import('lit-html').TemplateResult<1>;
10
+ private _formatDuration;
10
11
  private _renderTypeIcon;
11
12
  }
12
13
  //# sourceMappingURL=file-item.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-item.d.ts","sourceRoot":"","sources":["../../src/components/file-item.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,OAAO,EAAE,MAAM,KAAK,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGvD,qBAAa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,MAAM,0BAmWX;IAE8B,IAAI,EAAG,UAAU,CAAC;IAElD,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,QAAQ;IAWhB,MAAM;IA6GN,OAAO,CAAC,eAAe;CAcxB"}
1
+ {"version":3,"file":"file-item.d.ts","sourceRoot":"","sources":["../../src/components/file-item.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,OAAO,EAAE,MAAM,KAAK,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGvD,qBAAa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,MAAM,0BAqXX;IAE8B,IAAI,EAAG,UAAU,CAAC;IAElD,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,QAAQ;IAWhB,MAAM;IAiHN,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,eAAe;CAcxB"}
@@ -1,8 +1,21 @@
1
1
  import { LitElement } from 'lit';
2
2
  import { UploadFile } from '../store/store.types';
3
+ import { SourceDef } from '../types/source.types';
3
4
  export declare class SfxFileList extends LitElement {
4
5
  static styles: import('lit').CSSResult;
5
6
  files: UploadFile[];
7
+ showDropTile: boolean;
8
+ sources: SourceDef[];
9
+ accept: string;
10
+ private _moreOpen;
11
+ private _outsideClickHandler;
12
+ private _onDropTileClick;
13
+ private _onFileInput;
14
+ private _onSourceClick;
15
+ private _toggleMore;
16
+ disconnectedCallback(): void;
17
+ private _onMoreSourceClick;
18
+ private _renderDropTile;
6
19
  render(): import('lit-html').TemplateResult<1>;
7
20
  }
8
21
  //# sourceMappingURL=file-list.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-list.d.ts","sourceRoot":"","sources":["../../src/components/file-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAE5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,qBAAa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,MAAM,0BAuCX;IAE8B,KAAK,EAAE,UAAU,EAAE,CAAM;IAEzD,MAAM;CASP"}
1
+ {"version":3,"file":"file-list.d.ts","sourceRoot":"","sources":["../../src/components/file-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAqC,MAAM,KAAK,CAAC;AAIpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,qBAAa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,MAAM,0BA6SX;IAE8B,KAAK,EAAE,UAAU,EAAE,CAAM;IAC5B,YAAY,UAAS;IAClB,OAAO,EAAE,SAAS,EAAE,CAAM;IAC9B,MAAM,SAAM;IAE/B,OAAO,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,oBAAoB,CAO1B;IAEF,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,WAAW;IAUnB,oBAAoB;IAMpB,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,eAAe;IA6DvB,MAAM;CAUP"}
@@ -5,6 +5,10 @@ export declare class SfxSuccessCard extends LitElement {
5
5
  totalSize: number;
6
6
  thumbnails: string[];
7
7
  primaryLabel: string;
8
+ failedFiles: {
9
+ name: string;
10
+ error: string;
11
+ }[];
8
12
  private _uploadMore;
9
13
  private _primaryAction;
10
14
  render(): import('lit-html').TemplateResult<1>;
@@ -1 +1 @@
1
- {"version":3,"file":"success-card.d.ts","sourceRoot":"","sources":["../../src/components/success-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAOrD,qBAAa,cAAe,SAAQ,UAAU;IAC5C,MAAM,CAAC,MAAM,4BA8HV;IAEyB,SAAS,SAAK;IACd,SAAS,SAAK;IACf,UAAU,EAAE,MAAM,EAAE,CAAM;IACzB,YAAY,SAAU;IAElD,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,cAAc;IAMtB,MAAM;CAoCP"}
1
+ {"version":3,"file":"success-card.d.ts","sourceRoot":"","sources":["../../src/components/success-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAOrD,qBAAa,cAAe,SAAQ,UAAU;IAC5C,MAAM,CAAC,MAAM,4BAsMV;IAEyB,SAAS,SAAK;IACd,SAAS,SAAK;IACf,UAAU,EAAE,MAAM,EAAE,CAAM;IACzB,YAAY,SAAU;IACvB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAM;IAE/E,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,cAAc;IAMtB,MAAM;CA+DP"}
package/dist/define.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";const e=require("./sfx-uploader-ziRTzw0k.cjs"),s=(f,i)=>{typeof customElements<"u"&&!customElements.get(f)&&customElements.define(f,i)};s("sfx-uploader",e.SfxUploader);s("sfx-drop-zone",e.SfxDropZone);s("sfx-import-divider",e.SfxImportDivider);s("sfx-source-pills",e.SfxSourcePills);s("sfx-file-list",e.SfxFileList);s("sfx-file-item",e.SfxFileItem);s("sfx-success-card",e.SfxSuccessCard);s("sfx-actions-bar",e.SfxActionsBar);s("sfx-url-dialog",e.SfxUrlDialog);s("sfx-camera-dialog",e.SfxCameraDialog);s("sfx-screen-cast-dialog",e.SfxScreenCastDialog);
1
+ "use strict";const e=require("./sfx-uploader-DXyLpoIJ.cjs"),s=(f,i)=>{typeof customElements<"u"&&!customElements.get(f)&&customElements.define(f,i)};s("sfx-uploader",e.SfxUploader);s("sfx-drop-zone",e.SfxDropZone);s("sfx-import-divider",e.SfxImportDivider);s("sfx-source-pills",e.SfxSourcePills);s("sfx-file-list",e.SfxFileList);s("sfx-file-item",e.SfxFileItem);s("sfx-success-card",e.SfxSuccessCard);s("sfx-actions-bar",e.SfxActionsBar);s("sfx-url-dialog",e.SfxUrlDialog);s("sfx-camera-dialog",e.SfxCameraDialog);s("sfx-screen-cast-dialog",e.SfxScreenCastDialog);
package/dist/define.js CHANGED
@@ -1,4 +1,4 @@
1
- import { g as f, a as i, d as o, e as r, c as l, b as x, f as t, S as c, n as d, o as S, p as m } from "./sfx-uploader-CU9IwNC7.js";
1
+ import { g as f, a as i, d as o, e as r, c as l, b as x, f as t, S as c, n as d, o as S, p as m } from "./sfx-uploader-DTfESjzm.js";
2
2
  const s = (e, a) => {
3
3
  typeof customElements < "u" && !customElements.get(e) && customElements.define(e, a);
4
4
  };
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./sfx-uploader-ziRTzw0k.cjs");exports.CORE_SOURCES=e.CORE_SOURCES;exports.PublicEvents=e.PublicEvents;exports.SfxActionsBar=e.SfxActionsBar;exports.SfxDropZone=e.SfxDropZone;exports.SfxFileItem=e.SfxFileItem;exports.SfxFileList=e.SfxFileList;exports.SfxImportDivider=e.SfxImportDivider;exports.SfxSourcePills=e.SfxSourcePills;exports.SfxSuccessCard=e.SfxSuccessCard;exports.SfxUploader=e.SfxUploader;exports.Store=e.Store;exports.UploadEngine=e.UploadEngine;exports.buildAuthHeaders=e.buildAuthHeaders;exports.createStore=e.createStore;exports.exchangeSassKey=e.exchangeSassKey;exports.getApiBase=e.getApiBase;exports.getProviderSources=e.getProviderSources;exports.resolveAuth=e.resolveAuth;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./sfx-uploader-DXyLpoIJ.cjs");exports.CORE_SOURCES=e.CORE_SOURCES;exports.PublicEvents=e.PublicEvents;exports.SfxActionsBar=e.SfxActionsBar;exports.SfxDropZone=e.SfxDropZone;exports.SfxFileItem=e.SfxFileItem;exports.SfxFileList=e.SfxFileList;exports.SfxImportDivider=e.SfxImportDivider;exports.SfxSourcePills=e.SfxSourcePills;exports.SfxSuccessCard=e.SfxSuccessCard;exports.SfxUploader=e.SfxUploader;exports.Store=e.Store;exports.UploadEngine=e.UploadEngine;exports.buildAuthHeaders=e.buildAuthHeaders;exports.createStore=e.createStore;exports.exchangeSassKey=e.exchangeSassKey;exports.getApiBase=e.getApiBase;exports.getProviderSources=e.getProviderSources;exports.resolveAuth=e.resolveAuth;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as e, P as r, S, a as o, b as i, c as t, d as f, e as l, f as x, g as c, h as d, U as u, i as n, j as p, k as g, l as h, m, r as v } from "./sfx-uploader-CU9IwNC7.js";
1
+ import { C as e, P as r, S, a as o, b as i, c as t, d as f, e as l, f as x, g as c, h as d, U as u, i as n, j as p, k as g, l as h, m, r as v } from "./sfx-uploader-DTfESjzm.js";
2
2
  export {
3
3
  e as CORE_SOURCES,
4
4
  r as PublicEvents,
@@ -1,7 +1,7 @@
1
1
  import { LitElement as y, css as w, html as s, nothing as h } from "lit";
2
2
  import { property as k, state as d } from "lit/decorators.js";
3
3
  import { unsafeHTML as b } from "lit/directives/unsafe-html.js";
4
- import { q as _, t as $, m as z, u as C, A as v, v as I } from "./sfx-uploader-CU9IwNC7.js";
4
+ import { q as _, t as $, m as z, u as C, A as v, v as I } from "./sfx-uploader-DTfESjzm.js";
5
5
  const x = "sfx-uploader-token:";
6
6
  function p(n) {
7
7
  try {
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("lit"),l=require("lit/decorators.js"),b=require("lit/directives/unsafe-html.js"),c=require("./sfx-uploader-ziRTzw0k.cjs"),x="sfx-uploader-token:";function p(o){try{return localStorage.getItem(`${x}${o}`)}catch{return null}}function v(o,e){try{localStorage.setItem(`${x}${o}`,e)}catch{}}function u(o){try{localStorage.removeItem(`${x}${o}`)}catch{}}function k(o,e){const r=i=>{if(i.origin!==new URL(o).origin)return;const t=typeof i.data=="string"?y(i.data):i.data;t!=null&&t.token&&e(t.token)};return window.addEventListener("message",r),()=>window.removeEventListener("message",r)}function y(o){try{return JSON.parse(o)}catch{return null}}var _=Object.defineProperty,d=(o,e,r,i)=>{for(var t=void 0,n=o.length-1,h;n>=0;n--)(h=o[n])&&(t=h(e,r,t)||t);return t&&_(e,r,t),t};const g=class g extends s.LitElement{constructor(){super(...arguments),this.provider="google-drive",this.companionUrl="",this._authenticated=!1,this._loading=!1,this._items=[],this._selectedIds=new Set,this._breadcrumbs=[],this._nextPagePath=null,this._error=null,this._loadingMore=!1,this._username=null,this._cleanupAuthListener=null,this._authWindow=null,this._handleConnect=()=>{var r;const e=c.getAuthUrl(this.companionUrl,this.provider);this._authWindow=window.open(e,"_blank","width=600,height=600"),(r=this._cleanupAuthListener)==null||r.call(this),this._cleanupAuthListener=k(this.companionUrl,i=>{var t,n;(t=this._authWindow)==null||t.close(),this._authWindow=null,(n=this._cleanupAuthListener)==null||n.call(this),this._cleanupAuthListener=null,v(this.provider,i),this._authenticated=!0,this._loadFolder("")})},this._lastClickedIndex=null,this._toggleSelectAll=()=>{const e=this._items.filter(i=>!i.isFolder);e.every(i=>this._selectedIds.has(i.id))?this._selectedIds=new Set:this._selectedIds=new Set(e.map(i=>i.id))},this._onAddSelected=()=>{const e=p(this.provider);if(!e)return;const i=this._items.filter(t=>!t.isFolder&&this._selectedIds.has(t.id)).map(t=>({companionUrl:this.companionUrl,provider:this.provider,token:e,requestPath:t.requestPath,fileId:t.id,name:t.name,mimeType:t.mimeType,size:t.size,thumbnail:t.thumbnail}));this.dispatchEvent(new CustomEvent("connector-files-selected",{detail:{files:i},bubbles:!0,composed:!0}))},this._onClose=()=>{this.dispatchEvent(new CustomEvent("connector-close",{bubbles:!0,composed:!0}))},this._handleLogout=async()=>{const e=p(this.provider);if(e){try{await c.logout(this.companionUrl,this.provider,e)}catch{}u(this.provider)}this._reset()}}connectedCallback(){super.connectedCallback(),this._checkAuth()}disconnectedCallback(){var e;super.disconnectedCallback(),(e=this._cleanupAuthListener)==null||e.call(this),this._cleanupAuthListener=null}updated(e){e.has("provider")&&(this._reset(),this._checkAuth())}_reset(){this._authenticated=!1,this._loading=!1,this._items=[],this._selectedIds=new Set,this._breadcrumbs=[],this._nextPagePath=null,this._error=null,this._username=null}_checkAuth(){p(this.provider)&&(this._authenticated=!0,this._loadFolder(""))}get _providerDef(){return c.getProviderSources([this.provider])[0]??null}get _providerLabel(){var e;return((e=this._providerDef)==null?void 0:e.label)??this.provider}async _loadFolder(e){const r=p(this.provider);if(!r){this._authenticated=!1;return}this.offsetHeight>0&&(this.style.minHeight=`${this.offsetHeight}px`),this._loading=!0,this._error=null,this._items=[],this._selectedIds=new Set,this._lastClickedIndex=null,this._nextPagePath=null;try{const i=await c.listFiles(this.companionUrl,this.provider,r,e);this._items=i.items,this._nextPagePath=i.nextPagePath,i.username&&(this._username=i.username)}catch(i){i instanceof c.AuthExpiredError?(u(this.provider),this._authenticated=!1):this._error=i instanceof Error?i.message:"Failed to load files"}finally{this._loading=!1}}_onFolderClick(e){this._breadcrumbs=[...this._breadcrumbs,{name:e.name,path:e.requestPath}],this._loadFolder(e.requestPath)}_onBreadcrumbClick(e){if(e<0)this._breadcrumbs=[],this._loadFolder("");else{const r=this._breadcrumbs[e];this._breadcrumbs=this._breadcrumbs.slice(0,e+1),this._loadFolder(r.path)}}async _onLoadMore(){const e=p(this.provider);if(!(!e||!this._nextPagePath)){this._loadingMore=!0;try{const r=await c.listNextPage(this.companionUrl,e,this._nextPagePath);this._items=[...this._items,...r.items],this._nextPagePath=r.nextPagePath}catch(r){r instanceof c.AuthExpiredError&&(u(this.provider),this._authenticated=!1)}finally{this._loadingMore=!1}}}_toggleSelect(e,r){const i=this._items.filter(n=>!n.isFolder),t=i.findIndex(n=>n.id===e.id);if(r!=null&&r.shiftKey&&this._lastClickedIndex!==null&&t!==-1){const n=Math.min(this._lastClickedIndex,t),h=Math.max(this._lastClickedIndex,t),m=new Set(this._selectedIds);for(let f=n;f<=h;f++)m.add(i[f].id);this._selectedIds=m}else{const n=new Set(this._selectedIds);n.has(e.id)?n.delete(e.id):n.add(e.id),this._selectedIds=n}t!==-1&&(this._lastClickedIndex=t)}render(){return s.html`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("lit"),l=require("lit/decorators.js"),b=require("lit/directives/unsafe-html.js"),c=require("./sfx-uploader-DXyLpoIJ.cjs"),x="sfx-uploader-token:";function p(o){try{return localStorage.getItem(`${x}${o}`)}catch{return null}}function v(o,e){try{localStorage.setItem(`${x}${o}`,e)}catch{}}function u(o){try{localStorage.removeItem(`${x}${o}`)}catch{}}function k(o,e){const r=i=>{if(i.origin!==new URL(o).origin)return;const t=typeof i.data=="string"?y(i.data):i.data;t!=null&&t.token&&e(t.token)};return window.addEventListener("message",r),()=>window.removeEventListener("message",r)}function y(o){try{return JSON.parse(o)}catch{return null}}var _=Object.defineProperty,d=(o,e,r,i)=>{for(var t=void 0,n=o.length-1,h;n>=0;n--)(h=o[n])&&(t=h(e,r,t)||t);return t&&_(e,r,t),t};const g=class g extends s.LitElement{constructor(){super(...arguments),this.provider="google-drive",this.companionUrl="",this._authenticated=!1,this._loading=!1,this._items=[],this._selectedIds=new Set,this._breadcrumbs=[],this._nextPagePath=null,this._error=null,this._loadingMore=!1,this._username=null,this._cleanupAuthListener=null,this._authWindow=null,this._handleConnect=()=>{var r;const e=c.getAuthUrl(this.companionUrl,this.provider);this._authWindow=window.open(e,"_blank","width=600,height=600"),(r=this._cleanupAuthListener)==null||r.call(this),this._cleanupAuthListener=k(this.companionUrl,i=>{var t,n;(t=this._authWindow)==null||t.close(),this._authWindow=null,(n=this._cleanupAuthListener)==null||n.call(this),this._cleanupAuthListener=null,v(this.provider,i),this._authenticated=!0,this._loadFolder("")})},this._lastClickedIndex=null,this._toggleSelectAll=()=>{const e=this._items.filter(i=>!i.isFolder);e.every(i=>this._selectedIds.has(i.id))?this._selectedIds=new Set:this._selectedIds=new Set(e.map(i=>i.id))},this._onAddSelected=()=>{const e=p(this.provider);if(!e)return;const i=this._items.filter(t=>!t.isFolder&&this._selectedIds.has(t.id)).map(t=>({companionUrl:this.companionUrl,provider:this.provider,token:e,requestPath:t.requestPath,fileId:t.id,name:t.name,mimeType:t.mimeType,size:t.size,thumbnail:t.thumbnail}));this.dispatchEvent(new CustomEvent("connector-files-selected",{detail:{files:i},bubbles:!0,composed:!0}))},this._onClose=()=>{this.dispatchEvent(new CustomEvent("connector-close",{bubbles:!0,composed:!0}))},this._handleLogout=async()=>{const e=p(this.provider);if(e){try{await c.logout(this.companionUrl,this.provider,e)}catch{}u(this.provider)}this._reset()}}connectedCallback(){super.connectedCallback(),this._checkAuth()}disconnectedCallback(){var e;super.disconnectedCallback(),(e=this._cleanupAuthListener)==null||e.call(this),this._cleanupAuthListener=null}updated(e){e.has("provider")&&(this._reset(),this._checkAuth())}_reset(){this._authenticated=!1,this._loading=!1,this._items=[],this._selectedIds=new Set,this._breadcrumbs=[],this._nextPagePath=null,this._error=null,this._username=null}_checkAuth(){p(this.provider)&&(this._authenticated=!0,this._loadFolder(""))}get _providerDef(){return c.getProviderSources([this.provider])[0]??null}get _providerLabel(){var e;return((e=this._providerDef)==null?void 0:e.label)??this.provider}async _loadFolder(e){const r=p(this.provider);if(!r){this._authenticated=!1;return}this.offsetHeight>0&&(this.style.minHeight=`${this.offsetHeight}px`),this._loading=!0,this._error=null,this._items=[],this._selectedIds=new Set,this._lastClickedIndex=null,this._nextPagePath=null;try{const i=await c.listFiles(this.companionUrl,this.provider,r,e);this._items=i.items,this._nextPagePath=i.nextPagePath,i.username&&(this._username=i.username)}catch(i){i instanceof c.AuthExpiredError?(u(this.provider),this._authenticated=!1):this._error=i instanceof Error?i.message:"Failed to load files"}finally{this._loading=!1}}_onFolderClick(e){this._breadcrumbs=[...this._breadcrumbs,{name:e.name,path:e.requestPath}],this._loadFolder(e.requestPath)}_onBreadcrumbClick(e){if(e<0)this._breadcrumbs=[],this._loadFolder("");else{const r=this._breadcrumbs[e];this._breadcrumbs=this._breadcrumbs.slice(0,e+1),this._loadFolder(r.path)}}async _onLoadMore(){const e=p(this.provider);if(!(!e||!this._nextPagePath)){this._loadingMore=!0;try{const r=await c.listNextPage(this.companionUrl,e,this._nextPagePath);this._items=[...this._items,...r.items],this._nextPagePath=r.nextPagePath}catch(r){r instanceof c.AuthExpiredError&&(u(this.provider),this._authenticated=!1)}finally{this._loadingMore=!1}}}_toggleSelect(e,r){const i=this._items.filter(n=>!n.isFolder),t=i.findIndex(n=>n.id===e.id);if(r!=null&&r.shiftKey&&this._lastClickedIndex!==null&&t!==-1){const n=Math.min(this._lastClickedIndex,t),h=Math.max(this._lastClickedIndex,t),m=new Set(this._selectedIds);for(let f=n;f<=h;f++)m.add(i[f].id);this._selectedIds=m}else{const n=new Set(this._selectedIds);n.has(e.id)?n.delete(e.id):n.add(e.id),this._selectedIds=n}t!==-1&&(this._lastClickedIndex=t)}render(){return s.html`
2
2
  ${this._renderHeader()}
3
3
  ${this._authenticated?this._loading?this._renderLoading():this._error?this._renderError():this._renderBrowser():this._renderAuthView()}
4
4
  `}_renderHeader(){const e=this._providerDef;return s.html`