@openrails/contentkit-ui 0.99.3 → 0.100.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -2
- package/dist/client/discovery.d.ts +6 -1
- package/dist/client/discovery.js +10 -7
- package/dist/client/discovery.js.map +1 -1
- package/dist/client/generated/wire.d.ts +1 -0
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/components/admin/group-manager.js +124 -117
- package/dist/components/admin/group-manager.js.map +1 -1
- package/dist/components/admin/user-comment-standing.js +8 -6
- package/dist/components/admin/user-comment-standing.js.map +1 -1
- package/dist/components/content/card.js +2 -2
- package/dist/components/content/card.js.map +1 -1
- package/dist/components/content/editors.d.ts +2 -2
- package/dist/components/content/editors.js +447 -328
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/filters.js +36 -18
- package/dist/components/content/filters.js.map +1 -1
- package/dist/components/content/grid.js +1 -1
- package/dist/components/content/grid.js.map +1 -1
- package/dist/components/content/popular.d.ts +3 -3
- package/dist/components/content/popular.js +15 -9
- package/dist/components/content/popular.js.map +1 -1
- package/dist/components/groups/directory.js +13 -7
- package/dist/components/groups/directory.js.map +1 -1
- package/dist/components/groups/memberships.js +13 -7
- package/dist/components/groups/memberships.js.map +1 -1
- package/dist/components/rendition-img.js +73 -55
- package/dist/components/rendition-img.js.map +1 -1
- package/dist/components/social/moderation.js +14 -5
- package/dist/components/social/moderation.js.map +1 -1
- package/dist/locales/discovery/de.js +1 -0
- package/dist/locales/discovery/de.js.map +1 -1
- package/dist/locales/discovery/en.d.ts +1 -0
- package/dist/locales/discovery/en.js +1 -0
- package/dist/locales/discovery/en.js.map +1 -1
- package/dist/locales/discovery/es.js +1 -0
- package/dist/locales/discovery/es.js.map +1 -1
- package/dist/locales/discovery/ja.js +1 -0
- package/dist/locales/discovery/ja.js.map +1 -1
- package/dist/locales/discovery/ko.js +1 -0
- package/dist/locales/discovery/ko.js.map +1 -1
- package/dist/locales/discovery/zh.js +1 -0
- package/dist/locales/discovery/zh.js.map +1 -1
- package/dist/locales/en.d.ts +1 -0
- package/dist/react/read.d.ts +3 -2
- package/dist/react/read.js +68 -61
- package/dist/react/read.js.map +1 -1
- package/package.json +1 -1
package/dist/react/read.js
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import { itemRef as e } from "../client/media/ref.js";
|
|
2
2
|
import { useOptionalContentKitClient as t, useReadScope as n } from "./context.js";
|
|
3
|
-
import { chunkOffsets as r, mergeReads as i, processing as
|
|
4
|
-
import { readKey as
|
|
5
|
-
import { useCallback as
|
|
3
|
+
import { chunkOffsets as r, mergeReads as i, processing as ee } from "../client/media/windows.js";
|
|
4
|
+
import { readKey as a, storeFor as o } from "./store.js";
|
|
5
|
+
import { useCallback as s, useEffect as c, useMemo as l, useRef as u, useState as d, useSyncExternalStore as te } from "react";
|
|
6
6
|
//#region src/react/read.ts
|
|
7
|
-
var
|
|
7
|
+
var f = 2500, p = [];
|
|
8
8
|
function m(m, h = {}) {
|
|
9
|
-
let { read: g, client: _, prefix: v, offset: y, limit: b, download: x, editor: S, window: C, refresh: w = !0 } = h, T = h.poll ?? (S ?
|
|
9
|
+
let { read: g, client: _, prefix: v, offset: y, limit: b, download: x, editor: S, window: C, refresh: w = !0 } = h, T = h.poll ?? (S ? f : !1), E = t(_), D = n(), O = E ? o(E) : null, k = C?.chunk ?? 50, A = D + a(m, {
|
|
10
10
|
prefix: v,
|
|
11
11
|
download: x,
|
|
12
12
|
editor: S
|
|
13
|
-
}) + (C ? `#${k}` : `#${y ?? 0}:${b ?? 0}`), [j, M] =
|
|
13
|
+
}) + (C ? `#${k}` : `#${y ?? 0}:${b ?? 0}`), [j, M] = d({
|
|
14
14
|
base: A,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
store: O,
|
|
16
|
+
read: null
|
|
17
|
+
}), N = j.base === A && j.store === O;
|
|
18
|
+
N || M({
|
|
18
19
|
base: A,
|
|
19
|
-
|
|
20
|
+
store: O,
|
|
21
|
+
read: null
|
|
20
22
|
});
|
|
21
|
-
let
|
|
23
|
+
let P = N ? j.n : void 0, F = C ? r(C.start, C.end, P ?? C.start + 1, k) : [], I = C ? F.length ? F : [0] : [y ?? 0], L = l(() => I.map((e) => ({
|
|
22
24
|
offset: e,
|
|
23
25
|
limit: C ? k : b
|
|
24
|
-
})), [
|
|
26
|
+
})), [I.join(","), C ? k : b]), R = l(() => L.map((e) => D + a(m, {
|
|
25
27
|
prefix: v,
|
|
26
28
|
download: x,
|
|
27
29
|
editor: S,
|
|
@@ -29,20 +31,20 @@ function m(m, h = {}) {
|
|
|
29
31
|
limit: e.limit
|
|
30
32
|
})), [
|
|
31
33
|
D,
|
|
32
|
-
|
|
34
|
+
L,
|
|
33
35
|
m.kind,
|
|
34
36
|
m.id,
|
|
35
37
|
m.version,
|
|
36
38
|
v,
|
|
37
39
|
x,
|
|
38
40
|
S
|
|
39
|
-
]), [
|
|
40
|
-
if (!O || !
|
|
41
|
-
let n =
|
|
41
|
+
]), [z, B] = d(null), [V, H] = d(null), U = z?.base === A && z.given === g ? z : null, W = !!O && (g === void 0 || !!U), G = s((t) => {
|
|
42
|
+
if (!O || !W) return () => {};
|
|
43
|
+
let n = R.map((n, r) => O.subscribe(n, e(m), {
|
|
42
44
|
prefix: v,
|
|
43
45
|
download: x,
|
|
44
46
|
editor: S,
|
|
45
|
-
...
|
|
47
|
+
...L[r]
|
|
46
48
|
}, t, {
|
|
47
49
|
poll: T,
|
|
48
50
|
refresh: w
|
|
@@ -50,91 +52,96 @@ function m(m, h = {}) {
|
|
|
50
52
|
return () => n.forEach((e) => e());
|
|
51
53
|
}, [
|
|
52
54
|
O,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
W,
|
|
56
|
+
R,
|
|
55
57
|
T,
|
|
56
58
|
w
|
|
57
|
-
]),
|
|
58
|
-
if (!O || !
|
|
59
|
-
let e =
|
|
60
|
-
return t.length === e.length && t.every((t, n) => t === e[n]) ? t :
|
|
59
|
+
]), K = u(p), q = s(() => {
|
|
60
|
+
if (!O || !W) return p;
|
|
61
|
+
let e = R.map((e) => O.snapshot(e)), t = K.current;
|
|
62
|
+
return t.length === e.length && t.every((t, n) => t === e[n]) ? t : K.current = e;
|
|
61
63
|
}, [
|
|
62
64
|
O,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
]),
|
|
66
|
-
|
|
67
|
-
if (O &&
|
|
65
|
+
W,
|
|
66
|
+
R
|
|
67
|
+
]), J = te(G, q, q);
|
|
68
|
+
c(() => {
|
|
69
|
+
if (O && W) for (let e of R) O.load(e, U ? "reload" : "initial");
|
|
68
70
|
}, [
|
|
69
71
|
O,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
W,
|
|
73
|
+
R,
|
|
74
|
+
U
|
|
73
75
|
]);
|
|
74
|
-
let
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
let Y = l(() => i(J.map((e) => e.read)), [J]), X = J.some((e) => !!e.error);
|
|
77
|
+
c(() => {
|
|
78
|
+
let e = X ? null : Y;
|
|
79
|
+
C && (X || Y || J.length && J.every((e) => e.loaded)) && M((t) => t.base === A && t.store === O && t.read === e ? t : {
|
|
77
80
|
base: A,
|
|
78
|
-
|
|
81
|
+
store: O,
|
|
82
|
+
read: e,
|
|
83
|
+
n: Y?.total ?? (t.base === A && t.store === O ? t.n : void 0)
|
|
79
84
|
});
|
|
80
85
|
}, [
|
|
81
|
-
C,
|
|
86
|
+
!!C,
|
|
87
|
+
Y,
|
|
82
88
|
X,
|
|
83
|
-
|
|
84
|
-
A
|
|
89
|
+
J,
|
|
90
|
+
A,
|
|
91
|
+
O
|
|
85
92
|
]);
|
|
86
|
-
let
|
|
87
|
-
if (g !== void 0)
|
|
93
|
+
let ne = s(() => {
|
|
94
|
+
if (g !== void 0) B({
|
|
88
95
|
base: A,
|
|
89
96
|
given: g
|
|
90
97
|
});
|
|
91
|
-
else if (O) for (let e of
|
|
92
|
-
|
|
98
|
+
else if (O) for (let e of R) O.load(e, "reload");
|
|
99
|
+
H(null);
|
|
93
100
|
}, [
|
|
94
101
|
O,
|
|
95
|
-
|
|
102
|
+
R,
|
|
96
103
|
A,
|
|
97
104
|
g
|
|
98
|
-
]),
|
|
99
|
-
if (g !== void 0 && !
|
|
105
|
+
]), re = s(() => {
|
|
106
|
+
if (g !== void 0 && !U) B({
|
|
100
107
|
base: A,
|
|
101
108
|
given: g
|
|
102
109
|
});
|
|
103
|
-
else if (O) for (let e of
|
|
110
|
+
else if (O) for (let e of R) O.load(e, "refresh");
|
|
104
111
|
}, [
|
|
105
112
|
O,
|
|
106
|
-
|
|
113
|
+
R,
|
|
107
114
|
A,
|
|
108
115
|
g,
|
|
109
|
-
|
|
110
|
-
]),
|
|
111
|
-
if (O &&
|
|
112
|
-
else
|
|
116
|
+
U
|
|
117
|
+
]), ie = s((e) => {
|
|
118
|
+
if (O && W) for (let t of R) O.set(t, e);
|
|
119
|
+
else H({
|
|
113
120
|
base: A,
|
|
114
121
|
given: g,
|
|
115
122
|
read: e
|
|
116
123
|
});
|
|
117
124
|
}, [
|
|
118
125
|
O,
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
W,
|
|
127
|
+
R,
|
|
121
128
|
A,
|
|
122
129
|
g
|
|
123
130
|
]), Z, Q = !1, $;
|
|
124
|
-
if (
|
|
125
|
-
else if (!
|
|
131
|
+
if (V && V.base === A && V.given === g) Z = V.read;
|
|
132
|
+
else if (!J.length) Z = g ?? null;
|
|
126
133
|
else {
|
|
127
|
-
let e =
|
|
128
|
-
Z =
|
|
134
|
+
let e = J.every((e) => e.loaded);
|
|
135
|
+
Z = Y ?? (e ? null : g ?? (C && N && !X ? j.read : null)), Q = J.some((e) => e.loading || !e.loaded), $ = J.find((e) => e.error)?.error;
|
|
129
136
|
}
|
|
130
137
|
return {
|
|
131
138
|
read: Z,
|
|
132
139
|
loading: Q,
|
|
133
140
|
error: $,
|
|
134
|
-
processing:
|
|
135
|
-
reload:
|
|
136
|
-
refresh:
|
|
137
|
-
set:
|
|
141
|
+
processing: ee(Z),
|
|
142
|
+
reload: ne,
|
|
143
|
+
refresh: re,
|
|
144
|
+
set: ie
|
|
138
145
|
};
|
|
139
146
|
}
|
|
140
147
|
//#endregion
|
package/dist/react/read.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.js","names":[],"sources":["../../src/react/read.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type { ReadResult, RefBody } from \"../client/generated/wire.js\";\nimport type { ReadOptions } from \"../client/media/api.js\";\nimport { chunkOffsets, mergeReads, processing as isProcessing, READ_CHUNK } from \"../client/media/windows.js\";\nimport { itemRef } from \"../client/media/ref.js\";\nimport { useOptionalContentKitClient, useReadScope } from \"./context.js\";\nimport { readKey, storeFor, type ReadEntry } from \"./store.js\";\n\n/** Files [start, end) get URLs. */\nexport interface ReadWindow {\n start: number;\n end: number;\n /** Files per read. Default 50. */\n chunk?: number;\n}\n\nexport interface MediaReadOptions extends Omit<ReadOptions, \"offset\" | \"limit\"> {\n /**\n * Read in windows of `chunk` files and merge them: the files in\n * [start, end) get URLs, and windows once read stay loaded (and refreshed)\n * until the item or options change. Without it, one read of the server's\n * default range (or offset and limit).\n */\n window?: ReadWindow;\n offset?: number;\n limit?: number;\n /** Poll at this interval (ms) while uploads process. Default 2500 for editor reads, else off. */\n poll?: number | false;\n /** Read again shortly before the URLs expire. Default true. */\n refresh?: boolean;\n /** A read the host already has: shown until reload() or set(). */\n read?: ReadResult | null;\n /** Overrides the provider's client. */\n client?: ContentKitClient | null;\n}\n\nexport interface UseMediaRead {\n /** The read (windows merged); null until it loads or when it failed. */\n read: ReadResult | null;\n loading: boolean;\n error?: ContentKitError;\n /** Uploads are still processing (editor reads). */\n processing: boolean;\n /** Reads again now, restarting a read in flight. */\n reload: () => void;\n /** Reads again unless a read is in flight: a player's grant refresh. */\n refresh: () => void;\n /** Replaces the read without refetching, for every hook showing it. */\n set: (r: ReadResult) => void;\n}\n\nconst POLL = 2500;\nconst NONE: readonly ReadEntry[] = [];\n\n/**\n * A read of the item, shared with every hook reading the same item and\n * options: refreshed before its URLs expire, retried after a read rate limit,\n * polled while uploads process, reloaded after a commit through the client.\n * A window splits it into merged reads. Without a client (none passed, no\n * provider) it only shows a supplied read.\n */\nexport function useMediaRead(ref: RefBody, o: MediaReadOptions = {}): UseMediaRead {\n const { read: given, client: own, prefix, offset, limit, download, editor, window, refresh: refreshing = true } = o;\n const poll = o.poll ?? (editor ? POLL : false);\n const client = useOptionalContentKitClient(own);\n const scope = useReadScope();\n const store = client ? storeFor(client) : null;\n const chunk = window?.chunk ?? READ_CHUNK;\n const base = scope + readKey(ref, { prefix, download, editor }) + (window ? `#${chunk}` : `#${offset ?? 0}:${limit ?? 0}`);\n\n // Windows once wanted stay loaded until the item or options change.\n const [total, setTotal] = useState<{ base: string; n?: number }>({ base });\n const known = total.base === base ? total.n : undefined;\n // Until the first read states the total, only the window's first chunk.\n const wanted = window ? chunkOffsets(window.start, window.end, known ?? window.start + 1, chunk) : [];\n const [kept, setKept] = useState<{ base: string; offsets: number[] }>({ base, offsets: [] });\n const prior = kept.base === base ? kept.offsets : [];\n if (window && (kept.base !== base || wanted.some((w) => !prior.includes(w)))) {\n setKept({ base, offsets: [...new Set([...prior, ...wanted])].sort((a, b) => a - b) });\n }\n const offsets = window ? (prior.length ? prior : wanted.length ? wanted : [0]) : [offset ?? 0];\n const windows = useMemo(\n () => offsets.map((off) => ({ offset: off, limit: window ? chunk : limit })),\n // offsets is derived from the stable kept list\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [offsets.join(\",\"), window ? chunk : limit],\n );\n const keys = useMemo(() => windows.map((w) => scope + readKey(ref, { prefix, download, editor, offset: w.offset, limit: w.limit })), [scope, windows, ref.kind, ref.id, ref.version, prefix, download, editor]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // A supplied read is shown until reload() asks the server or set() replaces it.\n const [requested, setRequested] = useState<{ base: string; given?: ReadResult | null } | null>(null);\n const [local, setLocal] = useState<{ base: string; given?: ReadResult | null; read: ReadResult } | null>(null);\n const asked = requested?.base === base && requested.given === given ? requested : null;\n const fetching = !!store && (given === undefined || !!asked);\n\n const subscribe = useCallback(\n (l: () => void) => {\n if (!store || !fetching) return () => {};\n const offs = keys.map((key, i) => store.subscribe(key, itemRef(ref), { prefix, download, editor, ...windows[i] }, l, { poll, refresh: refreshing }, scope));\n return () => offs.forEach((off) => off());\n },\n // ref and options are in keys.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, fetching, keys, poll, refreshing],\n );\n const last = useRef<readonly ReadEntry[]>(NONE);\n const snapshot = useCallback(() => {\n if (!store || !fetching) return NONE;\n const next = keys.map((k) => store.snapshot(k));\n const prev = last.current;\n if (prev.length === next.length && prev.every((e, i) => e === next[i])) return prev;\n return (last.current = next);\n }, [store, fetching, keys]);\n const entries = useSyncExternalStore(subscribe, snapshot, snapshot);\n useEffect(() => {\n if (store && fetching) for (const k of keys) store.load(k, asked ? \"reload\" : \"initial\");\n }, [store, fetching, keys, asked]);\n\n const merged = useMemo(() => mergeReads(entries.map((e) => e.read)), [entries]);\n useEffect(() => {\n if (window && merged && merged.total !== known) setTotal({ base, n: merged.total });\n }, [window, merged, known, base]);\n\n const reload = useCallback(() => {\n if (given !== undefined) setRequested({ base, given });\n else if (store) for (const k of keys) store.load(k, \"reload\");\n setLocal(null);\n }, [store, keys, base, given]);\n const refresh = useCallback(() => {\n if (given !== undefined && !asked) setRequested({ base, given });\n else if (store) for (const k of keys) store.load(k, \"refresh\");\n }, [store, keys, base, given, asked]);\n const set = useCallback(\n (read: ReadResult) => {\n if (store && fetching) for (const k of keys) store.set(k, read);\n else setLocal({ base, given, read });\n },\n [store, fetching, keys, base, given],\n );\n\n let read: ReadResult | null;\n let loading = false;\n let error: ContentKitError | undefined;\n if (local && local.base === base && local.given === given) read = local.read;\n else if (!entries.length) read = given ?? null;\n else {\n const loaded = entries.every((e) => e.loaded);\n read = merged ?? (loaded ? null : (given ?? null));\n loading = entries.some((e) => e.loading || !e.loaded);\n error = entries.find((e) => e.error)?.error;\n }\n return { read, loading, error, processing: isProcessing(read), reload, refresh, set };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"read.js","names":[],"sources":["../../src/react/read.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type { ReadResult, RefBody } from \"../client/generated/wire.js\";\nimport type { ReadOptions } from \"../client/media/api.js\";\nimport { chunkOffsets, mergeReads, processing as isProcessing, READ_CHUNK } from \"../client/media/windows.js\";\nimport { itemRef } from \"../client/media/ref.js\";\nimport { useOptionalContentKitClient, useReadScope } from \"./context.js\";\nimport { readKey, storeFor, type ReadEntry } from \"./store.js\";\n\n/** Files [start, end) get URLs. */\nexport interface ReadWindow {\n start: number;\n end: number;\n /** Files per read. Default 50. */\n chunk?: number;\n}\n\nexport interface MediaReadOptions extends Omit<ReadOptions, \"offset\" | \"limit\"> {\n /**\n * Read in windows of `chunk` files and merge them: the files in\n * [start, end) get URLs. Only the requested windows stay active and refresh;\n * a prior read supplies placeholder metadata while the new range loads.\n * Without it, one read of the server's\n * default range (or offset and limit).\n */\n window?: ReadWindow;\n offset?: number;\n limit?: number;\n /** Poll at this interval (ms) while uploads process. Default 2500 for editor reads, else off. */\n poll?: number | false;\n /** Read again shortly before the URLs expire. Default true. */\n refresh?: boolean;\n /** A read the host already has: shown until reload() or set(). */\n read?: ReadResult | null;\n /** Overrides the provider's client. */\n client?: ContentKitClient | null;\n}\n\nexport interface UseMediaRead {\n /** The read (windows merged); null until it loads or when it failed. */\n read: ReadResult | null;\n loading: boolean;\n error?: ContentKitError;\n /** Uploads are still processing (editor reads). */\n processing: boolean;\n /** Reads again now, restarting a read in flight. */\n reload: () => void;\n /** Reads again unless a read is in flight: a player's grant refresh. */\n refresh: () => void;\n /** Replaces the read without refetching, for every hook showing it. */\n set: (r: ReadResult) => void;\n}\n\nconst POLL = 2500;\nconst NONE: readonly ReadEntry[] = [];\n\n/**\n * A read of the item, shared with every hook reading the same item and\n * options: refreshed before its URLs expire, retried after a read rate limit,\n * polled while uploads process, reloaded after a commit through the client.\n * A window splits it into merged reads. Without a client (none passed, no\n * provider) it only shows a supplied read.\n */\nexport function useMediaRead(ref: RefBody, o: MediaReadOptions = {}): UseMediaRead {\n const { read: given, client: own, prefix, offset, limit, download, editor, window, refresh: refreshing = true } = o;\n const poll = o.poll ?? (editor ? POLL : false);\n const client = useOptionalContentKitClient(own);\n const scope = useReadScope();\n const store = client ? storeFor(client) : null;\n const chunk = window?.chunk ?? READ_CHUNK;\n const base = scope + readKey(ref, { prefix, download, editor }) + (window ? `#${chunk}` : `#${offset ?? 0}:${limit ?? 0}`);\n\n // Keep one placeholder, never subscriptions for the reader's visit history.\n const [previous, setPrevious] = useState<{ base: string; store: typeof store; read: ReadResult | null; n?: number }>({ base, store, read: null });\n const same = previous.base === base && previous.store === store;\n if (!same) setPrevious({ base, store, read: null });\n const known = same ? previous.n : undefined;\n // Until the first read states the total, only the window's first chunk.\n const wanted = window ? chunkOffsets(window.start, window.end, known ?? window.start + 1, chunk) : [];\n const offsets = window ? (wanted.length ? wanted : [0]) : [offset ?? 0];\n const windows = useMemo(\n () => offsets.map((off) => ({ offset: off, limit: window ? chunk : limit })),\n // Window identity depends on its values, not the caller's array identity.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [offsets.join(\",\"), window ? chunk : limit],\n );\n const keys = useMemo(() => windows.map((w) => scope + readKey(ref, { prefix, download, editor, offset: w.offset, limit: w.limit })), [scope, windows, ref.kind, ref.id, ref.version, prefix, download, editor]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // A supplied read is shown until reload() asks the server or set() replaces it.\n const [requested, setRequested] = useState<{ base: string; given?: ReadResult | null } | null>(null);\n const [local, setLocal] = useState<{ base: string; given?: ReadResult | null; read: ReadResult } | null>(null);\n const asked = requested?.base === base && requested.given === given ? requested : null;\n const fetching = !!store && (given === undefined || !!asked);\n\n const subscribe = useCallback(\n (l: () => void) => {\n if (!store || !fetching) return () => {};\n const offs = keys.map((key, i) => store.subscribe(key, itemRef(ref), { prefix, download, editor, ...windows[i] }, l, { poll, refresh: refreshing }, scope));\n return () => offs.forEach((off) => off());\n },\n // ref and options are in keys.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, fetching, keys, poll, refreshing],\n );\n const last = useRef<readonly ReadEntry[]>(NONE);\n const snapshot = useCallback(() => {\n if (!store || !fetching) return NONE;\n const next = keys.map((k) => store.snapshot(k));\n const prev = last.current;\n if (prev.length === next.length && prev.every((e, i) => e === next[i])) return prev;\n return (last.current = next);\n }, [store, fetching, keys]);\n const entries = useSyncExternalStore(subscribe, snapshot, snapshot);\n useEffect(() => {\n if (store && fetching) for (const k of keys) store.load(k, asked ? \"reload\" : \"initial\");\n }, [store, fetching, keys, asked]);\n\n const merged = useMemo(() => mergeReads(entries.map((e) => e.read)), [entries]);\n const failed = entries.some((e) => !!e.error);\n useEffect(() => {\n const read = failed ? null : merged;\n if (window && (failed || merged || (entries.length && entries.every((e) => e.loaded)))) {\n setPrevious((prev) => prev.base === base && prev.store === store && prev.read === read ? prev : {\n base, store, read, n: merged?.total ?? (prev.base === base && prev.store === store ? prev.n : undefined),\n });\n }\n }, [!!window, merged, failed, entries, base, store]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const reload = useCallback(() => {\n if (given !== undefined) setRequested({ base, given });\n else if (store) for (const k of keys) store.load(k, \"reload\");\n setLocal(null);\n }, [store, keys, base, given]);\n const refresh = useCallback(() => {\n if (given !== undefined && !asked) setRequested({ base, given });\n else if (store) for (const k of keys) store.load(k, \"refresh\");\n }, [store, keys, base, given, asked]);\n const set = useCallback(\n (read: ReadResult) => {\n if (store && fetching) for (const k of keys) store.set(k, read);\n else setLocal({ base, given, read });\n },\n [store, fetching, keys, base, given],\n );\n\n let read: ReadResult | null;\n let loading = false;\n let error: ContentKitError | undefined;\n if (local && local.base === base && local.given === given) read = local.read;\n else if (!entries.length) read = given ?? null;\n else {\n const loaded = entries.every((e) => e.loaded);\n read = merged ?? (loaded ? null : (given ?? (window && same && !failed ? previous.read : null)));\n loading = entries.some((e) => e.loading || !e.loaded);\n error = entries.find((e) => e.error)?.error;\n }\n return { read, loading, error, processing: isProcessing(read), reload, refresh, set };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED