@openrails/contentkit-ui 0.79.0 → 0.81.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.
- package/README.md +82 -54
- package/dist/client/beacons.d.ts +53 -0
- package/dist/client/beacons.js +72 -0
- package/dist/client/beacons.js.map +1 -0
- package/dist/client/catalog.d.ts +2 -2
- package/dist/client/catalog.js +1 -1
- package/dist/client/catalog.js.map +1 -1
- package/dist/client/client.d.ts +24 -11
- package/dist/client/client.js +37 -29
- package/dist/client/client.js.map +1 -1
- package/dist/client/content/comments.d.ts +12 -8
- package/dist/client/content/comments.js +33 -20
- package/dist/client/content/comments.js.map +1 -1
- package/dist/client/content/favorites.d.ts +24 -9
- package/dist/client/content/favorites.js +21 -22
- package/dist/client/content/favorites.js.map +1 -1
- package/dist/client/content/moderation.d.ts +1 -1
- package/dist/client/content/moderation.js.map +1 -1
- package/dist/client/content/reactions.d.ts +11 -6
- package/dist/client/content/reactions.js +23 -18
- package/dist/client/content/reactions.js.map +1 -1
- package/dist/client/content/types.d.ts +40 -21
- package/dist/client/content/types.js +5 -2
- package/dist/client/content/types.js.map +1 -1
- package/dist/client/contents.d.ts +55 -0
- package/dist/client/contents.js +144 -0
- package/dist/client/contents.js.map +1 -0
- package/dist/client/discovery.d.ts +126 -0
- package/dist/client/discovery.js +125 -0
- package/dist/client/discovery.js.map +1 -0
- package/dist/client/generated/error-codes.d.ts +1 -1
- package/dist/client/generated/error-codes.js +12 -0
- package/dist/client/generated/error-codes.js.map +1 -1
- package/dist/client/generated/routes.d.ts +1244 -370
- package/dist/client/generated/routes.js +1870 -554
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +960 -134
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/group-fields.d.ts +25 -0
- package/dist/client/group-fields.js +63 -0
- package/dist/client/group-fields.js.map +1 -0
- package/dist/client/groups.d.ts +58 -0
- package/dist/client/groups.js +119 -0
- package/dist/client/groups.js.map +1 -0
- package/dist/client/http.d.ts +24 -12
- package/dist/client/http.js +20 -24
- package/dist/client/http.js.map +1 -1
- package/dist/client/index.d.ts +11 -6
- package/dist/client/media/api.d.ts +1 -1
- package/dist/client/media/api.js +4 -2
- package/dist/client/media/api.js.map +1 -1
- package/dist/client/media/client.d.ts +8 -9
- package/dist/client/media/client.js +58 -71
- package/dist/client/media/client.js.map +1 -1
- package/dist/client/media/ref.d.ts +30 -0
- package/dist/client/media/ref.js +10 -3
- package/dist/client/media/ref.js.map +1 -1
- package/dist/client/offers.d.ts +41 -0
- package/dist/client/offers.js +66 -0
- package/dist/client/offers.js.map +1 -0
- package/dist/client/route.d.ts +2 -0
- package/dist/client/route.js +2 -1
- package/dist/client/route.js.map +1 -1
- package/dist/client/versions.d.ts +20 -0
- package/dist/client/versions.js +53 -0
- package/dist/client/versions.js.map +1 -0
- package/dist/client.js +35 -30
- package/dist/components/admin/content-manager.d.ts +80 -0
- package/dist/components/admin/content-manager.js +591 -0
- package/dist/components/admin/content-manager.js.map +1 -0
- package/dist/components/admin/group-manager.d.ts +24 -0
- package/dist/components/admin/group-manager.js +244 -0
- package/dist/components/admin/group-manager.js.map +1 -0
- package/dist/components/admin/media-item-panel.js +1 -1
- package/dist/components/admin/media-item-panel.js.map +1 -1
- package/dist/components/content/card.d.ts +44 -0
- package/dist/components/content/card.js +285 -0
- package/dist/components/content/card.js.map +1 -0
- package/dist/components/content/editors.d.ts +40 -0
- package/dist/components/content/editors.js +764 -0
- package/dist/components/content/editors.js.map +1 -0
- package/dist/components/content/filters.d.ts +28 -0
- package/dist/components/content/filters.js +134 -0
- package/dist/components/content/filters.js.map +1 -0
- package/dist/components/content/grid.d.ts +62 -0
- package/dist/components/content/grid.js +233 -0
- package/dist/components/content/grid.js.map +1 -0
- package/dist/components/content/index.d.ts +8 -0
- package/dist/components/content/listing.d.ts +20 -0
- package/dist/components/content/listing.js +150 -0
- package/dist/components/content/listing.js.map +1 -0
- package/dist/components/content/offer-fields.d.ts +8 -0
- package/dist/components/content/offer-fields.js +127 -0
- package/dist/components/content/offer-fields.js.map +1 -0
- package/dist/components/content/paywall.d.ts +53 -0
- package/dist/components/content/paywall.js +221 -0
- package/dist/components/content/paywall.js.map +1 -0
- package/dist/components/content/search.d.ts +27 -0
- package/dist/components/content/search.js +164 -0
- package/dist/components/content/search.js.map +1 -0
- package/dist/components/groups/banner.d.ts +51 -0
- package/dist/components/groups/banner.js +194 -0
- package/dist/components/groups/banner.js.map +1 -0
- package/dist/components/groups/directory.d.ts +37 -0
- package/dist/components/groups/directory.js +117 -0
- package/dist/components/groups/directory.js.map +1 -0
- package/dist/components/groups/editor.d.ts +44 -0
- package/dist/components/groups/editor.js +860 -0
- package/dist/components/groups/editor.js.map +1 -0
- package/dist/components/groups/fields.d.ts +13 -0
- package/dist/components/groups/fields.js +68 -0
- package/dist/components/groups/fields.js.map +1 -0
- package/dist/components/groups/header.d.ts +25 -0
- package/dist/components/groups/header.js +131 -0
- package/dist/components/groups/header.js.map +1 -0
- package/dist/components/groups/index.d.ts +6 -0
- package/dist/components/groups/memberships.d.ts +55 -0
- package/dist/components/groups/memberships.js +527 -0
- package/dist/components/groups/memberships.js.map +1 -0
- package/dist/components/groups/parts.d.ts +49 -0
- package/dist/components/groups/parts.js +172 -0
- package/dist/components/groups/parts.js.map +1 -0
- package/dist/components/media-folder-editor.js +153 -152
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/social/comments.d.ts +7 -5
- package/dist/components/social/comments.js +6 -2
- package/dist/components/social/comments.js.map +1 -1
- package/dist/components/social/engagement.d.ts +4 -3
- package/dist/components/social/engagement.js.map +1 -1
- package/dist/components/social/moderation.d.ts +1 -1
- package/dist/components/social/moderation.js +3 -3
- package/dist/components/social/moderation.js.map +1 -1
- package/dist/editor/rich-text-editor.d.ts +4 -4
- package/dist/editor/rich-text-editor.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +23 -9
- package/dist/locales/admin/de.js +5 -66
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +5 -66
- package/dist/locales/admin/en.js +19 -80
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +5 -66
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +5 -66
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +5 -66
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +5 -66
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/content/de.d.ts +2 -0
- package/dist/locales/content/de.js +98 -0
- package/dist/locales/content/de.js.map +1 -0
- package/dist/locales/content/en.d.ts +93 -0
- package/dist/locales/content/en.js +98 -0
- package/dist/locales/content/en.js.map +1 -0
- package/dist/locales/content/es.d.ts +2 -0
- package/dist/locales/content/es.js +98 -0
- package/dist/locales/content/es.js.map +1 -0
- package/dist/locales/content/ja.d.ts +2 -0
- package/dist/locales/content/ja.js +98 -0
- package/dist/locales/content/ja.js.map +1 -0
- package/dist/locales/content/ko.d.ts +2 -0
- package/dist/locales/content/ko.js +98 -0
- package/dist/locales/content/ko.js.map +1 -0
- package/dist/locales/content/zh.d.ts +2 -0
- package/dist/locales/content/zh.js +98 -0
- package/dist/locales/content/zh.js.map +1 -0
- package/dist/locales/de.js +11 -2
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/discovery/de.d.ts +2 -0
- package/dist/locales/discovery/de.js +68 -0
- package/dist/locales/discovery/de.js.map +1 -0
- package/dist/locales/discovery/en.d.ts +63 -0
- package/dist/locales/discovery/en.js +68 -0
- package/dist/locales/discovery/en.js.map +1 -0
- package/dist/locales/discovery/es.d.ts +2 -0
- package/dist/locales/discovery/es.js +68 -0
- package/dist/locales/discovery/es.js.map +1 -0
- package/dist/locales/discovery/ja.d.ts +2 -0
- package/dist/locales/discovery/ja.js +68 -0
- package/dist/locales/discovery/ja.js.map +1 -0
- package/dist/locales/discovery/ko.d.ts +2 -0
- package/dist/locales/discovery/ko.js +68 -0
- package/dist/locales/discovery/ko.js.map +1 -0
- package/dist/locales/discovery/zh.d.ts +2 -0
- package/dist/locales/discovery/zh.js +68 -0
- package/dist/locales/discovery/zh.js.map +1 -0
- package/dist/locales/en.d.ts +288 -67
- package/dist/locales/en.js +11 -2
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +11 -2
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/groups/de.d.ts +2 -0
- package/dist/locales/groups/de.js +133 -0
- package/dist/locales/groups/de.js.map +1 -0
- package/dist/locales/groups/en.d.ts +128 -0
- package/dist/locales/groups/en.js +133 -0
- package/dist/locales/groups/en.js.map +1 -0
- package/dist/locales/groups/es.d.ts +2 -0
- package/dist/locales/groups/es.js +133 -0
- package/dist/locales/groups/es.js.map +1 -0
- package/dist/locales/groups/ja.d.ts +2 -0
- package/dist/locales/groups/ja.js +133 -0
- package/dist/locales/groups/ja.js.map +1 -0
- package/dist/locales/groups/ko.d.ts +2 -0
- package/dist/locales/groups/ko.js +133 -0
- package/dist/locales/groups/ko.js.map +1 -0
- package/dist/locales/groups/zh.d.ts +2 -0
- package/dist/locales/groups/zh.js +133 -0
- package/dist/locales/groups/zh.js.map +1 -0
- package/dist/locales/ja.js +11 -2
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +11 -2
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/social/de.js +2 -1
- package/dist/locales/social/de.js.map +1 -1
- package/dist/locales/social/en.d.ts +2 -1
- package/dist/locales/social/en.js +2 -1
- package/dist/locales/social/en.js.map +1 -1
- package/dist/locales/social/es.js +2 -1
- package/dist/locales/social/es.js.map +1 -1
- package/dist/locales/social/ja.js +2 -1
- package/dist/locales/social/ja.js.map +1 -1
- package/dist/locales/social/ko.js +2 -1
- package/dist/locales/social/ko.js.map +1 -1
- package/dist/locales/social/zh.js +2 -1
- package/dist/locales/social/zh.js.map +1 -1
- package/dist/locales/zh.js +11 -2
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/admin.d.ts +1 -1
- package/dist/react/admin.js +8 -6
- package/dist/react/admin.js.map +1 -1
- package/dist/react/comments.d.ts +9 -7
- package/dist/react/comments.js +42 -27
- package/dist/react/comments.js.map +1 -1
- package/dist/react/contents.d.ts +57 -0
- package/dist/react/contents.js +214 -0
- package/dist/react/contents.js.map +1 -0
- package/dist/react/context.d.ts +1 -1
- package/dist/react/context.js.map +1 -1
- package/dist/react/crop.js +45 -44
- package/dist/react/crop.js.map +1 -1
- package/dist/react/detail.d.ts +30 -0
- package/dist/react/detail.js +42 -0
- package/dist/react/detail.js.map +1 -0
- package/dist/react/discovery.d.ts +138 -0
- package/dist/react/discovery.js +299 -0
- package/dist/react/discovery.js.map +1 -0
- package/dist/react/engagement.d.ts +5 -5
- package/dist/react/engagement.js +55 -41
- package/dist/react/engagement.js.map +1 -1
- package/dist/react/folder.js +54 -53
- package/dist/react/folder.js.map +1 -1
- package/dist/react/groups.d.ts +115 -0
- package/dist/react/groups.js +229 -0
- package/dist/react/groups.js.map +1 -0
- package/dist/react/index.d.ts +5 -1
- package/dist/react/public.d.ts +6 -5
- package/dist/react/public.js +19 -22
- package/dist/react/public.js.map +1 -1
- package/dist/react/read.js +105 -106
- package/dist/react/read.js.map +1 -1
- package/dist/react/resources.d.ts +2 -2
- package/dist/react/resources.js +69 -40
- package/dist/react/resources.js.map +1 -1
- package/dist/react/store.js +41 -39
- package/dist/react/store.js.map +1 -1
- package/dist/react/upload.js +54 -53
- package/dist/react/upload.js.map +1 -1
- package/dist/react/use-resource.d.ts +2 -1
- package/dist/react/use-resource.js +1 -0
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react/versions.d.ts +57 -0
- package/dist/react/versions.js +94 -0
- package/dist/react/versions.js.map +1 -0
- package/dist/react/video.js +87 -86
- package/dist/react/video.js.map +1 -1
- package/dist/react.js +9 -5
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/client/content/posts.d.ts +0 -52
- package/dist/client/content/posts.js +0 -84
- package/dist/client/content/posts.js.map +0 -1
- package/dist/client/taxonomy.d.ts +0 -34
- package/dist/client/taxonomy.js +0 -84
- package/dist/client/taxonomy.js.map +0 -1
- package/dist/components/admin/post-manager.d.ts +0 -45
- package/dist/components/admin/post-manager.js +0 -602
- package/dist/components/admin/post-manager.js.map +0 -1
- package/dist/components/admin/taxonomy-manager.d.ts +0 -54
- package/dist/components/admin/taxonomy-manager.js +0 -976
- package/dist/components/admin/taxonomy-manager.js.map +0 -1
- package/dist/react/posts.d.ts +0 -61
- package/dist/react/posts.js +0 -183
- package/dist/react/posts.js.map +0 -1
package/dist/react/upload.js
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
1
1
|
import { toContentKitError as e } from "../client/errors.js";
|
|
2
2
|
import { ratio as t } from "../client/aspect.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { itemKey as n } from "../client/media/ref.js";
|
|
4
|
+
import { centeredCrop as r, constrainCrop as i, editOf as a, rotation as o, sameEdit as s, toOriginal as c } from "../client/crop.js";
|
|
5
|
+
import { encodeRemaining as l } from "../client/media/encode.js";
|
|
6
|
+
import { ItemUploadQueue as u } from "../client/media/queue.js";
|
|
7
|
+
import { useContentKitClient as d } from "./context.js";
|
|
8
|
+
import { useCallback as f, useEffect as p, useMemo as m, useRef as h, useState as g, useSyncExternalStore as _ } from "react";
|
|
8
9
|
//#region src/react/upload.ts
|
|
9
|
-
function
|
|
10
|
-
let
|
|
11
|
-
key:
|
|
12
|
-
queue: new
|
|
10
|
+
function v({ client: e, ...t }) {
|
|
11
|
+
let r = d(e), i = n(t.ref), a = () => ({
|
|
12
|
+
key: i,
|
|
13
|
+
queue: new u(r.media, {
|
|
13
14
|
...t,
|
|
14
15
|
autoStart: !1
|
|
15
16
|
})
|
|
16
|
-
}), [
|
|
17
|
-
|
|
18
|
-
let { queue:
|
|
19
|
-
return
|
|
20
|
-
...
|
|
21
|
-
queue:
|
|
22
|
-
add:
|
|
23
|
-
move:
|
|
24
|
-
update:
|
|
25
|
-
remove:
|
|
26
|
-
retry:
|
|
27
|
-
start:
|
|
28
|
-
pause:
|
|
29
|
-
commit:
|
|
17
|
+
}), [o, s] = g(a);
|
|
18
|
+
o.key !== i && s(a());
|
|
19
|
+
let { queue: c } = o, l = t.autoStart ?? !0;
|
|
20
|
+
return p(() => (l && c.start(), () => c.pause()), [c, l]), {
|
|
21
|
+
..._(c.subscribe, c.getSnapshot, c.getSnapshot),
|
|
22
|
+
queue: c,
|
|
23
|
+
add: c.add.bind(c),
|
|
24
|
+
move: c.move.bind(c),
|
|
25
|
+
update: c.update.bind(c),
|
|
26
|
+
remove: c.remove.bind(c),
|
|
27
|
+
retry: c.retry.bind(c),
|
|
28
|
+
start: c.start.bind(c),
|
|
29
|
+
pause: c.pause.bind(c),
|
|
30
|
+
commit: c.commit.bind(c)
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
|
-
function
|
|
33
|
-
let { media: n } =
|
|
34
|
-
|
|
35
|
-
let o =
|
|
33
|
+
function y({ client: t } = {}) {
|
|
34
|
+
let { media: n } = d(t), [r, i] = g({ status: "idle" }), a = h(null);
|
|
35
|
+
p(() => () => a.current?.abort(), []);
|
|
36
|
+
let o = f(async (t, { put: r, ...o }) => {
|
|
36
37
|
a.current?.abort();
|
|
37
38
|
let s = a.current = new AbortController();
|
|
38
39
|
i({ status: "uploading" });
|
|
@@ -69,55 +70,55 @@ function v({ client: t } = {}) {
|
|
|
69
70
|
error: n
|
|
70
71
|
}), n;
|
|
71
72
|
}
|
|
72
|
-
}, [n]), s =
|
|
73
|
+
}, [n]), s = f(() => a.current?.abort(), []);
|
|
73
74
|
return {
|
|
74
75
|
...r,
|
|
75
76
|
upload: o,
|
|
76
77
|
cancel: s
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
|
-
function
|
|
80
|
-
let u = t(
|
|
81
|
-
width:
|
|
82
|
-
height:
|
|
83
|
-
}), [
|
|
84
|
-
let e =
|
|
85
|
-
return [t ?
|
|
86
|
-
}), [b, x] = v, S =
|
|
80
|
+
function b({ source: e, aspect: n, initial: l }) {
|
|
81
|
+
let u = t(n), { width: d, height: p } = e, _ = m(() => ({
|
|
82
|
+
width: d,
|
|
83
|
+
height: p
|
|
84
|
+
}), [d, p]), [v, y] = g(() => {
|
|
85
|
+
let e = o(l?.rotate ?? 0), t = l?.crop;
|
|
86
|
+
return [t ? i(t, _, u, e) : r(_, u, e), e];
|
|
87
|
+
}), [b, x] = v, S = f((e) => y((t) => {
|
|
87
88
|
let n = typeof e == "function" ? e(t) : e;
|
|
88
|
-
return
|
|
89
|
+
return s({
|
|
89
90
|
crop: n[0],
|
|
90
91
|
rotate: n[1]
|
|
91
92
|
}, {
|
|
92
93
|
crop: t[0],
|
|
93
94
|
rotate: t[1]
|
|
94
95
|
}) ? t : n;
|
|
95
|
-
}), []), C =
|
|
96
|
+
}), []), C = f((e) => S(([, t]) => [i(e, _, u, t), t]), [
|
|
96
97
|
S,
|
|
97
98
|
_,
|
|
98
99
|
u
|
|
99
|
-
]), w =
|
|
100
|
+
]), w = f((e, t) => S(([, n]) => [i(c(e, t, _, n), _, u, n), n]), [
|
|
100
101
|
S,
|
|
101
102
|
_,
|
|
102
103
|
u
|
|
103
|
-
]), T =
|
|
104
|
-
let
|
|
105
|
-
return [
|
|
104
|
+
]), T = f((e) => S(([t, n]) => {
|
|
105
|
+
let r = o(n + e);
|
|
106
|
+
return [i(t, _, u, r), r];
|
|
106
107
|
}), [
|
|
107
108
|
S,
|
|
108
109
|
_,
|
|
109
110
|
u
|
|
110
|
-
]), E =
|
|
111
|
+
]), E = f(() => S([r(_, u), 0]), [
|
|
111
112
|
S,
|
|
112
113
|
_,
|
|
113
114
|
u
|
|
114
|
-
]), D =
|
|
115
|
+
]), D = h(null);
|
|
115
116
|
return {
|
|
116
117
|
crop: b,
|
|
117
118
|
rotate: x,
|
|
118
|
-
edit:
|
|
119
|
-
let e =
|
|
120
|
-
return
|
|
119
|
+
edit: m(() => {
|
|
120
|
+
let e = a(b, _, x);
|
|
121
|
+
return s(e, D.current) ? D.current : D.current = e;
|
|
121
122
|
}, [
|
|
122
123
|
b,
|
|
123
124
|
_,
|
|
@@ -129,8 +130,8 @@ function y({ source: e, aspect: c, initial: l }) {
|
|
|
129
130
|
reset: E
|
|
130
131
|
};
|
|
131
132
|
}
|
|
132
|
-
function
|
|
133
|
-
let [t, n] =
|
|
133
|
+
function x(e) {
|
|
134
|
+
let [t, n] = g(() => ({
|
|
134
135
|
at: e?.at,
|
|
135
136
|
received: Date.now()
|
|
136
137
|
}));
|
|
@@ -138,18 +139,18 @@ function b(e) {
|
|
|
138
139
|
at: e?.at,
|
|
139
140
|
received: Date.now()
|
|
140
141
|
});
|
|
141
|
-
let [r, i] =
|
|
142
|
-
return
|
|
142
|
+
let [r, i] = g(() => Date.now()), a = !!e?.eta && !e.stalled;
|
|
143
|
+
return p(() => {
|
|
143
144
|
if (!a) return;
|
|
144
145
|
i(Date.now());
|
|
145
146
|
let e = setInterval(() => i(Date.now()), 1e3);
|
|
146
147
|
return () => clearInterval(e);
|
|
147
148
|
}, [a, t]), {
|
|
148
149
|
progress: e ?? void 0,
|
|
149
|
-
remaining:
|
|
150
|
+
remaining: l(e, t.received, Math.max(r, t.received))
|
|
150
151
|
};
|
|
151
152
|
}
|
|
152
153
|
//#endregion
|
|
153
|
-
export {
|
|
154
|
+
export { b as useCrop, x as useEncodeProgress, y as useUpload, v as useUploadQueue };
|
|
154
155
|
|
|
155
156
|
//# sourceMappingURL=upload.js.map
|
package/dist/react/upload.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.js","names":[],"sources":["../../src/react/upload.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { ratio, type AspectRatio } from \"../client/aspect.js\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport { centeredCrop, constrainCrop, editOf, rotation, sameEdit, toOriginal, type Rotation, type Size } from \"../client/crop.js\";\nimport { toContentKitError, type ContentKitError } from \"../client/errors.js\";\nimport type { Crop, Edit, EncodeProgress, FileInfo } from \"../client/generated/wire.js\";\nimport type { Progress, PutOptions, UploadedFile, UploadOptions } from \"../client/media/client.js\";\nimport { encodeRemaining } from \"../client/media/encode.js\";\nimport { ItemUploadQueue, type QueueOptions, type QueueSnapshot } from \"../client/media/queue.js\";\nimport { useContentKitClient } from \"./context.js\";\n\nexport interface UseUploadQueue extends QueueSnapshot {\n queue: ItemUploadQueue;\n add: ItemUploadQueue[\"add\"];\n move: ItemUploadQueue[\"move\"];\n update: ItemUploadQueue[\"update\"];\n remove: ItemUploadQueue[\"remove\"];\n retry: ItemUploadQueue[\"retry\"];\n start: ItemUploadQueue[\"start\"];\n pause: ItemUploadQueue[\"pause\"];\n commit: ItemUploadQueue[\"commit\"];\n}\n\nexport interface UploadQueueOptions extends QueueOptions {\n /** Overrides the provider's client. */\n client?: ContentKitClient;\n}\n\n/**\n * A file queue for one item: another ref gets a fresh queue and the previous\n * one pauses (the other options are read once per queue). Unmounting pauses\n * running uploads.\n */\nexport function useUploadQueue({ client: own, ...options }: UploadQueueOptions): UseUploadQueue {\n const client = useContentKitClient(own);\n const key = `${options.ref.kind}/${options.ref.id}`;\n const open = () => ({ key, queue: new ItemUploadQueue(client.media, { ...options, autoStart: false }) });\n const [current, setCurrent] = useState(open);\n if (current.key !== key) setCurrent(open());\n const { queue } = current;\n const autoStart = options.autoStart ?? true;\n useEffect(() => {\n if (autoStart) queue.start();\n return () => queue.pause();\n }, [queue, autoStart]);\n const snap = useSyncExternalStore(queue.subscribe, queue.getSnapshot, queue.getSnapshot);\n return {\n ...snap,\n queue,\n add: queue.add.bind(queue),\n move: queue.move.bind(queue),\n update: queue.update.bind(queue),\n remove: queue.remove.bind(queue),\n retry: queue.retry.bind(queue),\n start: queue.start.bind(queue),\n pause: queue.pause.bind(queue),\n commit: queue.commit.bind(queue),\n };\n}\n\nexport interface UploadStatus {\n status: \"idle\" | \"uploading\" | \"done\" | \"error\";\n progress?: Progress;\n error?: ContentKitError;\n result?: UploadedFile & { file?: FileInfo };\n}\n\nexport interface UseUpload extends UploadStatus {\n /**\n * Uploads one file; with put it also commits it to its path (put's edit,\n * meta and index) and waits until it is processed (result.file).\n */\n upload: (file: File, opts: Omit<UploadOptions, \"signal\" | \"onProgress\"> & { put?: PutOptions }) => Promise<UploadedFile & { file?: FileInfo }>;\n cancel: () => void;\n}\n\n/** One upload at a time (a cover, an inline image); a new upload cancels the previous. */\nexport function useUpload({ client: own }: { client?: ContentKitClient } = {}): UseUpload {\n const { media } = useContentKitClient(own);\n const [s, set] = useState<UploadStatus>({ status: \"idle\" });\n const ctl = useRef<AbortController | null>(null);\n useEffect(() => () => ctl.current?.abort(), []);\n\n const upload = useCallback<UseUpload[\"upload\"]>(\n async (file, { put, ...opts }) => {\n ctl.current?.abort();\n const c = (ctl.current = new AbortController());\n set({ status: \"uploading\" });\n const o: UploadOptions = {\n ...opts,\n signal: c.signal,\n onProgress: (progress) => c === ctl.current && set({ status: \"uploading\", progress }),\n };\n try {\n let result: UploadedFile & { file?: FileInfo };\n if (put) {\n let up: UploadedFile | undefined;\n const f = await media.put(file, { ...o, ...put, onUploaded: (u) => (up = u) });\n result = { ...up!, file: f };\n } else result = await media.upload(file, o);\n if (c === ctl.current) set((prev) => ({ status: \"done\", progress: prev.progress, result }));\n return result;\n } catch (e) {\n const error = toContentKitError(e);\n if (c === ctl.current) set(error.code === \"aborted\" ? { status: \"idle\" } : { status: \"error\", error });\n throw error;\n }\n },\n [media],\n );\n const cancel = useCallback(() => ctl.current?.abort(), []);\n return { ...s, upload, cancel };\n}\n\nexport interface UseCropOptions {\n /** The upload's size (an editor read's w and h). */\n source: Size;\n /** The edited image's \"W:H\", e.g. the public preset's aspect; \"\" or omitted is free. */\n aspect?: AspectRatio;\n /** The current edit to start from. */\n initial?: Edit | null;\n}\n\nexport interface UseCrop {\n /** In original pixels, inside the source and at the aspect. */\n crop: Crop;\n rotate: Rotation;\n /** Ready for an edit or put op; null when nothing changes. Its identity changes only with its value. */\n edit: Edit | null;\n /** A rect in original pixels. */\n setCrop: (rect: Crop) => void;\n /** A rect on the image as displayed (after the rotation) at display size: a cropper's output. */\n setFromDisplay: (rect: Crop, display: Size) => void;\n /** Turns clockwise by deg (a multiple of 90); the crop keeps the aspect. */\n rotateBy: (deg: number) => void;\n reset: () => void;\n}\n\n/** Headless crop state for any cropper UI: a rect in original pixels, a rotation and the resulting edit. */\nexport function useCrop({ source: given, aspect: shape, initial }: UseCropOptions): UseCrop {\n const aspect = ratio(shape);\n const { width, height } = given;\n const source = useMemo(() => ({ width, height }), [width, height]);\n const start = (): [Crop, Rotation] => {\n const rotate = rotation(initial?.rotate ?? 0);\n const c = initial?.crop;\n return [c ? constrainCrop(c, source, aspect, rotate) : centeredCrop(source, aspect, rotate), rotate];\n };\n const [state, setState] = useState(start);\n const [crop, rotate] = state;\n const set = useCallback(\n (next: [Crop, Rotation] | ((s: [Crop, Rotation]) => [Crop, Rotation])) =>\n setState((s) => {\n const n = typeof next === \"function\" ? next(s) : next;\n return sameEdit({ crop: n[0], rotate: n[1] }, { crop: s[0], rotate: s[1] }) ? s : n;\n }),\n [],\n );\n const setCrop = useCallback((r: Crop) => set(([, rot]) => [constrainCrop(r, source, aspect, rot), rot]), [set, source, aspect]);\n const setFromDisplay = useCallback(\n (r: Crop, display: Size) => set(([, rot]) => [constrainCrop(toOriginal(r, display, source, rot), source, aspect, rot), rot]),\n [set, source, aspect],\n );\n const rotateBy = useCallback(\n (deg: number) =>\n set(([c, rot]) => {\n const next = rotation(rot + deg);\n return [constrainCrop(c, source, aspect, next), next];\n }),\n [set, source, aspect],\n );\n const reset = useCallback(() => set([centeredCrop(source, aspect), 0]), [set, source, aspect]);\n const last = useRef<Edit | null>(null);\n const edit = useMemo(() => {\n const e = editOf(crop, source, rotate);\n return sameEdit(e, last.current) ? last.current : (last.current = e);\n }, [crop, source, rotate]);\n return { crop, rotate, edit, setCrop, setFromDisplay, rotateBy, reset };\n}\n\nexport interface UseEncodeProgress {\n progress?: EncodeProgress;\n /** Seconds left, counting down each second between reports; undefined while unknown. */\n remaining?: number;\n}\n\n/**\n * A pending video file's encode progress from the read API (`files[i].progress`),\n * with the ETA counted down locally between polls.\n */\nexport function useEncodeProgress(progress?: EncodeProgress | null): UseEncodeProgress {\n const [base, setBase] = useState(() => ({ at: progress?.at, received: Date.now() }));\n if (progress?.at !== base.at) setBase({ at: progress?.at, received: Date.now() });\n const [now, setNow] = useState(() => Date.now());\n const ticking = !!progress?.eta && !progress.stalled;\n useEffect(() => {\n if (!ticking) return;\n setNow(Date.now());\n const id = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(id);\n }, [ticking, base]);\n return { progress: progress ?? undefined, remaining: encodeRemaining(progress, base.received, Math.max(now, base.received)) };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"upload.js","names":[],"sources":["../../src/react/upload.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { itemKey } from \"../client/media/ref.js\";\nimport { ratio, type AspectRatio } from \"../client/aspect.js\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport { centeredCrop, constrainCrop, editOf, rotation, sameEdit, toOriginal, type Rotation, type Size } from \"../client/crop.js\";\nimport { toContentKitError, type ContentKitError } from \"../client/errors.js\";\nimport type { Crop, Edit, EncodeProgress, FileInfo } from \"../client/generated/wire.js\";\nimport type { Progress, PutOptions, UploadedFile, UploadOptions } from \"../client/media/client.js\";\nimport { encodeRemaining } from \"../client/media/encode.js\";\nimport { ItemUploadQueue, type QueueOptions, type QueueSnapshot } from \"../client/media/queue.js\";\nimport { useContentKitClient } from \"./context.js\";\n\nexport interface UseUploadQueue extends QueueSnapshot {\n queue: ItemUploadQueue;\n add: ItemUploadQueue[\"add\"];\n move: ItemUploadQueue[\"move\"];\n update: ItemUploadQueue[\"update\"];\n remove: ItemUploadQueue[\"remove\"];\n retry: ItemUploadQueue[\"retry\"];\n start: ItemUploadQueue[\"start\"];\n pause: ItemUploadQueue[\"pause\"];\n commit: ItemUploadQueue[\"commit\"];\n}\n\nexport interface UploadQueueOptions extends QueueOptions {\n /** Overrides the provider's client. */\n client?: ContentKitClient;\n}\n\n/**\n * A file queue for one item: another ref gets a fresh queue and the previous\n * one pauses (the other options are read once per queue). Unmounting pauses\n * running uploads.\n */\nexport function useUploadQueue({ client: own, ...options }: UploadQueueOptions): UseUploadQueue {\n const client = useContentKitClient(own);\n const key = itemKey(options.ref);\n const open = () => ({ key, queue: new ItemUploadQueue(client.media, { ...options, autoStart: false }) });\n const [current, setCurrent] = useState(open);\n if (current.key !== key) setCurrent(open());\n const { queue } = current;\n const autoStart = options.autoStart ?? true;\n useEffect(() => {\n if (autoStart) queue.start();\n return () => queue.pause();\n }, [queue, autoStart]);\n const snap = useSyncExternalStore(queue.subscribe, queue.getSnapshot, queue.getSnapshot);\n return {\n ...snap,\n queue,\n add: queue.add.bind(queue),\n move: queue.move.bind(queue),\n update: queue.update.bind(queue),\n remove: queue.remove.bind(queue),\n retry: queue.retry.bind(queue),\n start: queue.start.bind(queue),\n pause: queue.pause.bind(queue),\n commit: queue.commit.bind(queue),\n };\n}\n\nexport interface UploadStatus {\n status: \"idle\" | \"uploading\" | \"done\" | \"error\";\n progress?: Progress;\n error?: ContentKitError;\n result?: UploadedFile & { file?: FileInfo };\n}\n\nexport interface UseUpload extends UploadStatus {\n /**\n * Uploads one file; with put it also commits it to its path (put's edit,\n * meta and index) and waits until it is processed (result.file).\n */\n upload: (file: File, opts: Omit<UploadOptions, \"signal\" | \"onProgress\"> & { put?: PutOptions }) => Promise<UploadedFile & { file?: FileInfo }>;\n cancel: () => void;\n}\n\n/** One upload at a time (a cover, an inline image); a new upload cancels the previous. */\nexport function useUpload({ client: own }: { client?: ContentKitClient } = {}): UseUpload {\n const { media } = useContentKitClient(own);\n const [s, set] = useState<UploadStatus>({ status: \"idle\" });\n const ctl = useRef<AbortController | null>(null);\n useEffect(() => () => ctl.current?.abort(), []);\n\n const upload = useCallback<UseUpload[\"upload\"]>(\n async (file, { put, ...opts }) => {\n ctl.current?.abort();\n const c = (ctl.current = new AbortController());\n set({ status: \"uploading\" });\n const o: UploadOptions = {\n ...opts,\n signal: c.signal,\n onProgress: (progress) => c === ctl.current && set({ status: \"uploading\", progress }),\n };\n try {\n let result: UploadedFile & { file?: FileInfo };\n if (put) {\n let up: UploadedFile | undefined;\n const f = await media.put(file, { ...o, ...put, onUploaded: (u) => (up = u) });\n result = { ...up!, file: f };\n } else result = await media.upload(file, o);\n if (c === ctl.current) set((prev) => ({ status: \"done\", progress: prev.progress, result }));\n return result;\n } catch (e) {\n const error = toContentKitError(e);\n if (c === ctl.current) set(error.code === \"aborted\" ? { status: \"idle\" } : { status: \"error\", error });\n throw error;\n }\n },\n [media],\n );\n const cancel = useCallback(() => ctl.current?.abort(), []);\n return { ...s, upload, cancel };\n}\n\nexport interface UseCropOptions {\n /** The upload's size (an editor read's w and h). */\n source: Size;\n /** The edited image's \"W:H\", e.g. the public preset's aspect; \"\" or omitted is free. */\n aspect?: AspectRatio;\n /** The current edit to start from. */\n initial?: Edit | null;\n}\n\nexport interface UseCrop {\n /** In original pixels, inside the source and at the aspect. */\n crop: Crop;\n rotate: Rotation;\n /** Ready for an edit or put op; null when nothing changes. Its identity changes only with its value. */\n edit: Edit | null;\n /** A rect in original pixels. */\n setCrop: (rect: Crop) => void;\n /** A rect on the image as displayed (after the rotation) at display size: a cropper's output. */\n setFromDisplay: (rect: Crop, display: Size) => void;\n /** Turns clockwise by deg (a multiple of 90); the crop keeps the aspect. */\n rotateBy: (deg: number) => void;\n reset: () => void;\n}\n\n/** Headless crop state for any cropper UI: a rect in original pixels, a rotation and the resulting edit. */\nexport function useCrop({ source: given, aspect: shape, initial }: UseCropOptions): UseCrop {\n const aspect = ratio(shape);\n const { width, height } = given;\n const source = useMemo(() => ({ width, height }), [width, height]);\n const start = (): [Crop, Rotation] => {\n const rotate = rotation(initial?.rotate ?? 0);\n const c = initial?.crop;\n return [c ? constrainCrop(c, source, aspect, rotate) : centeredCrop(source, aspect, rotate), rotate];\n };\n const [state, setState] = useState(start);\n const [crop, rotate] = state;\n const set = useCallback(\n (next: [Crop, Rotation] | ((s: [Crop, Rotation]) => [Crop, Rotation])) =>\n setState((s) => {\n const n = typeof next === \"function\" ? next(s) : next;\n return sameEdit({ crop: n[0], rotate: n[1] }, { crop: s[0], rotate: s[1] }) ? s : n;\n }),\n [],\n );\n const setCrop = useCallback((r: Crop) => set(([, rot]) => [constrainCrop(r, source, aspect, rot), rot]), [set, source, aspect]);\n const setFromDisplay = useCallback(\n (r: Crop, display: Size) => set(([, rot]) => [constrainCrop(toOriginal(r, display, source, rot), source, aspect, rot), rot]),\n [set, source, aspect],\n );\n const rotateBy = useCallback(\n (deg: number) =>\n set(([c, rot]) => {\n const next = rotation(rot + deg);\n return [constrainCrop(c, source, aspect, next), next];\n }),\n [set, source, aspect],\n );\n const reset = useCallback(() => set([centeredCrop(source, aspect), 0]), [set, source, aspect]);\n const last = useRef<Edit | null>(null);\n const edit = useMemo(() => {\n const e = editOf(crop, source, rotate);\n return sameEdit(e, last.current) ? last.current : (last.current = e);\n }, [crop, source, rotate]);\n return { crop, rotate, edit, setCrop, setFromDisplay, rotateBy, reset };\n}\n\nexport interface UseEncodeProgress {\n progress?: EncodeProgress;\n /** Seconds left, counting down each second between reports; undefined while unknown. */\n remaining?: number;\n}\n\n/**\n * A pending video file's encode progress from the read API (`files[i].progress`),\n * with the ETA counted down locally between polls.\n */\nexport function useEncodeProgress(progress?: EncodeProgress | null): UseEncodeProgress {\n const [base, setBase] = useState(() => ({ at: progress?.at, received: Date.now() }));\n if (progress?.at !== base.at) setBase({ at: progress?.at, received: Date.now() });\n const [now, setNow] = useState(() => Date.now());\n const ticking = !!progress?.eta && !progress.stalled;\n useEffect(() => {\n if (!ticking) return;\n setNow(Date.now());\n const id = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(id);\n }, [ticking, base]);\n return { progress: progress ?? undefined, remaining: encodeRemaining(progress, base.received, Math.max(now, base.received)) };\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ContentKitClient } from '../client/client.js';
|
|
2
2
|
import { ContentKitError } from '../client/errors.js';
|
|
3
3
|
import { Fetcher, Page, Resource, ResourceStore, Tag } from './resources.js';
|
|
4
|
-
/** The client, its shared store, and the provider's viewer and sign-in. */
|
|
4
|
+
/** The client, its shared store, and the provider's viewer, language and sign-in. */
|
|
5
5
|
export declare function useContentScope(own?: ContentKitClient | null): {
|
|
6
6
|
client: ContentKitClient;
|
|
7
7
|
store: ResourceStore;
|
|
8
8
|
scope: string;
|
|
9
9
|
viewer: string | null | undefined;
|
|
10
|
+
language: string | undefined;
|
|
10
11
|
onSignIn: (() => void) | undefined;
|
|
11
12
|
};
|
|
12
13
|
/** A shared read: fetched once per key while shown; initial is shown (and seeds the store) until it loads. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-resource.js","names":[],"sources":["../../src/react/use-resource.ts"],"sourcesContent":["import { useCallback, useContext, useEffect, useRef, useSyncExternalStore } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport { ContentKitContext, useContentKitClient, useReadScope } from \"./context.js\";\nimport { resourcesFor, type Fetcher, type Page, type Resource, type ResourceStore, type Tag } from \"./resources.js\";\n\n/** The client, its shared store, and the provider's viewer and sign-in. */\nexport function useContentScope(own?: ContentKitClient | null) {\n const ctx = useContext(ContentKitContext);\n const client = useContentKitClient(own);\n return { client, store: resourcesFor(client), scope: useReadScope(), viewer: ctx?.viewer, onSignIn: ctx?.onSignIn };\n}\n\nconst IDLE: Resource<never> = { data: undefined, loading: false, loaded: false };\nconst none = () => () => {};\n\n/** A shared read: fetched once per key while shown; initial is shown (and seeds the store) until it loads. */\nexport function useResource<T>(\n store: ResourceStore,\n key: string | null,\n tag: Tag,\n fetcher: Fetcher<T>,\n o: { initial?: T; more?: (cursor: string | number, signal: AbortSignal) => Promise<Page<unknown>> } = {},\n): Resource<T> & { reload: () => void } {\n const scope = useReadScope();\n const fetch = useRef(fetcher);\n const more = useRef(o.more);\n const initial = useRef(o.initial);\n useEffect(() => {\n fetch.current = fetcher;\n more.current = o.more;\n initial.current = o.initial;\n });\n const subscribe = useCallback(\n (l: () => void) => (key ? store.subscribe(key, { ...tag, readScope: scope }, l) : none()),\n // The tag is part of the key.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, key, scope],\n );\n const snapshot = useCallback(() => (key ? store.snapshot<T>(key) : IDLE), [store, key]);\n const entry = useSyncExternalStore(subscribe, snapshot, snapshot);\n useEffect(() => {\n if (!key) return;\n store.bind(key, (s) => fetch.current(s), more.current && ((c, s) => more.current!(c, s)));\n if (initial.current !== undefined && !store.snapshot(key).loaded && !store.snapshot(key).loading) store.set(key, initial.current);\n else store.load(key);\n }, [store, key]);\n const reload = useCallback(() => key && store.load(key, true), [store, key]);\n if (!entry.loaded && o.initial !== undefined) return { ...entry, data: o.initial, reload };\n return { ...entry, reload };\n}\n\n/** A shared list, a page at a time. */\nexport interface UseList<T> {\n items: T[];\n /** The first page is loading (also on reload). */\n loading: boolean;\n loadingMore: boolean;\n error?: ContentKitError;\n hasMore: boolean;\n loadMore: () => Promise<void>;\n reload: () => void;\n}\n\nexport type PageFetcher<T> = (cursor: string | number | undefined, signal: AbortSignal) => Promise<Page<T>>;\n\nexport function useList<T extends { id: string }>(store: ResourceStore, key: string | null, tag: Tag, page: PageFetcher<T>): UseList<T> {\n const r = useResource<Page<T>>(store, key, tag, (s) => page(undefined, s), { more: (c, s) => page(c, s) });\n const loadMore = useCallback(() => (key ? store.loadMore(key) : Promise.resolve()), [store, key]);\n return {\n items: r.data?.items ?? [],\n loading: r.loading || (!!key && !r.loaded),\n loadingMore: !!r.loadingMore,\n error: r.error,\n hasMore: r.data ? r.data.next !== null : false,\n loadMore,\n reload: r.reload,\n };\n}\n\n/**\n * A limit/offset list as pages. A full page means more may follow; with\n * underfill (the latest feed drops items the caller may not see) only an\n * empty page ends it.\n */\nexport function offsetPages<T>(limit: number, list: (q: { limit: number; offset: number }, signal: AbortSignal) => Promise<T[]>, underfill = false): PageFetcher<T> {\n return async (cursor, signal) => {\n const offset = typeof cursor === \"number\" ? cursor : 0;\n const items = await list({ limit, offset }, signal);\n const end = underfill ? items.length === 0 : items.length < limit;\n return { items, next: end ? null : offset + limit };\n };\n}\n\n/** A stable store key. */\nexport const keyOf = (...parts: unknown[]) => JSON.stringify(parts);\n\n/** One numbered page of a list. */\nexport interface UsePaged<T> {\n items: T[];\n loading: boolean;\n error?: ContentKitError;\n /** Another page follows. */\n hasNext: boolean;\n reload: () => void;\n}\n\n/** Page `page` (from 1) of a limit/offset list: one read of limit + 1 tells whether another follows. */\nexport function usePaged<T extends { id: string }>(\n store: ResourceStore,\n key: string | null,\n tag: Tag,\n page: number,\n limit: number,\n list: (q: { limit: number; offset: number }, signal: AbortSignal) => Promise<T[]>,\n): UsePaged<T> {\n const offset = (Math.max(1, page) - 1) * limit;\n const r = useResource<Page<T>>(store, key === null ? null : `${key}#${offset}`, tag, async (signal) => {\n const items = await list({ limit: limit + 1, offset }, signal);\n return { items: items.slice(0, limit), next: items.length > limit ? offset + limit : null };\n });\n return { items: r.data?.items ?? [], loading: r.loading || (!!key && !r.loaded), error: r.error, hasNext: r.data ? r.data.next !== null : false, reload: r.reload };\n}\n"],"mappings":";;;;AAOA,SAAgB,EAAgB,GAA+B;CAC7D,IAAM,IAAM,EAAW,CAAiB,GAClC,IAAS,EAAoB,CAAG;CACtC,OAAO;EAAE;EAAQ,OAAO,EAAa,CAAM;EAAG,OAAO,EAAa;EAAG,QAAQ,GAAK;EAAQ,UAAU,GAAK;CAAS;
|
|
1
|
+
{"version":3,"file":"use-resource.js","names":[],"sources":["../../src/react/use-resource.ts"],"sourcesContent":["import { useCallback, useContext, useEffect, useRef, useSyncExternalStore } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport { ContentKitContext, useContentKitClient, useReadScope } from \"./context.js\";\nimport { resourcesFor, type Fetcher, type Page, type Resource, type ResourceStore, type Tag } from \"./resources.js\";\n\n/** The client, its shared store, and the provider's viewer, language and sign-in. */\nexport function useContentScope(own?: ContentKitClient | null) {\n const ctx = useContext(ContentKitContext);\n const client = useContentKitClient(own);\n return { client, store: resourcesFor(client), scope: useReadScope(), viewer: ctx?.viewer, language: ctx?.language, onSignIn: ctx?.onSignIn };\n}\n\nconst IDLE: Resource<never> = { data: undefined, loading: false, loaded: false };\nconst none = () => () => {};\n\n/** A shared read: fetched once per key while shown; initial is shown (and seeds the store) until it loads. */\nexport function useResource<T>(\n store: ResourceStore,\n key: string | null,\n tag: Tag,\n fetcher: Fetcher<T>,\n o: { initial?: T; more?: (cursor: string | number, signal: AbortSignal) => Promise<Page<unknown>> } = {},\n): Resource<T> & { reload: () => void } {\n const scope = useReadScope();\n const fetch = useRef(fetcher);\n const more = useRef(o.more);\n const initial = useRef(o.initial);\n useEffect(() => {\n fetch.current = fetcher;\n more.current = o.more;\n initial.current = o.initial;\n });\n const subscribe = useCallback(\n (l: () => void) => (key ? store.subscribe(key, { ...tag, readScope: scope }, l) : none()),\n // The tag is part of the key.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, key, scope],\n );\n const snapshot = useCallback(() => (key ? store.snapshot<T>(key) : IDLE), [store, key]);\n const entry = useSyncExternalStore(subscribe, snapshot, snapshot);\n useEffect(() => {\n if (!key) return;\n store.bind(key, (s) => fetch.current(s), more.current && ((c, s) => more.current!(c, s)));\n if (initial.current !== undefined && !store.snapshot(key).loaded && !store.snapshot(key).loading) store.set(key, initial.current);\n else store.load(key);\n }, [store, key]);\n const reload = useCallback(() => key && store.load(key, true), [store, key]);\n if (!entry.loaded && o.initial !== undefined) return { ...entry, data: o.initial, reload };\n return { ...entry, reload };\n}\n\n/** A shared list, a page at a time. */\nexport interface UseList<T> {\n items: T[];\n /** The first page is loading (also on reload). */\n loading: boolean;\n loadingMore: boolean;\n error?: ContentKitError;\n hasMore: boolean;\n loadMore: () => Promise<void>;\n reload: () => void;\n}\n\nexport type PageFetcher<T> = (cursor: string | number | undefined, signal: AbortSignal) => Promise<Page<T>>;\n\nexport function useList<T extends { id: string }>(store: ResourceStore, key: string | null, tag: Tag, page: PageFetcher<T>): UseList<T> {\n const r = useResource<Page<T>>(store, key, tag, (s) => page(undefined, s), { more: (c, s) => page(c, s) });\n const loadMore = useCallback(() => (key ? store.loadMore(key) : Promise.resolve()), [store, key]);\n return {\n items: r.data?.items ?? [],\n loading: r.loading || (!!key && !r.loaded),\n loadingMore: !!r.loadingMore,\n error: r.error,\n hasMore: r.data ? r.data.next !== null : false,\n loadMore,\n reload: r.reload,\n };\n}\n\n/**\n * A limit/offset list as pages. A full page means more may follow; with\n * underfill (the latest feed drops items the caller may not see) only an\n * empty page ends it.\n */\nexport function offsetPages<T>(limit: number, list: (q: { limit: number; offset: number }, signal: AbortSignal) => Promise<T[]>, underfill = false): PageFetcher<T> {\n return async (cursor, signal) => {\n const offset = typeof cursor === \"number\" ? cursor : 0;\n const items = await list({ limit, offset }, signal);\n const end = underfill ? items.length === 0 : items.length < limit;\n return { items, next: end ? null : offset + limit };\n };\n}\n\n/** A stable store key. */\nexport const keyOf = (...parts: unknown[]) => JSON.stringify(parts);\n\n/** One numbered page of a list. */\nexport interface UsePaged<T> {\n items: T[];\n loading: boolean;\n error?: ContentKitError;\n /** Another page follows. */\n hasNext: boolean;\n reload: () => void;\n}\n\n/** Page `page` (from 1) of a limit/offset list: one read of limit + 1 tells whether another follows. */\nexport function usePaged<T extends { id: string }>(\n store: ResourceStore,\n key: string | null,\n tag: Tag,\n page: number,\n limit: number,\n list: (q: { limit: number; offset: number }, signal: AbortSignal) => Promise<T[]>,\n): UsePaged<T> {\n const offset = (Math.max(1, page) - 1) * limit;\n const r = useResource<Page<T>>(store, key === null ? null : `${key}#${offset}`, tag, async (signal) => {\n const items = await list({ limit: limit + 1, offset }, signal);\n return { items: items.slice(0, limit), next: items.length > limit ? offset + limit : null };\n });\n return { items: r.data?.items ?? [], loading: r.loading || (!!key && !r.loaded), error: r.error, hasNext: r.data ? r.data.next !== null : false, reload: r.reload };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ContentKitClient } from '../client/client.js';
|
|
2
|
+
import { ContentKitError } from '../client/errors.js';
|
|
3
|
+
import { PlanSegment, ReaderPlan } from '../client/generated/wire.js';
|
|
4
|
+
import { ReadWindow } from './read.js';
|
|
5
|
+
export interface UseReaderPlan {
|
|
6
|
+
/** null while loading, pending or failed. */
|
|
7
|
+
plan: ReaderPlan | null;
|
|
8
|
+
/** The version has no current publication yet; the hook asks again. */
|
|
9
|
+
pending: boolean;
|
|
10
|
+
loading: boolean;
|
|
11
|
+
error?: ContentKitError;
|
|
12
|
+
reload: () => void;
|
|
13
|
+
}
|
|
14
|
+
/** When the plan changes by itself: its next scheduled segment's release. */
|
|
15
|
+
export declare function nextRelease(plan: ReaderPlan | null, now?: number): number | null;
|
|
16
|
+
/**
|
|
17
|
+
* A version's reader plan for this viewer: its segments (released or not,
|
|
18
|
+
* open or locked), previews, playback item and reader metadata. It asks again
|
|
19
|
+
* while the version is being published and when its next segment is released.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useReaderPlan(content: string | null | undefined, version: string | null | undefined, o?: {
|
|
22
|
+
poll?: number;
|
|
23
|
+
client?: ContentKitClient;
|
|
24
|
+
}): UseReaderPlan;
|
|
25
|
+
/** A segment's page with the URL of one rendition, once its item's read signed it. */
|
|
26
|
+
export interface ReaderPage {
|
|
27
|
+
name: string;
|
|
28
|
+
w: number;
|
|
29
|
+
h: number;
|
|
30
|
+
/** undefined until read, or when the page lacks the rendition. */
|
|
31
|
+
url?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface UseSegmentPages {
|
|
34
|
+
pages: ReaderPage[];
|
|
35
|
+
loading: boolean;
|
|
36
|
+
error?: ContentKitError;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* An open segment's pages with URLs of one rendition, read through its
|
|
40
|
+
* published item (windowed for long segments, refreshed before the URLs expire).
|
|
41
|
+
*/
|
|
42
|
+
export declare function useSegmentPages(segment: PlanSegment | null | undefined, rendition: string, o?: {
|
|
43
|
+
window?: ReadWindow;
|
|
44
|
+
client?: ContentKitClient;
|
|
45
|
+
}): UseSegmentPages;
|
|
46
|
+
export interface UseVersionDownload {
|
|
47
|
+
/** Prepares the zip (asking again while it is prepared) and resolves with it. */
|
|
48
|
+
download: () => Promise<Blob>;
|
|
49
|
+
/** Prepared by the server, waiting. */
|
|
50
|
+
preparing: boolean;
|
|
51
|
+
error?: ContentKitError;
|
|
52
|
+
}
|
|
53
|
+
/** A version's pages as a zip, charged to the viewer's download quota. */
|
|
54
|
+
export declare function useVersionDownload(content: string, version: string, o?: {
|
|
55
|
+
poll?: number;
|
|
56
|
+
client?: ContentKitClient;
|
|
57
|
+
}): UseVersionDownload;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { toContentKitError as e } from "../client/errors.js";
|
|
2
|
+
import { useMediaRead as t } from "./read.js";
|
|
3
|
+
import { keyOf as n, useContentScope as r, useResource as i } from "./use-resource.js";
|
|
4
|
+
import { isPending as a } from "../client/versions.js";
|
|
5
|
+
import { useCallback as o, useEffect as s, useMemo as c, useState as l } from "react";
|
|
6
|
+
//#region src/react/versions.ts
|
|
7
|
+
var u = 2 ** 31 - 1;
|
|
8
|
+
function d(e, t = Date.now()) {
|
|
9
|
+
let n = (e?.segments ?? []).flatMap((e) => !e.released && e.release_at ? [Date.parse(e.release_at)] : []).filter((e) => e > t);
|
|
10
|
+
return n.length ? Math.min(...n) : null;
|
|
11
|
+
}
|
|
12
|
+
function f(e, t, o = {}) {
|
|
13
|
+
let { client: c, store: l, scope: f } = r(o.client), p = e && t ? n("reader-plan", f, e, t) : null, m = i(l, p, {
|
|
14
|
+
type: "reader-plan",
|
|
15
|
+
id: t ?? void 0
|
|
16
|
+
}, (n) => c.versions.reader(e, t, n)), h = a(m.data), g = m.data && !h ? m.data : null, { data: _, reload: v } = m;
|
|
17
|
+
return s(() => {
|
|
18
|
+
let e = a(_) ? Date.now() + (o.poll ?? 5e3) : d(_ || null);
|
|
19
|
+
if (e === null) return;
|
|
20
|
+
let t = setTimeout(v, Math.min(u, Math.max(0, e - Date.now()) + 500));
|
|
21
|
+
return () => clearTimeout(t);
|
|
22
|
+
}, [
|
|
23
|
+
_,
|
|
24
|
+
v,
|
|
25
|
+
o.poll
|
|
26
|
+
]), {
|
|
27
|
+
plan: g,
|
|
28
|
+
pending: h,
|
|
29
|
+
loading: !!p && (m.loading || !m.loaded),
|
|
30
|
+
error: m.error,
|
|
31
|
+
reload: v
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function p(e, n, r = {}) {
|
|
35
|
+
let i = e?.item ?? null, a = t(i ?? {
|
|
36
|
+
kind: "",
|
|
37
|
+
id: ""
|
|
38
|
+
}, {
|
|
39
|
+
window: r.window,
|
|
40
|
+
read: i ? void 0 : null,
|
|
41
|
+
client: r.client
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
pages: c(() => {
|
|
45
|
+
let t = new Map((a.read?.files ?? []).flatMap((e) => e.url ? [[e.path, e.url]] : []));
|
|
46
|
+
return (e?.pages ?? []).map((e) => {
|
|
47
|
+
let r = e.files[n];
|
|
48
|
+
return {
|
|
49
|
+
name: e.name,
|
|
50
|
+
w: e.w,
|
|
51
|
+
h: e.h,
|
|
52
|
+
url: r ? t.get(r) : void 0
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
}, [
|
|
56
|
+
e,
|
|
57
|
+
n,
|
|
58
|
+
a.read
|
|
59
|
+
]),
|
|
60
|
+
loading: !!i && a.loading,
|
|
61
|
+
error: a.error
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function m(t, n, i = {}) {
|
|
65
|
+
let { client: s } = r(i.client), [c, u] = l(!1), [d, f] = l();
|
|
66
|
+
return {
|
|
67
|
+
download: o(async () => {
|
|
68
|
+
f(void 0), u(!0);
|
|
69
|
+
try {
|
|
70
|
+
for (;;) {
|
|
71
|
+
let e = await s.versions.download(t, n);
|
|
72
|
+
if (!a(e)) return e;
|
|
73
|
+
await new Promise((e) => setTimeout(e, i.poll ?? 3e3));
|
|
74
|
+
}
|
|
75
|
+
} catch (t) {
|
|
76
|
+
let n = e(t);
|
|
77
|
+
throw f(n), n;
|
|
78
|
+
} finally {
|
|
79
|
+
u(!1);
|
|
80
|
+
}
|
|
81
|
+
}, [
|
|
82
|
+
s,
|
|
83
|
+
t,
|
|
84
|
+
n,
|
|
85
|
+
i.poll
|
|
86
|
+
]),
|
|
87
|
+
preparing: c,
|
|
88
|
+
error: d
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { d as nextRelease, f as useReaderPlan, p as useSegmentPages, m as useVersionDownload };
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=versions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versions.js","names":[],"sources":["../../src/react/versions.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../client/errors.js\";\nimport type { Pending, PlanSegment, ReaderPlan } from \"../client/generated/wire.js\";\nimport { isPending } from \"../client/versions.js\";\nimport { useMediaRead, type ReadWindow } from \"./read.js\";\nimport { keyOf, useContentScope, useResource } from \"./use-resource.js\";\n\nexport interface UseReaderPlan {\n /** null while loading, pending or failed. */\n plan: ReaderPlan | null;\n /** The version has no current publication yet; the hook asks again. */\n pending: boolean;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n// setTimeout's longest delay.\nconst MAX_DELAY = 2 ** 31 - 1;\n\n/** When the plan changes by itself: its next scheduled segment's release. */\nexport function nextRelease(plan: ReaderPlan | null, now = Date.now()): number | null {\n const at = (plan?.segments ?? []).flatMap((s) => (!s.released && s.release_at ? [Date.parse(s.release_at)] : [])).filter((t) => t > now);\n return at.length ? Math.min(...at) : null;\n}\n\n/**\n * A version's reader plan for this viewer: its segments (released or not,\n * open or locked), previews, playback item and reader metadata. It asks again\n * while the version is being published and when its next segment is released.\n */\nexport function useReaderPlan(content: string | null | undefined, version: string | null | undefined, o: { poll?: number; client?: ContentKitClient } = {}): UseReaderPlan {\n const { client, store, scope } = useContentScope(o.client);\n const key = content && version ? keyOf(\"reader-plan\", scope, content, version) : null;\n const r = useResource<ReaderPlan | Pending>(store, key, { type: \"reader-plan\", id: version ?? undefined }, (s) => client.versions.reader(content!, version!, s));\n const pending = isPending(r.data);\n const plan = r.data && !pending ? (r.data as ReaderPlan) : null;\n const { data, reload } = r;\n // Every answer schedules the next look: a pending one polls, a plan waits for its next release.\n useEffect(() => {\n const at = isPending(data) ? Date.now() + (o.poll ?? 5000) : nextRelease(data ? (data as ReaderPlan) : null);\n if (at === null) return;\n const t = setTimeout(reload, Math.min(MAX_DELAY, Math.max(0, at - Date.now()) + 500));\n return () => clearTimeout(t);\n }, [data, reload, o.poll]);\n return { plan, pending, loading: !!key && (r.loading || !r.loaded), error: r.error, reload };\n}\n\n/** A segment's page with the URL of one rendition, once its item's read signed it. */\nexport interface ReaderPage {\n name: string;\n w: number;\n h: number;\n /** undefined until read, or when the page lacks the rendition. */\n url?: string;\n}\n\nexport interface UseSegmentPages {\n pages: ReaderPage[];\n loading: boolean;\n error?: ContentKitError;\n}\n\n/**\n * An open segment's pages with URLs of one rendition, read through its\n * published item (windowed for long segments, refreshed before the URLs expire).\n */\nexport function useSegmentPages(segment: PlanSegment | null | undefined, rendition: string, o: { window?: ReadWindow; client?: ContentKitClient } = {}): UseSegmentPages {\n const item = segment?.item ?? null;\n const read = useMediaRead(item ?? { kind: \"\", id: \"\" }, { window: o.window, read: item ? undefined : null, client: o.client });\n const pages = useMemo(() => {\n const urls = new Map((read.read?.files ?? []).flatMap((f) => (f.url ? [[f.path, f.url] as const] : [])));\n return (segment?.pages ?? []).map((p) => {\n const path = p.files[rendition];\n return { name: p.name, w: p.w, h: p.h, url: path ? urls.get(path) : undefined };\n });\n }, [segment, rendition, read.read]);\n return { pages, loading: !!item && read.loading, error: read.error };\n}\n\nexport interface UseVersionDownload {\n /** Prepares the zip (asking again while it is prepared) and resolves with it. */\n download: () => Promise<Blob>;\n /** Prepared by the server, waiting. */\n preparing: boolean;\n error?: ContentKitError;\n}\n\n/** A version's pages as a zip, charged to the viewer's download quota. */\nexport function useVersionDownload(content: string, version: string, o: { poll?: number; client?: ContentKitClient } = {}): UseVersionDownload {\n const { client } = useContentScope(o.client);\n const [preparing, setPreparing] = useState(false);\n const [error, setError] = useState<ContentKitError>();\n const download = useCallback(async () => {\n setError(undefined);\n setPreparing(true);\n try {\n for (;;) {\n const out = await client.versions.download(content, version);\n if (!isPending(out)) return out;\n await new Promise((r) => setTimeout(r, o.poll ?? 3000));\n }\n } catch (e) {\n const err = toContentKitError(e);\n setError(err);\n throw err;\n } finally {\n setPreparing(false);\n }\n }, [client, content, version, o.poll]);\n return { download, preparing, error };\n}\n"],"mappings":"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"}
|