@openrails/contentkit-ui 0.85.1 → 0.86.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 (154) hide show
  1. package/README.md +7 -4
  2. package/dist/client/beacons.d.ts +13 -4
  3. package/dist/client/beacons.js +14 -7
  4. package/dist/client/beacons.js.map +1 -1
  5. package/dist/client/client.d.ts +3 -0
  6. package/dist/client/client.js +29 -27
  7. package/dist/client/client.js.map +1 -1
  8. package/dist/client/codes.d.ts +6 -1
  9. package/dist/client/codes.js +4 -1
  10. package/dist/client/codes.js.map +1 -1
  11. package/dist/client/generated/error-codes.js +1 -1
  12. package/dist/client/generated/error-codes.js.map +1 -1
  13. package/dist/client/generated/routes.d.ts +14 -1
  14. package/dist/client/generated/routes.js +17 -1
  15. package/dist/client/generated/routes.js.map +1 -1
  16. package/dist/client/generated/wire.d.ts +29 -0
  17. package/dist/client/generated/wire.js.map +1 -1
  18. package/dist/client/index.d.ts +2 -1
  19. package/dist/client/media/queue.d.ts +4 -2
  20. package/dist/client/media/queue.js +18 -12
  21. package/dist/client/media/queue.js.map +1 -1
  22. package/dist/client/media/rules.d.ts +7 -1
  23. package/dist/client/media/rules.js +27 -21
  24. package/dist/client/media/rules.js.map +1 -1
  25. package/dist/client/stats.d.ts +32 -0
  26. package/dist/client/stats.js +35 -0
  27. package/dist/client/stats.js.map +1 -0
  28. package/dist/client.js +30 -29
  29. package/dist/components/admin/content-manager.js +206 -206
  30. package/dist/components/admin/content-manager.js.map +1 -1
  31. package/dist/components/admin/group-manager.js +71 -70
  32. package/dist/components/admin/group-manager.js.map +1 -1
  33. package/dist/components/admin/media-item-panel.d.ts +24 -7
  34. package/dist/components/admin/media-item-panel.js +209 -197
  35. package/dist/components/admin/media-item-panel.js.map +1 -1
  36. package/dist/components/admin/poll-manager.js +25 -25
  37. package/dist/components/admin/stats-dashboard.d.ts +22 -0
  38. package/dist/components/admin/stats-dashboard.js +257 -0
  39. package/dist/components/admin/stats-dashboard.js.map +1 -0
  40. package/dist/components/content/card.js +42 -42
  41. package/dist/components/content/card.js.map +1 -1
  42. package/dist/components/content/editors.js +455 -427
  43. package/dist/components/content/editors.js.map +1 -1
  44. package/dist/components/content/grid.js +47 -47
  45. package/dist/components/content/index.d.ts +2 -1
  46. package/dist/components/content/listing.js +34 -34
  47. package/dist/components/content/listing.js.map +1 -1
  48. package/dist/components/content/paywall.d.ts +17 -5
  49. package/dist/components/content/paywall.js +115 -100
  50. package/dist/components/content/paywall.js.map +1 -1
  51. package/dist/components/content/reader-stats.d.ts +12 -0
  52. package/dist/components/content/reader-stats.js +47 -0
  53. package/dist/components/content/reader-stats.js.map +1 -0
  54. package/dist/components/groups/banner.js +33 -33
  55. package/dist/components/groups/directory.js +11 -11
  56. package/dist/components/groups/editor.js +293 -293
  57. package/dist/components/groups/editor.js.map +1 -1
  58. package/dist/components/groups/header.js +27 -27
  59. package/dist/components/groups/header.js.map +1 -1
  60. package/dist/components/groups/memberships.js +180 -180
  61. package/dist/components/groups/parts.d.ts +0 -2
  62. package/dist/components/groups/parts.js +9 -27
  63. package/dist/components/groups/parts.js.map +1 -1
  64. package/dist/components/media-folder-editor.js +239 -189
  65. package/dist/components/media-folder-editor.js.map +1 -1
  66. package/dist/components/notifications.js +17 -17
  67. package/dist/components/slot-upload.d.ts +2 -2
  68. package/dist/components/slot-upload.js +84 -79
  69. package/dist/components/slot-upload.js.map +1 -1
  70. package/dist/components/social/bans.js +34 -34
  71. package/dist/components/social/moderation.js +52 -48
  72. package/dist/components/social/moderation.js.map +1 -1
  73. package/dist/components/video-player.d.ts +2 -0
  74. package/dist/components/video-player.js +318 -314
  75. package/dist/components/video-player.js.map +1 -1
  76. package/dist/i18n/context.d.ts +2 -0
  77. package/dist/i18n/context.js +23 -5
  78. package/dist/i18n/context.js.map +1 -1
  79. package/dist/index.d.ts +2 -1
  80. package/dist/index.js +12 -10
  81. package/dist/locales/admin/de.js +27 -0
  82. package/dist/locales/admin/de.js.map +1 -1
  83. package/dist/locales/admin/en.d.ts +27 -0
  84. package/dist/locales/admin/en.js +27 -0
  85. package/dist/locales/admin/en.js.map +1 -1
  86. package/dist/locales/admin/es.js +27 -0
  87. package/dist/locales/admin/es.js.map +1 -1
  88. package/dist/locales/admin/ja.js +27 -0
  89. package/dist/locales/admin/ja.js.map +1 -1
  90. package/dist/locales/admin/ko.js +27 -0
  91. package/dist/locales/admin/ko.js.map +1 -1
  92. package/dist/locales/admin/zh.js +27 -0
  93. package/dist/locales/admin/zh.js.map +1 -1
  94. package/dist/locales/content/de.js +6 -0
  95. package/dist/locales/content/de.js.map +1 -1
  96. package/dist/locales/content/en.d.ts +6 -0
  97. package/dist/locales/content/en.js +6 -0
  98. package/dist/locales/content/en.js.map +1 -1
  99. package/dist/locales/content/es.js +6 -0
  100. package/dist/locales/content/es.js.map +1 -1
  101. package/dist/locales/content/ja.js +6 -0
  102. package/dist/locales/content/ja.js.map +1 -1
  103. package/dist/locales/content/ko.js +6 -0
  104. package/dist/locales/content/ko.js.map +1 -1
  105. package/dist/locales/content/zh.js +6 -0
  106. package/dist/locales/content/zh.js.map +1 -1
  107. package/dist/locales/de.js +1 -0
  108. package/dist/locales/de.js.map +1 -1
  109. package/dist/locales/en.d.ts +34 -0
  110. package/dist/locales/en.js +1 -0
  111. package/dist/locales/en.js.map +1 -1
  112. package/dist/locales/es.js +1 -0
  113. package/dist/locales/es.js.map +1 -1
  114. package/dist/locales/ja.js +1 -0
  115. package/dist/locales/ja.js.map +1 -1
  116. package/dist/locales/ko.js +1 -0
  117. package/dist/locales/ko.js.map +1 -1
  118. package/dist/locales/zh.js +1 -0
  119. package/dist/locales/zh.js.map +1 -1
  120. package/dist/react/admin.js +22 -23
  121. package/dist/react/admin.js.map +1 -1
  122. package/dist/react/canonical.d.ts +4 -3
  123. package/dist/react/canonical.js +34 -33
  124. package/dist/react/canonical.js.map +1 -1
  125. package/dist/react/contents.js +144 -144
  126. package/dist/react/contents.js.map +1 -1
  127. package/dist/react/detail.d.ts +12 -6
  128. package/dist/react/detail.js +31 -24
  129. package/dist/react/detail.js.map +1 -1
  130. package/dist/react/folder.d.ts +7 -2
  131. package/dist/react/folder.js +165 -147
  132. package/dist/react/folder.js.map +1 -1
  133. package/dist/react/groups.d.ts +0 -1
  134. package/dist/react/groups.js +13 -12
  135. package/dist/react/groups.js.map +1 -1
  136. package/dist/react/index.d.ts +4 -2
  137. package/dist/react/location.d.ts +11 -0
  138. package/dist/react/location.js +18 -0
  139. package/dist/react/location.js.map +1 -0
  140. package/dist/react/public.d.ts +8 -0
  141. package/dist/react/public.js +32 -27
  142. package/dist/react/public.js.map +1 -1
  143. package/dist/react/stats.d.ts +24 -0
  144. package/dist/react/stats.js +28 -0
  145. package/dist/react/stats.js.map +1 -0
  146. package/dist/react/use-resource.js +8 -7
  147. package/dist/react/use-resource.js.map +1 -1
  148. package/dist/react/versions.js +20 -20
  149. package/dist/react.js +26 -24
  150. package/dist/styles.css +1 -1
  151. package/dist/urls/index.d.ts +35 -10
  152. package/dist/urls.js +100 -70
  153. package/dist/urls.js.map +1 -1
  154. package/package.json +1 -1
@@ -20,56 +20,57 @@ var s = (e, t, n) => ({
20
20
  value: t
21
21
  });
22
22
  function c(c, l = {}) {
23
- let u = t(), d = n(e)?.navigate, f = l.location ?? (typeof location > "u" ? "" : location.pathname + location.search + location.hash), p = c?.content_kind, m = c?.code, h = c?.slug, g = JSON.stringify(c?.slugs ?? {}), _ = l.languages?.join(","), v = i(() => p && m ? {
24
- content_kind: p,
25
- code: m,
26
- slug: h ?? "",
27
- slugs: JSON.parse(g)
23
+ let u = t(), d = n(e), f = d?.navigate, p = d?.language, m = l.location ?? (typeof location > "u" ? "" : location.pathname + location.search + location.hash), h = c?.content_kind, g = c?.code, _ = c?.slug, v = JSON.stringify(c?.slugs ?? {}), y = l.languages?.join(","), b = i(() => h && g ? {
24
+ content_kind: h,
25
+ code: g,
26
+ slug: _ ?? "",
27
+ slugs: JSON.parse(v)
28
28
  } : null, [
29
- p,
30
- m,
31
29
  h,
32
- g
33
- ]), y = i(() => {
34
- if (!v) return { alternates: {} };
35
- let e = u.origin ?? (typeof location > "u" ? void 0 : location.origin), t = f.includes("#") ? f.slice(f.indexOf("#")) : "", n = u.canonical(f, v), r = n?.path ?? u.path(v), i = e ? u.hreflang(v, {
30
+ g,
31
+ _,
32
+ v
33
+ ]), x = i(() => {
34
+ if (!b) return { alternates: {} };
35
+ let e = u.origin ?? (typeof location > "u" ? void 0 : location.origin), t = m.includes("#") ? m.slice(m.indexOf("#")) : "", n = p && u.languages.includes(p) ? p : void 0, r = u.canonical(m, b, { language: n }), i = r?.path ?? u.path(b, { language: n }), a = e ? u.hreflang(b, {
36
36
  origin: e,
37
- languages: _?.split(","),
37
+ languages: y?.split(","),
38
38
  defaultLanguage: l.defaultLanguage
39
39
  }) : {};
40
40
  return {
41
- path: r,
42
- url: e ? e + r : void 0,
43
- alternates: i,
44
- redirect: n?.redirect ? n.location + t : void 0
41
+ path: i,
42
+ url: e ? e + i : void 0,
43
+ alternates: a,
44
+ redirect: r?.redirect ? r.location + t : void 0
45
45
  };
46
46
  }, [
47
- v,
48
- f,
47
+ b,
48
+ m,
49
49
  u,
50
- _,
50
+ p,
51
+ y,
51
52
  l.defaultLanguage
52
- ]), { redirect: b } = y;
53
+ ]), { redirect: S } = x;
53
54
  r(() => {
54
- b && (d ? d(b, { replace: !0 }) : history.replaceState(history.state, "", b));
55
- }, [b, d]);
56
- let { url: x, alternates: S } = y, { title: C, image: w } = l, T = JSON.stringify(S);
55
+ S && (f ? f(S, { replace: !0 }) : history.replaceState(history.state, "", S));
56
+ }, [S, f]);
57
+ let { url: C, alternates: w } = x, { title: T, image: E } = l, D = JSON.stringify(w);
57
58
  return r(() => {
58
- if (!x || typeof document > "u") return;
59
- let e = [s("canonical", x), a("og:url", x)];
60
- C && e.push(a("og:title", C)), w && e.push(a("og:image", w));
61
- for (let [t, n] of Object.entries(JSON.parse(T))) e.push(s("alternate", n, t));
59
+ if (!C || typeof document > "u") return;
60
+ let e = [s("canonical", C), a("og:url", C)];
61
+ T && e.push(a("og:title", T)), E && e.push(a("og:image", E));
62
+ for (let [t, n] of Object.entries(JSON.parse(D))) e.push(s("alternate", n, t));
62
63
  let t = e.map((e) => o(document.head.querySelector(e.selector) ?? document.head.appendChild(e.create()), e.attr, e.value));
63
64
  return () => t.forEach((e) => e.remove());
64
65
  }, [
65
- x,
66
66
  C,
67
- w,
68
- T
67
+ T,
68
+ E,
69
+ D
69
70
  ]), {
70
- path: y.path,
71
- url: y.url,
72
- alternates: y.alternates
71
+ path: x.path,
72
+ url: x.url,
73
+ alternates: x.alternates
73
74
  };
74
75
  }
75
76
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"canonical.js","names":[],"sources":["../../src/react/canonical.ts"],"sourcesContent":["import { useContext, useEffect, useMemo } from \"react\";\nimport type { ContentLink } from \"../urls/index.js\";\nimport { ContentKitContext, useContentURLs } from \"./context.js\";\n\nexport interface CanonicalContentOptions {\n /** og:title. */\n title?: string;\n /** og:image, an absolute URL. */\n image?: string;\n /**\n * The current location (pathname, search, hash). Default\n * window.location; pass the router's so a navigation checks again.\n */\n location?: string;\n /** Languages the content exists in, for hreflang; default every configured language. */\n languages?: readonly string[];\n /** The language hreflang x-default points at. */\n defaultLanguage?: string;\n}\n\nexport interface CanonicalContent {\n /** The canonical path in the page's language; undefined until link arrives. */\n path?: string;\n /** Its absolute URL. */\n url?: string;\n /** hreflang alternates by language (and x-default). */\n alternates: Record<string, string>;\n}\n\ntype Tag = { selector: string; create: () => HTMLElement; attr: string; value: string };\n\nconst meta = (property: string, value: string): Tag => ({\n selector: `meta[property=\"${property}\"]`,\n create: () => withAttr(document.createElement(\"meta\"), \"property\", property),\n attr: \"content\",\n value,\n});\n\nfunction withAttr<E extends HTMLElement>(el: E, name: string, value: string): E {\n el.setAttribute(name, value);\n return el;\n}\n\nconst link = (rel: string, value: string, hreflang?: string): Tag => ({\n selector: hreflang ? `link[rel=\"${rel}\"][hreflang=\"${hreflang}\"]` : `link[rel=\"${rel}\"]:not([hreflang])`,\n create: () => {\n const el = withAttr(document.createElement(\"link\"), \"rel\", rel);\n if (hreflang) el.setAttribute(\"hreflang\", hreflang);\n return el;\n },\n attr: \"href\",\n value,\n});\n\n/**\n * A content page's canonical URL once its data (link) arrives: replaces the\n * address with the canonical path (code spelling, merged code, current slug)\n * through the provider's navigate (else history.replaceState), and keeps\n * `<link rel=canonical>`, og:url, og:title, og:image and hreflang alternates\n * (each language's own slug) in the head while mounted; unmounting removes\n * the tags it set, server-rendered ones included. Needs the provider's `urls`.\n */\nexport function useCanonicalContent(content: ContentLink | null | undefined, o: CanonicalContentOptions = {}): CanonicalContent {\n const urls = useContentURLs();\n const navigate = useContext(ContentKitContext)?.navigate;\n const at = o.location ?? (typeof location === \"undefined\" ? \"\" : location.pathname + location.search + location.hash);\n const kind = content?.content_kind;\n const code = content?.code;\n const slug = content?.slug;\n const slugs = JSON.stringify(content?.slugs ?? {});\n const languages = o.languages?.join(\",\");\n const lnk = useMemo(\n () => (kind && code ? ({ content_kind: kind, code, slug: slug ?? \"\", slugs: JSON.parse(slugs) as Record<string, string> } satisfies ContentLink) : null),\n [kind, code, slug, slugs],\n );\n\n const result = useMemo((): CanonicalContent & { redirect?: string } => {\n if (!lnk) return { alternates: {} };\n const origin = urls.origin ?? (typeof location === \"undefined\" ? undefined : location.origin);\n const hash = at.includes(\"#\") ? at.slice(at.indexOf(\"#\")) : \"\";\n const c = urls.canonical(at, lnk);\n const path = c?.path ?? urls.path(lnk);\n const alternates = origin ? urls.hreflang(lnk, { origin, languages: languages?.split(\",\"), defaultLanguage: o.defaultLanguage }) : {};\n return { path, url: origin ? origin + path : undefined, alternates, redirect: c?.redirect ? c.location + hash : undefined };\n }, [lnk, at, urls, languages, o.defaultLanguage]);\n\n const { redirect } = result;\n useEffect(() => {\n if (!redirect) return;\n if (navigate) navigate(redirect, { replace: true });\n else history.replaceState(history.state, \"\", redirect);\n }, [redirect, navigate]);\n\n const { url, alternates } = result;\n const { title, image } = o;\n const alternatesKey = JSON.stringify(alternates);\n useEffect(() => {\n if (!url || typeof document === \"undefined\") return;\n const tags: Tag[] = [link(\"canonical\", url), meta(\"og:url\", url)];\n if (title) tags.push(meta(\"og:title\", title));\n if (image) tags.push(meta(\"og:image\", image));\n for (const [lang, href] of Object.entries(JSON.parse(alternatesKey) as Record<string, string>)) tags.push(link(\"alternate\", href, lang));\n const set = tags.map((t) => withAttr(document.head.querySelector<HTMLElement>(t.selector) ?? document.head.appendChild(t.create()), t.attr, t.value));\n // The tags describe this page: leaving it removes them, server-rendered ones\n // included (restoring those would leave this page's values on the next).\n return () => set.forEach((el) => el.remove());\n }, [url, title, image, alternatesKey]);\n\n return { path: result.path, url: result.url, alternates: result.alternates };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"canonical.js","names":[],"sources":["../../src/react/canonical.ts"],"sourcesContent":["import { useContext, useEffect, useMemo } from \"react\";\nimport type { ContentLink } from \"../urls/index.js\";\nimport { ContentKitContext, useContentURLs } from \"./context.js\";\n\nexport interface CanonicalContentOptions {\n /** og:title. */\n title?: string;\n /** og:image, an absolute URL. */\n image?: string;\n /**\n * The current location (pathname, search, hash). Default\n * window.location; pass the router's so a navigation checks again.\n */\n location?: string;\n /** Languages the content exists in, for hreflang; default every configured language. */\n languages?: readonly string[];\n /** The language hreflang x-default points at. */\n defaultLanguage?: string;\n}\n\nexport interface CanonicalContent {\n /** The canonical path in the page's language, never a version's (?v=); undefined until link arrives. */\n path?: string;\n /** Its absolute URL. */\n url?: string;\n /** hreflang alternates by language (and x-default). */\n alternates: Record<string, string>;\n}\n\ntype Tag = { selector: string; create: () => HTMLElement; attr: string; value: string };\n\nconst meta = (property: string, value: string): Tag => ({\n selector: `meta[property=\"${property}\"]`,\n create: () => withAttr(document.createElement(\"meta\"), \"property\", property),\n attr: \"content\",\n value,\n});\n\nfunction withAttr<E extends HTMLElement>(el: E, name: string, value: string): E {\n el.setAttribute(name, value);\n return el;\n}\n\nconst link = (rel: string, value: string, hreflang?: string): Tag => ({\n selector: hreflang ? `link[rel=\"${rel}\"][hreflang=\"${hreflang}\"]` : `link[rel=\"${rel}\"]:not([hreflang])`,\n create: () => {\n const el = withAttr(document.createElement(\"link\"), \"rel\", rel);\n if (hreflang) el.setAttribute(\"hreflang\", hreflang);\n return el;\n },\n attr: \"href\",\n value,\n});\n\n/**\n * A content page's canonical URL once its data (link) arrives: replaces the\n * address with the canonical path (language prefix, the reader's when the\n * address has none; code spelling, merged code, current slug; the query, ?v=\n * included, kept) through the provider's navigate (else history.replaceState), and keeps\n * `<link rel=canonical>`, og:url, og:title, og:image and hreflang alternates\n * (each language's own slug) in the head while mounted; unmounting removes\n * the tags it set, server-rendered ones included. Needs the provider's `urls`.\n */\nexport function useCanonicalContent(content: ContentLink | null | undefined, o: CanonicalContentOptions = {}): CanonicalContent {\n const urls = useContentURLs();\n const ctx = useContext(ContentKitContext);\n const navigate = ctx?.navigate;\n const reader = ctx?.language;\n const at = o.location ?? (typeof location === \"undefined\" ? \"\" : location.pathname + location.search + location.hash);\n const kind = content?.content_kind;\n const code = content?.code;\n const slug = content?.slug;\n const slugs = JSON.stringify(content?.slugs ?? {});\n const languages = o.languages?.join(\",\");\n const lnk = useMemo(\n () => (kind && code ? ({ content_kind: kind, code, slug: slug ?? \"\", slugs: JSON.parse(slugs) as Record<string, string> } satisfies ContentLink) : null),\n [kind, code, slug, slugs],\n );\n\n const result = useMemo((): CanonicalContent & { redirect?: string } => {\n if (!lnk) return { alternates: {} };\n const origin = urls.origin ?? (typeof location === \"undefined\" ? undefined : location.origin);\n const hash = at.includes(\"#\") ? at.slice(at.indexOf(\"#\")) : \"\";\n const language = reader && urls.languages.includes(reader) ? reader : undefined;\n const c = urls.canonical(at, lnk, { language });\n const path = c?.path ?? urls.path(lnk, { language });\n const alternates = origin ? urls.hreflang(lnk, { origin, languages: languages?.split(\",\"), defaultLanguage: o.defaultLanguage }) : {};\n return { path, url: origin ? origin + path : undefined, alternates, redirect: c?.redirect ? c.location + hash : undefined };\n }, [lnk, at, urls, reader, languages, o.defaultLanguage]);\n\n const { redirect } = result;\n useEffect(() => {\n if (!redirect) return;\n if (navigate) navigate(redirect, { replace: true });\n else history.replaceState(history.state, \"\", redirect);\n }, [redirect, navigate]);\n\n const { url, alternates } = result;\n const { title, image } = o;\n const alternatesKey = JSON.stringify(alternates);\n useEffect(() => {\n if (!url || typeof document === \"undefined\") return;\n const tags: Tag[] = [link(\"canonical\", url), meta(\"og:url\", url)];\n if (title) tags.push(meta(\"og:title\", title));\n if (image) tags.push(meta(\"og:image\", image));\n for (const [lang, href] of Object.entries(JSON.parse(alternatesKey) as Record<string, string>)) tags.push(link(\"alternate\", href, lang));\n const set = tags.map((t) => withAttr(document.head.querySelector<HTMLElement>(t.selector) ?? document.head.appendChild(t.create()), t.attr, t.value));\n // The tags describe this page: leaving it removes them, server-rendered ones\n // included (restoring those would leave this page's values on the next).\n return () => set.forEach((el) => el.remove());\n }, [url, title, image, alternatesKey]);\n\n return { path: result.path, url: result.url, alternates: result.alternates };\n}\n"],"mappings":"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"}
@@ -1,214 +1,214 @@
1
1
  import { useGuarded as e } from "./context.js";
2
- import { useMediaRead as t } from "./read.js";
3
- import { keyOf as n, offsetPages as r, useContentScope as i, useList as a, useResource as o } from "./use-resource.js";
2
+ import { keyOf as t, offsetPages as n, useContentScope as r, useList as i, useResource as a } from "./use-resource.js";
3
+ import { useMediaRead as o } from "./read.js";
4
4
  import { BODY_SUFFIX as s, IMAGE_SCHEME as c, imageRef as l, imageRefs as u } from "../client/contents.js";
5
5
  import { useCallback as d, useEffect as f, useMemo as p, useRef as m, useState as h } from "react";
6
6
  //#region src/react/contents.ts
7
- function g(e = {}, t = {}) {
8
- let { client: o, store: s, scope: c } = i(t.client), { pageSize: l, ...u } = e, d = l ?? 20;
9
- return a(s, n("contents", c, u.kind, u.state, u.owner_group, u.q, u.language, d), {
7
+ function g(e = {}, a = {}) {
8
+ let { client: o, store: s, scope: c } = r(a.client), { pageSize: l, ...u } = e, d = l ?? 20;
9
+ return i(s, t("contents", c, u.kind, u.state, u.owner_group, u.q, u.language, d), {
10
10
  type: "contents",
11
11
  scope: u.state === "deleted" ? "deleted" : void 0
12
- }, r(d, (e, t) => o.contents.manage({
12
+ }, n(d, (e, t) => o.contents.manage({
13
13
  ...u,
14
14
  ...e
15
15
  }, t)));
16
16
  }
17
- var _ = (e) => [...new Set([...(e ?? "").matchAll(u())].map((e) => e[1]))], v = (e) => {
17
+ var ee = (e) => [...new Set([...(e ?? "").matchAll(u())].map((e) => e[1]))], _ = (e) => {
18
18
  let t = e.slice(e.lastIndexOf("/") + 1), n = t.lastIndexOf(".");
19
19
  return n > 0 ? t.slice(0, n) : t;
20
20
  };
21
- function y(r, a, g, y = {}) {
22
- let { client: b, store: ee, scope: x } = i(y.client), [te, ne] = h(null), S = r ?? te, C = S ? n("content", x, S) : null, w = o(ee, C, {
21
+ function v(n, i, g, v = {}) {
22
+ let { client: y, store: te, scope: ne } = r(v.client), [b, re] = h(null), x = n ?? b, S = x ? t("content", ne, x) : null, C = a(te, S, {
23
23
  type: "content",
24
- id: S ?? void 0
25
- }, (e) => b.contents.get(S, g, e), { initial: y.initial }), T = w.data ?? null, [re, E] = h(0), D = e(), O = d(async (e) => {
26
- E((e) => e + 1);
24
+ id: x ?? void 0
25
+ }, (e) => y.contents.get(x, g, e), { initial: v.initial }), w = C.data ?? null, [ie, T] = h(0), E = e(), D = d(async (e) => {
26
+ T((e) => e + 1);
27
27
  try {
28
- return await D(e);
28
+ return await E(e);
29
29
  } finally {
30
- E((e) => e - 1);
30
+ T((e) => e - 1);
31
31
  }
32
- }, [D]), k = d(() => {
33
- if (!S) throw Error("contentkit-ui: create the item first");
34
- return S;
35
- }, [S]), A = T?.text?.[g], j = A?.body, M = T?.cover, [N, ie] = h(/* @__PURE__ */ new Map()), P = m([]);
32
+ }, [E]), O = d(() => {
33
+ if (!x) throw Error("contentkit-ui: create the item first");
34
+ return x;
35
+ }, [x]), k = w?.text?.[g], A = k?.body, j = w?.cover, [M, ae] = h(/* @__PURE__ */ new Map()), N = m([]);
36
36
  f(() => {
37
- let e = P.current;
37
+ let e = N.current;
38
38
  return () => {
39
39
  for (let t of e) URL.revokeObjectURL(t);
40
40
  };
41
41
  }, []);
42
- let F = p(() => new Map(Object.entries(T?.images ?? {})), [T?.images]), I = !!M && !M.url && !N.has(M.image) && !F.has(M.image), L = p(() => _(j).filter((e) => !N.has(e) && !F.has(e)), [
43
- j,
44
- N,
45
- F
46
- ]), R = p(() => I ? [...L, M.image] : L, [
42
+ let P = p(() => new Map(Object.entries(w?.images ?? {})), [w?.images]), F = !!j && !j.url && !M.has(j.image) && !P.has(j.image), I = p(() => ee(A).filter((e) => !M.has(e) && !P.has(e)), [
43
+ A,
44
+ M,
45
+ P
46
+ ]), L = p(() => F ? [...I, j.image] : I, [
47
+ F,
47
48
  I,
48
- L,
49
- M
50
- ]), z = p(() => ({
51
- kind: a,
52
- id: S ?? "none"
53
- }), [a, S]), B = p(() => ({
54
- kind: a + s,
55
- id: S ?? "none"
56
- }), [a, S]), V = t(z, {
49
+ j
50
+ ]), R = p(() => ({
51
+ kind: i,
52
+ id: x ?? "none"
53
+ }), [i, x]), oe = p(() => ({
54
+ kind: i + s,
55
+ id: x ?? "none"
56
+ }), [i, x]), z = o(R, {
57
57
  editor: !0,
58
- read: I ? void 0 : null,
59
- client: b
60
- }), H = t(B, {
58
+ read: F ? void 0 : null,
59
+ client: y
60
+ }), B = o(oe, {
61
61
  editor: !0,
62
- read: L.length ? void 0 : null,
63
- client: b
64
- }), U = p(() => [...V.read?.files ?? [], ...H.read?.files ?? []], [V.read, H.read]), W = p(() => {
62
+ read: I.length ? void 0 : null,
63
+ client: y
64
+ }), V = p(() => [...z.read?.files ?? [], ...B.read?.files ?? []], [z.read, B.read]), H = p(() => {
65
65
  let e = /* @__PURE__ */ new Map();
66
- for (let t of U) t.upload && t.editor_url && e.set(v(t.path), t.editor_url);
66
+ for (let t of V) t.upload && t.editor_url && e.set(_(t.path), t.editor_url);
67
67
  return e;
68
- }, [U]), ae = (e) => U.some((t) => t.failed && v(t.path) === e), G = (!!V.read || !!H.read) && R.some((e) => !W.has(e) && !ae(e)), K = m(0), q = V.reload, J = H.reload, Y = d(() => {
69
- q(), J();
70
- }, [q, J]);
68
+ }, [V]), U = (e) => V.some((t) => t.failed && _(t.path) === e), W = (!!z.read || !!B.read) && L.some((e) => !H.has(e) && !U(e)), G = m(0), K = z.reload, q = B.reload, J = d(() => {
69
+ K(), q();
70
+ }, [K, q]);
71
71
  f(() => {
72
- if (!G) {
73
- K.current = 0;
72
+ if (!W) {
73
+ G.current = 0;
74
74
  return;
75
75
  }
76
- if (K.current >= 6) return;
76
+ if (G.current >= 6) return;
77
77
  let e = setTimeout(() => {
78
- K.current++, Y();
79
- }, 1e3 * 2 ** K.current);
78
+ G.current++, J();
79
+ }, 1e3 * 2 ** G.current);
80
80
  return () => clearTimeout(e);
81
81
  }, [
82
- G,
83
- U,
84
- Y
82
+ W,
83
+ V,
84
+ J
85
85
  ]);
86
- let X = m(/* @__PURE__ */ new Map());
86
+ let Y = m(/* @__PURE__ */ new Map());
87
87
  f(() => {
88
88
  for (let e of [
89
- N,
90
- F,
91
- W
92
- ]) for (let [t, n] of e) X.current.set(n, t);
89
+ M,
90
+ P,
91
+ H
92
+ ]) for (let [t, n] of e) Y.current.set(n, t);
93
93
  }, [
94
- N,
95
- F,
96
- W
94
+ M,
95
+ P,
96
+ H
97
97
  ]);
98
- let Z = d((e) => {
98
+ let X = d((e) => {
99
99
  if (!e) return;
100
100
  let t = e.startsWith("contentkit:") ? e.slice(c.length) : e;
101
- return N.get(t) ?? F.get(t) ?? W.get(t) ?? e;
101
+ return M.get(t) ?? P.get(t) ?? H.get(t) ?? e;
102
102
  }, [
103
- N,
104
- F,
105
- W
106
- ]), oe = p(() => A ? {
107
- ...A,
108
- body: (A.body ?? "").replace(u(), (e, t) => N.get(t) ?? F.get(t) ?? W.get(t) ?? e)
103
+ M,
104
+ P,
105
+ H
106
+ ]), se = p(() => k ? {
107
+ ...k,
108
+ body: (k.body ?? "").replace(u(), (e, t) => M.get(t) ?? P.get(t) ?? H.get(t) ?? e)
109
109
  } : void 0, [
110
- A,
111
- N,
112
- F,
113
- W
114
- ]), Q = d((e) => {
115
- let t = new Map(X.current);
110
+ k,
111
+ M,
112
+ P,
113
+ H
114
+ ]), Z = d((e) => {
115
+ let t = new Map(Y.current);
116
116
  for (let e of [
117
- N,
118
- F,
119
- W
117
+ M,
118
+ P,
119
+ H
120
120
  ]) for (let [n, r] of e) t.set(r, n);
121
121
  let n = e;
122
122
  for (let [e, r] of t) n = n.split(e).join(l(r)).split(e.replaceAll("&", "&amp;")).join(l(r));
123
123
  return n;
124
124
  }, [
125
- N,
126
- F,
127
- W
128
- ]), $ = d((e, t) => {
125
+ M,
126
+ P,
127
+ H
128
+ ]), Q = d((e, t) => {
129
129
  if (typeof URL.createObjectURL != "function") return;
130
130
  let n = URL.createObjectURL(t);
131
- return P.current.push(n), ie((t) => new Map(t).set(e, n)), n;
132
- }, []), se = d((e) => O(async () => {
133
- let t = await b.contents.create(e);
134
- return ne(t.id), t;
135
- }), [b, O]), ce = d((e) => O(() => b.contents.update(k(), e)), [
136
- b,
137
- O,
138
- k
139
- ]), le = d((e) => O(() => b.contents.putText(k(), g, e.body === void 0 ? e : {
131
+ return N.current.push(n), ae((t) => new Map(t).set(e, n)), n;
132
+ }, []), ce = d((e) => D(async () => {
133
+ let t = await y.contents.create(e);
134
+ return re(t.id), t;
135
+ }), [y, D]), le = d((e) => D(() => y.contents.update(O(), e)), [
136
+ y,
137
+ D,
138
+ O
139
+ ]), ue = d((e) => D(() => y.contents.putText(O(), g, e.body === void 0 ? e : {
140
140
  ...e,
141
- body: Q(e.body)
141
+ body: Z(e.body)
142
142
  })), [
143
- b,
143
+ y,
144
+ D,
144
145
  O,
145
- k,
146
146
  g,
147
- Q
148
- ]), ue = d((e) => O(() => b.contents.publish(k(), e)), [
149
- b,
150
- O,
151
- k
152
- ]), de = d(() => O(() => b.contents.unpublish(k())), [
153
- b,
154
- O,
155
- k
156
- ]), fe = d(() => O(() => b.contents.remove(k())), [
157
- b,
158
- O,
159
- k
160
- ]), pe = d(() => O(() => b.contents.restore(k())), [
161
- b,
162
- O,
163
- k
164
- ]), me = d((e) => O(async () => {
165
- if (!e) return await b.contents.setCover(k(), null), null;
166
- let t = await b.media.uploadNamed({
167
- kind: a,
168
- id: k()
169
- }, e), n = await b.contents.setCover(k(), t.name), r = $(t.name, e) ?? n.cover?.url ?? null;
170
- return r && X.current.set(r, t.name), r;
147
+ Z
148
+ ]), $ = d((e) => D(() => y.contents.publish(O(), e)), [
149
+ y,
150
+ D,
151
+ O
152
+ ]), de = d(() => D(() => y.contents.unpublish(O())), [
153
+ y,
154
+ D,
155
+ O
156
+ ]), fe = d(() => D(() => y.contents.remove(O())), [
157
+ y,
158
+ D,
159
+ O
160
+ ]), pe = d(() => D(() => y.contents.restore(O())), [
161
+ y,
162
+ D,
163
+ O
164
+ ]), me = d((e) => D(async () => {
165
+ if (!e) return await y.contents.setCover(O(), null), null;
166
+ let t = await y.media.uploadNamed({
167
+ kind: i,
168
+ id: O()
169
+ }, e), n = await y.contents.setCover(O(), t.name), r = Q(t.name, e) ?? n.cover?.url ?? null;
170
+ return r && Y.current.set(r, t.name), r;
171
171
  }), [
172
- b,
172
+ y,
173
+ D,
173
174
  O,
174
- k,
175
- a,
176
- $
177
- ]), he = d((e) => O(async () => {
178
- let t = await b.media.uploadInline({
179
- kind: a + s,
180
- id: k()
181
- }, e), n = $(t.name, e) ?? t.url ?? t.ref;
182
- return X.current.set(n, t.name), n;
175
+ i,
176
+ Q
177
+ ]), he = d((e) => D(async () => {
178
+ let t = await y.media.uploadInline({
179
+ kind: i + s,
180
+ id: O()
181
+ }, e), n = Q(t.name, e) ?? t.url ?? t.ref;
182
+ return Y.current.set(n, t.name), n;
183
183
  }), [
184
- b,
184
+ y,
185
+ D,
185
186
  O,
186
- k,
187
- a,
188
- $
187
+ i,
188
+ Q
189
189
  ]);
190
190
  return {
191
- content: T,
192
- reload: w.reload,
193
- loading: !!C && (w.loading || !w.loaded && y.initial === void 0),
194
- error: w.error,
195
- saving: re > 0,
196
- create: se,
197
- update: ce,
198
- putText: le,
199
- publish: ue,
191
+ content: w,
192
+ reload: C.reload,
193
+ loading: !!S && (C.loading || !C.loaded && v.initial === void 0),
194
+ error: C.error,
195
+ saving: ie > 0,
196
+ create: ce,
197
+ update: le,
198
+ putText: ue,
199
+ publish: $,
200
200
  unpublish: de,
201
201
  remove: fe,
202
202
  restore: pe,
203
203
  setCover: me,
204
204
  uploadImage: he,
205
- imageSrc: Z,
206
- coverSrc: Z(M?.image),
207
- text: oe,
208
- storedBody: Q
205
+ imageSrc: X,
206
+ coverSrc: X(j?.image),
207
+ text: se,
208
+ storedBody: Z
209
209
  };
210
210
  }
211
211
  //#endregion
212
- export { y as useContent, g as useManagedContents };
212
+ export { v as useContent, g as useManagedContents };
213
213
 
214
214
  //# sourceMappingURL=contents.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contents.js","names":[],"sources":["../../src/react/contents.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type { CatalogText, Content, ContentInput, ContentPatch } from \"../client/generated/wire.js\";\nimport { BODY_SUFFIX, IMAGE_SCHEME, imageRef, imageRefs, type ManageQuery } from \"../client/contents.js\";\nimport { useMediaRead } from \"./read.js\";\nimport { useGuarded } from \"./context.js\";\nimport { keyOf, offsetPages, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\n\nexport interface ManageFilter extends Omit<ManageQuery, \"limit\" | \"offset\"> {\n pageSize?: number;\n}\n\n/** The content items the caller manages, newest first, a page at a time. */\nexport function useManagedContents(f: ManageFilter = {}, o: { client?: ContentKitClient } = {}): UseList<Content> {\n const { client, store, scope } = useContentScope(o.client);\n const { pageSize, ...q } = f;\n const size = pageSize ?? 20;\n return useList(\n store,\n keyOf(\"contents\", scope, q.kind, q.state, q.owner_group, q.q, q.language, size),\n { type: \"contents\", scope: q.state === \"deleted\" ? \"deleted\" : undefined },\n offsetPages(size, (page, signal) => client.contents.manage({ ...q, ...page }, signal)),\n );\n}\n\nexport interface UseContent {\n /** null before create (or while loading). */\n content: Content | null;\n loading: boolean;\n error?: ContentKitError;\n /** Writes in flight. */\n saving: boolean;\n /** Reads the item again. */\n reload: () => void;\n /** Creates the item as a draft; the hook then edits it. */\n create: (input: ContentInput) => Promise<Content>;\n update: (patch: ContentPatch) => Promise<Content>;\n /** Sets the text in the hook's language; a body from the editor is stored with image references (storedBody). */\n putText: (text: CatalogText) => Promise<Content>;\n /** Publishes now, or schedules for at. */\n publish: (at?: string) => Promise<Content>;\n unpublish: () => Promise<Content>;\n remove: () => Promise<void>;\n restore: () => Promise<Content>;\n /** Uploads the cover (null clears it); resolves with a URL that shows it now. */\n setCover: (file: Blob | null) => Promise<string | null>;\n /** Uploads an image for the body; resolves with a URL that shows it now, to place in the editor. */\n uploadImage: (file: Blob) => Promise<string>;\n /**\n * A URL that shows one of the item's images now, by name (\"i-{uuid}\") or\n * reference: a fresh upload from its file, else its public file\n * (`content.images`), else, while it has none (an unpublished item's), its\n * signed editor view from an editor read. Anything else is returned as is.\n */\n imageSrc: (image: string | null | undefined) => string | undefined;\n /** The cover through imageSrc. */\n coverSrc: string | undefined;\n /** The language's stored text, its body's images through imageSrc: what an editor shows. */\n text: CatalogText | undefined;\n /** HTML from the editor with every image URL this hook showed turned back into the image's reference. */\n storedBody: (html: string) => string;\n}\n\n/** The names of the images a body references, once each. */\nconst refNames = (body: string | undefined) => [...new Set([...(body ?? \"\").matchAll(imageRefs())].map((m) => m[1]!))];\nconst uploadName = (path: string) => {\n const base = path.slice(path.lastIndexOf(\"/\") + 1);\n const dot = base.lastIndexOf(\".\");\n return dot > 0 ? base.slice(0, dot) : base;\n};\n\n/**\n * One content item of kind for its editors: read, create, text in language,\n * publish, delete, restore, cover and body images. null creates a new item.\n */\nexport function useContent(id: string | null | undefined, kind: string, language: string, o: { initial?: Content; client?: ContentKitClient } = {}): UseContent {\n const { client, store, scope } = useContentScope(o.client);\n const [created, setCreated] = useState<string | null>(null);\n const cid = id ?? created;\n const key = cid ? keyOf(\"content\", scope, cid) : null;\n const r = useResource<Content | null>(store, key, { type: \"content\", id: cid ?? undefined }, (s) => client.contents.get(cid!, language, s), { initial: o.initial });\n const content = r.data ?? null;\n const [inflight, setInflight] = useState(0);\n const guarded = useGuarded();\n const run = useCallback(async <T>(fn: () => Promise<T>): Promise<T> => {\n setInflight((n) => n + 1);\n try {\n return await guarded(fn);\n } finally {\n setInflight((n) => n - 1);\n }\n }, [guarded]);\n const need = useCallback(() => {\n if (!cid) throw new Error(\"contentkit-ui: create the item first\");\n return cid;\n }, [cid]);\n const stored = content?.text?.[language];\n const body = stored?.body;\n const cover = content?.cover;\n\n // Images: fresh uploads show from their file, published ones from\n // content.images, the rest (an unpublished item's) from an editor read.\n const [previews, setPreviews] = useState<ReadonlyMap<string, string>>(new Map());\n const blobs = useRef<string[]>([]);\n useEffect(() => {\n const urls = blobs.current;\n return () => {\n for (const u of urls) URL.revokeObjectURL(u);\n };\n }, []);\n const published = useMemo(() => new Map(Object.entries(content?.images ?? {})), [content?.images]);\n // The cover is the item's folder's; body images are its body folder's ({kind}.body).\n const coverPending = !!cover && !cover.url && !previews.has(cover.image) && !published.has(cover.image);\n const bodyPending = useMemo(() => refNames(body).filter((n) => !previews.has(n) && !published.has(n)), [body, previews, published]);\n const pending = useMemo(() => (coverPending ? [...bodyPending, cover!.image] : bodyPending), [coverPending, bodyPending, cover]);\n const folder = useMemo(() => ({ kind, id: cid ?? \"none\" }), [kind, cid]);\n const bodyFolder = useMemo(() => ({ kind: kind + BODY_SUFFIX, id: cid ?? \"none\" }), [kind, cid]);\n const coverRead = useMediaRead(folder, { editor: true, read: coverPending ? undefined : null, client });\n const bodyRead = useMediaRead(bodyFolder, { editor: true, read: bodyPending.length ? undefined : null, client });\n const files = useMemo(() => [...(coverRead.read?.files ?? []), ...(bodyRead.read?.files ?? [])], [coverRead.read, bodyRead.read]);\n const views = useMemo(() => {\n const out = new Map<string, string>();\n for (const f of files) if (f.upload && f.editor_url) out.set(uploadName(f.path), f.editor_url);\n return out;\n }, [files]);\n // Editor views render on the first editor read that misses them: read again, backing off.\n const failed = (n: string) => files.some((f) => f.failed && uploadName(f.path) === n);\n const missing = (!!coverRead.read || !!bodyRead.read) && pending.some((n) => !views.has(n) && !failed(n));\n const tries = useRef(0);\n const reloadCover = coverRead.reload;\n const reloadBody = bodyRead.reload;\n const reload = useCallback(() => {\n reloadCover();\n reloadBody();\n }, [reloadCover, reloadBody]);\n useEffect(() => {\n if (!missing) {\n tries.current = 0;\n return;\n }\n if (tries.current >= 6) return;\n const t = setTimeout(() => {\n tries.current++;\n reload();\n }, 1000 * 2 ** tries.current);\n return () => clearTimeout(t);\n }, [missing, files, reload]);\n\n // Every URL shown for an image, of this and earlier reads, back to its name.\n const shown = useRef(new Map<string, string>());\n useEffect(() => {\n for (const m of [previews, published, views]) for (const [n, u] of m) shown.current.set(u, n);\n }, [previews, published, views]);\n\n const imageSrc = useCallback(\n (image: string | null | undefined) => {\n if (!image) return undefined;\n const n = image.startsWith(IMAGE_SCHEME) ? image.slice(IMAGE_SCHEME.length) : image;\n return previews.get(n) ?? published.get(n) ?? views.get(n) ?? image;\n },\n [previews, published, views],\n );\n const text = useMemo(\n () => (stored ? { ...stored, body: (stored.body ?? \"\").replace(imageRefs(), (ref, n: string) => previews.get(n) ?? published.get(n) ?? views.get(n) ?? ref) } : undefined),\n [stored, previews, published, views],\n );\n const storedBody = useCallback(\n (html: string) => {\n const back = new Map(shown.current);\n for (const m of [previews, published, views]) for (const [n, u] of m) back.set(u, n);\n let out = html;\n for (const [u, n] of back) out = out.split(u).join(imageRef(n)).split(u.replaceAll(\"&\", \"&amp;\")).join(imageRef(n));\n return out;\n },\n [previews, published, views],\n );\n const preview = useCallback((name: string, file: Blob): string | undefined => {\n if (typeof URL.createObjectURL !== \"function\") return undefined;\n const url = URL.createObjectURL(file);\n blobs.current.push(url);\n setPreviews((m) => new Map(m).set(name, url));\n return url;\n }, []);\n\n const create = useCallback(\n (input: ContentInput) =>\n run(async () => {\n const c = await client.contents.create(input);\n setCreated(c.id);\n return c;\n }),\n [client, run],\n );\n const update = useCallback((patch: ContentPatch) => run(() => client.contents.update(need(), patch)), [client, run, need]);\n const putText = useCallback(\n (t: CatalogText) => run(() => client.contents.putText(need(), language, t.body === undefined ? t : { ...t, body: storedBody(t.body) })),\n [client, run, need, language, storedBody],\n );\n const publish = useCallback((at?: string) => run(() => client.contents.publish(need(), at)), [client, run, need]);\n const unpublish = useCallback(() => run(() => client.contents.unpublish(need())), [client, run, need]);\n const remove = useCallback(() => run(() => client.contents.remove(need())), [client, run, need]);\n const restore = useCallback(() => run(() => client.contents.restore(need())), [client, run, need]);\n const setCover = useCallback(\n (file: Blob | null) =>\n run(async () => {\n if (!file) {\n await client.contents.setCover(need(), null);\n return null;\n }\n const up = await client.media.uploadNamed({ kind, id: need() }, file);\n const saved = await client.contents.setCover(need(), up.name);\n const url = preview(up.name, file) ?? saved.cover?.url ?? null;\n if (url) shown.current.set(url, up.name);\n return url;\n }),\n [client, run, need, kind, preview],\n );\n const uploadImage = useCallback(\n (file: Blob) =>\n run(async () => {\n const up = await client.media.uploadInline({ kind: kind + BODY_SUFFIX, id: need() }, file);\n const url = preview(up.name, file) ?? up.url ?? up.ref;\n shown.current.set(url, up.name);\n return url;\n }),\n [client, run, need, kind, preview],\n );\n return {\n content,\n reload: r.reload,\n loading: !!key && (r.loading || (!r.loaded && o.initial === undefined)),\n error: r.error,\n saving: inflight > 0,\n create,\n update,\n putText,\n publish,\n unpublish,\n remove,\n restore,\n setCover,\n uploadImage,\n imageSrc,\n coverSrc: imageSrc(cover?.image),\n text,\n storedBody,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"contents.js","names":[],"sources":["../../src/react/contents.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type { CatalogText, Content, ContentInput, ContentPatch } from \"../client/generated/wire.js\";\nimport { BODY_SUFFIX, IMAGE_SCHEME, imageRef, imageRefs, type ManageQuery } from \"../client/contents.js\";\nimport { useMediaRead } from \"./read.js\";\nimport { useGuarded } from \"./context.js\";\nimport { keyOf, offsetPages, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\n\nexport interface ManageFilter extends Omit<ManageQuery, \"limit\" | \"offset\"> {\n pageSize?: number;\n}\n\n/** The content items the caller manages, newest first, a page at a time. */\nexport function useManagedContents(f: ManageFilter = {}, o: { client?: ContentKitClient } = {}): UseList<Content> {\n const { client, store, scope } = useContentScope(o.client);\n const { pageSize, ...q } = f;\n const size = pageSize ?? 20;\n return useList(\n store,\n keyOf(\"contents\", scope, q.kind, q.state, q.owner_group, q.q, q.language, size),\n { type: \"contents\", scope: q.state === \"deleted\" ? \"deleted\" : undefined },\n offsetPages(size, (page, signal) => client.contents.manage({ ...q, ...page }, signal)),\n );\n}\n\nexport interface UseContent {\n /** null before create (or while loading). */\n content: Content | null;\n loading: boolean;\n error?: ContentKitError;\n /** Writes in flight. */\n saving: boolean;\n /** Reads the item again. */\n reload: () => void;\n /** Creates the item as a draft; the hook then edits it. */\n create: (input: ContentInput) => Promise<Content>;\n update: (patch: ContentPatch) => Promise<Content>;\n /** Sets the text in the hook's language; a body from the editor is stored with image references (storedBody). */\n putText: (text: CatalogText) => Promise<Content>;\n /** Publishes now, or schedules for at. */\n publish: (at?: string) => Promise<Content>;\n unpublish: () => Promise<Content>;\n remove: () => Promise<void>;\n restore: () => Promise<Content>;\n /** Uploads the cover (null clears it); resolves with a URL that shows it now. */\n setCover: (file: Blob | null) => Promise<string | null>;\n /** Uploads an image for the body; resolves with a URL that shows it now, to place in the editor. */\n uploadImage: (file: Blob) => Promise<string>;\n /**\n * A URL that shows one of the item's images now, by name (\"i-{uuid}\") or\n * reference: a fresh upload from its file, else its public file\n * (`content.images`), else, while it has none (an unpublished item's), its\n * signed editor view from an editor read. Anything else is returned as is.\n */\n imageSrc: (image: string | null | undefined) => string | undefined;\n /** The cover through imageSrc. */\n coverSrc: string | undefined;\n /** The language's stored text, its body's images through imageSrc: what an editor shows. */\n text: CatalogText | undefined;\n /** HTML from the editor with every image URL this hook showed turned back into the image's reference. */\n storedBody: (html: string) => string;\n}\n\n/** The names of the images a body references, once each. */\nconst refNames = (body: string | undefined) => [...new Set([...(body ?? \"\").matchAll(imageRefs())].map((m) => m[1]!))];\nconst uploadName = (path: string) => {\n const base = path.slice(path.lastIndexOf(\"/\") + 1);\n const dot = base.lastIndexOf(\".\");\n return dot > 0 ? base.slice(0, dot) : base;\n};\n\n/**\n * One content item of kind for its editors: read, create, text in language,\n * publish, delete, restore, cover and body images. null creates a new item.\n */\nexport function useContent(id: string | null | undefined, kind: string, language: string, o: { initial?: Content; client?: ContentKitClient } = {}): UseContent {\n const { client, store, scope } = useContentScope(o.client);\n const [created, setCreated] = useState<string | null>(null);\n const cid = id ?? created;\n const key = cid ? keyOf(\"content\", scope, cid) : null;\n const r = useResource<Content | null>(store, key, { type: \"content\", id: cid ?? undefined }, (s) => client.contents.get(cid!, language, s), { initial: o.initial });\n const content = r.data ?? null;\n const [inflight, setInflight] = useState(0);\n const guarded = useGuarded();\n const run = useCallback(async <T>(fn: () => Promise<T>): Promise<T> => {\n setInflight((n) => n + 1);\n try {\n return await guarded(fn);\n } finally {\n setInflight((n) => n - 1);\n }\n }, [guarded]);\n const need = useCallback(() => {\n if (!cid) throw new Error(\"contentkit-ui: create the item first\");\n return cid;\n }, [cid]);\n const stored = content?.text?.[language];\n const body = stored?.body;\n const cover = content?.cover;\n\n // Images: fresh uploads show from their file, published ones from\n // content.images, the rest (an unpublished item's) from an editor read.\n const [previews, setPreviews] = useState<ReadonlyMap<string, string>>(new Map());\n const blobs = useRef<string[]>([]);\n useEffect(() => {\n const urls = blobs.current;\n return () => {\n for (const u of urls) URL.revokeObjectURL(u);\n };\n }, []);\n const published = useMemo(() => new Map(Object.entries(content?.images ?? {})), [content?.images]);\n // The cover is the item's folder's; body images are its body folder's ({kind}.body).\n const coverPending = !!cover && !cover.url && !previews.has(cover.image) && !published.has(cover.image);\n const bodyPending = useMemo(() => refNames(body).filter((n) => !previews.has(n) && !published.has(n)), [body, previews, published]);\n const pending = useMemo(() => (coverPending ? [...bodyPending, cover!.image] : bodyPending), [coverPending, bodyPending, cover]);\n const folder = useMemo(() => ({ kind, id: cid ?? \"none\" }), [kind, cid]);\n const bodyFolder = useMemo(() => ({ kind: kind + BODY_SUFFIX, id: cid ?? \"none\" }), [kind, cid]);\n const coverRead = useMediaRead(folder, { editor: true, read: coverPending ? undefined : null, client });\n const bodyRead = useMediaRead(bodyFolder, { editor: true, read: bodyPending.length ? undefined : null, client });\n const files = useMemo(() => [...(coverRead.read?.files ?? []), ...(bodyRead.read?.files ?? [])], [coverRead.read, bodyRead.read]);\n const views = useMemo(() => {\n const out = new Map<string, string>();\n for (const f of files) if (f.upload && f.editor_url) out.set(uploadName(f.path), f.editor_url);\n return out;\n }, [files]);\n // Editor views render on the first editor read that misses them: read again, backing off.\n const failed = (n: string) => files.some((f) => f.failed && uploadName(f.path) === n);\n const missing = (!!coverRead.read || !!bodyRead.read) && pending.some((n) => !views.has(n) && !failed(n));\n const tries = useRef(0);\n const reloadCover = coverRead.reload;\n const reloadBody = bodyRead.reload;\n const reload = useCallback(() => {\n reloadCover();\n reloadBody();\n }, [reloadCover, reloadBody]);\n useEffect(() => {\n if (!missing) {\n tries.current = 0;\n return;\n }\n if (tries.current >= 6) return;\n const t = setTimeout(() => {\n tries.current++;\n reload();\n }, 1000 * 2 ** tries.current);\n return () => clearTimeout(t);\n }, [missing, files, reload]);\n\n // Every URL shown for an image, of this and earlier reads, back to its name.\n const shown = useRef(new Map<string, string>());\n useEffect(() => {\n for (const m of [previews, published, views]) for (const [n, u] of m) shown.current.set(u, n);\n }, [previews, published, views]);\n\n const imageSrc = useCallback(\n (image: string | null | undefined) => {\n if (!image) return undefined;\n const n = image.startsWith(IMAGE_SCHEME) ? image.slice(IMAGE_SCHEME.length) : image;\n return previews.get(n) ?? published.get(n) ?? views.get(n) ?? image;\n },\n [previews, published, views],\n );\n const text = useMemo(\n () => (stored ? { ...stored, body: (stored.body ?? \"\").replace(imageRefs(), (ref, n: string) => previews.get(n) ?? published.get(n) ?? views.get(n) ?? ref) } : undefined),\n [stored, previews, published, views],\n );\n const storedBody = useCallback(\n (html: string) => {\n const back = new Map(shown.current);\n for (const m of [previews, published, views]) for (const [n, u] of m) back.set(u, n);\n let out = html;\n for (const [u, n] of back) out = out.split(u).join(imageRef(n)).split(u.replaceAll(\"&\", \"&amp;\")).join(imageRef(n));\n return out;\n },\n [previews, published, views],\n );\n const preview = useCallback((name: string, file: Blob): string | undefined => {\n if (typeof URL.createObjectURL !== \"function\") return undefined;\n const url = URL.createObjectURL(file);\n blobs.current.push(url);\n setPreviews((m) => new Map(m).set(name, url));\n return url;\n }, []);\n\n const create = useCallback(\n (input: ContentInput) =>\n run(async () => {\n const c = await client.contents.create(input);\n setCreated(c.id);\n return c;\n }),\n [client, run],\n );\n const update = useCallback((patch: ContentPatch) => run(() => client.contents.update(need(), patch)), [client, run, need]);\n const putText = useCallback(\n (t: CatalogText) => run(() => client.contents.putText(need(), language, t.body === undefined ? t : { ...t, body: storedBody(t.body) })),\n [client, run, need, language, storedBody],\n );\n const publish = useCallback((at?: string) => run(() => client.contents.publish(need(), at)), [client, run, need]);\n const unpublish = useCallback(() => run(() => client.contents.unpublish(need())), [client, run, need]);\n const remove = useCallback(() => run(() => client.contents.remove(need())), [client, run, need]);\n const restore = useCallback(() => run(() => client.contents.restore(need())), [client, run, need]);\n const setCover = useCallback(\n (file: Blob | null) =>\n run(async () => {\n if (!file) {\n await client.contents.setCover(need(), null);\n return null;\n }\n const up = await client.media.uploadNamed({ kind, id: need() }, file);\n const saved = await client.contents.setCover(need(), up.name);\n const url = preview(up.name, file) ?? saved.cover?.url ?? null;\n if (url) shown.current.set(url, up.name);\n return url;\n }),\n [client, run, need, kind, preview],\n );\n const uploadImage = useCallback(\n (file: Blob) =>\n run(async () => {\n const up = await client.media.uploadInline({ kind: kind + BODY_SUFFIX, id: need() }, file);\n const url = preview(up.name, file) ?? up.url ?? up.ref;\n shown.current.set(url, up.name);\n return url;\n }),\n [client, run, need, kind, preview],\n );\n return {\n content,\n reload: r.reload,\n loading: !!key && (r.loading || (!r.loaded && o.initial === undefined)),\n error: r.error,\n saving: inflight > 0,\n create,\n update,\n putText,\n publish,\n unpublish,\n remove,\n restore,\n setCover,\n uploadImage,\n imageSrc,\n coverSrc: imageSrc(cover?.image),\n text,\n storedBody,\n };\n}\n"],"mappings":"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"}
@@ -5,11 +5,13 @@ import { Content, Decision, Version } from '../client/generated/wire.js';
5
5
  export declare function liveVersions(c: Content | null | undefined): Version[];
6
6
  /** The version a reader of language opens by default: the first live one serving it, else the first live one. */
7
7
  export declare function defaultVersion(c: Content | null | undefined, language?: string): Version | null;
8
+ /** The version selected names: its code (any spelling, the page's ?v=) or its id; undefined when none. */
9
+ export declare function findVersion(versions: readonly Version[], selected: string | null | undefined): Version | undefined;
8
10
  export interface UseContentDetail {
9
11
  content: Content | null;
10
12
  /** Live versions, first first. */
11
13
  versions: Version[];
12
- /** The version shown: the one asked for when live, else the language's default. */
14
+ /** The version shown: the one asked for (?v=) when live, else the language's default. */
13
15
  version: Version | null;
14
16
  /** The shown version's access decision: allowed, what is sold, previews. */
15
17
  decision: Decision | null;
@@ -19,12 +21,16 @@ export interface UseContentDetail {
19
21
  error?: ContentKitError;
20
22
  reload: () => void;
21
23
  }
24
+ export interface ContentDetailOptions {
25
+ language?: string;
26
+ /** The version to show, by code or id; default the page's ?v=. Unknown or not live: the language's default. */
27
+ version?: string | null;
28
+ /** The page's location for its ?v=; default window.location. */
29
+ location?: string;
30
+ client?: ContentKitClient;
31
+ }
22
32
  /**
23
33
  * A content page's data: text in the reader's language, live versions with
24
34
  * their segments and access decisions, groups, attributes and the version to show.
25
35
  */
26
- export declare function useContentDetail(id: string | null | undefined, o?: {
27
- language?: string;
28
- version?: string | null;
29
- client?: ContentKitClient;
30
- }): UseContentDetail;
36
+ export declare function useContentDetail(id: string | null | undefined, o?: ContentDetailOptions): UseContentDetail;