@openrails/contentkit-ui 0.0.0-placeholder → 0.68.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 (367) hide show
  1. package/README.md +424 -1
  2. package/dist/appearance.d.ts +38 -0
  3. package/dist/appearance.js +15 -0
  4. package/dist/appearance.js.map +1 -0
  5. package/dist/assets/hash.worker-BYfo-7MQ.js.map +1 -0
  6. package/dist/client/aspect.d.ts +6 -0
  7. package/dist/client/aspect.js +17 -0
  8. package/dist/client/aspect.js.map +1 -0
  9. package/dist/client/client.d.ts +51 -0
  10. package/dist/client/client.js +35 -0
  11. package/dist/client/client.js.map +1 -0
  12. package/dist/client/codes.d.ts +12 -0
  13. package/dist/client/codes.js +19 -0
  14. package/dist/client/codes.js.map +1 -0
  15. package/dist/client/content/bans.d.ts +15 -0
  16. package/dist/client/content/bans.js +40 -0
  17. package/dist/client/content/bans.js.map +1 -0
  18. package/dist/client/content/comments.d.ts +36 -0
  19. package/dist/client/content/comments.js +93 -0
  20. package/dist/client/content/comments.js.map +1 -0
  21. package/dist/client/content/favorites.d.ts +14 -0
  22. package/dist/client/content/favorites.js +42 -0
  23. package/dist/client/content/favorites.js.map +1 -0
  24. package/dist/client/content/moderation.d.ts +18 -0
  25. package/dist/client/content/moderation.js +37 -0
  26. package/dist/client/content/moderation.js.map +1 -0
  27. package/dist/client/content/polls.d.ts +47 -0
  28. package/dist/client/content/polls.js +148 -0
  29. package/dist/client/content/polls.js.map +1 -0
  30. package/dist/client/content/posts.d.ts +44 -0
  31. package/dist/client/content/posts.js +91 -0
  32. package/dist/client/content/posts.js.map +1 -0
  33. package/dist/client/content/reactions.d.ts +12 -0
  34. package/dist/client/content/reactions.js +36 -0
  35. package/dist/client/content/reactions.js.map +1 -0
  36. package/dist/client/content/types.d.ts +91 -0
  37. package/dist/client/content/types.js +8 -0
  38. package/dist/client/content/types.js.map +1 -0
  39. package/dist/client/crop.d.ts +32 -0
  40. package/dist/client/crop.js +103 -0
  41. package/dist/client/crop.js.map +1 -0
  42. package/dist/client/errors.d.ts +54 -0
  43. package/dist/client/errors.js +80 -0
  44. package/dist/client/errors.js.map +1 -0
  45. package/dist/client/gallery.d.ts +43 -0
  46. package/dist/client/gallery.js +86 -0
  47. package/dist/client/gallery.js.map +1 -0
  48. package/dist/client/generated/error-codes.d.ts +5 -0
  49. package/dist/client/generated/error-codes.js +131 -0
  50. package/dist/client/generated/error-codes.js.map +1 -0
  51. package/dist/client/generated/routes.d.ts +1086 -0
  52. package/dist/client/generated/routes.js +1400 -0
  53. package/dist/client/generated/routes.js.map +1 -0
  54. package/dist/client/generated/wire.d.ts +630 -0
  55. package/dist/client/generated/wire.js +6 -0
  56. package/dist/client/generated/wire.js.map +1 -0
  57. package/dist/client/http.d.ts +79 -0
  58. package/dist/client/http.js +74 -0
  59. package/dist/client/http.js.map +1 -0
  60. package/dist/client/image.d.ts +24 -0
  61. package/dist/client/image.js +65 -0
  62. package/dist/client/image.js.map +1 -0
  63. package/dist/client/index.d.ts +33 -0
  64. package/dist/client/media/api.d.ts +36 -0
  65. package/dist/client/media/api.js +61 -0
  66. package/dist/client/media/api.js.map +1 -0
  67. package/dist/client/media/client.d.ts +247 -0
  68. package/dist/client/media/client.js +407 -0
  69. package/dist/client/media/client.js.map +1 -0
  70. package/dist/client/media/encode.d.ts +3 -0
  71. package/dist/client/media/encode.js +8 -0
  72. package/dist/client/media/encode.js.map +1 -0
  73. package/dist/client/media/hash-stream.d.ts +6 -0
  74. package/dist/client/media/hash-stream.js +16 -0
  75. package/dist/client/media/hash-stream.js.map +1 -0
  76. package/dist/client/media/hash.d.ts +12 -0
  77. package/dist/client/media/hash.js +48 -0
  78. package/dist/client/media/hash.js.map +1 -0
  79. package/dist/client/media/hash.worker-inline.js +18 -0
  80. package/dist/client/media/hash.worker-inline.js.map +1 -0
  81. package/dist/client/media/pacer.d.ts +21 -0
  82. package/dist/client/media/pacer.js +25 -0
  83. package/dist/client/media/pacer.js.map +1 -0
  84. package/dist/client/media/queue.d.ts +112 -0
  85. package/dist/client/media/queue.js +274 -0
  86. package/dist/client/media/queue.js.map +1 -0
  87. package/dist/client/media/ref.d.ts +6 -0
  88. package/dist/client/media/ref.js +10 -0
  89. package/dist/client/media/ref.js.map +1 -0
  90. package/dist/client/media/rules.d.ts +52 -0
  91. package/dist/client/media/rules.js +139 -0
  92. package/dist/client/media/rules.js.map +1 -0
  93. package/dist/client/media/transport.d.ts +13 -0
  94. package/dist/client/media/transport.js +33 -0
  95. package/dist/client/media/transport.js.map +1 -0
  96. package/dist/client/media/windows.d.ts +15 -0
  97. package/dist/client/media/windows.js +39 -0
  98. package/dist/client/media/windows.js.map +1 -0
  99. package/dist/client/playback.d.ts +200 -0
  100. package/dist/client/playback.js +142 -0
  101. package/dist/client/playback.js.map +1 -0
  102. package/dist/client/player.d.ts +102 -0
  103. package/dist/client/player.js +155 -0
  104. package/dist/client/player.js.map +1 -0
  105. package/dist/client/public.d.ts +25 -0
  106. package/dist/client/public.js +18 -0
  107. package/dist/client/public.js.map +1 -0
  108. package/dist/client/rendition.d.ts +19 -0
  109. package/dist/client/rendition.js +16 -0
  110. package/dist/client/rendition.js.map +1 -0
  111. package/dist/client/route.d.ts +39 -0
  112. package/dist/client/route.js +31 -0
  113. package/dist/client/route.js.map +1 -0
  114. package/dist/client/taxonomy.d.ts +30 -0
  115. package/dist/client/taxonomy.js +77 -0
  116. package/dist/client/taxonomy.js.map +1 -0
  117. package/dist/client.js +33 -0
  118. package/dist/components/encode-progress.d.ts +15 -0
  119. package/dist/components/encode-progress.js +49 -0
  120. package/dist/components/encode-progress.js.map +1 -0
  121. package/dist/components/hover-preview.d.ts +29 -0
  122. package/dist/components/hover-preview.js +49 -0
  123. package/dist/components/hover-preview.js.map +1 -0
  124. package/dist/components/image-crop-dialog.d.ts +48 -0
  125. package/dist/components/image-crop-dialog.js +359 -0
  126. package/dist/components/image-crop-dialog.js.map +1 -0
  127. package/dist/components/lazy-mount.d.ts +10 -0
  128. package/dist/components/lazy-mount.js +22 -0
  129. package/dist/components/lazy-mount.js.map +1 -0
  130. package/dist/components/media-folder-editor.d.ts +45 -0
  131. package/dist/components/media-folder-editor.js +564 -0
  132. package/dist/components/media-folder-editor.js.map +1 -0
  133. package/dist/components/media-gallery.d.ts +54 -0
  134. package/dist/components/media-gallery.js +597 -0
  135. package/dist/components/media-gallery.js.map +1 -0
  136. package/dist/components/media-readiness-notice.d.ts +24 -0
  137. package/dist/components/media-readiness-notice.js +61 -0
  138. package/dist/components/media-readiness-notice.js.map +1 -0
  139. package/dist/components/player-controls.d.ts +71 -0
  140. package/dist/components/player-controls.js +264 -0
  141. package/dist/components/player-controls.js.map +1 -0
  142. package/dist/components/progress.d.ts +5 -0
  143. package/dist/components/progress.js +14 -0
  144. package/dist/components/progress.js.map +1 -0
  145. package/dist/components/rendition-img.d.ts +34 -0
  146. package/dist/components/rendition-img.js +78 -0
  147. package/dist/components/rendition-img.js.map +1 -0
  148. package/dist/components/slot-editor.d.ts +95 -0
  149. package/dist/components/slot-editor.js +182 -0
  150. package/dist/components/slot-editor.js.map +1 -0
  151. package/dist/components/slot-image.d.ts +23 -0
  152. package/dist/components/slot-image.js +48 -0
  153. package/dist/components/slot-image.js.map +1 -0
  154. package/dist/components/slot-upload.d.ts +41 -0
  155. package/dist/components/slot-upload.js +213 -0
  156. package/dist/components/slot-upload.js.map +1 -0
  157. package/dist/components/social/bans.d.ts +42 -0
  158. package/dist/components/social/bans.js +300 -0
  159. package/dist/components/social/bans.js.map +1 -0
  160. package/dist/components/social/comments.d.ts +42 -0
  161. package/dist/components/social/comments.js +517 -0
  162. package/dist/components/social/comments.js.map +1 -0
  163. package/dist/components/social/engagement.d.ts +45 -0
  164. package/dist/components/social/engagement.js +129 -0
  165. package/dist/components/social/engagement.js.map +1 -0
  166. package/dist/components/social/index.d.ts +6 -0
  167. package/dist/components/social/moderation.d.ts +32 -0
  168. package/dist/components/social/moderation.js +383 -0
  169. package/dist/components/social/moderation.js.map +1 -0
  170. package/dist/components/social/parts.d.ts +50 -0
  171. package/dist/components/social/parts.js +106 -0
  172. package/dist/components/social/parts.js.map +1 -0
  173. package/dist/components/social/poll-editor.d.ts +34 -0
  174. package/dist/components/social/poll-editor.js +567 -0
  175. package/dist/components/social/poll-editor.js.map +1 -0
  176. package/dist/components/social/poll.d.ts +30 -0
  177. package/dist/components/social/poll.js +252 -0
  178. package/dist/components/social/poll.js.map +1 -0
  179. package/dist/components/sortable-list.d.ts +29 -0
  180. package/dist/components/sortable-list.js +121 -0
  181. package/dist/components/sortable-list.js.map +1 -0
  182. package/dist/components/video-mini-player.d.ts +35 -0
  183. package/dist/components/video-mini-player.js +236 -0
  184. package/dist/components/video-mini-player.js.map +1 -0
  185. package/dist/components/video-player.d.ts +146 -0
  186. package/dist/components/video-player.js +630 -0
  187. package/dist/components/video-player.js.map +1 -0
  188. package/dist/components/video-poster-picker.d.ts +59 -0
  189. package/dist/components/video-poster-picker.js +335 -0
  190. package/dist/components/video-poster-picker.js.map +1 -0
  191. package/dist/components/video-poster.d.ts +24 -0
  192. package/dist/components/video-poster.js +46 -0
  193. package/dist/components/video-poster.js.map +1 -0
  194. package/dist/i18n/context.d.ts +4 -0
  195. package/dist/i18n/context.js +11 -0
  196. package/dist/i18n/context.js.map +1 -0
  197. package/dist/i18n/messages.d.ts +40 -0
  198. package/dist/i18n/messages.js +94 -0
  199. package/dist/i18n/messages.js.map +1 -0
  200. package/dist/index.d.ts +23 -0
  201. package/dist/index.js +41 -0
  202. package/dist/locales/de.d.ts +2 -0
  203. package/dist/locales/de.js +271 -0
  204. package/dist/locales/de.js.map +1 -0
  205. package/dist/locales/en.d.ts +457 -0
  206. package/dist/locales/en.js +271 -0
  207. package/dist/locales/en.js.map +1 -0
  208. package/dist/locales/es.d.ts +2 -0
  209. package/dist/locales/es.js +271 -0
  210. package/dist/locales/es.js.map +1 -0
  211. package/dist/locales/ja.d.ts +2 -0
  212. package/dist/locales/ja.js +271 -0
  213. package/dist/locales/ja.js.map +1 -0
  214. package/dist/locales/ko.d.ts +2 -0
  215. package/dist/locales/ko.js +271 -0
  216. package/dist/locales/ko.js.map +1 -0
  217. package/dist/locales/social/de.d.ts +2 -0
  218. package/dist/locales/social/de.js +198 -0
  219. package/dist/locales/social/de.js.map +1 -0
  220. package/dist/locales/social/en.d.ts +195 -0
  221. package/dist/locales/social/en.js +198 -0
  222. package/dist/locales/social/en.js.map +1 -0
  223. package/dist/locales/social/es.d.ts +2 -0
  224. package/dist/locales/social/es.js +198 -0
  225. package/dist/locales/social/es.js.map +1 -0
  226. package/dist/locales/social/ja.d.ts +2 -0
  227. package/dist/locales/social/ja.js +198 -0
  228. package/dist/locales/social/ja.js.map +1 -0
  229. package/dist/locales/social/ko.d.ts +2 -0
  230. package/dist/locales/social/ko.js +198 -0
  231. package/dist/locales/social/ko.js.map +1 -0
  232. package/dist/locales/social/zh.d.ts +2 -0
  233. package/dist/locales/social/zh.js +198 -0
  234. package/dist/locales/social/zh.js.map +1 -0
  235. package/dist/locales/zh.d.ts +2 -0
  236. package/dist/locales/zh.js +271 -0
  237. package/dist/locales/zh.js.map +1 -0
  238. package/dist/provider.d.ts +22 -0
  239. package/dist/provider.js +59 -0
  240. package/dist/provider.js.map +1 -0
  241. package/dist/react/canonical.d.ts +33 -0
  242. package/dist/react/canonical.js +88 -0
  243. package/dist/react/canonical.js.map +1 -0
  244. package/dist/react/comments.d.ts +82 -0
  245. package/dist/react/comments.js +147 -0
  246. package/dist/react/comments.js.map +1 -0
  247. package/dist/react/config.d.ts +13 -0
  248. package/dist/react/config.js +14 -0
  249. package/dist/react/config.js.map +1 -0
  250. package/dist/react/context.d.ts +48 -0
  251. package/dist/react/context.js +37 -0
  252. package/dist/react/context.js.map +1 -0
  253. package/dist/react/crop.d.ts +49 -0
  254. package/dist/react/crop.js +107 -0
  255. package/dist/react/crop.js.map +1 -0
  256. package/dist/react/engagement.d.ts +38 -0
  257. package/dist/react/engagement.js +88 -0
  258. package/dist/react/engagement.js.map +1 -0
  259. package/dist/react/folder.d.ts +83 -0
  260. package/dist/react/folder.js +183 -0
  261. package/dist/react/folder.js.map +1 -0
  262. package/dist/react/gallery.d.ts +140 -0
  263. package/dist/react/gallery.js +477 -0
  264. package/dist/react/gallery.js.map +1 -0
  265. package/dist/react/index.d.ts +21 -0
  266. package/dist/react/inline-preview.d.ts +24 -0
  267. package/dist/react/inline-preview.js +76 -0
  268. package/dist/react/inline-preview.js.map +1 -0
  269. package/dist/react/player.d.ts +70 -0
  270. package/dist/react/player.js +214 -0
  271. package/dist/react/player.js.map +1 -0
  272. package/dist/react/polls.d.ts +74 -0
  273. package/dist/react/polls.js +176 -0
  274. package/dist/react/polls.js.map +1 -0
  275. package/dist/react/posts.d.ts +59 -0
  276. package/dist/react/posts.js +149 -0
  277. package/dist/react/posts.js.map +1 -0
  278. package/dist/react/provider.d.ts +23 -0
  279. package/dist/react/provider.js +35 -0
  280. package/dist/react/provider.js.map +1 -0
  281. package/dist/react/public.d.ts +39 -0
  282. package/dist/react/public.js +70 -0
  283. package/dist/react/public.js.map +1 -0
  284. package/dist/react/read.d.ts +52 -0
  285. package/dist/react/read.js +143 -0
  286. package/dist/react/read.js.map +1 -0
  287. package/dist/react/resources.d.ts +70 -0
  288. package/dist/react/resources.js +247 -0
  289. package/dist/react/resources.js.map +1 -0
  290. package/dist/react/slot.d.ts +102 -0
  291. package/dist/react/slot.js +181 -0
  292. package/dist/react/slot.js.map +1 -0
  293. package/dist/react/store.d.ts +51 -0
  294. package/dist/react/store.js +164 -0
  295. package/dist/react/store.js.map +1 -0
  296. package/dist/react/upload.d.ts +85 -0
  297. package/dist/react/upload.js +150 -0
  298. package/dist/react/upload.js.map +1 -0
  299. package/dist/react/use-resource.d.ts +43 -0
  300. package/dist/react/use-resource.js +66 -0
  301. package/dist/react/use-resource.js.map +1 -0
  302. package/dist/react/video.d.ts +118 -0
  303. package/dist/react/video.js +184 -0
  304. package/dist/react/video.js.map +1 -0
  305. package/dist/react/viewport.d.ts +19 -0
  306. package/dist/react/viewport.js +30 -0
  307. package/dist/react/viewport.js.map +1 -0
  308. package/dist/react.js +21 -0
  309. package/dist/scope.d.ts +14 -0
  310. package/dist/scope.js +30 -0
  311. package/dist/scope.js.map +1 -0
  312. package/dist/styles.css +3 -0
  313. package/dist/ui/alert-dialog.d.ts +18 -0
  314. package/dist/ui/alert-dialog.js +86 -0
  315. package/dist/ui/alert-dialog.js.map +1 -0
  316. package/dist/ui/alert.d.ts +10 -0
  317. package/dist/ui/alert.js +38 -0
  318. package/dist/ui/alert.js.map +1 -0
  319. package/dist/ui/avatar.d.ts +11 -0
  320. package/dist/ui/avatar.js +31 -0
  321. package/dist/ui/avatar.js.map +1 -0
  322. package/dist/ui/badge.d.ts +7 -0
  323. package/dist/ui/badge.js +31 -0
  324. package/dist/ui/badge.js.map +1 -0
  325. package/dist/ui/button.d.ts +8 -0
  326. package/dist/ui/button.js +46 -0
  327. package/dist/ui/button.js.map +1 -0
  328. package/dist/ui/dialog.d.ts +17 -0
  329. package/dist/ui/dialog.js +91 -0
  330. package/dist/ui/dialog.js.map +1 -0
  331. package/dist/ui/dropdown-menu.d.ts +15 -0
  332. package/dist/ui/dropdown-menu.js +105 -0
  333. package/dist/ui/dropdown-menu.js.map +1 -0
  334. package/dist/ui/input.d.ts +3 -0
  335. package/dist/ui/input.js +17 -0
  336. package/dist/ui/input.js.map +1 -0
  337. package/dist/ui/label.d.ts +3 -0
  338. package/dist/ui/label.js +15 -0
  339. package/dist/ui/label.js.map +1 -0
  340. package/dist/ui/progress.d.ts +7 -0
  341. package/dist/ui/progress.js +31 -0
  342. package/dist/ui/progress.js.map +1 -0
  343. package/dist/ui/select.d.ts +15 -0
  344. package/dist/ui/select.js +98 -0
  345. package/dist/ui/select.js.map +1 -0
  346. package/dist/ui/skeleton.d.ts +2 -0
  347. package/dist/ui/skeleton.js +14 -0
  348. package/dist/ui/skeleton.js.map +1 -0
  349. package/dist/ui/slider.d.ts +3 -0
  350. package/dist/ui/slider.js +35 -0
  351. package/dist/ui/slider.js.map +1 -0
  352. package/dist/ui/switch.d.ts +5 -0
  353. package/dist/ui/switch.js +20 -0
  354. package/dist/ui/switch.js.map +1 -0
  355. package/dist/ui/tabs.d.ts +10 -0
  356. package/dist/ui/tabs.js +47 -0
  357. package/dist/ui/tabs.js.map +1 -0
  358. package/dist/ui/textarea.d.ts +3 -0
  359. package/dist/ui/textarea.js +15 -0
  360. package/dist/ui/textarea.js.map +1 -0
  361. package/dist/ui/toggle-group.d.ts +5 -0
  362. package/dist/ui/toggle-group.js +23 -0
  363. package/dist/ui/toggle-group.js.map +1 -0
  364. package/dist/urls/index.d.ts +100 -0
  365. package/dist/urls.js +118 -0
  366. package/dist/urls.js.map +1 -0
  367. package/package.json +113 -3
@@ -0,0 +1,107 @@
1
+ import { toContentKitError as e } from "../client/errors.js";
2
+ import { useContentKitClient as t, useErrorReporter as n } from "./context.js";
3
+ import { useCallback as r, useEffect as i, useRef as a, useState as o } from "react";
4
+ //#region src/react/crop.ts
5
+ function s(s, c, l = {}) {
6
+ let { media: u } = t(l.client), d = n(l.onError), f = c ? `${s.kind}/${s.id}/${c}` : "", [p, m] = o(0), [h, g] = o({
7
+ key: "",
8
+ state: { status: "idle" }
9
+ }), _ = a({
10
+ o: l,
11
+ ref: s,
12
+ path: c
13
+ });
14
+ _.current = {
15
+ o: l,
16
+ ref: s,
17
+ path: c
18
+ }, i(() => {
19
+ let { ref: t, path: n } = _.current;
20
+ if (!n) return;
21
+ let r = new AbortController();
22
+ return g({
23
+ key: f,
24
+ state: { status: "loading" }
25
+ }), u.editorView(t, n, { signal: r.signal }).then((e) => g({
26
+ key: f,
27
+ state: {
28
+ status: "cropping",
29
+ source: {
30
+ url: e.url,
31
+ width: e.width,
32
+ height: e.height
33
+ },
34
+ edit: e.edit ?? null
35
+ }
36
+ }), (t) => {
37
+ if (r.signal.aborted) return;
38
+ let i = e(t);
39
+ g({
40
+ key: f,
41
+ state: {
42
+ status: "error",
43
+ error: i
44
+ }
45
+ }), d(i, "crop.load", n.split("/").pop());
46
+ }), () => r.abort();
47
+ }, [
48
+ u,
49
+ f,
50
+ p,
51
+ d
52
+ ]);
53
+ let v = h.key === f ? h.state : { status: f ? "loading" : "idle" }, y = a(v);
54
+ y.current = v;
55
+ let b = r(async (t) => {
56
+ let n = y.current, { ref: r, path: i, o: a } = _.current, o = "source" in n ? n.source : void 0;
57
+ if (i && o) {
58
+ g({
59
+ key: f,
60
+ state: {
61
+ status: "saving",
62
+ source: o,
63
+ edit: t
64
+ }
65
+ });
66
+ try {
67
+ let e = await u.commit(r, [{
68
+ op: "edit",
69
+ path: i,
70
+ ...t ? { edit: t } : {}
71
+ }]);
72
+ return a.wait && await u.waitFor(r, i), g({
73
+ key: f,
74
+ state: {
75
+ status: "done",
76
+ files: e
77
+ }
78
+ }), a.onSaved?.(e), e;
79
+ } catch (n) {
80
+ let r = e(n);
81
+ g({
82
+ key: f,
83
+ state: {
84
+ status: "error",
85
+ error: r,
86
+ source: o,
87
+ edit: t
88
+ }
89
+ }), d(r, "crop.save", i.split("/").pop());
90
+ return;
91
+ }
92
+ }
93
+ }, [
94
+ u,
95
+ f,
96
+ d
97
+ ]), x = r(() => m((e) => e + 1), []);
98
+ return {
99
+ ...v,
100
+ save: b,
101
+ retry: x
102
+ };
103
+ }
104
+ //#endregion
105
+ export { s as useEditorCrop };
106
+
107
+ //# sourceMappingURL=crop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crop.js","names":[],"sources":["../../src/react/crop.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../client/errors.js\";\nimport type { Edit, FileInfo, RefBody } from \"../client/generated/wire.js\";\nimport type { CropSource } from \"../client/image.js\";\nimport { useContentKitClient, useErrorReporter, type ContentKitErrorHandler } from \"./context.js\";\n\nexport interface EditorCropOptions {\n /** save() also waits until the worker rendered the edit. Default false (an editor read shows it processing). */\n wait?: boolean;\n /** With the item's uploads after each save. */\n onSaved?: (files: FileInfo[]) => void;\n /** Every failed load or save; default the provider's. */\n onError?: ContentKitErrorHandler;\n /** Overrides the provider's client. */\n client?: ContentKitClient;\n}\n\n/** source is the upload's editor view and its oriented size; edit its current edit. */\nexport type EditorCropState =\n | { status: \"idle\" }\n | { status: \"loading\" }\n | { status: \"cropping\"; source: CropSource; edit: Edit | null }\n | { status: \"saving\"; source: CropSource; edit: Edit | null }\n | { status: \"done\"; files: FileInfo[] }\n | { status: \"error\"; error: ContentKitError; source?: CropSource; edit?: Edit | null };\n\nexport type UseEditorCrop = EditorCropState & {\n /** Commits the edit (null removes it); resolves with the item's uploads, or undefined on failure. */\n save: (edit: Edit | null) => Promise<FileInfo[] | undefined>;\n /** Loads the editor view again after a failure. */\n retry: () => void;\n};\n\n/**\n * Re-crops a kept upload: while path is set, its editor view (the original,\n * oriented, unedited) loads for a cropper; save() commits an edit op. Nothing\n * is uploaded. Clear path to close.\n */\nexport function useEditorCrop(ref: RefBody, path: string | null | undefined, o: EditorCropOptions = {}): UseEditorCrop {\n const { media } = useContentKitClient(o.client);\n const report = useErrorReporter(o.onError);\n const key = path ? `${ref.kind}/${ref.id}/${path}` : \"\";\n const [attempt, setAttempt] = useState(0);\n const [s, setS] = useState<{ key: string; state: EditorCropState }>({ key: \"\", state: { status: \"idle\" } });\n const opts = useRef({ o, ref, path });\n opts.current = { o, ref, path };\n\n useEffect(() => {\n const { ref, path } = opts.current;\n if (!path) return;\n const ctl = new AbortController();\n setS({ key, state: { status: \"loading\" } });\n media.editorView(ref, path, { signal: ctl.signal }).then(\n (v) => setS({ key, state: { status: \"cropping\", source: { url: v.url, width: v.width, height: v.height }, edit: v.edit ?? null } }),\n (e: unknown) => {\n if (ctl.signal.aborted) return;\n const error = toContentKitError(e);\n setS({ key, state: { status: \"error\", error } });\n report(error, \"crop.load\", path.split(\"/\").pop());\n },\n );\n return () => ctl.abort();\n }, [media, key, attempt, report]);\n\n const current = s.key === key ? s.state : ({ status: key ? \"loading\" : \"idle\" } as EditorCropState);\n const now = useRef(current);\n now.current = current;\n\n const save = useCallback(\n async (edit: Edit | null) => {\n const c = now.current;\n const { ref, path, o } = opts.current;\n const source = \"source\" in c ? c.source : undefined;\n if (!path || !source) return undefined;\n setS({ key, state: { status: \"saving\", source, edit } });\n try {\n const files = await media.commit(ref, [{ op: \"edit\", path, ...(edit ? { edit } : {}) }]);\n if (o.wait) await media.waitFor(ref, path);\n setS({ key, state: { status: \"done\", files } });\n o.onSaved?.(files);\n return files;\n } catch (e) {\n const error = toContentKitError(e);\n setS({ key, state: { status: \"error\", error, source, edit } });\n report(error, \"crop.save\", path.split(\"/\").pop());\n return undefined;\n }\n },\n [media, key, report],\n );\n const retry = useCallback(() => setAttempt((n) => n + 1), []);\n return { ...current, save, retry };\n}\n"],"mappings":";;;;AAuCA,SAAgB,EAAc,GAAc,GAAiC,IAAuB,CAAC,GAAkB;CACrH,IAAM,EAAE,aAAU,EAAoB,EAAE,MAAM,GACxC,IAAS,EAAiB,EAAE,OAAO,GACnC,IAAM,IAAO,GAAG,EAAI,KAAK,GAAG,EAAI,GAAG,GAAG,MAAS,IAC/C,CAAC,GAAS,KAAc,EAAS,CAAC,GAClC,CAAC,GAAG,KAAQ,EAAkD;EAAE,KAAK;EAAI,OAAO,EAAE,QAAQ,OAAO;CAAE,CAAC,GACpG,IAAO,EAAO;EAAE;EAAG;EAAK;CAAK,CAAC;CAGpC,AAFA,EAAK,UAAU;EAAE;EAAG;EAAK;CAAK,GAE9B,QAAgB;EACd,IAAM,EAAE,QAAK,YAAS,EAAK;EAC3B,IAAI,CAAC,GAAM;EACX,IAAM,IAAM,IAAI,gBAAgB;EAWhC,OAVA,EAAK;GAAE;GAAK,OAAO,EAAE,QAAQ,UAAU;EAAE,CAAC,GAC1C,EAAM,WAAW,GAAK,GAAM,EAAE,QAAQ,EAAI,OAAO,CAAC,CAAC,CAAC,MACjD,MAAM,EAAK;GAAE;GAAK,OAAO;IAAE,QAAQ;IAAY,QAAQ;KAAE,KAAK,EAAE;KAAK,OAAO,EAAE;KAAO,QAAQ,EAAE;IAAO;IAAG,MAAM,EAAE,QAAQ;GAAK;EAAE,CAAC,IACjI,MAAe;GACd,IAAI,EAAI,OAAO,SAAS;GACxB,IAAM,IAAQ,EAAkB,CAAC;GAEjC,AADA,EAAK;IAAE;IAAK,OAAO;KAAE,QAAQ;KAAS;IAAM;GAAE,CAAC,GAC/C,EAAO,GAAO,aAAa,EAAK,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;EAClD,CACF,SACa,EAAI,MAAM;CACzB,GAAG;EAAC;EAAO;EAAK;EAAS;CAAM,CAAC;CAEhC,IAAM,IAAU,EAAE,QAAQ,IAAM,EAAE,QAAS,EAAE,QAAQ,IAAM,YAAY,OAAO,GACxE,IAAM,EAAO,CAAO;CAC1B,EAAI,UAAU;CAEd,IAAM,IAAO,EACX,OAAO,MAAsB;EAC3B,IAAM,IAAI,EAAI,SACR,EAAE,QAAK,SAAM,SAAM,EAAK,SACxB,IAAS,YAAY,IAAI,EAAE,SAAS,KAAA;EACtC,IAAC,KAAS,GACd;KAAK;IAAE;IAAK,OAAO;KAAE,QAAQ;KAAU;KAAQ;IAAK;GAAE,CAAC;GACvD,IAAI;IACF,IAAM,IAAQ,MAAM,EAAM,OAAO,GAAK,CAAC;KAAE,IAAI;KAAQ;KAAM,GAAI,IAAO,EAAE,QAAK,IAAI,CAAC;IAAG,CAAC,CAAC;IAIvF,OAHI,EAAE,QAAM,MAAM,EAAM,QAAQ,GAAK,CAAI,GACzC,EAAK;KAAE;KAAK,OAAO;MAAE,QAAQ;MAAQ;KAAM;IAAE,CAAC,GAC9C,EAAE,UAAU,CAAK,GACV;GACT,SAAS,GAAG;IACV,IAAM,IAAQ,EAAkB,CAAC;IAEjC,AADA,EAAK;KAAE;KAAK,OAAO;MAAE,QAAQ;MAAS;MAAO;MAAQ;KAAK;IAAE,CAAC,GAC7D,EAAO,GAAO,aAAa,EAAK,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;IAChD;GACF;EAZuD;CAazD,GACA;EAAC;EAAO;EAAK;CAAM,CACrB,GACM,IAAQ,QAAkB,GAAY,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;CAC5D,OAAO;EAAE,GAAG;EAAS;EAAM;CAAM;AACnC"}
@@ -0,0 +1,38 @@
1
+ import { ContentKitClient } from '../client/client.js';
2
+ import { ContentKitError } from '../client/errors.js';
3
+ import { Reaction } from '../client/content/types.js';
4
+ import { FavoriteState, ReactionCounts, RefBody } from '../client/generated/wire.js';
5
+ export interface UseReaction {
6
+ counts: ReactionCounts;
7
+ loading: boolean;
8
+ error?: ContentKitError;
9
+ /** Sets the caller's reaction at once; rolled back if the server refuses it. */
10
+ set: (value: Reaction) => Promise<void>;
11
+ /** Sets value, or clears it when it is the current one. */
12
+ toggle: (value: 1 | -1) => Promise<void>;
13
+ }
14
+ /** An item's likes and dislikes and the caller's own reaction (initial: counts the host already has). */
15
+ export declare function useReaction(ref: RefBody, o?: {
16
+ initial?: ReactionCounts;
17
+ client?: ContentKitClient;
18
+ }): UseReaction;
19
+ export interface UseFavorite {
20
+ favorited: boolean;
21
+ /** How many favorited the item; undefined until read. */
22
+ count?: number;
23
+ loading: boolean;
24
+ /** A write is in flight. */
25
+ pending: boolean;
26
+ error?: ContentKitError;
27
+ /** Sets it at once (count moved by one); rolled back if the server refuses it. */
28
+ set: (favorited: boolean) => Promise<void>;
29
+ toggle: () => Promise<void>;
30
+ }
31
+ /**
32
+ * An item's favorite count and whether the signed-in caller favorited it
33
+ * (initial: what the host already has). Signed out, favorited stays false.
34
+ */
35
+ export declare function useFavorite(ref: RefBody, o?: {
36
+ initial?: FavoriteState;
37
+ client?: ContentKitClient;
38
+ }): UseFavorite;
@@ -0,0 +1,88 @@
1
+ import { toContentKitError as e } from "../client/errors.js";
2
+ import { keyOf as t, useContentScope as n, useResource as r } from "./use-resource.js";
3
+ import { withReaction as i } from "./comments.js";
4
+ import { useCallback as a, useState as o } from "react";
5
+ //#region src/react/engagement.ts
6
+ var s = {
7
+ likes: 0,
8
+ dislikes: 0,
9
+ mine: 0
10
+ };
11
+ function c(o, c = {}) {
12
+ let { client: l, store: u, viewer: d } = n(c.client), f = t("reaction", d, o.kind, o.id), p = r(u, f, {
13
+ type: "reaction",
14
+ ref: {
15
+ kind: o.kind,
16
+ id: o.id
17
+ }
18
+ }, (e) => l.reactions.get(o, e), { initial: c.initial }), m = p.data ?? s, { kind: h, id: g } = o, _ = a(async (t) => {
19
+ let n = u.snapshot(f).data ?? m, r = u.mark(f);
20
+ u.set(f, i(n, t));
21
+ try {
22
+ await l.reactions.set({
23
+ kind: h,
24
+ id: g
25
+ }, t);
26
+ } catch (t) {
27
+ throw u.rollback(f, r, n), e(t);
28
+ }
29
+ }, [
30
+ l,
31
+ u,
32
+ f,
33
+ h,
34
+ g,
35
+ m
36
+ ]), v = a((e) => _(m.mine === e ? 0 : e), [_, m.mine]);
37
+ return {
38
+ counts: m,
39
+ loading: p.loading || !p.loaded && c.initial === void 0,
40
+ error: p.error,
41
+ set: _,
42
+ toggle: v
43
+ };
44
+ }
45
+ function l(i, s = {}) {
46
+ let { client: c, store: l, viewer: u } = n(s.client), d = t("favorite", u, i.kind, i.id), f = r(l, d, {
47
+ type: "favorite",
48
+ ref: {
49
+ kind: i.kind,
50
+ id: i.id
51
+ }
52
+ }, (e) => c.favorites.get(i, e), { initial: s.initial }), p = !!f.data?.favorited, [m, h] = o(!1), { kind: g, id: _ } = i, v = a(async (t) => {
53
+ let n = l.snapshot(d).data, r = l.mark(d);
54
+ n && n.favorited !== t && l.set(d, {
55
+ favorited: t,
56
+ count: Math.max(0, n.count + (t ? 1 : -1))
57
+ }), h(!0);
58
+ try {
59
+ await c.favorites.set({
60
+ kind: g,
61
+ id: _
62
+ }, t);
63
+ } catch (t) {
64
+ throw n && l.rollback(d, r, n), e(t);
65
+ } finally {
66
+ h(!1);
67
+ }
68
+ }, [
69
+ c,
70
+ l,
71
+ d,
72
+ g,
73
+ _
74
+ ]), y = a(() => v(!p), [v, p]);
75
+ return {
76
+ favorited: p,
77
+ count: f.data?.count,
78
+ loading: f.loading || !f.loaded && s.initial === void 0,
79
+ pending: m,
80
+ error: f.error,
81
+ set: v,
82
+ toggle: y
83
+ };
84
+ }
85
+ //#endregion
86
+ export { l as useFavorite, c as useReaction };
87
+
88
+ //# sourceMappingURL=engagement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engagement.js","names":[],"sources":["../../src/react/engagement.ts"],"sourcesContent":["import { useCallback, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport { toContentKitError } from \"../client/errors.js\";\nimport type { Reaction } from \"../client/content/types.js\";\nimport type { FavoriteState, ReactionCounts, RefBody } from \"../client/generated/wire.js\";\nimport { withReaction } from \"./comments.js\";\nimport { keyOf, useContentScope, useResource } from \"./use-resource.js\";\n\nexport interface UseReaction {\n counts: ReactionCounts;\n loading: boolean;\n error?: ContentKitError;\n /** Sets the caller's reaction at once; rolled back if the server refuses it. */\n set: (value: Reaction) => Promise<void>;\n /** Sets value, or clears it when it is the current one. */\n toggle: (value: 1 | -1) => Promise<void>;\n}\n\nconst ZERO: ReactionCounts = { likes: 0, dislikes: 0, mine: 0 };\n\n/** An item's likes and dislikes and the caller's own reaction (initial: counts the host already has). */\nexport function useReaction(ref: RefBody, o: { initial?: ReactionCounts; client?: ContentKitClient } = {}): UseReaction {\n const { client, store, viewer } = useContentScope(o.client);\n const key = keyOf(\"reaction\", viewer, ref.kind, ref.id);\n const r = useResource<ReactionCounts>(store, key, { type: \"reaction\", ref: { kind: ref.kind, id: ref.id } }, (s) => client.reactions.get(ref, s), { initial: o.initial });\n const counts = r.data ?? ZERO;\n const { kind, id } = ref;\n const set = useCallback(\n async (value: Reaction) => {\n const prev = store.snapshot<ReactionCounts>(key).data ?? counts;\n const token = store.mark(key);\n store.set(key, withReaction(prev, value));\n try {\n await client.reactions.set({ kind, id }, value);\n } catch (e) {\n store.rollback(key, token, prev);\n throw toContentKitError(e);\n }\n },\n [client, store, key, kind, id, counts],\n );\n const toggle = useCallback((value: 1 | -1) => set(counts.mine === value ? 0 : value), [set, counts.mine]);\n return { counts, loading: r.loading || (!r.loaded && o.initial === undefined), error: r.error, set, toggle };\n}\n\nexport interface UseFavorite {\n favorited: boolean;\n /** How many favorited the item; undefined until read. */\n count?: number;\n loading: boolean;\n /** A write is in flight. */\n pending: boolean;\n error?: ContentKitError;\n /** Sets it at once (count moved by one); rolled back if the server refuses it. */\n set: (favorited: boolean) => Promise<void>;\n toggle: () => Promise<void>;\n}\n\n/**\n * An item's favorite count and whether the signed-in caller favorited it\n * (initial: what the host already has). Signed out, favorited stays false.\n */\nexport function useFavorite(ref: RefBody, o: { initial?: FavoriteState; client?: ContentKitClient } = {}): UseFavorite {\n const { client, store, viewer } = useContentScope(o.client);\n const key = keyOf(\"favorite\", viewer, ref.kind, ref.id);\n const r = useResource<FavoriteState>(store, key, { type: \"favorite\", ref: { kind: ref.kind, id: ref.id } }, (s) => client.favorites.get(ref, s), { initial: o.initial });\n const favorited = !!r.data?.favorited;\n const [pending, setPending] = useState(false);\n const { kind, id } = ref;\n const set = useCallback(\n async (next: boolean) => {\n const prev = store.snapshot<FavoriteState>(key).data;\n const token = store.mark(key);\n if (prev && prev.favorited !== next) store.set<FavoriteState>(key, { favorited: next, count: Math.max(0, prev.count + (next ? 1 : -1)) });\n setPending(true);\n try {\n await client.favorites.set({ kind, id }, next);\n } catch (e) {\n if (prev) store.rollback(key, token, prev);\n throw toContentKitError(e);\n } finally {\n setPending(false);\n }\n },\n [client, store, key, kind, id],\n );\n const toggle = useCallback(() => set(!favorited), [set, favorited]);\n return { favorited, count: r.data?.count, loading: r.loading || (!r.loaded && o.initial === undefined), pending, error: r.error, set, toggle };\n}\n"],"mappings":";;;;;AAmBA,IAAM,IAAuB;CAAE,OAAO;CAAG,UAAU;CAAG,MAAM;AAAE;AAG9D,SAAgB,EAAY,GAAc,IAA6D,CAAC,GAAgB;CACtH,IAAM,EAAE,WAAQ,UAAO,cAAW,EAAgB,EAAE,MAAM,GACpD,IAAM,EAAM,YAAY,GAAQ,EAAI,MAAM,EAAI,EAAE,GAChD,IAAI,EAA4B,GAAO,GAAK;EAAE,MAAM;EAAY,KAAK;GAAE,MAAM,EAAI;GAAM,IAAI,EAAI;EAAG;CAAE,IAAI,MAAM,EAAO,UAAU,IAAI,GAAK,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,GAClK,IAAS,EAAE,QAAQ,GACnB,EAAE,SAAM,UAAO,GACf,IAAM,EACV,OAAO,MAAoB;EACzB,IAAM,IAAO,EAAM,SAAyB,CAAG,CAAC,CAAC,QAAQ,GACnD,IAAQ,EAAM,KAAK,CAAG;EAC5B,EAAM,IAAI,GAAK,EAAa,GAAM,CAAK,CAAC;EACxC,IAAI;GACF,MAAM,EAAO,UAAU,IAAI;IAAE;IAAM;GAAG,GAAG,CAAK;EAChD,SAAS,GAAG;GAEV,MADA,EAAM,SAAS,GAAK,GAAO,CAAI,GACzB,EAAkB,CAAC;EAC3B;CACF,GACA;EAAC;EAAQ;EAAO;EAAK;EAAM;EAAI;CAAM,CACvC,GACM,IAAS,GAAa,MAAkB,EAAI,EAAO,SAAS,IAAQ,IAAI,CAAK,GAAG,CAAC,GAAK,EAAO,IAAI,CAAC;CACxG,OAAO;EAAE;EAAQ,SAAS,EAAE,WAAY,CAAC,EAAE,UAAU,EAAE,YAAY,KAAA;EAAY,OAAO,EAAE;EAAO;EAAK;CAAO;AAC7G;AAmBA,SAAgB,EAAY,GAAc,IAA4D,CAAC,GAAgB;CACrH,IAAM,EAAE,WAAQ,UAAO,cAAW,EAAgB,EAAE,MAAM,GACpD,IAAM,EAAM,YAAY,GAAQ,EAAI,MAAM,EAAI,EAAE,GAChD,IAAI,EAA2B,GAAO,GAAK;EAAE,MAAM;EAAY,KAAK;GAAE,MAAM,EAAI;GAAM,IAAI,EAAI;EAAG;CAAE,IAAI,MAAM,EAAO,UAAU,IAAI,GAAK,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,GACjK,IAAY,CAAC,CAAC,EAAE,MAAM,WACtB,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,EAAE,SAAM,UAAO,GACf,IAAM,EACV,OAAO,MAAkB;EACvB,IAAM,IAAO,EAAM,SAAwB,CAAG,CAAC,CAAC,MAC1C,IAAQ,EAAM,KAAK,CAAG;EAE5B,AADI,KAAQ,EAAK,cAAc,KAAM,EAAM,IAAmB,GAAK;GAAE,WAAW;GAAM,OAAO,KAAK,IAAI,GAAG,EAAK,SAAS,IAAO,IAAI,GAAG;EAAE,CAAC,GACxI,EAAW,EAAI;EACf,IAAI;GACF,MAAM,EAAO,UAAU,IAAI;IAAE;IAAM;GAAG,GAAG,CAAI;EAC/C,SAAS,GAAG;GAEV,MADI,KAAM,EAAM,SAAS,GAAK,GAAO,CAAI,GACnC,EAAkB,CAAC;EAC3B,UAAU;GACR,EAAW,EAAK;EAClB;CACF,GACA;EAAC;EAAQ;EAAO;EAAK;EAAM;CAAE,CAC/B,GACM,IAAS,QAAkB,EAAI,CAAC,CAAS,GAAG,CAAC,GAAK,CAAS,CAAC;CAClE,OAAO;EAAE;EAAW,OAAO,EAAE,MAAM;EAAO,SAAS,EAAE,WAAY,CAAC,EAAE,UAAU,EAAE,YAAY,KAAA;EAAY;EAAS,OAAO,EAAE;EAAO;EAAK;CAAO;AAC/I"}
@@ -0,0 +1,83 @@
1
+ import { ContentKitClient } from '../client/client.js';
2
+ import { ContentKitError } from '../client/errors.js';
3
+ import { Edit, FileInfo, ReadResult, RefBody, UploadRule } from '../client/generated/wire.js';
4
+ import { Screened } from '../client/media/rules.js';
5
+ import { ContentKitErrorHandler } from './context.js';
6
+ import { UseMediaRead } from './read.js';
7
+ import { UseUploadQueue } from './upload.js';
8
+ export interface MediaFolderOptions {
9
+ /**
10
+ * The upload paths shown and added to, e.g. ["images/{name}",
11
+ * "videos/{name}"]: one group each. Default every pattern path of the kind
12
+ * the server does not name. A file goes to the first path whose rule takes
13
+ * its type; before the server states rules, to the first path.
14
+ */
15
+ paths?: readonly string[];
16
+ /**
17
+ * "manual" (default): commit() adds the uploaded files. "auto": each
18
+ * upload commits once those before it have, in the order added (a draft).
19
+ */
20
+ commit?: "manual" | "auto";
21
+ /** A file's name under its path; default its own, numbered around names taken. */
22
+ name?: (file: File) => string;
23
+ /** Files uploading at once. Default 2. */
24
+ concurrency?: number;
25
+ /** Poll interval (ms) while uploads process. Default 2500. */
26
+ poll?: number | false;
27
+ /** Every failure (uploads, commits, updates, processing); default the provider's. */
28
+ onError?: ContentKitErrorHandler;
29
+ /** Overrides the provider's client. */
30
+ client?: ContentKitClient;
31
+ }
32
+ export interface FolderGroup {
33
+ /** The upload path, e.g. "images/{name}". */
34
+ path: string;
35
+ /** Its rules, once an editor read states them. */
36
+ rule?: UploadRule;
37
+ /** Its uploads in manifest order. */
38
+ files: FileInfo[];
39
+ }
40
+ export interface UseMediaFolder {
41
+ /** The editor read of the item (every window, polled while processing). */
42
+ read: UseMediaRead;
43
+ groups: FolderGroup[];
44
+ /** Every group's uploads. */
45
+ uploads: FileInfo[];
46
+ queue: UseUploadQueue;
47
+ /** Screens files against the rules and queues the rest; returns the refusals. */
48
+ add: (files: Iterable<File>) => Screened["refused"];
49
+ /** The last add()'s refusals. */
50
+ refused: Screened["refused"];
51
+ dismiss: () => void;
52
+ /** Moves an upload to index among its group's uploads. */
53
+ move: (path: string, index: number) => Promise<void>;
54
+ remove: (paths: readonly string[]) => Promise<void>;
55
+ /** Renames an upload within its path; the extension stays unless name has one. */
56
+ rename: (path: string, name: string) => Promise<void>;
57
+ edit: (path: string, edit: Edit | null) => Promise<void>;
58
+ /** Uploads file in place of the upload at path (same position and meta, no edit). */
59
+ replace: (path: string, file: File) => Promise<void>;
60
+ /** Commits the uploaded files in queue order and clears them from the queue. */
61
+ commit: () => Promise<FileInfo[]>;
62
+ /** Stops every upload, aborts its multipart upload and empties the queue (before deleting a draft). */
63
+ discard: () => void;
64
+ /** An update (move, remove, rename, edit, replace) is running. */
65
+ updating: boolean;
66
+ committing: boolean;
67
+ /** The last update's or commit's failure; cleared by the next success. */
68
+ error?: ContentKitError;
69
+ }
70
+ /** The upload's name under its group ("images/a.png" in "images/{name}" is "a.png"). */
71
+ export declare const nameIn: (group: {
72
+ path: string;
73
+ }, path: string) => string;
74
+ /** Its smallest derived image with a URL: a thumbnail for an editor. */
75
+ export declare function thumbnailOf(read: ReadResult | null | undefined, upload: FileInfo): FileInfo | undefined;
76
+ /**
77
+ * An item's folder for its editors: the editor read, an upload queue, the
78
+ * kind's upload rules screening files before they upload, and the updates
79
+ * (move, remove, rename, edit, replace). Uploads the worker fails after this
80
+ * mounted are reported once ("folder.process"). The queue is the first
81
+ * item's: key the component by ref to switch items.
82
+ */
83
+ export declare function useMediaFolder(ref: RefBody, o?: MediaFolderOptions): UseMediaFolder;
@@ -0,0 +1,183 @@
1
+ import { ContentKitError as e, failureError as t, toContentKitError as n } from "../client/errors.js";
2
+ import { stem as r } from "../client/media/client.js";
3
+ import { filesFor as i, isPattern as a, ruleDir as o, ruleFor as s, screenFiles as c, uniqueName as l, uploadRules as u } from "../client/media/rules.js";
4
+ import { useContentKitClient as d, useErrorReporter as f } from "./context.js";
5
+ import { useUploadQueue as p } from "./upload.js";
6
+ import { useMediaRead as m } from "./read.js";
7
+ import { useCallback as h, useEffect as g, useMemo as _, useRef as v, useState as y } from "react";
8
+ //#region src/react/folder.ts
9
+ var b = {
10
+ start: 0,
11
+ end: 2 ** 53 - 1,
12
+ chunk: 200
13
+ }, x = (e, t) => t.slice(o(e.path).length);
14
+ function S(e, t) {
15
+ let n;
16
+ for (let r of e?.files ?? []) !r.upload && r.from === t.path && r.url && r.type.startsWith("image/") && (!n || (r.w ?? Infinity) < (n.w ?? Infinity)) && (n = r);
17
+ return n;
18
+ }
19
+ function C(S, C = {}) {
20
+ let w = d(C.client), T = f(C.onError), E = m(S, {
21
+ editor: !0,
22
+ window: b,
23
+ poll: C.poll,
24
+ client: w
25
+ }), D = u(E.read), O = C.paths?.join("\n"), k = _(() => O === void 0 ? D.filter((e) => a(e.path) && !e.named).map((e) => e.path) : O.split("\n").filter(Boolean), [O, D]), A = _(() => {
26
+ let e = D.length ? D : k.map((e) => ({ path: e }));
27
+ return k.map((t) => ({
28
+ path: t,
29
+ rule: D.find((e) => e.path === t),
30
+ files: i(E.read, { path: t }, e)
31
+ }));
32
+ }, [
33
+ k,
34
+ D,
35
+ E.read
36
+ ]), j = _(() => A.flatMap((e) => e.files), [A]), M = p({
37
+ client: w,
38
+ ref: S,
39
+ path: `${o(k[0] ?? "{name}")}{name}`,
40
+ concurrency: C.concurrency
41
+ }), N = M.queue, [P, F] = y([]), [I, L] = y(0), [R, z] = y(!1), [B, V] = y(), [H, U] = y(), W = v(C);
42
+ W.current = C;
43
+ let G = v({
44
+ groups: A,
45
+ ref: S
46
+ });
47
+ G.current = {
48
+ groups: A,
49
+ ref: S
50
+ };
51
+ let K = h((e) => {
52
+ let { groups: t } = G.current, n = t.map((e) => e.rule ?? {
53
+ path: e.path,
54
+ types: [],
55
+ max_bytes: 0
56
+ }), r = N.getSnapshot().items.filter((e) => e.status !== "failed"), i = (e, t) => s(n, e)?.path === t.path, a = c(e, n, (e) => t.find((t) => t.path === e.path).files.length + r.filter((t) => i(t.path, e)).length), u = /* @__PURE__ */ new Map(), d = (e) => {
57
+ let n = u.get(e.path);
58
+ if (!n) {
59
+ let a = t.find((t) => t.path === e.path);
60
+ n = [...a.files.map((e) => x(a, e.path)), ...r.filter((t) => i(t.path, e)).map((e) => x(a, e.path))], u.set(e.path, n);
61
+ }
62
+ return n;
63
+ }, f = /* @__PURE__ */ new Map();
64
+ for (let { file: e, rule: t } of a.accepted) {
65
+ let n = d(t), r = W.current.name?.(e) ?? l(e.name, n);
66
+ n.push(r), f.set(e, o(t.path) + r);
67
+ }
68
+ f.size && (N.add(f.keys(), { path: (e) => f.get(e) }), N.getSnapshot().blocked && N.start(), U(void 0)), F(a.refused);
69
+ for (let e of a.refused) T(e.error, "upload", e.file.name);
70
+ return a.refused;
71
+ }, [N, T]), q = h(async (e, t) => {
72
+ L((e) => e + 1);
73
+ try {
74
+ t ? await t() : await w.media.commit(G.current.ref, e), V(void 0);
75
+ } catch (e) {
76
+ let t = n(e);
77
+ throw t.code !== "aborted" && V(t), T(t, "folder.update"), t;
78
+ } finally {
79
+ L((e) => e - 1);
80
+ }
81
+ }, [w, T]), J = h(async () => {
82
+ z(!0);
83
+ try {
84
+ let e = await N.commit(void 0, { head: W.current.commit === "auto" });
85
+ for (let e of N.getSnapshot().items) e.status === "committed" && N.remove(e.id);
86
+ return V(void 0), e;
87
+ } catch (e) {
88
+ let t = n(e);
89
+ throw V(t), T(t, "folder.commit"), t;
90
+ } finally {
91
+ z(!1);
92
+ }
93
+ }, [N, T]), Y = C.commit === "auto", X = M.items[0]?.status === "uploaded";
94
+ g(() => {
95
+ Y && X && !R && !H && J().catch((e) => U(n(e)));
96
+ }, [
97
+ Y,
98
+ X,
99
+ R,
100
+ H,
101
+ J
102
+ ]);
103
+ let Z = h(async () => (U(void 0), J()), [J]), Q = v(/* @__PURE__ */ new Set());
104
+ g(() => {
105
+ for (let e of M.items) e.status === "failed" && e.error && !Q.current.has(e.error) && (Q.current.add(e.error), T(e.error, "upload", e.file.name));
106
+ M.blocked && !Q.current.has(M.blocked) && (Q.current.add(M.blocked), T(M.blocked, "upload"));
107
+ }, [
108
+ M.items,
109
+ M.blocked,
110
+ T
111
+ ]);
112
+ let $ = v(null);
113
+ g(() => {
114
+ if (!E.read) return;
115
+ let e = j.filter((e) => e.failed);
116
+ if (!$.current) {
117
+ $.current = new Set(e.map((e) => `${e.path}:${e.failed.of}`));
118
+ return;
119
+ }
120
+ for (let n of e) {
121
+ let e = `${n.path}:${n.failed.of}`;
122
+ $.current.has(e) || ($.current.add(e), T(t(n.failed), "folder.process", n.path.split("/").pop()));
123
+ }
124
+ }, [
125
+ E.read,
126
+ j,
127
+ T
128
+ ]), g(() => void (E.error && T(E.error, "folder.load")), [E.error, T]);
129
+ let ee = (e) => G.current.groups.find((t) => s([{ path: t.path }], e));
130
+ return {
131
+ read: E,
132
+ groups: A,
133
+ uploads: j,
134
+ queue: M,
135
+ add: K,
136
+ refused: P,
137
+ dismiss: h(() => F([]), []),
138
+ move: h((e, t) => q([{
139
+ op: "move",
140
+ path: e,
141
+ index: t
142
+ }]), [q]),
143
+ remove: h((e) => q(e.map((e) => ({
144
+ op: "remove",
145
+ path: e
146
+ }))), [q]),
147
+ rename: h((t, n) => {
148
+ let i = ee(t), a = (i ? o(i.path) : t.slice(0, t.lastIndexOf("/") + 1)) + n.trim();
149
+ if (r(a) === r(t)) return Promise.resolve();
150
+ if (i?.files.some((e) => r(e.path) === r(a))) {
151
+ let t = new e("conflict", `${n} exists`, { status: 409 });
152
+ return V(t), Promise.reject(t);
153
+ }
154
+ return q([{
155
+ op: "rename",
156
+ path: t,
157
+ to: a
158
+ }]);
159
+ }, [q]),
160
+ edit: h((e, t) => q([{
161
+ op: "edit",
162
+ path: e,
163
+ ...t ? { edit: t } : {}
164
+ }]), [q]),
165
+ replace: h((e, t) => q([], () => w.media.put(t, {
166
+ ref: G.current.ref,
167
+ path: r(e),
168
+ wait: !1
169
+ })), [q, w]),
170
+ commit: Z,
171
+ discard: h(() => {
172
+ for (let e of N.getSnapshot().items) N.remove(e.id);
173
+ N.pause();
174
+ }, [N]),
175
+ updating: I > 0,
176
+ committing: R,
177
+ error: B ?? H
178
+ };
179
+ }
180
+ //#endregion
181
+ export { x as nameIn, S as thumbnailOf, C as useMediaFolder };
182
+
183
+ //# sourceMappingURL=folder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"folder.js","names":[],"sources":["../../src/react/folder.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport { ContentKitError, failureError, toContentKitError } from \"../client/errors.js\";\nimport type { Edit, FileInfo, Op, ReadResult, RefBody, UploadRule } from \"../client/generated/wire.js\";\nimport { stem } from \"../client/media/client.js\";\nimport { filesFor, isPattern, ruleDir, ruleFor, screenFiles, uniqueName, uploadRules, type Screened } from \"../client/media/rules.js\";\nimport { useContentKitClient, useErrorReporter, type ContentKitErrorHandler } from \"./context.js\";\nimport { useMediaRead, type UseMediaRead } from \"./read.js\";\nimport { useUploadQueue, type UseUploadQueue } from \"./upload.js\";\n\nexport interface MediaFolderOptions {\n /**\n * The upload paths shown and added to, e.g. [\"images/{name}\",\n * \"videos/{name}\"]: one group each. Default every pattern path of the kind\n * the server does not name. A file goes to the first path whose rule takes\n * its type; before the server states rules, to the first path.\n */\n paths?: readonly string[];\n /**\n * \"manual\" (default): commit() adds the uploaded files. \"auto\": each\n * upload commits once those before it have, in the order added (a draft).\n */\n commit?: \"manual\" | \"auto\";\n /** A file's name under its path; default its own, numbered around names taken. */\n name?: (file: File) => string;\n /** Files uploading at once. Default 2. */\n concurrency?: number;\n /** Poll interval (ms) while uploads process. Default 2500. */\n poll?: number | false;\n /** Every failure (uploads, commits, updates, processing); default the provider's. */\n onError?: ContentKitErrorHandler;\n /** Overrides the provider's client. */\n client?: ContentKitClient;\n}\n\nexport interface FolderGroup {\n /** The upload path, e.g. \"images/{name}\". */\n path: string;\n /** Its rules, once an editor read states them. */\n rule?: UploadRule;\n /** Its uploads in manifest order. */\n files: FileInfo[];\n}\n\nexport interface UseMediaFolder {\n /** The editor read of the item (every window, polled while processing). */\n read: UseMediaRead;\n groups: FolderGroup[];\n /** Every group's uploads. */\n uploads: FileInfo[];\n queue: UseUploadQueue;\n /** Screens files against the rules and queues the rest; returns the refusals. */\n add: (files: Iterable<File>) => Screened[\"refused\"];\n /** The last add()'s refusals. */\n refused: Screened[\"refused\"];\n dismiss: () => void;\n /** Moves an upload to index among its group's uploads. */\n move: (path: string, index: number) => Promise<void>;\n remove: (paths: readonly string[]) => Promise<void>;\n /** Renames an upload within its path; the extension stays unless name has one. */\n rename: (path: string, name: string) => Promise<void>;\n edit: (path: string, edit: Edit | null) => Promise<void>;\n /** Uploads file in place of the upload at path (same position and meta, no edit). */\n replace: (path: string, file: File) => Promise<void>;\n /** Commits the uploaded files in queue order and clears them from the queue. */\n commit: () => Promise<FileInfo[]>;\n /** Stops every upload, aborts its multipart upload and empties the queue (before deleting a draft). */\n discard: () => void;\n /** An update (move, remove, rename, edit, replace) is running. */\n updating: boolean;\n committing: boolean;\n /** The last update's or commit's failure; cleared by the next success. */\n error?: ContentKitError;\n}\n\nconst ALL = { start: 0, end: Number.MAX_SAFE_INTEGER, chunk: 200 };\n\n/** The upload's name under its group (\"images/a.png\" in \"images/{name}\" is \"a.png\"). */\nexport const nameIn = (group: { path: string }, path: string) => path.slice(ruleDir(group.path).length);\n\n/** Its smallest derived image with a URL: a thumbnail for an editor. */\nexport function thumbnailOf(read: ReadResult | null | undefined, upload: FileInfo): FileInfo | undefined {\n let best: FileInfo | undefined;\n for (const f of read?.files ?? []) {\n if (f.upload || f.from !== upload.path || !f.url || !f.type.startsWith(\"image/\")) continue;\n if (!best || (f.w ?? Infinity) < (best.w ?? Infinity)) best = f;\n }\n return best;\n}\n\n/**\n * An item's folder for its editors: the editor read, an upload queue, the\n * kind's upload rules screening files before they upload, and the updates\n * (move, remove, rename, edit, replace). Uploads the worker fails after this\n * mounted are reported once (\"folder.process\"). The queue is the first\n * item's: key the component by ref to switch items.\n */\nexport function useMediaFolder(ref: RefBody, o: MediaFolderOptions = {}): UseMediaFolder {\n const client = useContentKitClient(o.client);\n const report = useErrorReporter(o.onError);\n const read = useMediaRead(ref, { editor: true, window: ALL, poll: o.poll, client });\n const rules = uploadRules(read.read);\n const pathsKey = o.paths?.join(\"\\n\");\n const groupPaths = useMemo(\n () => (pathsKey !== undefined ? pathsKey.split(\"\\n\").filter(Boolean) : rules.filter((r) => isPattern(r.path) && !r.named).map((r) => r.path)),\n [pathsKey, rules],\n );\n const groups = useMemo((): FolderGroup[] => {\n const known: { path: string }[] = rules.length ? rules : groupPaths.map((path) => ({ path }));\n return groupPaths.map((path) => ({ path, rule: rules.find((r) => r.path === path), files: filesFor(read.read, { path }, known) }));\n }, [groupPaths, rules, read.read]);\n const uploads = useMemo(() => groups.flatMap((g) => g.files), [groups]);\n\n const queue = useUploadQueue({ client, ref, path: `${ruleDir(groupPaths[0] ?? \"{name}\")}{name}`, concurrency: o.concurrency });\n // The UploadQueue itself is stable; the hook's wrapper is new every render.\n const q = queue.queue;\n const [refused, setRefused] = useState<Screened[\"refused\"]>([]);\n const [updating, setUpdating] = useState(0);\n const [committing, setCommitting] = useState(false);\n const [error, setError] = useState<ContentKitError>();\n // An automatic commit that failed: no more until commit() or new files.\n const [stalled, setStalled] = useState<ContentKitError | undefined>();\n const opts = useRef(o);\n opts.current = o;\n const state = useRef({ groups, ref });\n state.current = { groups, ref };\n\n const add = useCallback(\n (files: Iterable<File>) => {\n const { groups } = state.current;\n const gs = groups.map((g) => g.rule ?? { path: g.path, types: [], max_bytes: 0 });\n const queued = q.getSnapshot().items.filter((i) => i.status !== \"failed\");\n const inGroup = (path: string, rule: UploadRule) => ruleFor(gs, path)?.path === rule.path;\n const s = screenFiles(files, gs, (rule) => groups.find((g) => g.path === rule.path)!.files.length + queued.filter((i) => inGroup(i.path, rule)).length);\n const taken = new Map<string, string[]>();\n const takenIn = (rule: UploadRule) => {\n let t = taken.get(rule.path);\n if (!t) {\n const g = groups.find((x) => x.path === rule.path)!;\n t = [...g.files.map((f) => nameIn(g, f.path)), ...queued.filter((i) => inGroup(i.path, rule)).map((i) => nameIn(g, i.path))];\n taken.set(rule.path, t);\n }\n return t;\n };\n const paths = new Map<File, string>();\n for (const { file, rule } of s.accepted) {\n const t = takenIn(rule);\n const name = opts.current.name?.(file) ?? uniqueName(file.name, t);\n t.push(name);\n paths.set(file, ruleDir(rule.path) + name);\n }\n if (paths.size) {\n q.add(paths.keys(), { path: (f) => paths.get(f)! });\n if (q.getSnapshot().blocked) q.start();\n setStalled(undefined);\n }\n setRefused(s.refused);\n for (const r of s.refused) report(r.error, \"upload\", r.file.name);\n return s.refused;\n },\n [q, report],\n );\n\n const update = useCallback(\n async (ops: Op[], run?: () => Promise<unknown>) => {\n setUpdating((n) => n + 1);\n try {\n if (run) await run();\n else await client.media.commit(state.current.ref, ops);\n setError(undefined);\n } catch (e) {\n const err = toContentKitError(e);\n if (err.code !== \"aborted\") setError(err);\n report(err, \"folder.update\");\n throw err;\n } finally {\n setUpdating((n) => n - 1);\n }\n },\n [client, report],\n );\n\n const commit = useCallback(async () => {\n setCommitting(true);\n try {\n const files = await q.commit(undefined, { head: opts.current.commit === \"auto\" });\n for (const i of q.getSnapshot().items) if (i.status === \"committed\") q.remove(i.id);\n setError(undefined);\n return files;\n } catch (e) {\n const err = toContentKitError(e);\n setError(err);\n report(err, \"folder.commit\");\n throw err;\n } finally {\n setCommitting(false);\n }\n }, [q, report]);\n\n // A draft commits the uploaded head of the queue as it finishes; a failed commit waits for commit().\n const auto = o.commit === \"auto\";\n const head = queue.items[0];\n const headReady = head?.status === \"uploaded\";\n useEffect(() => {\n if (!auto || !headReady || committing || stalled) return;\n commit().catch((e: unknown) => setStalled(toContentKitError(e)));\n }, [auto, headReady, committing, stalled, commit]);\n const manualCommit = useCallback(async () => {\n setStalled(undefined);\n return commit();\n }, [commit]);\n\n // Each failed upload and queue-wide refusal is reported once; rows keep showing it.\n const seen = useRef(new Set<unknown>());\n useEffect(() => {\n for (const i of queue.items) {\n if (i.status !== \"failed\" || !i.error || seen.current.has(i.error)) continue;\n seen.current.add(i.error);\n report(i.error, \"upload\", i.file.name);\n }\n if (queue.blocked && !seen.current.has(queue.blocked)) {\n seen.current.add(queue.blocked);\n report(queue.blocked, \"upload\");\n }\n }, [queue.items, queue.blocked, report]);\n\n // Processing failures that appear after the first read.\n const failures = useRef<Set<string> | null>(null);\n useEffect(() => {\n if (!read.read) return;\n const failed = uploads.filter((f) => f.failed);\n if (!failures.current) {\n failures.current = new Set(failed.map((f) => `${f.path}:${f.failed!.of}`));\n return;\n }\n for (const f of failed) {\n const key = `${f.path}:${f.failed!.of}`;\n if (failures.current.has(key)) continue;\n failures.current.add(key);\n report(failureError(f.failed!), \"folder.process\", f.path.split(\"/\").pop());\n }\n }, [read.read, uploads, report]);\n\n useEffect(() => void (read.error && report(read.error, \"folder.load\")), [read.error, report]);\n\n // Reads the latest groups, so callbacks stay stable.\n const groupOf = (path: string) => state.current.groups.find((g) => ruleFor([{ path: g.path }], path));\n return {\n read,\n groups,\n uploads,\n queue,\n add,\n refused,\n dismiss: useCallback(() => setRefused([]), []),\n move: useCallback((path, index) => update([{ op: \"move\", path, index }]), [update]),\n remove: useCallback((paths) => update(paths.map((path): Op => ({ op: \"remove\", path }))), [update]),\n rename: useCallback(\n (path, name) => {\n const g = groupOf(path);\n const to = (g ? ruleDir(g.path) : path.slice(0, path.lastIndexOf(\"/\") + 1)) + name.trim();\n if (stem(to) === stem(path)) return Promise.resolve();\n if (g?.files.some((f) => stem(f.path) === stem(to))) {\n const err = new ContentKitError(\"conflict\", `${name} exists`, { status: 409 });\n setError(err);\n return Promise.reject(err);\n }\n return update([{ op: \"rename\", path, to }]);\n },\n [update],\n ),\n edit: useCallback((path, edit) => update([{ op: \"edit\", path, ...(edit ? { edit } : {}) }]), [update]),\n replace: useCallback(\n (path, file) => update([], () => client.media.put(file, { ref: state.current.ref, path: stem(path), wait: false })),\n [update, client],\n ),\n commit: manualCommit,\n discard: useCallback(() => {\n for (const i of q.getSnapshot().items) q.remove(i.id);\n q.pause();\n }, [q]),\n updating: updating > 0,\n committing,\n error: error ?? stalled,\n };\n}\n"],"mappings":"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"}