@ttt-productions/upload-ui 0.7.17 → 0.7.19
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/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/react/guard/guarded-link.d.ts +0 -27
- package/dist/react/guard/guarded-link.d.ts.map +1 -1
- package/dist/react/guard/guarded-link.js.map +1 -1
- package/dist/react/guard/local-upload-guard-provider.d.ts +0 -81
- package/dist/react/guard/local-upload-guard-provider.d.ts.map +1 -1
- package/dist/react/guard/local-upload-guard-provider.js +3 -60
- package/dist/react/guard/local-upload-guard-provider.js.map +1 -1
- package/dist/react/guard/use-guarded-navigation.d.ts +0 -7
- package/dist/react/guard/use-guarded-navigation.d.ts.map +1 -1
- package/dist/react/guard/use-guarded-navigation.js +0 -28
- package/dist/react/guard/use-guarded-navigation.js.map +1 -1
- package/dist/react/tray/in-flight-uploads-provider.d.ts +1 -126
- package/dist/react/tray/in-flight-uploads-provider.d.ts.map +1 -1
- package/dist/react/tray/in-flight-uploads-provider.js +10 -133
- package/dist/react/tray/in-flight-uploads-provider.js.map +1 -1
- package/dist/react/tray/use-clear-upload-activity.d.ts +1 -26
- package/dist/react/tray/use-clear-upload-activity.d.ts.map +1 -1
- package/dist/react/tray/use-clear-upload-activity.js +2 -20
- package/dist/react/tray/use-clear-upload-activity.js.map +1 -1
- package/dist/react/tray/use-mark-upload-activity-seen.d.ts +0 -4
- package/dist/react/tray/use-mark-upload-activity-seen.d.ts.map +1 -1
- package/dist/react/tray/use-mark-upload-activity-seen.js +5 -25
- package/dist/react/tray/use-mark-upload-activity-seen.js.map +1 -1
- package/dist/react/tray/use-upload-processing.d.ts +0 -10
- package/dist/react/tray/use-upload-processing.d.ts.map +1 -1
- package/dist/react/tray/use-upload-processing.js +0 -18
- package/dist/react/tray/use-upload-processing.js.map +1 -1
- package/dist/react/upload/deferred-upload-form-shell.d.ts +1 -19
- package/dist/react/upload/deferred-upload-form-shell.d.ts.map +1 -1
- package/dist/react/upload/deferred-upload-form-shell.js +0 -1
- package/dist/react/upload/deferred-upload-form-shell.js.map +1 -1
- package/dist/react/upload/use-guarded-upload.d.ts +0 -29
- package/dist/react/upload/use-guarded-upload.d.ts.map +1 -1
- package/dist/react/upload/use-guarded-upload.js +0 -13
- package/dist/react/upload/use-guarded-upload.js.map +1 -1
- package/dist/upload-display.d.ts +0 -14
- package/dist/upload-display.d.ts.map +1 -1
- package/dist/upload-display.js +2 -5
- package/dist/upload-display.js.map +1 -1
- package/package.json +13 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-guarded-upload.d.ts","sourceRoot":"","sources":["../../../src/react/upload/use-guarded-upload.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAGlE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,eAAe,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,
|
|
1
|
+
{"version":3,"file":"use-guarded-upload.d.ts","sourceRoot":"","sources":["../../../src/react/upload/use-guarded-upload.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAGlE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,eAAe,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,wBAAgB,gBAAgB,WAIf,iBAAiB,KAAG,OAAO,CAAC,IAAI,CAAC,CA+BjD"}
|
|
@@ -1,19 +1,6 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
import { uploadFileResumable } from '@ttt-productions/upload-core/browser';
|
|
3
3
|
import { useLocalUploadGuard } from '../guard/local-upload-guard-provider.js';
|
|
4
|
-
/**
|
|
5
|
-
* Wraps `uploadFileResumable` with the canonical local-upload guard + phase reporting.
|
|
6
|
-
*
|
|
7
|
-
* Every upload-capable mutation hook MUST use this helper instead of calling
|
|
8
|
-
* `uploadFileResumable` directly. The helper owns:
|
|
9
|
-
* - phase reporting: preparing → uploading (with percent) → finalizing
|
|
10
|
-
* - beforeunload guard registration during the upload window only
|
|
11
|
-
* - error safety: the guard is unregistered in a `finally` block
|
|
12
|
-
*
|
|
13
|
-
* The helper does NOT call `onProgress?.(null)` — callers do that from the
|
|
14
|
-
* mutation's `onSuccess` and `onError` callbacks (because the upload window
|
|
15
|
-
* ends when the upload completes, but the mutation may have more work after).
|
|
16
|
-
*/
|
|
17
4
|
export function useGuardedUpload() {
|
|
18
5
|
const { registerUpload, unregisterUpload } = useLocalUploadGuard();
|
|
19
6
|
return useCallback(async (args) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-guarded-upload.js","sourceRoot":"","sources":["../../../src/react/upload/use-guarded-upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAG3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"use-guarded-upload.js","sourceRoot":"","sources":["../../../src/react/upload/use-guarded-upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAG3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAa9E,MAAM,UAAU,gBAAgB;IAC9B,MAAM,EAAE,cAAc,EAAE,gBAAgB,EAAE,GAAG,mBAAmB,EAAE,CAAC;IAEnE,OAAO,WAAW,CAChB,KAAK,EAAE,IAAuB,EAAiB,EAAE;QAC/C,MAAM,EACJ,QAAQ,EACR,UAAU,EACV,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,uBAAuB,GACxB,GAAG,IAAI,CAAC;QAET,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,cAAc,CAAC,QAAQ,CAAC,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,mBAAmB,CAAC;gBACxB,OAAO;gBACP,IAAI;gBACJ,IAAI;gBACJ,QAAQ;gBACR,MAAM;gBACN,GAAG,CAAC,uBAAuB,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9E,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;aAC3E,CAAC,CAAC;QACL,CAAC;gBAAS,CAAC;YACT,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;QACD,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC,EACD,CAAC,cAAc,EAAE,gBAAgB,CAAC,CACnC,CAAC;AACJ,CAAC","sourcesContent":["import { useCallback } from 'react';\nimport { uploadFileResumable } from '@ttt-productions/upload-core/browser';\nimport type { FirebaseStorage } from 'firebase/storage';\nimport type { UploadState } from '@ttt-productions/media-schemas';\nimport { useLocalUploadGuard } from '../guard/local-upload-guard-provider.js';\n\nexport interface GuardedUploadArgs {\n storage: FirebaseStorage;\n path: string;\n file: File;\n metadata: { contentType: string };\n uploadId: string;\n onProgress?: (state: UploadState | null) => void;\n signal?: AbortSignal;\n allowNeutralContentType?: boolean;\n}\n\nexport function useGuardedUpload() {\n const { registerUpload, unregisterUpload } = useLocalUploadGuard();\n\n return useCallback(\n async (args: GuardedUploadArgs): Promise<void> => {\n const {\n uploadId,\n onProgress,\n storage,\n path,\n file,\n metadata,\n signal,\n allowNeutralContentType,\n } = args;\n\n onProgress?.({ phase: 'preparing', percent: null });\n registerUpload(uploadId);\n try {\n await uploadFileResumable({\n storage,\n path,\n file,\n metadata,\n signal,\n ...(allowNeutralContentType === true ? { allowNeutralContentType: true } : {}),\n onProgress: ({ percent }) => onProgress?.({ phase: 'uploading', percent }),\n });\n } finally {\n unregisterUpload(uploadId);\n }\n onProgress?.({ phase: 'finalizing', percent: null });\n },\n [registerUpload, unregisterUpload],\n );\n}\n"]}
|
package/dist/upload-display.d.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
/** A byte count as a short size: `850 B`, `24 KB`, `1.2 MB`, `3 GB`. `null` for no usable count. */
|
|
2
1
|
export declare function formatFileSize(bytes: number | undefined): string | null;
|
|
3
|
-
/** The app's words for an upload row's time and file kind. */
|
|
4
2
|
export interface UploadDisplayCopy {
|
|
5
|
-
/** Under a minute old. */
|
|
6
3
|
justNow: string;
|
|
7
4
|
minutesAgo: (minutes: number) => string;
|
|
8
5
|
hoursAgo: (hours: number) => string;
|
|
9
|
-
/** Accepted on the previous calendar day, given the local clock time. */
|
|
10
6
|
yesterdayAt: (time: string) => string;
|
|
11
|
-
/** Accepted before yesterday, given the short local date and clock time. */
|
|
12
7
|
dateAt: (date: string, time: string) => string;
|
|
13
|
-
/** The file's kind, by its simplified media type; `other` for anything else. */
|
|
14
8
|
fileType: {
|
|
15
9
|
image: string;
|
|
16
10
|
video: string;
|
|
@@ -20,19 +14,11 @@ export interface UploadDisplayCopy {
|
|
|
20
14
|
}
|
|
21
15
|
export interface UploadDisplayConfig {
|
|
22
16
|
copy: UploadDisplayCopy;
|
|
23
|
-
/** How long a row's time reads as relative before it reads as a clock time. */
|
|
24
17
|
relativeTimeCutoffMs: number;
|
|
25
|
-
/** Locale for the clock time and date; the runtime's own when omitted. */
|
|
26
18
|
locale?: Intl.LocalesArgument;
|
|
27
19
|
}
|
|
28
20
|
export interface UploadDisplayFormatters {
|
|
29
|
-
/**
|
|
30
|
-
* An upload's accept time. Within the cutoff of now: just now, minutes ago, or hours ago. Older:
|
|
31
|
-
* the clock time for today, yesterday and the clock time, or the short date and the clock time —
|
|
32
|
-
* by local calendar day.
|
|
33
|
-
*/
|
|
34
21
|
formatUploadTimestamp: (createdAtMs: number, nowMs: number) => string;
|
|
35
|
-
/** The file's kind from its stored content type; `null` when it has none. */
|
|
36
22
|
getFileTypeLabel: (contentType: string | undefined) => string | null;
|
|
37
23
|
}
|
|
38
24
|
export declare function createUploadDisplayFormatters(config: UploadDisplayConfig): UploadDisplayFormatters;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-display.d.ts","sourceRoot":"","sources":["../src/upload-display.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"upload-display.d.ts","sourceRoot":"","sources":["../src/upload-display.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAUvE;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/C,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,IAAI,CAAC,eAAe,CAAC;CAC/B;AAED,MAAM,WAAW,uBAAuB;IACtC,qBAAqB,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACtE,gBAAgB,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,IAAI,CAAC;CACtE;AAUD,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,mBAAmB,GAC1B,uBAAuB,CA2CzB"}
|
package/dist/upload-display.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
// What an upload row shows besides its title: the file's size, its kind, and when it was accepted.
|
|
2
|
-
// The mechanics are shared; every word, the relative-time cutoff and the locale are the app's.
|
|
3
1
|
import { getSimplifiedMediaType } from '@ttt-productions/media-schemas';
|
|
4
|
-
/** A byte count as a short size: `850 B`, `24 KB`, `1.2 MB`, `3 GB`. `null` for no usable count. */
|
|
5
2
|
export function formatFileSize(bytes) {
|
|
6
3
|
if (bytes === undefined || !Number.isFinite(bytes) || bytes < 0)
|
|
7
4
|
return null;
|
|
@@ -38,8 +35,8 @@ export function createUploadDisplayFormatters(config) {
|
|
|
38
35
|
const time = created.toLocaleTimeString(locale, { hour: 'numeric', minute: '2-digit' });
|
|
39
36
|
if (sameCalendarDay(created, now))
|
|
40
37
|
return time;
|
|
41
|
-
//
|
|
42
|
-
//
|
|
38
|
+
// Stepping the date, not subtracting 24 hours: a day that crosses a daylight-saving change is 23
|
|
39
|
+
// or 25 hours long.
|
|
43
40
|
const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
|
|
44
41
|
if (sameCalendarDay(created, yesterday))
|
|
45
42
|
return copy.yesterdayAt(time);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-display.js","sourceRoot":"","sources":["../src/upload-display.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"upload-display.js","sourceRoot":"","sources":["../src/upload-display.ts"],"names":[],"mappings":"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","sourcesContent":["import { getSimplifiedMediaType } from '@ttt-productions/media-schemas';\n\nexport function formatFileSize(bytes: number | undefined): string | null {\n if (bytes === undefined || !Number.isFinite(bytes) || bytes < 0) return null;\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n if (bytes < 1024 * 1024 * 1024) {\n const mb = bytes / (1024 * 1024);\n return `${mb < 10 ? mb.toFixed(1) : Math.round(mb)} MB`;\n }\n const gb = bytes / (1024 * 1024 * 1024);\n return `${gb < 10 ? gb.toFixed(1) : Math.round(gb)} GB`;\n}\n\nexport interface UploadDisplayCopy {\n justNow: string;\n minutesAgo: (minutes: number) => string;\n hoursAgo: (hours: number) => string;\n yesterdayAt: (time: string) => string;\n dateAt: (date: string, time: string) => string;\n fileType: { image: string; video: string; audio: string; other: string };\n}\n\nexport interface UploadDisplayConfig {\n copy: UploadDisplayCopy;\n relativeTimeCutoffMs: number;\n locale?: Intl.LocalesArgument;\n}\n\nexport interface UploadDisplayFormatters {\n formatUploadTimestamp: (createdAtMs: number, nowMs: number) => string;\n getFileTypeLabel: (contentType: string | undefined) => string | null;\n}\n\nfunction sameCalendarDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\nexport function createUploadDisplayFormatters(\n config: UploadDisplayConfig,\n): UploadDisplayFormatters {\n const { copy, relativeTimeCutoffMs, locale } = config;\n\n const formatUploadTimestamp = (createdAtMs: number, nowMs: number): string => {\n const diffMs = Math.max(0, nowMs - createdAtMs);\n if (diffMs < relativeTimeCutoffMs) {\n if (diffMs < 60_000) return copy.justNow;\n const minutes = Math.floor(diffMs / 60_000);\n if (minutes < 60) return copy.minutesAgo(minutes);\n return copy.hoursAgo(Math.floor(diffMs / 3_600_000));\n }\n\n const created = new Date(createdAtMs);\n const now = new Date(nowMs);\n const time = created.toLocaleTimeString(locale, { hour: 'numeric', minute: '2-digit' });\n if (sameCalendarDay(created, now)) return time;\n\n // Stepping the date, not subtracting 24 hours: a day that crosses a daylight-saving change is 23\n // or 25 hours long.\n const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);\n if (sameCalendarDay(created, yesterday)) return copy.yesterdayAt(time);\n\n return copy.dateAt(\n created.toLocaleDateString(locale, { month: 'short', day: 'numeric' }),\n time,\n );\n };\n\n const getFileTypeLabel = (contentType: string | undefined): string | null => {\n if (!contentType) return null;\n switch (getSimplifiedMediaType(contentType)) {\n case 'image':\n return copy.fileType.image;\n case 'video':\n return copy.fileType.video;\n case 'audio':\n return copy.fileType.audio;\n default:\n return copy.fileType.other;\n }\n };\n\n return { formatUploadTimestamp, getFileTypeLabel };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttt-productions/upload-ui",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.19",
|
|
4
4
|
"description": "Upload UI primitives: local upload guard provider, useGuardedUpload helper, DeferredUploadFormShell for forms that defer Firebase Storage upload until form submit.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,13 +40,14 @@
|
|
|
40
40
|
"prepublishOnly": "npm run clean && npm run build"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@ttt-productions/file-input": "^0.11.
|
|
44
|
-
"@ttt-productions/media-schemas": "^0.14.
|
|
45
|
-
"@ttt-productions/ui-core": "^0.11.
|
|
46
|
-
"@ttt-productions/upload-core": "^0.7.
|
|
43
|
+
"@ttt-productions/file-input": "^0.11.17",
|
|
44
|
+
"@ttt-productions/media-schemas": "^0.14.12",
|
|
45
|
+
"@ttt-productions/ui-core": "^0.11.35",
|
|
46
|
+
"@ttt-productions/upload-core": "^0.7.8"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@tanstack/react-query": ">=5.
|
|
49
|
+
"@tanstack/react-query": ">=5.90.0",
|
|
50
|
+
"@ttt-productions/query-core": "^0.14.24",
|
|
50
51
|
"firebase": ">=12.0.0",
|
|
51
52
|
"react": ">=19.0.0",
|
|
52
53
|
"react-dom": ">=19.0.0"
|
|
@@ -55,6 +56,9 @@
|
|
|
55
56
|
"@tanstack/react-query": {
|
|
56
57
|
"optional": true
|
|
57
58
|
},
|
|
59
|
+
"@ttt-productions/query-core": {
|
|
60
|
+
"optional": true
|
|
61
|
+
},
|
|
58
62
|
"firebase": {
|
|
59
63
|
"optional": true
|
|
60
64
|
},
|
|
@@ -65,6 +69,9 @@
|
|
|
65
69
|
"optional": true
|
|
66
70
|
}
|
|
67
71
|
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@ttt-productions/query-core": "^0.14.24"
|
|
74
|
+
},
|
|
68
75
|
"author": "DJ (TTT Productions)",
|
|
69
76
|
"license": "MIT"
|
|
70
77
|
}
|