@scaleflex/uploader 0.1.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 (96) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/LICENSE +50 -0
  3. package/README.md +123 -0
  4. package/dist/auth/auth.service.d.ts +25 -0
  5. package/dist/auth/auth.service.d.ts.map +1 -0
  6. package/dist/auth/auth.types.d.ts +24 -0
  7. package/dist/auth/auth.types.d.ts.map +1 -0
  8. package/dist/auth/index.d.ts +3 -0
  9. package/dist/auth/index.d.ts.map +1 -0
  10. package/dist/components/actions-bar.d.ts +17 -0
  11. package/dist/components/actions-bar.d.ts.map +1 -0
  12. package/dist/components/camera-dialog.d.ts +27 -0
  13. package/dist/components/camera-dialog.d.ts.map +1 -0
  14. package/dist/components/drop-zone.d.ts +28 -0
  15. package/dist/components/drop-zone.d.ts.map +1 -0
  16. package/dist/components/file-item.d.ts +12 -0
  17. package/dist/components/file-item.d.ts.map +1 -0
  18. package/dist/components/file-list.d.ts +8 -0
  19. package/dist/components/file-list.d.ts.map +1 -0
  20. package/dist/components/import-divider.d.ts +6 -0
  21. package/dist/components/import-divider.d.ts.map +1 -0
  22. package/dist/components/index.d.ts +9 -0
  23. package/dist/components/index.d.ts.map +1 -0
  24. package/dist/components/provider-browser.d.ts +48 -0
  25. package/dist/components/provider-browser.d.ts.map +1 -0
  26. package/dist/components/screen-cast-dialog.d.ts +29 -0
  27. package/dist/components/screen-cast-dialog.d.ts.map +1 -0
  28. package/dist/components/search-provider-browser.d.ts +36 -0
  29. package/dist/components/search-provider-browser.d.ts.map +1 -0
  30. package/dist/components/source-pills.d.ts +11 -0
  31. package/dist/components/source-pills.d.ts.map +1 -0
  32. package/dist/components/success-card.d.ts +10 -0
  33. package/dist/components/success-card.d.ts.map +1 -0
  34. package/dist/components/url-dialog.d.ts +25 -0
  35. package/dist/components/url-dialog.d.ts.map +1 -0
  36. package/dist/connectors/companion-client.d.ts +58 -0
  37. package/dist/connectors/companion-client.d.ts.map +1 -0
  38. package/dist/connectors/connector.types.d.ts +56 -0
  39. package/dist/connectors/connector.types.d.ts.map +1 -0
  40. package/dist/connectors/index.d.ts +5 -0
  41. package/dist/connectors/index.d.ts.map +1 -0
  42. package/dist/connectors/provider-registry.d.ts +8 -0
  43. package/dist/connectors/provider-registry.d.ts.map +1 -0
  44. package/dist/connectors/token-store.d.ts +10 -0
  45. package/dist/connectors/token-store.d.ts.map +1 -0
  46. package/dist/controllers/store.controller.d.ts +14 -0
  47. package/dist/controllers/store.controller.d.ts.map +1 -0
  48. package/dist/define.cjs +1 -0
  49. package/dist/define.d.ts +2 -0
  50. package/dist/define.d.ts.map +1 -0
  51. package/dist/define.js +15 -0
  52. package/dist/engine/companion-upload.d.ts +23 -0
  53. package/dist/engine/companion-upload.d.ts.map +1 -0
  54. package/dist/engine/index.d.ts +2 -0
  55. package/dist/engine/index.d.ts.map +1 -0
  56. package/dist/engine/upload-engine.d.ts +56 -0
  57. package/dist/engine/upload-engine.d.ts.map +1 -0
  58. package/dist/engine/xhr-upload.d.ts +25 -0
  59. package/dist/engine/xhr-upload.d.ts.map +1 -0
  60. package/dist/events/event-bus.d.ts +38 -0
  61. package/dist/events/event-bus.d.ts.map +1 -0
  62. package/dist/events/public-events.d.ts +23 -0
  63. package/dist/events/public-events.d.ts.map +1 -0
  64. package/dist/index.cjs +1 -0
  65. package/dist/index.d.ts +17 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +21 -0
  68. package/dist/provider-browser-C-S_MPrC.js +832 -0
  69. package/dist/provider-browser-CmCwv0ph.cjs +581 -0
  70. package/dist/react.cjs +1 -0
  71. package/dist/react.d.ts +33 -0
  72. package/dist/react.d.ts.map +1 -0
  73. package/dist/react.js +125 -0
  74. package/dist/search-provider-browser-DxmLznEB.cjs +390 -0
  75. package/dist/search-provider-browser-jCOer2Y9.js +537 -0
  76. package/dist/sfx-uploader-BVDK-9xi.cjs +2029 -0
  77. package/dist/sfx-uploader-C2lWIRnU.js +3789 -0
  78. package/dist/sfx-uploader.d.ts +131 -0
  79. package/dist/sfx-uploader.d.ts.map +1 -0
  80. package/dist/store/helpers.d.ts +16 -0
  81. package/dist/store/helpers.d.ts.map +1 -0
  82. package/dist/store/index.d.ts +7 -0
  83. package/dist/store/index.d.ts.map +1 -0
  84. package/dist/store/store.d.ts +14 -0
  85. package/dist/store/store.d.ts.map +1 -0
  86. package/dist/store/store.types.d.ts +77 -0
  87. package/dist/store/store.types.d.ts.map +1 -0
  88. package/dist/test-utils.d.ts +5 -0
  89. package/dist/test-utils.d.ts.map +1 -0
  90. package/dist/types/source.types.d.ts +12 -0
  91. package/dist/types/source.types.d.ts.map +1 -0
  92. package/dist/utils/file-utils.d.ts +14 -0
  93. package/dist/utils/file-utils.d.ts.map +1 -0
  94. package/dist/utils/validate.d.ts +6 -0
  95. package/dist/utils/validate.d.ts.map +1 -0
  96. package/package.json +72 -0
@@ -0,0 +1,832 @@
1
+ import { LitElement as _, css as k, html as n, nothing as h } from "lit";
2
+ import { property as v, state as d } from "lit/decorators.js";
3
+ import { q as y, t as w, m as $, u as z, A as g, v as I } from "./sfx-uploader-C2lWIRnU.js";
4
+ const x = "sfx-uploader-token:";
5
+ function p(o) {
6
+ try {
7
+ return localStorage.getItem(`${x}${o}`);
8
+ } catch {
9
+ return null;
10
+ }
11
+ }
12
+ function C(o, e) {
13
+ try {
14
+ localStorage.setItem(`${x}${o}`, e);
15
+ } catch {
16
+ }
17
+ }
18
+ function f(o) {
19
+ try {
20
+ localStorage.removeItem(`${x}${o}`);
21
+ } catch {
22
+ }
23
+ }
24
+ function P(o, e) {
25
+ const i = (r) => {
26
+ if (r.origin !== new URL(o).origin) return;
27
+ const t = typeof r.data == "string" ? L(r.data) : r.data;
28
+ t != null && t.token && e(t.token);
29
+ };
30
+ return window.addEventListener("message", i), () => window.removeEventListener("message", i);
31
+ }
32
+ function L(o) {
33
+ try {
34
+ return JSON.parse(o);
35
+ } catch {
36
+ return null;
37
+ }
38
+ }
39
+ var S = Object.defineProperty, l = (o, e, i, r) => {
40
+ for (var t = void 0, s = o.length - 1, c; s >= 0; s--)
41
+ (c = o[s]) && (t = c(e, i, t) || t);
42
+ return t && S(e, i, t), t;
43
+ };
44
+ const b = class b extends _ {
45
+ constructor() {
46
+ super(...arguments), this.provider = "google-drive", this.companionUrl = "", this._authenticated = !1, this._loading = !1, this._items = [], this._selectedIds = /* @__PURE__ */ new Set(), this._breadcrumbs = [], this._nextPagePath = null, this._error = null, this._loadingMore = !1, this._username = null, this._cleanupAuthListener = null, this._authWindow = null, this._handleConnect = () => {
47
+ var i;
48
+ const e = y(this.companionUrl, this.provider);
49
+ this._authWindow = window.open(e, "_blank", "width=600,height=600"), (i = this._cleanupAuthListener) == null || i.call(this), this._cleanupAuthListener = P(this.companionUrl, (r) => {
50
+ var t, s;
51
+ (t = this._authWindow) == null || t.close(), this._authWindow = null, (s = this._cleanupAuthListener) == null || s.call(this), this._cleanupAuthListener = null, C(this.provider, r), this._authenticated = !0, this._loadFolder("");
52
+ });
53
+ }, this._lastClickedIndex = null, this._toggleSelectAll = () => {
54
+ const e = this._items.filter((r) => !r.isFolder);
55
+ e.every((r) => this._selectedIds.has(r.id)) ? this._selectedIds = /* @__PURE__ */ new Set() : this._selectedIds = new Set(e.map((r) => r.id));
56
+ }, this._onAddSelected = () => {
57
+ const e = p(this.provider);
58
+ if (!e) return;
59
+ const r = this._items.filter(
60
+ (t) => !t.isFolder && this._selectedIds.has(t.id)
61
+ ).map((t) => ({
62
+ companionUrl: this.companionUrl,
63
+ provider: this.provider,
64
+ token: e,
65
+ requestPath: t.requestPath,
66
+ fileId: t.id,
67
+ name: t.name,
68
+ mimeType: t.mimeType,
69
+ size: t.size,
70
+ thumbnail: t.thumbnail
71
+ }));
72
+ this.dispatchEvent(
73
+ new CustomEvent("connector-files-selected", {
74
+ detail: { files: r },
75
+ bubbles: !0,
76
+ composed: !0
77
+ })
78
+ );
79
+ }, this._onClose = () => {
80
+ this.dispatchEvent(
81
+ new CustomEvent("connector-close", {
82
+ bubbles: !0,
83
+ composed: !0
84
+ })
85
+ );
86
+ }, this._handleLogout = async () => {
87
+ const e = p(this.provider);
88
+ if (e) {
89
+ try {
90
+ await w(this.companionUrl, this.provider, e);
91
+ } catch {
92
+ }
93
+ f(this.provider);
94
+ }
95
+ this._reset();
96
+ };
97
+ }
98
+ connectedCallback() {
99
+ super.connectedCallback(), this._checkAuth();
100
+ }
101
+ disconnectedCallback() {
102
+ var e;
103
+ super.disconnectedCallback(), (e = this._cleanupAuthListener) == null || e.call(this), this._cleanupAuthListener = null;
104
+ }
105
+ updated(e) {
106
+ e.has("provider") && (this._reset(), this._checkAuth());
107
+ }
108
+ _reset() {
109
+ this._authenticated = !1, this._loading = !1, this._items = [], this._selectedIds = /* @__PURE__ */ new Set(), this._breadcrumbs = [], this._nextPagePath = null, this._error = null, this._username = null;
110
+ }
111
+ _checkAuth() {
112
+ p(this.provider) && (this._authenticated = !0, this._loadFolder(""));
113
+ }
114
+ get _providerLabel() {
115
+ var i;
116
+ return ((i = $([this.provider])[0]) == null ? void 0 : i.label) ?? this.provider;
117
+ }
118
+ // --- Folder navigation ---
119
+ async _loadFolder(e) {
120
+ const i = p(this.provider);
121
+ if (!i) {
122
+ this._authenticated = !1;
123
+ return;
124
+ }
125
+ this.offsetHeight > 0 && (this.style.minHeight = `${this.offsetHeight}px`), this._loading = !0, this._error = null, this._items = [], this._selectedIds = /* @__PURE__ */ new Set(), this._lastClickedIndex = null, this._nextPagePath = null;
126
+ try {
127
+ const r = await z(this.companionUrl, this.provider, i, e);
128
+ this._items = r.items, this._nextPagePath = r.nextPagePath, r.username && (this._username = r.username);
129
+ } catch (r) {
130
+ r instanceof g ? (f(this.provider), this._authenticated = !1) : this._error = r instanceof Error ? r.message : "Failed to load files";
131
+ } finally {
132
+ this._loading = !1;
133
+ }
134
+ }
135
+ _onFolderClick(e) {
136
+ this._breadcrumbs = [...this._breadcrumbs, { name: e.name, path: e.requestPath }], this._loadFolder(e.requestPath);
137
+ }
138
+ _onBreadcrumbClick(e) {
139
+ if (e < 0)
140
+ this._breadcrumbs = [], this._loadFolder("");
141
+ else {
142
+ const i = this._breadcrumbs[e];
143
+ this._breadcrumbs = this._breadcrumbs.slice(0, e + 1), this._loadFolder(i.path);
144
+ }
145
+ }
146
+ // --- Load more ---
147
+ async _onLoadMore() {
148
+ const e = p(this.provider);
149
+ if (!(!e || !this._nextPagePath)) {
150
+ this._loadingMore = !0;
151
+ try {
152
+ const i = await I(this.companionUrl, e, this._nextPagePath);
153
+ this._items = [...this._items, ...i.items], this._nextPagePath = i.nextPagePath;
154
+ } catch (i) {
155
+ i instanceof g && (f(this.provider), this._authenticated = !1);
156
+ } finally {
157
+ this._loadingMore = !1;
158
+ }
159
+ }
160
+ }
161
+ _toggleSelect(e, i) {
162
+ const r = this._items.filter((s) => !s.isFolder), t = r.findIndex((s) => s.id === e.id);
163
+ if (i != null && i.shiftKey && this._lastClickedIndex !== null && t !== -1) {
164
+ const s = Math.min(this._lastClickedIndex, t), c = Math.max(this._lastClickedIndex, t), m = new Set(this._selectedIds);
165
+ for (let u = s; u <= c; u++)
166
+ m.add(r[u].id);
167
+ this._selectedIds = m;
168
+ } else {
169
+ const s = new Set(this._selectedIds);
170
+ s.has(e.id) ? s.delete(e.id) : s.add(e.id), this._selectedIds = s;
171
+ }
172
+ t !== -1 && (this._lastClickedIndex = t);
173
+ }
174
+ // --- Render ---
175
+ render() {
176
+ return n`
177
+ ${this._renderHeader()}
178
+ ${this._authenticated ? this._loading ? this._renderLoading() : this._error ? this._renderError() : this._renderBrowser() : this._renderAuthView()}
179
+ `;
180
+ }
181
+ _renderHeader() {
182
+ return n`
183
+ <div class="browser-header">
184
+ <button class="back-btn" @click=${this._onClose}>
185
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
186
+ <polyline points="15 18 9 12 15 6" />
187
+ </svg>
188
+ </button>
189
+ <span class="browser-title">${this._providerLabel}</span>
190
+ ${this._authenticated ? n`
191
+ ${this._username ? n`<span class="username">${this._username}</span>` : h}
192
+ <button class="logout-btn" @click=${this._handleLogout}>Log out</button>
193
+ ` : h}
194
+ </div>
195
+ `;
196
+ }
197
+ _renderAuthView() {
198
+ return n`
199
+ <div class="auth-view">
200
+ <div class="auth-icon">
201
+ <svg viewBox="0 0 24 24"><path d="M12 2a5 5 0 015 5v3h1a2 2 0 012 2v8a2 2 0 01-2 2H6a2 2 0 01-2-2v-8a2 2 0 012-2h1V7a5 5 0 015-5zm3 8H9v-3a3 3 0 016 0v3z" fill="currentColor"/></svg>
202
+ </div>
203
+ <div class="auth-text">
204
+ Connect to ${this._providerLabel} to browse and select files
205
+ </div>
206
+ <button class="connect-btn" @click=${this._handleConnect}>
207
+ Connect to ${this._providerLabel}
208
+ </button>
209
+ </div>
210
+ `;
211
+ }
212
+ _renderLoading() {
213
+ return n`
214
+ <div class="skeleton-list">
215
+ ${[1, 2, 3, 4, 5, 6].map(() => n`
216
+ <div class="skeleton-row">
217
+ <div class="skeleton-check"></div>
218
+ <div class="skeleton-thumb"></div>
219
+ <div class="skeleton-text">
220
+ <div class="skeleton-name"></div>
221
+ <div class="skeleton-size"></div>
222
+ </div>
223
+ </div>
224
+ `)}
225
+ </div>
226
+ `;
227
+ }
228
+ _renderError() {
229
+ return n`
230
+ <div class="error-view">
231
+ <div class="error-text">${this._error}</div>
232
+ <button class="retry-btn" @click=${() => {
233
+ const e = this._breadcrumbs[this._breadcrumbs.length - 1];
234
+ this._loadFolder((e == null ? void 0 : e.path) ?? "");
235
+ }}>
236
+ Retry
237
+ </button>
238
+ </div>
239
+ `;
240
+ }
241
+ _renderBrowser() {
242
+ const e = this._items.filter((t) => !t.isFolder), i = this._items.filter((t) => t.isFolder), r = this._selectedIds.size;
243
+ return n`
244
+ ${this._renderBreadcrumbs()}
245
+
246
+ <div class="file-list">
247
+ ${i.length === 0 && e.length === 0 ? n`<div class="empty-state"><div class="empty-text">This folder is empty</div></div>` : h}
248
+
249
+ ${i.map(
250
+ (t) => n`
251
+ <div class="file-item" @click=${() => this._onFolderClick(t)}>
252
+ <div class="file-thumb">
253
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
254
+ <path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z" />
255
+ </svg>
256
+ </div>
257
+ <div class="file-info">
258
+ <div class="file-name">${t.name}</div>
259
+ </div>
260
+ </div>
261
+ `
262
+ )}
263
+
264
+ ${e.map(
265
+ (t) => n`
266
+ <div
267
+ class="file-item ${this._selectedIds.has(t.id) ? "selected" : ""}"
268
+ @click=${(s) => this._toggleSelect(t, s)}
269
+ >
270
+ <input
271
+ type="checkbox"
272
+ .checked=${this._selectedIds.has(t.id)}
273
+ @click=${(s) => s.stopPropagation()}
274
+ @change=${() => this._toggleSelect(t)}
275
+ />
276
+ <div class="file-thumb">
277
+ ${t.thumbnail ? n`<img src=${t.thumbnail} alt="" loading="lazy" referrerpolicy="no-referrer"
278
+ @error=${(s) => {
279
+ const c = s.target;
280
+ c.style.display = "none", c.parentElement.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>';
281
+ }}
282
+ />` : n`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
283
+ <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
284
+ <polyline points="14 2 14 8 20 8" />
285
+ </svg>`}
286
+ </div>
287
+ <div class="file-info">
288
+ <div class="file-name">${t.name}</div>
289
+ ${t.size ? n`<div class="file-size">${A(t.size)}</div>` : h}
290
+ </div>
291
+ </div>
292
+ `
293
+ )}
294
+
295
+ ${this._nextPagePath ? n`
296
+ <button
297
+ class="load-more-btn"
298
+ ?disabled=${this._loadingMore}
299
+ @click=${this._onLoadMore}
300
+ >
301
+ ${this._loadingMore ? "Loading..." : "Load more"}
302
+ </button>
303
+ ` : h}
304
+ </div>
305
+
306
+ ${e.length > 0 ? n`
307
+ <div class="browser-footer">
308
+ <button class="select-all-btn" @click=${this._toggleSelectAll}>
309
+ ${e.every((t) => this._selectedIds.has(t.id)) ? "Deselect all" : "Select all"}
310
+ </button>
311
+ <span class="selected-count">
312
+ ${r > 0 ? `${r} file${r === 1 ? "" : "s"} selected` : "Select files to add"}
313
+ </span>
314
+ <button
315
+ class="add-btn"
316
+ ?disabled=${r === 0}
317
+ @click=${this._onAddSelected}
318
+ >
319
+ Add ${r > 0 ? r : ""} file${r === 1 ? "" : "s"}
320
+ </button>
321
+ </div>
322
+ ` : h}
323
+ `;
324
+ }
325
+ _renderBreadcrumbs() {
326
+ return this._breadcrumbs.length === 0 ? h : n`
327
+ <div class="breadcrumbs">
328
+ <button class="crumb" @click=${() => this._onBreadcrumbClick(-1)}>Root</button>
329
+ ${this._breadcrumbs.map(
330
+ (e, i) => n`
331
+ <span class="crumb-sep">/</span>
332
+ ${i < this._breadcrumbs.length - 1 ? n`<button class="crumb" @click=${() => this._onBreadcrumbClick(i)}>${e.name}</button>` : n`<span class="crumb-current">${e.name}</span>`}
333
+ `
334
+ )}
335
+ </div>
336
+ `;
337
+ }
338
+ };
339
+ b.styles = k`
340
+ :host {
341
+ display: flex;
342
+ flex-direction: column;
343
+ height: 100%;
344
+ min-height: 300px;
345
+ font-family: var(--sfx-up-font, 'Inter', system-ui, -apple-system, sans-serif);
346
+ color: var(--sfx-up-text, #1e293b);
347
+ }
348
+
349
+ /* --- Header --- */
350
+ .browser-header {
351
+ display: flex;
352
+ align-items: center;
353
+ gap: 10px;
354
+ padding: 14px 20px;
355
+ border-bottom: 1px solid var(--sfx-up-border-light, #f1f5f9);
356
+ flex-shrink: 0;
357
+ }
358
+
359
+ .back-btn {
360
+ width: 32px;
361
+ height: 32px;
362
+ border: none;
363
+ background: none;
364
+ border-radius: 8px;
365
+ cursor: pointer;
366
+ display: flex;
367
+ align-items: center;
368
+ justify-content: center;
369
+ color: var(--sfx-up-text-muted, #94a3b8);
370
+ transition: all 0.15s;
371
+ flex-shrink: 0;
372
+ }
373
+
374
+ .back-btn:hover {
375
+ background: #f1f5f9;
376
+ color: var(--sfx-up-text, #1e293b);
377
+ }
378
+
379
+ .back-btn svg {
380
+ width: 18px;
381
+ height: 18px;
382
+ }
383
+
384
+ .browser-title {
385
+ font-size: 14px;
386
+ font-weight: 600;
387
+ flex: 1;
388
+ }
389
+
390
+ .logout-btn {
391
+ border: none;
392
+ background: none;
393
+ font-family: inherit;
394
+ font-size: 12px;
395
+ color: var(--sfx-up-text-muted, #94a3b8);
396
+ cursor: pointer;
397
+ padding: 4px 8px;
398
+ border-radius: 6px;
399
+ transition: all 0.15s;
400
+ flex-shrink: 0;
401
+ }
402
+
403
+ .logout-btn:hover {
404
+ background: #fef2f2;
405
+ color: var(--sfx-up-error, #dc2626);
406
+ }
407
+
408
+ .username {
409
+ font-size: 12px;
410
+ color: var(--sfx-up-text-muted, #94a3b8);
411
+ flex-shrink: 0;
412
+ }
413
+
414
+ /* --- Auth view --- */
415
+ .auth-view {
416
+ flex: 1;
417
+ display: flex;
418
+ flex-direction: column;
419
+ align-items: center;
420
+ justify-content: center;
421
+ gap: 16px;
422
+ padding: 40px 24px;
423
+ text-align: center;
424
+ }
425
+
426
+ .auth-icon {
427
+ width: 56px;
428
+ height: 56px;
429
+ border-radius: 16px;
430
+ background: var(--sfx-up-primary-bg, #eff6ff);
431
+ color: var(--sfx-up-primary, #2563eb);
432
+ display: flex;
433
+ align-items: center;
434
+ justify-content: center;
435
+ }
436
+
437
+ .auth-icon svg {
438
+ width: 28px;
439
+ height: 28px;
440
+ fill: currentColor;
441
+ }
442
+
443
+ .auth-text {
444
+ font-size: 14px;
445
+ color: var(--sfx-up-text-secondary, #475569);
446
+ max-width: 280px;
447
+ }
448
+
449
+ .connect-btn {
450
+ height: 40px;
451
+ padding: 0 24px;
452
+ border: none;
453
+ border-radius: 10px;
454
+ background: linear-gradient(135deg, var(--sfx-up-primary, #2563eb), var(--sfx-up-primary-mid, #3b82f6));
455
+ color: #fff;
456
+ font-family: inherit;
457
+ font-size: 14px;
458
+ font-weight: 600;
459
+ cursor: pointer;
460
+ transition: all 0.18s;
461
+ box-shadow: 0 2px 10px rgba(37, 99, 235, 0.28);
462
+ }
463
+
464
+ .connect-btn:hover {
465
+ transform: translateY(-1px);
466
+ box-shadow: 0 4px 16px rgba(37, 99, 235, 0.38);
467
+ }
468
+
469
+ /* --- Breadcrumbs --- */
470
+ .breadcrumbs {
471
+ display: flex;
472
+ align-items: center;
473
+ gap: 4px;
474
+ padding: 10px 20px;
475
+ font-size: 12px;
476
+ color: var(--sfx-up-text-muted, #94a3b8);
477
+ border-bottom: 1px solid var(--sfx-up-border-light, #f1f5f9);
478
+ flex-shrink: 0;
479
+ flex-wrap: wrap;
480
+ }
481
+
482
+ .crumb {
483
+ cursor: pointer;
484
+ color: var(--sfx-up-primary, #2563eb);
485
+ border: none;
486
+ background: none;
487
+ font-family: inherit;
488
+ font-size: 12px;
489
+ padding: 2px 4px;
490
+ border-radius: 4px;
491
+ transition: background 0.15s;
492
+ }
493
+
494
+ .crumb:hover {
495
+ background: var(--sfx-up-primary-bg, #eff6ff);
496
+ }
497
+
498
+ .crumb-sep {
499
+ color: var(--sfx-up-text-muted, #94a3b8);
500
+ }
501
+
502
+ .crumb-current {
503
+ color: var(--sfx-up-text, #1e293b);
504
+ font-weight: 500;
505
+ }
506
+
507
+ /* --- File list --- */
508
+ .file-list {
509
+ flex: 1;
510
+ overflow-y: auto;
511
+ padding: 8px 12px;
512
+ min-height: 0;
513
+ }
514
+
515
+ .file-item {
516
+ display: flex;
517
+ align-items: center;
518
+ gap: 12px;
519
+ padding: 10px 12px;
520
+ border-radius: 10px;
521
+ cursor: pointer;
522
+ transition: background 0.15s;
523
+ user-select: none;
524
+ }
525
+
526
+ .file-item:hover {
527
+ background: #f8fafc;
528
+ }
529
+
530
+ .file-item.selected {
531
+ background: var(--sfx-up-primary-bg, #eff6ff);
532
+ }
533
+
534
+ .file-item input[type='checkbox'] {
535
+ width: 16px;
536
+ height: 16px;
537
+ accent-color: var(--sfx-up-primary, #2563eb);
538
+ flex-shrink: 0;
539
+ cursor: pointer;
540
+ }
541
+
542
+ .file-thumb {
543
+ width: 36px;
544
+ height: 36px;
545
+ border-radius: 8px;
546
+ background: #f1f5f9;
547
+ display: flex;
548
+ align-items: center;
549
+ justify-content: center;
550
+ flex-shrink: 0;
551
+ overflow: hidden;
552
+ }
553
+
554
+ .file-thumb img {
555
+ width: 100%;
556
+ height: 100%;
557
+ object-fit: cover;
558
+ }
559
+
560
+ .file-thumb svg {
561
+ width: 18px;
562
+ height: 18px;
563
+ color: var(--sfx-up-text-muted, #94a3b8);
564
+ }
565
+
566
+ .file-info {
567
+ flex: 1;
568
+ min-width: 0;
569
+ }
570
+
571
+ .file-name {
572
+ font-size: 13px;
573
+ font-weight: 500;
574
+ white-space: nowrap;
575
+ overflow: hidden;
576
+ text-overflow: ellipsis;
577
+ }
578
+
579
+ .file-size {
580
+ font-size: 11px;
581
+ color: var(--sfx-up-text-muted, #94a3b8);
582
+ }
583
+
584
+ /* --- Footer --- */
585
+ .browser-footer {
586
+ display: flex;
587
+ align-items: center;
588
+ justify-content: space-between;
589
+ padding: 12px 20px;
590
+ border-top: 1px solid var(--sfx-up-border-light, #f1f5f9);
591
+ flex-shrink: 0;
592
+ }
593
+
594
+ .selected-count {
595
+ font-size: 13px;
596
+ color: var(--sfx-up-text-secondary, #475569);
597
+ font-weight: 500;
598
+ }
599
+
600
+ .add-btn {
601
+ height: 36px;
602
+ padding: 0 20px;
603
+ border: none;
604
+ border-radius: 9px;
605
+ background: linear-gradient(135deg, var(--sfx-up-primary, #2563eb), var(--sfx-up-primary-mid, #3b82f6));
606
+ color: #fff;
607
+ font-family: inherit;
608
+ font-size: 13px;
609
+ font-weight: 600;
610
+ cursor: pointer;
611
+ transition: all 0.18s;
612
+ box-shadow: 0 2px 10px rgba(37, 99, 235, 0.28);
613
+ }
614
+
615
+ .add-btn:hover:not(:disabled) {
616
+ transform: translateY(-1px);
617
+ box-shadow: 0 4px 16px rgba(37, 99, 235, 0.38);
618
+ }
619
+
620
+ .add-btn:disabled {
621
+ opacity: 0.5;
622
+ cursor: not-allowed;
623
+ }
624
+
625
+ .select-all-btn {
626
+ border: none;
627
+ background: none;
628
+ font-family: inherit;
629
+ font-size: 12px;
630
+ font-weight: 600;
631
+ color: var(--sfx-up-primary, #2563eb);
632
+ cursor: pointer;
633
+ padding: 4px 8px;
634
+ border-radius: 6px;
635
+ transition: background 0.15s;
636
+ flex-shrink: 0;
637
+ }
638
+
639
+ .select-all-btn:hover {
640
+ background: var(--sfx-up-primary-bg, #eff6ff);
641
+ }
642
+
643
+ /* --- Loading / Error --- */
644
+ .loading, .error-view, .empty-state {
645
+ flex: 1;
646
+ display: flex;
647
+ flex-direction: column;
648
+ align-items: center;
649
+ justify-content: center;
650
+ gap: 12px;
651
+ padding: 40px 24px;
652
+ text-align: center;
653
+ }
654
+
655
+ .spinner {
656
+ width: 28px;
657
+ height: 28px;
658
+ border: 3px solid var(--sfx-up-border, #e8edf5);
659
+ border-top-color: var(--sfx-up-primary, #2563eb);
660
+ border-radius: 50%;
661
+ animation: spin 0.7s linear infinite;
662
+ }
663
+
664
+ .error-text {
665
+ font-size: 14px;
666
+ color: var(--sfx-up-error, #dc2626);
667
+ }
668
+
669
+ .retry-btn {
670
+ height: 34px;
671
+ padding: 0 16px;
672
+ border: 1.5px solid var(--sfx-up-border, #e8edf5);
673
+ background: none;
674
+ border-radius: 8px;
675
+ font-family: inherit;
676
+ font-size: 13px;
677
+ font-weight: 600;
678
+ cursor: pointer;
679
+ color: var(--sfx-up-text-secondary, #475569);
680
+ transition: all 0.15s;
681
+ }
682
+
683
+ .retry-btn:hover {
684
+ background: #f8faff;
685
+ border-color: #d1dff0;
686
+ }
687
+
688
+ .load-more-btn {
689
+ display: block;
690
+ margin: 8px auto;
691
+ padding: 8px 20px;
692
+ border: 1.5px solid var(--sfx-up-border, #e8edf5);
693
+ background: none;
694
+ border-radius: 8px;
695
+ font-family: inherit;
696
+ font-size: 13px;
697
+ font-weight: 500;
698
+ cursor: pointer;
699
+ color: var(--sfx-up-primary, #2563eb);
700
+ transition: all 0.15s;
701
+ }
702
+
703
+ .load-more-btn:hover {
704
+ background: var(--sfx-up-primary-bg, #eff6ff);
705
+ }
706
+
707
+ .empty-text {
708
+ font-size: 14px;
709
+ color: var(--sfx-up-text-muted, #94a3b8);
710
+ }
711
+
712
+ /* --- Skeleton loading --- */
713
+ .skeleton-list {
714
+ flex: 1;
715
+ padding: 8px 12px;
716
+ min-height: 0;
717
+ }
718
+
719
+ .skeleton-row {
720
+ display: flex;
721
+ align-items: center;
722
+ gap: 12px;
723
+ padding: 10px 12px;
724
+ }
725
+
726
+ .skeleton-check {
727
+ width: 16px;
728
+ height: 16px;
729
+ border-radius: 4px;
730
+ background: #f1f5f9;
731
+ }
732
+
733
+ .skeleton-thumb {
734
+ width: 36px;
735
+ height: 36px;
736
+ border-radius: 8px;
737
+ background: #f1f5f9;
738
+ flex-shrink: 0;
739
+ animation: shimmer 1.5s ease-in-out infinite;
740
+ }
741
+
742
+ .skeleton-text {
743
+ flex: 1;
744
+ display: flex;
745
+ flex-direction: column;
746
+ gap: 6px;
747
+ }
748
+
749
+ .skeleton-name {
750
+ height: 14px;
751
+ border-radius: 6px;
752
+ background: #f1f5f9;
753
+ animation: shimmer 1.5s ease-in-out infinite;
754
+ }
755
+
756
+ .skeleton-size {
757
+ height: 11px;
758
+ width: 60px;
759
+ border-radius: 6px;
760
+ background: #f1f5f9;
761
+ animation: shimmer 1.5s ease-in-out infinite;
762
+ }
763
+
764
+ .skeleton-row:nth-child(1) .skeleton-name { width: 65%; animation-delay: 0s; }
765
+ .skeleton-row:nth-child(1) .skeleton-thumb { animation-delay: 0s; }
766
+ .skeleton-row:nth-child(2) .skeleton-name { width: 45%; animation-delay: 0.1s; }
767
+ .skeleton-row:nth-child(2) .skeleton-thumb { animation-delay: 0.1s; }
768
+ .skeleton-row:nth-child(3) .skeleton-name { width: 75%; animation-delay: 0.2s; }
769
+ .skeleton-row:nth-child(3) .skeleton-thumb { animation-delay: 0.2s; }
770
+ .skeleton-row:nth-child(4) .skeleton-name { width: 55%; animation-delay: 0.3s; }
771
+ .skeleton-row:nth-child(4) .skeleton-thumb { animation-delay: 0.3s; }
772
+ .skeleton-row:nth-child(5) .skeleton-name { width: 60%; animation-delay: 0.4s; }
773
+ .skeleton-row:nth-child(5) .skeleton-thumb { animation-delay: 0.4s; }
774
+ .skeleton-row:nth-child(6) .skeleton-name { width: 50%; animation-delay: 0.5s; }
775
+ .skeleton-row:nth-child(6) .skeleton-thumb { animation-delay: 0.5s; }
776
+
777
+ @keyframes shimmer {
778
+ 0%, 100% { opacity: 1; }
779
+ 50% { opacity: 0.4; }
780
+ }
781
+
782
+ @keyframes spin {
783
+ to { transform: rotate(360deg); }
784
+ }
785
+
786
+ @media (prefers-reduced-motion: reduce) {
787
+ .spinner { animation: none; }
788
+ .skeleton-thumb, .skeleton-name, .skeleton-size { animation: none; }
789
+ }
790
+ `;
791
+ let a = b;
792
+ l([
793
+ v({ type: String })
794
+ ], a.prototype, "provider");
795
+ l([
796
+ v({ type: String })
797
+ ], a.prototype, "companionUrl");
798
+ l([
799
+ d()
800
+ ], a.prototype, "_authenticated");
801
+ l([
802
+ d()
803
+ ], a.prototype, "_loading");
804
+ l([
805
+ d()
806
+ ], a.prototype, "_items");
807
+ l([
808
+ d()
809
+ ], a.prototype, "_selectedIds");
810
+ l([
811
+ d()
812
+ ], a.prototype, "_breadcrumbs");
813
+ l([
814
+ d()
815
+ ], a.prototype, "_nextPagePath");
816
+ l([
817
+ d()
818
+ ], a.prototype, "_error");
819
+ l([
820
+ d()
821
+ ], a.prototype, "_loadingMore");
822
+ l([
823
+ d()
824
+ ], a.prototype, "_username");
825
+ function A(o) {
826
+ if (o === 0) return "0 B";
827
+ const e = ["B", "KB", "MB", "GB"], i = Math.min(Math.floor(Math.log(o) / Math.log(1024)), e.length - 1);
828
+ return `${(o / Math.pow(1024, i)).toFixed(i === 0 ? 0 : 1)} ${e[i]}`;
829
+ }
830
+ export {
831
+ a as SfxProviderBrowser
832
+ };