@openrails/contentkit-ui 0.98.6 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +26 -0
  2. package/dist/client/content/comments.d.ts +4 -2
  3. package/dist/client/content/comments.js +10 -6
  4. package/dist/client/content/comments.js.map +1 -1
  5. package/dist/client/generated/routes.d.ts +28 -2
  6. package/dist/client/generated/routes.js +39 -2
  7. package/dist/client/generated/routes.js.map +1 -1
  8. package/dist/client/generated/wire.d.ts +85 -0
  9. package/dist/client/generated/wire.js.map +1 -1
  10. package/dist/client/media/client.d.ts +4 -0
  11. package/dist/client/media/client.js +8 -4
  12. package/dist/client/media/client.js.map +1 -1
  13. package/dist/client/media/queue.js +42 -26
  14. package/dist/client/media/queue.js.map +1 -1
  15. package/dist/client/media/rules.d.ts +6 -0
  16. package/dist/client/media/rules.js +64 -10
  17. package/dist/client/media/rules.js.map +1 -1
  18. package/dist/client/versions.d.ts +6 -2
  19. package/dist/client/versions.js +26 -0
  20. package/dist/client/versions.js.map +1 -1
  21. package/dist/components/admin/page-review.d.ts +13 -0
  22. package/dist/components/admin/page-review.js +216 -0
  23. package/dist/components/admin/page-review.js.map +1 -0
  24. package/dist/components/content/card.js +98 -103
  25. package/dist/components/content/card.js.map +1 -1
  26. package/dist/components/content/daily-releases.d.ts +8 -1
  27. package/dist/components/content/daily-releases.js +291 -133
  28. package/dist/components/content/daily-releases.js.map +1 -1
  29. package/dist/components/content/editors.js +216 -210
  30. package/dist/components/content/editors.js.map +1 -1
  31. package/dist/components/content/filter-dialog.d.ts +11 -0
  32. package/dist/components/content/filter-dialog.js +29 -0
  33. package/dist/components/content/filter-dialog.js.map +1 -0
  34. package/dist/components/content/filters.d.ts +10 -0
  35. package/dist/components/content/filters.js +5 -2
  36. package/dist/components/content/filters.js.map +1 -1
  37. package/dist/components/content/grid.js +19 -14
  38. package/dist/components/content/grid.js.map +1 -1
  39. package/dist/components/content/index.d.ts +2 -1
  40. package/dist/components/content/release-reveal.d.ts +5 -0
  41. package/dist/components/content/release-reveal.js +62 -0
  42. package/dist/components/content/release-reveal.js.map +1 -0
  43. package/dist/components/social/comments.d.ts +1 -1
  44. package/dist/components/social/comments.js +15 -15
  45. package/dist/components/social/comments.js.map +1 -1
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.js +24 -22
  48. package/dist/locales/admin/de.js +23 -0
  49. package/dist/locales/admin/de.js.map +1 -1
  50. package/dist/locales/admin/en.d.ts +23 -0
  51. package/dist/locales/admin/en.js +23 -0
  52. package/dist/locales/admin/en.js.map +1 -1
  53. package/dist/locales/admin/es.js +23 -0
  54. package/dist/locales/admin/es.js.map +1 -1
  55. package/dist/locales/admin/ja.js +23 -0
  56. package/dist/locales/admin/ja.js.map +1 -1
  57. package/dist/locales/admin/ko.js +23 -0
  58. package/dist/locales/admin/ko.js.map +1 -1
  59. package/dist/locales/admin/zh.js +23 -0
  60. package/dist/locales/admin/zh.js.map +1 -1
  61. package/dist/locales/discovery/de.js +11 -0
  62. package/dist/locales/discovery/de.js.map +1 -1
  63. package/dist/locales/discovery/en.d.ts +11 -0
  64. package/dist/locales/discovery/en.js +11 -0
  65. package/dist/locales/discovery/en.js.map +1 -1
  66. package/dist/locales/discovery/es.js +11 -0
  67. package/dist/locales/discovery/es.js.map +1 -1
  68. package/dist/locales/discovery/ja.js +11 -0
  69. package/dist/locales/discovery/ja.js.map +1 -1
  70. package/dist/locales/discovery/ko.js +11 -0
  71. package/dist/locales/discovery/ko.js.map +1 -1
  72. package/dist/locales/discovery/zh.js +11 -0
  73. package/dist/locales/discovery/zh.js.map +1 -1
  74. package/dist/locales/en.d.ts +34 -0
  75. package/dist/locales/social/en.js +2 -2
  76. package/dist/locales/social/en.js.map +1 -1
  77. package/dist/react/comments.d.ts +2 -1
  78. package/dist/react/comments.js +10 -8
  79. package/dist/react/comments.js.map +1 -1
  80. package/dist/react/folder.js +39 -39
  81. package/dist/react/folder.js.map +1 -1
  82. package/dist/react/index.d.ts +1 -0
  83. package/dist/react/page-review.d.ts +14 -0
  84. package/dist/react/page-review.js +36 -0
  85. package/dist/react/page-review.js.map +1 -0
  86. package/dist/react/public.d.ts +3 -1
  87. package/dist/react/public.js +76 -72
  88. package/dist/react/public.js.map +1 -1
  89. package/dist/react/resources.d.ts +5 -13
  90. package/dist/react/resources.js +58 -49
  91. package/dist/react/resources.js.map +1 -1
  92. package/dist/react/use-resource.d.ts +1 -1
  93. package/dist/react/use-resource.js +23 -13
  94. package/dist/react/use-resource.js.map +1 -1
  95. package/dist/react/versions.js +70 -42
  96. package/dist/react/versions.js.map +1 -1
  97. package/dist/react.js +8 -7
  98. package/dist/styles.css +1 -1
  99. package/package.json +1 -1
@@ -1,91 +1,95 @@
1
1
  import { defaultImage as e, isPattern as t, ruleDir as n, stableImage as r } from "../client/media/rules.js";
2
2
  import { useOptionalContentKitClient as i, useReadScope as a } from "./context.js";
3
- import { useContentScope as o } from "./use-resource.js";
4
- import { useKinds as s } from "./groups.js";
5
- import { useMediaRead as c } from "./read.js";
6
- import { useEffect as l, useMemo as u, useState as d } from "react";
3
+ import { resourcesFor as o } from "./resources.js";
4
+ import { keyOf as s, useContentScope as c, useResource as l } from "./use-resource.js";
5
+ import { useKinds as u } from "./groups.js";
6
+ import { useMediaRead as d } from "./read.js";
7
+ import { useCallback as f, useEffect as p, useMemo as m, useState as h } from "react";
7
8
  //#region src/react/public.ts
8
- var f = /* @__PURE__ */ new WeakMap(), p = /* @__PURE__ */ new WeakMap();
9
- function m(e = {}) {
10
- let t = i(e.client), [, n] = d(0), r = t ? f.get(t) : void 0;
11
- return l(() => {
12
- if (!t || f.has(t)) return;
13
- let e = !0, r = p.get(t);
14
- return r || (r = t.media.presets().then((e) => void f.set(t, { presets: e }), (e) => void f.set(t, {
15
- presets: [],
16
- error: e
17
- })).finally(() => p.delete(t)), p.set(t, r)), r.then(() => e && n((e) => e + 1)), () => {
18
- e = !1;
19
- };
20
- }, [t]), {
21
- presets: r?.presets ?? [],
22
- loaded: !!r || !t,
23
- error: r?.error
9
+ var g = /* @__PURE__ */ new WeakMap();
10
+ function _(e = {}) {
11
+ let t = i(e.client), n = t ? o(t) : null, r = t ? s("presets") : null, a = t ? g.get(t) : void 0, c = l(n, r, { type: "presets" }, async () => {
12
+ let e = await t.media.presets();
13
+ return g.set(t, e), e;
14
+ }, { initial: a });
15
+ return p(() => {
16
+ r && n?.snapshot(r).error && n.load(r, !0);
17
+ }, [r, n]), {
18
+ presets: c.data ?? [],
19
+ loaded: c.loaded || !!a || !t,
20
+ error: c.error,
21
+ reload: c.reload
24
22
  };
25
23
  }
26
- function h(r, a, o = {}) {
27
- let { kind: s, id: l, version: d } = r, f = i(o.client), { presets: p, loaded: h } = m({ client: f }), g = p.find((e) => e.kind === s && e.name === a), _ = o.image !== void 0, v = g ? t(g.from) ? n(g.from) : g.from : void 0, y = c(r, {
28
- prefix: v,
29
- read: _ || !h ? null : o.read,
30
- client: f
31
- });
24
+ function v(r, a, o = {}) {
25
+ let { kind: s, id: c, version: l } = r, u = i(o.client), { presets: p, loaded: h, error: g, reload: v } = _({ client: u }), y = p.find((e) => e.kind === s && e.name === a), b = o.image !== void 0, x = y ? t(y.from) ? n(y.from) : y.from : void 0, S = d(r, {
26
+ prefix: x,
27
+ read: b || !h ? null : o.read,
28
+ client: u
29
+ }), C = m(() => {
30
+ let t = b ? o.image : S.read?.public?.find((e) => e.preset === a);
31
+ if (t && t.renditions.length) return {
32
+ image: {
33
+ preset: a,
34
+ renditions: t.renditions,
35
+ aspect: "aspect" in t && t.aspect || y?.aspect
36
+ },
37
+ isDefault: !1
38
+ };
39
+ if (!b && !S.read) return {
40
+ image: null,
41
+ isDefault: !1
42
+ };
43
+ let n = y && e(y, c, l);
44
+ return n ? {
45
+ image: n,
46
+ isDefault: !0
47
+ } : {
48
+ image: null,
49
+ isDefault: !1
50
+ };
51
+ }, [
52
+ b,
53
+ o.image,
54
+ S.read,
55
+ a,
56
+ y,
57
+ c,
58
+ l
59
+ ]), w = S.reload, T = f(() => {
60
+ g && v(), w();
61
+ }, [
62
+ g,
63
+ v,
64
+ w
65
+ ]);
32
66
  return {
33
- ...u(() => {
34
- let t = _ ? o.image : y.read?.public?.find((e) => e.preset === a);
35
- if (t && t.renditions.length) return {
36
- image: {
37
- preset: a,
38
- renditions: t.renditions,
39
- aspect: "aspect" in t && t.aspect || g?.aspect
40
- },
41
- isDefault: !1
42
- };
43
- if (!_ && !y.read) return {
44
- image: null,
45
- isDefault: !1
46
- };
47
- let n = g && e(g, l, d);
48
- return n ? {
49
- image: n,
50
- isDefault: !0
51
- } : {
52
- image: null,
53
- isDefault: !1
54
- };
55
- }, [
56
- _,
57
- o.image,
58
- y.read,
59
- a,
60
- g,
61
- l,
62
- d
63
- ]),
64
- rule: g,
65
- loading: !h || y.loading,
66
- error: y.error,
67
- reload: y.reload
67
+ ...C,
68
+ rule: y,
69
+ loading: !h || S.loading,
70
+ error: S.error ?? g,
71
+ reload: T
68
72
  };
69
73
  }
70
- function g(e, i = {}) {
71
- let { client: f, viewer: p } = o(i.client), m = a(), { kinds: h } = s({ client: f }), g = h?.avatars, _ = !!g && !!e && e === p, v = g ? t(g.from) ? n(g.from) : g.from : void 0, y = c({
74
+ function y(e, i = {}) {
75
+ let { client: o, viewer: s } = c(i.client), l = a(), { kinds: f } = u({ client: o }), g = f?.avatars, _ = !!g && !!e && e === s, v = g ? t(g.from) ? n(g.from) : g.from : void 0, y = d({
72
76
  kind: g?.kind ?? "",
73
77
  id: e ?? ""
74
78
  }, {
75
- client: f,
79
+ client: o,
76
80
  prefix: v,
77
81
  read: _ ? void 0 : null
78
- }), [b, x] = d(null);
79
- !_ && b && x(null), _ && y.read && (b?.read !== y.read || b.client !== f || b.scope !== m || b.id !== e) && x({
80
- client: f,
81
- scope: m,
82
+ }), [b, x] = h(null);
83
+ !_ && b && x(null), _ && y.read && (b?.read !== y.read || b.client !== o || b.scope !== l || b.id !== e) && x({
84
+ client: o,
85
+ scope: l,
82
86
  id: e,
83
87
  read: y.read
84
88
  });
85
89
  let S = y.error && (y.error.transient || y.error.status >= 500);
86
90
  _ && y.error && !S && b && x(null);
87
- let { refresh: C } = y, w = y.read ?? (_ && (y.loading || S) && b?.client === f && b.scope === m && b.id === e ? b.read : null);
88
- return l(() => {
91
+ let { refresh: C } = y, w = y.read ?? (_ && (y.loading || S) && b?.client === o && b.scope === l && b.id === e ? b.read : null);
92
+ return p(() => {
89
93
  if (!_) return;
90
94
  let e = () => {
91
95
  document.visibilityState === "visible" && C();
@@ -93,7 +97,7 @@ function g(e, i = {}) {
93
97
  return window.addEventListener("focus", C), document.addEventListener("visibilitychange", e), () => {
94
98
  window.removeEventListener("focus", C), document.removeEventListener("visibilitychange", e);
95
99
  };
96
- }, [_, C]), u(() => {
100
+ }, [_, C]), m(() => {
97
101
  if (!g || !e) return null;
98
102
  if (!_) return r(g, e);
99
103
  let t = w?.public?.find((e) => e.preset === g.name);
@@ -110,6 +114,6 @@ function g(e, i = {}) {
110
114
  ]);
111
115
  }
112
116
  //#endregion
113
- export { g as useAvatar, m as usePresets, h as usePublicImage };
117
+ export { y as useAvatar, _ as usePresets, v as usePublicImage };
114
118
 
115
119
  //# sourceMappingURL=public.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.js","names":[],"sources":["../../src/react/public.ts"],"sourcesContent":["import { useEffect, useMemo, useState } 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 { PresetRule } from \"../client/generated/wire.js\";\nimport { defaultImage, isPattern, ruleDir, stableImage } from \"../client/media/rules.js\";\nimport type { PublicPreset } from \"../client/public.js\";\nimport { useOptionalContentKitClient, useReadScope } from \"./context.js\";\nimport { useKinds } from \"./groups.js\";\nimport { useMediaRead } from \"./read.js\";\nimport { useContentScope } from \"./use-resource.js\";\n\nexport interface UsePresets {\n /** Every kind's public presets; empty until they load (or when the server has none). */\n presets: PresetRule[];\n loaded: boolean;\n error?: ContentKitError;\n}\n\nconst settled = new WeakMap<ContentKitClient, { presets: PresetRule[]; error?: ContentKitError }>();\nconst inflight = new WeakMap<ContentKitClient, Promise<void>>();\n\n/** The public presets (`GET /media/presets`), fetched once per client. */\nexport function usePresets(o: { client?: ContentKitClient | null } = {}): UsePresets {\n const client = useOptionalContentKitClient(o.client);\n const [, rerender] = useState(0);\n const done = client ? settled.get(client) : undefined;\n useEffect(() => {\n if (!client || settled.has(client)) return;\n let live = true;\n let load = inflight.get(client);\n if (!load) {\n load = client.media.presets().then(\n (presets) => void settled.set(client, { presets }),\n (error: ContentKitError) => void settled.set(client, { presets: [], error }),\n ).finally(() => inflight.delete(client));\n inflight.set(client, load);\n }\n void load.then(() => live && rerender((n) => n + 1));\n return () => {\n live = false;\n };\n }, [client]);\n return { presets: done?.presets ?? [], loaded: !!done || !client, error: done?.error };\n}\n\nexport interface PublicImageOptions {\n /** The host's listing of the item's image (its API's): shown without a read. */\n image?: PublicPreset | null;\n /** A read of the item the host already has. */\n read?: ReadResult | null;\n /** Overrides the provider's client. */\n client?: ContentKitClient | null;\n}\n\nexport interface UsePublicImage {\n /** The item's current renditions; else the kind's default image (when the preset has one); null while unknown or when there is neither. */\n image: PublicPreset | null;\n /** The preset's rules (aspect, widths, min_width) once the presets load. */\n rule?: PresetRule;\n /** image is the kind's default, not the item's own. */\n isDefault: boolean;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n/**\n * An item's public image for a preset (\"avatar\", \"cover\", a version's\n * \"poster\"): the exact renditions from a read's `public` (or the host's\n * listing), else the kind's default image, else none. Reads refresh after\n * commits through the same client.\n */\nexport function usePublicImage(item: RefBody, preset: string, o: PublicImageOptions = {}): UsePublicImage {\n const { kind, id, version } = item;\n const client = useOptionalContentKitClient(o.client);\n const { presets, loaded } = usePresets({ client });\n const rule = presets.find((p) => p.kind === kind && p.name === preset);\n const listed = o.image !== undefined;\n // The read waits for the presets, so it lists only the preset's upload.\n const prefix = rule ? (isPattern(rule.from) ? ruleDir(rule.from) : rule.from) : undefined;\n const r = useMediaRead(item, { prefix, read: listed || !loaded ? null : o.read, client });\n const image = useMemo((): { image: PublicPreset | null; isDefault: boolean } => {\n const own = listed ? o.image : r.read?.public?.find((p) => p.preset === preset);\n if (own && own.renditions.length) return { image: { preset, renditions: own.renditions, aspect: (\"aspect\" in own && own.aspect) || rule?.aspect }, isDefault: false };\n if (!listed && !r.read) return { image: null, isDefault: false };\n const def = rule && defaultImage(rule, id, version);\n return def ? { image: def, isDefault: true } : { image: null, isDefault: false };\n }, [listed, o.image, r.read, preset, rule, id, version]);\n return { ...image, rule, loading: !loaded || r.loading, error: r.error, reload: r.reload };\n}\n\n/**\n * A person's avatar. The signed-in viewer reads their current immutable\n * publication and follows upload/crop/removal events. Other accounts keep the\n * stable public URL without one API request per author in a listing.\n */\nexport function useAvatar(userId: string | null | undefined, o: { client?: ContentKitClient } = {}): PublicPreset | null {\n const { client, viewer } = useContentScope(o.client);\n const scope = useReadScope();\n const { kinds } = useKinds({ client });\n const rule = kinds?.avatars;\n const own = !!rule && !!userId && userId === viewer;\n const prefix = rule ? (isPattern(rule.from) ? ruleDir(rule.from) : rule.from) : undefined;\n const current = useMediaRead({ kind: rule?.kind ?? \"\", id: userId ?? \"\" }, { client, prefix, read: own ? undefined : null });\n const [last, setLast] = useState<{ client: ContentKitClient; scope: string; id: string; read: ReadResult } | null>(null);\n if (!own && last) setLast(null);\n if (own && current.read && (last?.read !== current.read || last.client !== client || last.scope !== scope || last.id !== userId)) {\n setLast({ client, scope, id: userId!, read: current.read });\n }\n const transient = current.error && (current.error.transient || current.error.status >= 500);\n if (own && current.error && !transient && last) setLast(null);\n const { refresh } = current;\n const read = current.read ?? (own && (current.loading || transient) && last?.client === client && last.scope === scope && last.id === userId ? last.read : null);\n\n\n // Another app can change the shared avatar while this tab is inactive.\n // The read store deduplicates refreshes from multiple consumers.\n useEffect(() => {\n if (!own) return;\n const visible = () => { if (document.visibilityState === \"visible\") refresh(); };\n window.addEventListener(\"focus\", refresh);\n document.addEventListener(\"visibilitychange\", visible);\n return () => {\n window.removeEventListener(\"focus\", refresh);\n document.removeEventListener(\"visibilitychange\", visible);\n };\n }, [own, refresh]);\n\n return useMemo(() => {\n if (!rule || !userId) return null;\n if (!own) return stableImage(rule, userId);\n const publication = read?.public?.find((p) => p.preset === rule.name);\n return publication?.renditions.length ? { preset: rule.name, aspect: rule.aspect, renditions: publication.renditions } : null;\n }, [rule, userId, own, read]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"public.js","names":[],"sources":["../../src/react/public.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } 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 { PresetRule } from \"../client/generated/wire.js\";\nimport { defaultImage, isPattern, ruleDir, stableImage } from \"../client/media/rules.js\";\nimport type { PublicPreset } from \"../client/public.js\";\nimport { useOptionalContentKitClient, useReadScope } from \"./context.js\";\nimport { useKinds } from \"./groups.js\";\nimport { useMediaRead } from \"./read.js\";\nimport { keyOf, useContentScope, useResource } from \"./use-resource.js\";\nimport { resourcesFor } from \"./resources.js\";\n\nexport interface UsePresets {\n /** Every kind's public presets; empty until they load (or when the server has none). */\n presets: PresetRule[];\n loaded: boolean;\n error?: ContentKitError;\n /** Retry a failed read; successful public presets remain cached. */\n reload: () => void;\n}\n\n// Seed remounts synchronously with successful, immutable public metadata.\n// Failures stay in the mounted resource and are never cached here.\nconst settled = new WeakMap<ContentKitClient, PresetRule[]>();\n\n/** Public presets, shared across consumers; failed reads can be retried. */\nexport function usePresets(o: { client?: ContentKitClient | null } = {}): UsePresets {\n const client = useOptionalContentKitClient(o.client);\n const store = client ? resourcesFor(client) : null;\n const key = client ? keyOf(\"presets\") : null;\n const initial = client ? settled.get(client) : undefined;\n const r = useResource<PresetRule[]>(store, key, { type: \"presets\" }, async () => {\n const presets = await client!.media.presets();\n settled.set(client!, presets);\n return presets;\n }, { initial });\n useEffect(() => {\n // A remount may join a failed slot before its deferred cleanup. Retry\n // once on mounting, rather than retrying continuously after each error.\n if (key && store?.snapshot(key).error) store.load(key, true);\n }, [key, store]);\n return { presets: r.data ?? [], loaded: r.loaded || !!initial || !client, error: r.error, reload: r.reload };\n}\n\nexport interface PublicImageOptions {\n /** The host's listing of the item's image (its API's): shown without a read. */\n image?: PublicPreset | null;\n /** A read of the item the host already has. */\n read?: ReadResult | null;\n /** Overrides the provider's client. */\n client?: ContentKitClient | null;\n}\n\nexport interface UsePublicImage {\n /** The item's current renditions; else the kind's default image (when the preset has one); null while unknown or when there is neither. */\n image: PublicPreset | null;\n /** The preset's rules (aspect, widths, min_width) once the presets load. */\n rule?: PresetRule;\n /** image is the kind's default, not the item's own. */\n isDefault: boolean;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n/**\n * An item's public image for a preset (\"avatar\", \"cover\", a version's\n * \"poster\"): the exact renditions from a read's `public` (or the host's\n * listing), else the kind's default image, else none. Reads refresh after\n * commits through the same client.\n */\nexport function usePublicImage(item: RefBody, preset: string, o: PublicImageOptions = {}): UsePublicImage {\n const { kind, id, version } = item;\n const client = useOptionalContentKitClient(o.client);\n const { presets, loaded, error: presetError, reload: reloadPresets } = usePresets({ client });\n const rule = presets.find((p) => p.kind === kind && p.name === preset);\n const listed = o.image !== undefined;\n // The read waits for the presets, so it lists only the preset's upload.\n const prefix = rule ? (isPattern(rule.from) ? ruleDir(rule.from) : rule.from) : undefined;\n const r = useMediaRead(item, { prefix, read: listed || !loaded ? null : o.read, client });\n const image = useMemo((): { image: PublicPreset | null; isDefault: boolean } => {\n const own = listed ? o.image : r.read?.public?.find((p) => p.preset === preset);\n if (own && own.renditions.length) return { image: { preset, renditions: own.renditions, aspect: (\"aspect\" in own && own.aspect) || rule?.aspect }, isDefault: false };\n if (!listed && !r.read) return { image: null, isDefault: false };\n const def = rule && defaultImage(rule, id, version);\n return def ? { image: def, isDefault: true } : { image: null, isDefault: false };\n }, [listed, o.image, r.read, preset, rule, id, version]);\n const reloadRead = r.reload;\n const reload = useCallback(() => { if (presetError) reloadPresets(); reloadRead(); }, [presetError, reloadPresets, reloadRead]);\n return { ...image, rule, loading: !loaded || r.loading, error: r.error ?? presetError, reload };\n}\n\n/**\n * A person's avatar. The signed-in viewer reads their current immutable\n * publication and follows upload/crop/removal events. Other accounts keep the\n * stable public URL without one API request per author in a listing.\n */\nexport function useAvatar(userId: string | null | undefined, o: { client?: ContentKitClient } = {}): PublicPreset | null {\n const { client, viewer } = useContentScope(o.client);\n const scope = useReadScope();\n const { kinds } = useKinds({ client });\n const rule = kinds?.avatars;\n const own = !!rule && !!userId && userId === viewer;\n const prefix = rule ? (isPattern(rule.from) ? ruleDir(rule.from) : rule.from) : undefined;\n const current = useMediaRead({ kind: rule?.kind ?? \"\", id: userId ?? \"\" }, { client, prefix, read: own ? undefined : null });\n const [last, setLast] = useState<{ client: ContentKitClient; scope: string; id: string; read: ReadResult } | null>(null);\n if (!own && last) setLast(null);\n if (own && current.read && (last?.read !== current.read || last.client !== client || last.scope !== scope || last.id !== userId)) {\n setLast({ client, scope, id: userId!, read: current.read });\n }\n const transient = current.error && (current.error.transient || current.error.status >= 500);\n if (own && current.error && !transient && last) setLast(null);\n const { refresh } = current;\n const read = current.read ?? (own && (current.loading || transient) && last?.client === client && last.scope === scope && last.id === userId ? last.read : null);\n\n\n // Another app can change the shared avatar while this tab is inactive.\n // The read store deduplicates refreshes from multiple consumers.\n useEffect(() => {\n if (!own) return;\n const visible = () => { if (document.visibilityState === \"visible\") refresh(); };\n window.addEventListener(\"focus\", refresh);\n document.addEventListener(\"visibilitychange\", visible);\n return () => {\n window.removeEventListener(\"focus\", refresh);\n document.removeEventListener(\"visibilitychange\", visible);\n };\n }, [own, refresh]);\n\n return useMemo(() => {\n if (!rule || !userId) return null;\n if (!own) return stableImage(rule, userId);\n const publication = read?.public?.find((p) => p.preset === rule.name);\n return publication?.renditions.length ? { preset: rule.name, aspect: rule.aspect, renditions: publication.renditions } : null;\n }, [rule, userId, own, read]);\n}\n"],"mappings":"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"}
@@ -22,21 +22,13 @@ export interface Tag {
22
22
  type: string;
23
23
  readScope?: string;
24
24
  target?: Target;
25
+ language?: string;
25
26
  id?: string;
26
27
  scope?: string;
27
28
  }
28
- interface Slot {
29
- tag: Tag;
30
- listeners: Set<() => void>;
31
- entry: Resource<unknown>;
32
- fetcher?: Fetcher<unknown>;
29
+ interface Binding {
30
+ fetcher: Fetcher<unknown>;
33
31
  more?: (cursor: string | number, signal: AbortSignal) => Promise<Page<unknown>>;
34
- ctl?: AbortController;
35
- moreCtl?: AbortController;
36
- /** Bumped by mark(): an optimistic write rolls back only if no newer one started. */
37
- version: number;
38
- /** Identifies the full read; item patches and appended pages retain it. */
39
- readVersion: number;
40
32
  }
41
33
  /**
42
34
  * The content reads hooks share, per client: one request per key while any
@@ -49,8 +41,8 @@ export declare class ResourceStore {
49
41
  constructor(client: ContentKitClient);
50
42
  subscribe(key: string, tag: Tag, listener: () => void): () => void;
51
43
  snapshot<T>(key: string): Resource<T>;
52
- /** The latest fetchers of a key: its first read, and a list's next page. */
53
- bind(key: string, fetcher: Fetcher<unknown>, more?: Slot["more"]): void;
44
+ /** Registers one subscriber's key-bound fetchers; cleanup releases only it. */
45
+ bind(key: string, fetcher: Fetcher<unknown>, more?: Binding["more"]): () => void;
54
46
  /** Fetches unless loaded or in flight; force refetches (a list from its first page). */
55
47
  load(key: string, force?: boolean): void;
56
48
  /** Appends a list's next page; resolves once it landed. */
@@ -1,63 +1,68 @@
1
1
  import { toContentKitError as e } from "../client/errors.js";
2
2
  import { sameTarget as t } from "../client/content/types.js";
3
3
  //#region src/react/resources.ts
4
- var n = {
4
+ var n = (e) => [...e.bindings.values()].at(-1), r = {
5
5
  data: void 0,
6
6
  loading: !1,
7
7
  loaded: !1
8
- }, r = class {
8
+ }, i = class {
9
9
  slots = /* @__PURE__ */ new Map();
10
10
  version = 0;
11
11
  constructor(e) {
12
12
  e.subscribe((e, t) => this.apply(e, t));
13
13
  }
14
- subscribe(e, t, r) {
14
+ subscribe(e, t, n) {
15
15
  let i = this.slots.get(e);
16
16
  i || this.slots.set(e, i = {
17
17
  tag: t,
18
18
  listeners: /* @__PURE__ */ new Set(),
19
- entry: n,
19
+ bindings: /* @__PURE__ */ new Map(),
20
+ entry: r,
20
21
  version: 0,
21
22
  readVersion: ++this.version
22
23
  });
23
24
  let a = i;
24
- return a.listeners.add(r), () => {
25
- a.listeners.delete(r), queueMicrotask(() => {
25
+ return a.listeners.add(n), () => {
26
+ a.listeners.delete(n), queueMicrotask(() => {
26
27
  a.listeners.size || this.slots.get(e) !== a || (a.ctl?.abort(), a.moreCtl?.abort(), this.slots.delete(e));
27
28
  });
28
29
  };
29
30
  }
30
31
  snapshot(e) {
31
- return this.slots.get(e)?.entry ?? n;
32
+ return this.slots.get(e)?.entry ?? r;
32
33
  }
33
34
  bind(e, t, n) {
34
35
  let r = this.slots.get(e);
35
- r && Object.assign(r, {
36
+ if (!r) return () => {};
37
+ let i = Symbol();
38
+ return r.bindings.set(i, {
36
39
  fetcher: t,
37
40
  more: n
38
- });
41
+ }), () => {
42
+ r.bindings.delete(i);
43
+ };
39
44
  }
40
- load(t, n = !1) {
41
- let r = this.slots.get(t);
42
- if (!r?.fetcher || !n && (r.entry.loaded || r.ctl)) return;
43
- r.ctl?.abort(), r.moreCtl?.abort(), r.moreCtl = void 0;
44
- let i = r.ctl = new AbortController();
45
- this.update(r, {
45
+ load(t, r = !1) {
46
+ let i = this.slots.get(t), a = i && n(i);
47
+ if (!i || !a || !r && (i.entry.loaded || i.ctl)) return;
48
+ i.ctl?.abort(), i.moreCtl?.abort(), i.moreCtl = void 0;
49
+ let o = i.ctl = new AbortController();
50
+ this.update(i, {
46
51
  loading: !0,
47
52
  loadingMore: !1,
48
53
  error: void 0
49
- }), r.fetcher(i.signal).then((e) => {
50
- r.ctl === i && (r.ctl = void 0, r.readVersion = ++this.version, this.update(r, {
54
+ }), a.fetcher(o.signal).then((e) => {
55
+ i.ctl === o && (i.ctl = void 0, i.readVersion = ++this.version, this.update(i, {
51
56
  data: e,
52
57
  loading: !1,
53
58
  loaded: !0,
54
59
  error: void 0
55
60
  }));
56
61
  }, (t) => {
57
- if (r.ctl !== i) return;
58
- r.ctl = void 0;
62
+ if (i.ctl !== o) return;
63
+ i.ctl = void 0;
59
64
  let n = e(t);
60
- n.code !== "aborted" && this.update(r, {
65
+ n.code !== "aborted" && this.update(i, {
61
66
  loading: !1,
62
67
  loaded: !0,
63
68
  error: n
@@ -65,26 +70,26 @@ var n = {
65
70
  });
66
71
  }
67
72
  async loadMore(t) {
68
- let n = this.slots.get(t), r = n?.entry.data;
69
- if (!n?.more || !r || r.next === null || n.moreCtl || n.ctl) return;
70
- let i = n.moreCtl = new AbortController();
71
- this.update(n, { loadingMore: !0 });
73
+ let r = this.slots.get(t), i = r && n(r), a = r?.entry.data;
74
+ if (!r || !i?.more || !a || a.next === null || r.moreCtl || r.ctl) return;
75
+ let o = r.moreCtl = new AbortController();
76
+ this.update(r, { loadingMore: !0 });
72
77
  try {
73
- let e = await n.more(r.next, i.signal);
74
- if (n.moreCtl !== i) return;
75
- let t = n.entry.data, a = new Set(t.items.map((e) => e.id));
76
- this.update(n, {
78
+ let e = await i.more(a.next, o.signal);
79
+ if (r.moreCtl !== o) return;
80
+ let t = r.entry.data, n = new Set(t.items.map((e) => e.id));
81
+ this.update(r, {
77
82
  data: {
78
- items: [...t.items, ...e.items.filter((e) => !a.has(e.id))],
83
+ items: [...t.items, ...e.items.filter((e) => !n.has(e.id))],
79
84
  next: e.next
80
85
  },
81
86
  error: void 0
82
87
  });
83
88
  } catch (t) {
84
- let r = e(t);
85
- n.moreCtl === i && r.code !== "aborted" && this.update(n, { error: r });
89
+ let n = e(t);
90
+ r.moreCtl === o && n.code !== "aborted" && this.update(r, { error: n });
86
91
  } finally {
87
- n.moreCtl === i && (n.moreCtl = void 0, this.update(n, { loadingMore: !1 }));
92
+ r.moreCtl === o && (r.moreCtl = void 0, this.update(r, { loadingMore: !1 }));
88
93
  }
89
94
  }
90
95
  set(e, t) {
@@ -142,6 +147,10 @@ var n = {
142
147
  };
143
148
  });
144
149
  switch (e.type) {
150
+ case "media.committed":
151
+ case "media.processed":
152
+ this.invalidate((t) => t.type === "page-review" && t.id === e.ref.version);
153
+ break;
145
154
  case "notifications.updated":
146
155
  this.updateNotification(e.item, n);
147
156
  break;
@@ -149,14 +158,14 @@ var n = {
149
158
  this.invalidate((e) => e.type === "notifications");
150
159
  break;
151
160
  case "comment.created": {
152
- let n = e.comment.reply_to_id, a = !e.comment.moderation;
153
- r((r) => n ? r.type === "replies" && r.id === n : r.type === "comments" && t(r.target, e.target), (t) => t.items.some((t) => t.id === e.comment.id) ? t : {
161
+ let n = e.comment.reply_to_id, a = !e.comment.moderation, o = (n) => t(n.target, e.target) && (!n.language || n.language === e.comment.language);
162
+ r((e) => n ? e.type === "replies" && e.id === n : e.type === "comments" && o(e), (t) => t.items.some((t) => t.id === e.comment.id) ? t : {
154
163
  ...t,
155
164
  items: n ? [...t.items, e.comment] : [e.comment, ...t.items]
156
165
  }), n && a && i(["comments"], (e) => e.id === n ? {
157
166
  ...e,
158
167
  reply_count: e.reply_count + 1
159
- } : e), this.invalidate((e) => e.type === "latest" || e.type === "admin-comments");
168
+ } : e), this.invalidate((e) => e.type === "latest" || e.type === "admin-comments"), n || this.invalidate((e) => e.type === "standing" && o(e));
160
169
  break;
161
170
  }
162
171
  case "comment.updated":
@@ -164,7 +173,7 @@ var n = {
164
173
  ...t,
165
174
  ...e.comment,
166
175
  author: e.comment.author ?? t.author
167
- } : t);
176
+ } : t), this.invalidate((e) => e.type === "standing");
168
177
  break;
169
178
  case "comment.reacted":
170
179
  i(a, (t) => t.id === e.id ? {
@@ -188,11 +197,11 @@ var n = {
188
197
  ...t,
189
198
  deleted: !0,
190
199
  deleted_at: (/* @__PURE__ */ new Date()).toISOString()
191
- } : t);
200
+ } : t), this.invalidate((e) => e.type === "standing");
192
201
  break;
193
202
  }
194
203
  case "comment.restored":
195
- this.invalidate((e) => a.includes(e.type));
204
+ this.invalidate((e) => a.includes(e.type) || e.type === "standing");
196
205
  break;
197
206
  case "reaction.changed":
198
207
  r((n) => n.type === "reaction" && t(n.target, e.target), () => e.counts), e.target.type === "contents" && (o(e.target.id, (t) => ({
@@ -221,17 +230,17 @@ var n = {
221
230
  })), this.invalidate((e) => e.type === "daily-releases")), this.invalidate((e) => e.type === "favorites");
222
231
  break;
223
232
  case "content.saved":
224
- r((t) => t.type === "content" && t.id === e.content.id, () => e.content), this.invalidate((t) => t.type === "contents" || t.type === "cards" || t.type === "daily-releases" || t.type === "content-detail" && t.id === e.content.id);
233
+ r((t) => t.type === "content" && t.id === e.content.id, () => e.content), this.invalidate((t) => t.type === "contents" || t.type === "cards" || t.type === "daily-releases" || t.type === "content-detail" && t.id === e.content.id), this.invalidate((t) => t.type === "standing" && t.target?.type === "contents" && t.target.id === e.content.id);
225
234
  break;
226
235
  case "content.changed":
227
- this.invalidate((t) => (t.type === "content" || t.type === "content-detail") && t.id === e.id || t.type === "contents" || t.type === "cards" || t.type === "daily-releases");
236
+ this.invalidate((t) => (t.type === "content" || t.type === "content-detail") && t.id === e.id || t.type === "contents" || t.type === "cards" || t.type === "daily-releases"), this.invalidate((t) => t.type === "standing" && t.target?.type === "contents" && t.target.id === e.id);
228
237
  break;
229
238
  case "content.deleted":
230
239
  i([
231
240
  "contents",
232
241
  "cards",
233
242
  "history"
234
- ], (t) => t.id === e.id ? null : t), this.invalidate((t) => (t.type === "content" || t.type === "content-detail") && t.id === e.id || t.type === "contents" && t.scope === "deleted" || t.type === "daily-releases");
243
+ ], (t) => t.id === e.id ? null : t), this.invalidate((t) => (t.type === "content" || t.type === "content-detail") && t.id === e.id || t.type === "contents" && t.scope === "deleted" || t.type === "daily-releases"), this.invalidate((t) => t.type === "standing" && t.target?.type === "contents" && t.target.id === e.id);
235
244
  break;
236
245
  case "poll.created":
237
246
  this.invalidate((e) => e.type === "polls" || e.type === "poll" && !e.id);
@@ -256,7 +265,7 @@ var n = {
256
265
  this.invalidate((e) => e.type === "cards" || e.type === "history" || e.type === "release-dates" || e.type === "daily-releases");
257
266
  break;
258
267
  case "access.changed":
259
- this.invalidate((e) => e.type === "cards" || e.type === "history" || e.type === "content-detail" || e.type === "reader-plan" || e.type.startsWith("group") || e.type === "daily-releases");
268
+ this.invalidate((e) => e.type === "cards" || e.type === "history" || e.type === "content-detail" || e.type === "reader-plan" || e.type.startsWith("group") || e.type === "daily-releases" || e.type === "standing");
260
269
  break;
261
270
  case "history.changed":
262
271
  this.invalidate((e) => e.type === "history" || e.type === "cards" || e.type === "daily-releases");
@@ -268,9 +277,9 @@ var n = {
268
277
  this.invalidate((t) => t.type === "moderation-rules" && t.scope === e.rules);
269
278
  break;
270
279
  case "reader.changed":
271
- this.invalidate((t) => t.type === "reader-plan" && t.id === e.version);
280
+ this.invalidate((t) => (t.type === "reader-plan" || t.type === "page-review") && t.id === e.version);
272
281
  break;
273
- case "moderation.resolved": i(["held"], (t) => t.id === e.id ? null : t), e.kind === "comment" ? this.invalidate((e) => a.includes(e.type)) : this.invalidate((t) => t.type === "content" && t.id === e.id || t.type === "contents");
282
+ case "moderation.resolved": i(["held"], (t) => t.id === e.id ? null : t), e.kind === "comment" ? this.invalidate((e) => a.includes(e.type) || e.type === "standing") : this.invalidate((t) => t.type === "content" && t.id === e.id || t.type === "contents");
274
283
  }
275
284
  }
276
285
  updateNotification(e, t) {
@@ -300,12 +309,12 @@ var n = {
300
309
  };
301
310
  for (let t of e.listeners) t();
302
311
  }
303
- }, i = /* @__PURE__ */ new WeakMap();
304
- function a(e) {
305
- let t = i.get(e);
306
- return t || i.set(e, t = new r(e)), t;
312
+ }, a = /* @__PURE__ */ new WeakMap();
313
+ function o(e) {
314
+ let t = a.get(e);
315
+ return t || a.set(e, t = new i(e)), t;
307
316
  }
308
317
  //#endregion
309
- export { r as ResourceStore, a as resourcesFor };
318
+ export { i as ResourceStore, o as resourcesFor };
310
319
 
311
320
  //# sourceMappingURL=resources.js.map