@jxsuite/studio 10.2.0 → 10.3.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 (271) hide show
  1. package/dist/chunks/{2020-bx702wqa.js → 2020-906vx2dq.js} +3 -3
  2. package/dist/chunks/adapter-hnvad61x.js +4 -0
  3. package/dist/chunks/add-new-flow-3tkn72ey.js +4 -0
  4. package/dist/chunks/cf-account-picker-xb8vvt2h.js +4 -0
  5. package/dist/chunks/cf-settings-mkbcz4z2.js +4 -0
  6. package/dist/chunks/components-w5zqwva1.js +4 -0
  7. package/dist/chunks/content-source-1vzxq1ba.js +4 -0
  8. package/dist/chunks/convert-to-repeater-gwzh9gar.js +4 -0
  9. package/dist/chunks/editor-wvf5e6j9.js +4 -0
  10. package/dist/chunks/entry-commands-mx2whrjx.js +4 -0
  11. package/dist/chunks/extension-sections-338ee35t.js +4 -0
  12. package/dist/chunks/file-ops-9bxvk59j.js +4 -0
  13. package/dist/chunks/files-t07yqqej.js +4 -0
  14. package/dist/chunks/format-host-5ja5gxyk.js +4 -0
  15. package/dist/chunks/fs-events-3424ezp3.js +4 -0
  16. package/dist/chunks/grid-open-1mpq9mzb.js +4 -0
  17. package/dist/chunks/{grid-view-tghcwrrt.js → grid-view-w9nfy203.js} +16 -16
  18. package/dist/chunks/icons-gb967qc8.js +4 -0
  19. package/dist/chunks/iframe-host-wsg0bn73.js +4 -0
  20. package/dist/chunks/image-bake-4afr4y6a.js +4 -0
  21. package/dist/chunks/image-editor-x7t8jbjn.js +4 -0
  22. package/dist/chunks/index-f9qr7kzh.js +4 -0
  23. package/dist/chunks/{index-vr006kbt.js → index-yjrfeks8.js} +3 -3
  24. package/dist/chunks/{javascript-z1g3s9fd.js → javascript-hy2mws8v.js} +3 -3
  25. package/dist/chunks/{jsonMode-7szwg8c4.js → jsonMode-vj30te2h.js} +6 -6
  26. package/dist/chunks/jx-validate-ttr5ewf0.js +4 -0
  27. package/dist/chunks/layers-m49nmwvx.js +4 -0
  28. package/dist/chunks/layers-panel-hvy2e549.js +4 -0
  29. package/dist/chunks/lit-html-k2mb9k0r.js +4 -0
  30. package/dist/chunks/media-library-ae67q4at.js +4 -0
  31. package/dist/chunks/media-open-yp9jm834.js +4 -0
  32. package/dist/chunks/media-picker-s41ngdfr.js +4 -0
  33. package/dist/chunks/{monaco-binding-v42w9c1v.js → monaco-binding-a51py33c.js} +3 -3
  34. package/dist/chunks/monaco-buffer-pa0g6ax7.js +4 -0
  35. package/dist/chunks/{monaco-setup-7bffxd6v.js → monaco-setup-g9kterhx.js} +3 -3
  36. package/dist/chunks/notify-bwehrp7q.js +4 -0
  37. package/dist/chunks/parse-hee7ne9b.js +4 -0
  38. package/dist/chunks/platform-kv0k65cy.js +4 -0
  39. package/dist/chunks/publish-panel-gzfxcm0t.js +4 -0
  40. package/dist/chunks/publish-quick-w3nxd7q4.js +4 -0
  41. package/dist/chunks/publish-workspace-dppd82tc.js +4 -0
  42. package/dist/chunks/quick-search-tdxaam55.js +4 -0
  43. package/dist/chunks/references-vqyr5s9x.js +4 -0
  44. package/dist/chunks/right-panel-0yrw4cgz.js +4 -0
  45. package/dist/chunks/source-control-6fk72me2.js +4 -0
  46. package/dist/chunks/{studio-j3d2fjqz.js → studio-0939t1q1.js} +4 -4
  47. package/dist/chunks/studio-0gvvqj3h.js +5 -0
  48. package/dist/chunks/studio-0khd8xtx.js +4 -0
  49. package/dist/chunks/studio-0w3541dg.js +7 -0
  50. package/dist/chunks/{studio-9b7177jq.js → studio-0x6f3nk9.js} +4 -4
  51. package/dist/chunks/studio-1410q5dw.js +5 -0
  52. package/dist/chunks/{studio-awxwjawq.js → studio-15hwqgd8.js} +4 -4
  53. package/dist/chunks/studio-1ks5d9y4.js +5 -0
  54. package/dist/chunks/{studio-881z1xrx.js → studio-2ggfzrrd.js} +4 -4
  55. package/dist/chunks/{studio-4jhw38b2.js → studio-321ym1tt.js} +4 -4
  56. package/dist/chunks/studio-3c10v2q1.js +5 -0
  57. package/dist/chunks/{studio-bvs9kpst.js → studio-3na1r48j.js} +8 -8
  58. package/dist/chunks/{studio-86r8hp7r.js → studio-3q7mhbgx.js} +5 -5
  59. package/dist/chunks/studio-3qr08sxq.js +4 -0
  60. package/dist/chunks/studio-3xk9zdgb.js +5 -0
  61. package/dist/chunks/{studio-qh8berdz.js → studio-423tfdte.js} +4 -4
  62. package/dist/chunks/{studio-75kcdbsk.js → studio-45mj4jqe.js} +4 -4
  63. package/dist/chunks/studio-4f7thq0p.js +5 -0
  64. package/dist/chunks/studio-4fnb5648.js +5 -0
  65. package/dist/chunks/studio-4zd6an2b.js +5 -0
  66. package/dist/chunks/studio-53wy9ek3.js +5 -0
  67. package/dist/chunks/studio-5n193zqd.js +5 -0
  68. package/dist/chunks/{studio-9rbe2xpw.js → studio-5tet77de.js} +3 -3
  69. package/dist/chunks/{studio-ybnwymxw.js → studio-7rrdbvex.js} +4 -4
  70. package/dist/chunks/studio-8kx6m0rg.js +5 -0
  71. package/dist/chunks/{studio-sxdb9h3q.js → studio-90zkgne5.js} +7 -7
  72. package/dist/chunks/studio-9c6cbq2c.js +4 -0
  73. package/dist/chunks/studio-9dq7rwc7.js +5 -0
  74. package/dist/chunks/{studio-cg1bfyhf.js → studio-9qx1ywbv.js} +8 -8
  75. package/dist/chunks/studio-a65kbs2e.js +9 -0
  76. package/dist/chunks/studio-aam8zt8z.js +5 -0
  77. package/dist/chunks/{studio-er5f383a.js → studio-abh9kfdh.js} +4 -4
  78. package/dist/chunks/studio-b4e0ftkt.js +5 -0
  79. package/dist/chunks/studio-b68k0z00.js +5 -0
  80. package/dist/chunks/{studio-399a25za.js → studio-bct64zmj.js} +4 -4
  81. package/dist/chunks/studio-bz0b5brj.js +6 -0
  82. package/dist/chunks/studio-cfnn70h1.js +5 -0
  83. package/dist/chunks/studio-daksw8kh.js +5 -0
  84. package/dist/chunks/{studio-r7pf0rkv.js → studio-e7vjyp04.js} +7 -7
  85. package/dist/chunks/studio-ea6r1zyr.js +5 -0
  86. package/dist/chunks/studio-egnjpyde.js +9 -0
  87. package/dist/chunks/studio-ejrypvmq.js +5 -0
  88. package/dist/chunks/studio-eqcddvc2.js +928 -0
  89. package/dist/chunks/studio-f8tyeyzt.js +5 -0
  90. package/dist/chunks/studio-fj6c905s.js +5 -0
  91. package/dist/chunks/{studio-646nn2ys.js → studio-fkrr7kgg.js} +5 -5
  92. package/dist/chunks/studio-fspe7m9t.js +5 -0
  93. package/dist/chunks/studio-g0hxtcga.js +5 -0
  94. package/dist/chunks/{studio-th7z3fg7.js → studio-g9brbewz.js} +4 -4
  95. package/dist/chunks/studio-ggx3j7nd.js +5 -0
  96. package/dist/chunks/{studio-43y04qck.js → studio-hfxttkyr.js} +4 -4
  97. package/dist/chunks/studio-hh394phe.js +5 -0
  98. package/dist/chunks/{studio-pjtntksy.js → studio-j0zf5x2x.js} +4 -4
  99. package/dist/chunks/studio-jeb7hth3.js +5 -0
  100. package/dist/chunks/studio-k0xzrse2.js +64 -0
  101. package/dist/chunks/studio-k1xqrgm5.js +5 -0
  102. package/dist/chunks/studio-k2evngrj.js +7 -0
  103. package/dist/chunks/studio-k3we3kqb.js +5 -0
  104. package/dist/chunks/{studio-sevbc3xv.js → studio-n9qba0gx.js} +4 -4
  105. package/dist/chunks/{studio-6hzdjfv0.js → studio-nf8esxxc.js} +4 -4
  106. package/dist/chunks/studio-nn4f9m9c.js +5 -0
  107. package/dist/chunks/studio-nskxe9q1.js +6 -0
  108. package/dist/chunks/{studio-ea74s8c1.js → studio-nvcn2ykc.js} +4 -4
  109. package/dist/chunks/studio-nwynxqtb.js +5 -0
  110. package/dist/chunks/studio-nzemfbkk.js +14 -0
  111. package/dist/chunks/studio-p2a03pgm.js +5 -0
  112. package/dist/chunks/{studio-4g8yb6jn.js → studio-pm17wdc4.js} +4 -4
  113. package/dist/chunks/{studio-71m92v9s.js → studio-q80fg1d6.js} +7 -7
  114. package/dist/chunks/studio-r050sez0.js +6 -0
  115. package/dist/chunks/studio-s7t4vp1d.js +6 -0
  116. package/dist/chunks/studio-s9fng7m8.js +7 -0
  117. package/dist/chunks/studio-sce30r7b.js +4 -0
  118. package/dist/chunks/studio-stahswgb.js +7 -0
  119. package/dist/chunks/studio-swedpd82.js +5 -0
  120. package/dist/chunks/studio-thz5t120.js +5 -0
  121. package/dist/chunks/studio-tpxcryf2.js +5 -0
  122. package/dist/chunks/{studio-wc6za3zs.js → studio-v5wktj6f.js} +4 -4
  123. package/dist/chunks/{studio-kg1abnz0.js → studio-vpevkfxw.js} +4 -4
  124. package/dist/chunks/studio-waekn290.js +5 -0
  125. package/dist/chunks/studio-wfct4h6n.js +5 -0
  126. package/dist/chunks/studio-wgc54sxf.js +5 -0
  127. package/dist/chunks/studio-wqfaqw4m.js +5 -0
  128. package/dist/chunks/studio-wse1rs8t.js +7 -0
  129. package/dist/chunks/studio-x0gsfr1d.js +16 -0
  130. package/dist/chunks/{studio-hhp4x8xf.js → studio-xpx91fby.js} +5 -5
  131. package/dist/chunks/studio-y1b86ast.js +5 -0
  132. package/dist/chunks/studio-yrcrncev.js +5 -0
  133. package/dist/chunks/{studio-rzqaz21g.js → studio-yzpskb0j.js} +4 -4
  134. package/dist/chunks/studio-zfdbmhp3.js +5 -0
  135. package/dist/chunks/{tsMode-f54j66ym.js → tsMode-jg1dtphj.js} +7 -7
  136. package/dist/chunks/workspace-9btkc8tk.js +4 -0
  137. package/dist/chunks/workspace-home-qcc4z5ag.js +4 -0
  138. package/dist/chunks/{ws-client-e8kj684q.js → ws-client-arz2qsy9.js} +3 -3
  139. package/dist/iframe-entry.js +13 -13
  140. package/dist/manifest.json +83 -78
  141. package/dist/studio.js +84 -84
  142. package/package.json +2 -2
  143. package/src/browse/library-pane.ts +44 -29
  144. package/src/browse/library-preview.ts +6 -2
  145. package/src/canvas/asset-refs.ts +13 -4
  146. package/src/canvas/asset-resolve.ts +54 -11
  147. package/src/canvas/canvas-render.ts +25 -0
  148. package/src/canvas/iframe-entry.ts +5 -1
  149. package/src/canvas/iframe-host.ts +16 -6
  150. package/src/canvas/iframe-protocol.ts +9 -1
  151. package/src/commands/context.ts +5 -0
  152. package/src/commands/live-context.ts +5 -2
  153. package/src/editor/shortcuts.ts +3 -0
  154. package/src/files/asset-versions.ts +108 -2
  155. package/src/files/file-ops.ts +11 -1
  156. package/src/files/files.ts +111 -48
  157. package/src/files/media-paths.ts +12 -4
  158. package/src/files/media-upload.ts +195 -21
  159. package/src/files/new-file-name.ts +39 -1
  160. package/src/media/image-bake.ts +164 -0
  161. package/src/media/image-editor.ts +846 -0
  162. package/src/media/image-format.ts +262 -0
  163. package/src/media/image-recipe.ts +651 -0
  164. package/src/media/media-commands.ts +65 -1
  165. package/src/media/media-library-model.ts +1 -1
  166. package/src/media/media-library.ts +175 -15
  167. package/src/media/media-open.ts +156 -3
  168. package/src/media/media-pane.ts +8 -4
  169. package/src/panels/pane-context.ts +6 -1
  170. package/src/panels/tab-strip.ts +12 -3
  171. package/src/studio.ts +13 -2
  172. package/src/surfaces/image-editor.json +1390 -0
  173. package/src/surfaces/image-editor.ts +272 -0
  174. package/src/surfaces/media-library.json +129 -1
  175. package/src/surfaces/media-library.ts +17 -2
  176. package/src/types.ts +2 -1
  177. package/src/workspace/tab-workspace.ts +2 -1
  178. package/src/workspace/workspace-switch.ts +3 -1
  179. package/src/workspace/workspace.ts +22 -1
  180. package/dist/chunks/adapter-pp011m5x.js +0 -4
  181. package/dist/chunks/add-new-flow-ecqmzz76.js +0 -4
  182. package/dist/chunks/cf-account-picker-c07znkqt.js +0 -4
  183. package/dist/chunks/cf-settings-0v2bmqy0.js +0 -4
  184. package/dist/chunks/components-yn0dn2pq.js +0 -4
  185. package/dist/chunks/content-source-g0j41yy6.js +0 -4
  186. package/dist/chunks/convert-to-repeater-sbjk7tgn.js +0 -4
  187. package/dist/chunks/editor-xz02jeh1.js +0 -4
  188. package/dist/chunks/entry-commands-kmt02crp.js +0 -4
  189. package/dist/chunks/extension-sections-0rprf12d.js +0 -4
  190. package/dist/chunks/file-ops-mexj5qed.js +0 -4
  191. package/dist/chunks/files-b2tcppdd.js +0 -4
  192. package/dist/chunks/format-host-btsevv0c.js +0 -4
  193. package/dist/chunks/fs-events-r0apejva.js +0 -4
  194. package/dist/chunks/grid-open-n2a8xkht.js +0 -4
  195. package/dist/chunks/icons-853n6qt3.js +0 -4
  196. package/dist/chunks/iframe-host-gx0ypyh3.js +0 -4
  197. package/dist/chunks/index-bs4k9tr6.js +0 -4
  198. package/dist/chunks/jx-validate-ymf10teh.js +0 -4
  199. package/dist/chunks/layers-p9nfya38.js +0 -4
  200. package/dist/chunks/layers-panel-tt1hzhhf.js +0 -4
  201. package/dist/chunks/lit-html-x18n2sfz.js +0 -4
  202. package/dist/chunks/media-library-0n45gv8r.js +0 -4
  203. package/dist/chunks/media-picker-s09at95z.js +0 -4
  204. package/dist/chunks/monaco-buffer-een2ea0v.js +0 -4
  205. package/dist/chunks/notify-qwb8radt.js +0 -4
  206. package/dist/chunks/parse-v77xtwv7.js +0 -4
  207. package/dist/chunks/platform-8jnez0wr.js +0 -4
  208. package/dist/chunks/publish-panel-aysnj611.js +0 -4
  209. package/dist/chunks/publish-quick-kpbqs9mz.js +0 -4
  210. package/dist/chunks/publish-workspace-nd0a8q99.js +0 -4
  211. package/dist/chunks/quick-search-vg0jkhk2.js +0 -4
  212. package/dist/chunks/references-a7v6a0e2.js +0 -4
  213. package/dist/chunks/right-panel-cvk1vxx5.js +0 -4
  214. package/dist/chunks/source-control-fsqzc6he.js +0 -4
  215. package/dist/chunks/studio-05jfwbmf.js +0 -5
  216. package/dist/chunks/studio-0q5jwddh.js +0 -9
  217. package/dist/chunks/studio-0w2dr0q8.js +0 -5
  218. package/dist/chunks/studio-1tzpds97.js +0 -9
  219. package/dist/chunks/studio-216b27sv.js +0 -4
  220. package/dist/chunks/studio-2ejhqns4.js +0 -5
  221. package/dist/chunks/studio-2r90cts3.js +0 -16
  222. package/dist/chunks/studio-399xknkb.js +0 -6
  223. package/dist/chunks/studio-4ncmwqw5.js +0 -5
  224. package/dist/chunks/studio-5atwjgkj.js +0 -7
  225. package/dist/chunks/studio-5frqk7c0.js +0 -5
  226. package/dist/chunks/studio-6cwj6xrx.js +0 -5
  227. package/dist/chunks/studio-78pywnp2.js +0 -6
  228. package/dist/chunks/studio-886t6ztg.js +0 -5
  229. package/dist/chunks/studio-8wnvtr4z.js +0 -5
  230. package/dist/chunks/studio-8z66jk4z.js +0 -5
  231. package/dist/chunks/studio-b2qpt0xy.js +0 -14
  232. package/dist/chunks/studio-c71806xz.js +0 -7
  233. package/dist/chunks/studio-cbwks69x.js +0 -928
  234. package/dist/chunks/studio-cg710sk9.js +0 -5
  235. package/dist/chunks/studio-cw0wb9qk.js +0 -7
  236. package/dist/chunks/studio-cyheys7k.js +0 -5
  237. package/dist/chunks/studio-ea5m9kg5.js +0 -5
  238. package/dist/chunks/studio-efdxjwyp.js +0 -64
  239. package/dist/chunks/studio-egmw2837.js +0 -5
  240. package/dist/chunks/studio-f746039f.js +0 -5
  241. package/dist/chunks/studio-fmdymd9v.js +0 -5
  242. package/dist/chunks/studio-gcm12z00.js +0 -6
  243. package/dist/chunks/studio-gj98m8gy.js +0 -7
  244. package/dist/chunks/studio-hasbgjah.js +0 -5
  245. package/dist/chunks/studio-hz5n7x27.js +0 -5
  246. package/dist/chunks/studio-jeraxdgv.js +0 -7
  247. package/dist/chunks/studio-jvgek9xt.js +0 -5
  248. package/dist/chunks/studio-jws1a87n.js +0 -5
  249. package/dist/chunks/studio-k2sz13zg.js +0 -5
  250. package/dist/chunks/studio-k3m4jkdk.js +0 -5
  251. package/dist/chunks/studio-kg5ya5r2.js +0 -5
  252. package/dist/chunks/studio-khwbgrtg.js +0 -5
  253. package/dist/chunks/studio-mx6wzh25.js +0 -5
  254. package/dist/chunks/studio-mxs3ar9t.js +0 -5
  255. package/dist/chunks/studio-nm4szey4.js +0 -5
  256. package/dist/chunks/studio-nqxqf8p2.js +0 -4
  257. package/dist/chunks/studio-qn7z4krm.js +0 -5
  258. package/dist/chunks/studio-qyed0ah6.js +0 -5
  259. package/dist/chunks/studio-r4bcdwhq.js +0 -5
  260. package/dist/chunks/studio-rtfnhrdg.js +0 -5
  261. package/dist/chunks/studio-s5tzw84t.js +0 -5
  262. package/dist/chunks/studio-t51y8v1d.js +0 -5
  263. package/dist/chunks/studio-t98vq4r6.js +0 -5
  264. package/dist/chunks/studio-tsxpqvh0.js +0 -6
  265. package/dist/chunks/studio-v1yascv2.js +0 -5
  266. package/dist/chunks/studio-wxq6v5sv.js +0 -5
  267. package/dist/chunks/studio-y60sts62.js +0 -4
  268. package/dist/chunks/studio-zndrqawb.js +0 -5
  269. package/dist/chunks/studio-zwaxn5s2.js +0 -5
  270. package/dist/chunks/workspace-home-x1787wpv.js +0 -4
  271. package/dist/chunks/workspace-zpe1np43.js +0 -4
@@ -83,6 +83,7 @@ import { openMenu } from "../surfaces/menu";
83
83
  import type { MenuHandle, MenuRowProjection } from "../surfaces/menu";
84
84
  import { saveFile } from "../files/file-ops";
85
85
  import { collabReadOnly } from "../collab/collab-session";
86
+ import { imageEditorDirty } from "../media/image-editor";
86
87
  import { collabState } from "../collab/collab-state";
87
88
  import { elementAtPoint, rectOf } from "../utils/geometry";
88
89
  import { resolveRegion } from "../ui/regions";
@@ -255,6 +256,8 @@ export function mount(host: HTMLElement) {
255
256
  // A tab's workspace follows its editor (`project.json` is Styles' in its stylebook only).
256
257
  void tab.session.ui.canvasMode;
257
258
  void tab.doc.dirty;
259
+ // An image edit is the tab's unsaved work too (§9.5), held beside the document, not in it.
260
+ void imageEditorDirty(tab);
258
261
  void tab.documentPath;
259
262
  void tab.pinned;
260
263
  void tab.preview;
@@ -689,7 +692,7 @@ function chipView(
689
692
  const pill = entryDraftPill(tab);
690
693
  return [
691
694
  {
692
- dirty: tab.doc.dirty,
695
+ dirty: tab.doc.dirty || imageEditorDirty(tab),
693
696
  draft: pill?.draft ?? false,
694
697
  index,
695
698
  key: id,
@@ -1336,11 +1339,17 @@ export function tabLabel(tab: Tab): string {
1336
1339
  * buffer rather than resyncing over a half-typed heading), and that text exists nowhere else.
1337
1340
  * {@link tabBufferUnsaved} is that residue, and it is the user's own typing by construction.
1338
1341
  *
1342
+ * **And an image tab's unsaved work is not in its document at all.** A media tab's document is a
1343
+ * stub; an Image editor edit (§9.5) is a recipe held beside it, so it is a third source of dirt,
1344
+ * and it takes the residue's side of the peer-count gate for the residue's reason: a recipe has
1345
+ * never been published, mirrored or written, so no peer focused on the path holds a copy of it.
1346
+ *
1339
1347
  * @param {Tab} tab
1340
1348
  */
1341
1349
  export function shouldWarnOnClose(tab: Tab): boolean {
1342
1350
  const residue = tabBufferUnsaved(tab);
1343
- if (!tab.doc.dirty && !residue) {
1351
+ const image = imageEditorDirty(tab);
1352
+ if (!tab.doc.dirty && !residue && !image) {
1344
1353
  return false;
1345
1354
  }
1346
1355
  const state = collabState(tab);
@@ -1361,7 +1370,7 @@ export function shouldWarnOnClose(tab: Tab): boolean {
1361
1370
  lock holder is by definition a peer focused on this path, so the busier the room got, the
1362
1371
  quieter the close became. Asked before the peer count rather than after, because the peer count
1363
1372
  has no jurisdiction over text the room has never been told about. */
1364
- if (residue) {
1373
+ if (residue || image) {
1365
1374
  return true;
1366
1375
  }
1367
1376
  const peersHere = state.peers.filter((p) => p.state.focusedPath === tab.documentPath);
package/src/studio.ts CHANGED
@@ -212,6 +212,7 @@ import { setProjectAdopter } from "./services/project-adoption";
212
212
  import { setImportHandoff } from "./services/import-seed";
213
213
  import { watchConnection } from "./services/connection";
214
214
  import { commitTabBuffers, tabBufferUnsaved } from "./services/monaco-buffer";
215
+ import { imageEditorDirty } from "./media/image-editor";
215
216
  import { clearTyping } from "./tabs/typing";
216
217
  import * as leftPanelMod from "./panels/left-panel";
217
218
  import * as tabStrip from "./panels/tab-strip";
@@ -605,12 +606,19 @@ setInsertZoneClickHandler(runInsertZoneAction);
605
606
  setFileDropHandler(applyFileDrop);
606
607
  // Every upload surface routes through uploadAssets(); refresh the three caches that list project
607
608
  // Files afterwards. Injected here because all three modules import from media-upload.
608
- setMediaChangedHandler(async (dir) => {
609
+ setMediaChangedHandler(async (dir, overwritten) => {
609
610
  invalidateMediaCache();
610
611
  invalidateLibrary();
611
612
  invalidateSiteIndex();
612
613
  await loadDirectory(dir);
613
614
  renderLeftPanel();
615
+ /* Bytes replaced IN PLACE change no listing, so nothing above redraws what was already drawn from
616
+ them. Every pane draws again, and its asset resolver now carries the path's repaint key. */
617
+ if (overwritten !== undefined) {
618
+ for (const pane of workspace.panes) {
619
+ renderCanvas(pane.id);
620
+ }
621
+ }
614
622
  });
615
623
  // The in-iframe "/" trigger drives the parent-realm slash menu across the bridge.
616
624
  setCanvasSlashHandler(canvasSlashHandler);
@@ -677,7 +685,7 @@ document.addEventListener(
677
685
  */
678
686
  export function hasUnsavedTabs(): boolean {
679
687
  for (const tab of workspace.tabs.values()) {
680
- if (tab.doc.dirty || tabBufferUnsaved(tab)) {
688
+ if (tab.doc.dirty || tabBufferUnsaved(tab) || imageEditorDirty(tab)) {
681
689
  return true;
682
690
  }
683
691
  }
@@ -1119,6 +1127,9 @@ if (_projectParam) {
1119
1127
  /* Through `loadDirectory` (inside `loadProjectDirectories`), not `platform.listDirectory`:
1120
1128
  the loader is what reads the `.gitignore` chain governing each directory. */
1121
1129
  await loadProjectDirectories();
1130
+ /* The other two ways into a project subscribe, and this one did not, so a project opened
1131
+ by its URL never heard about a file changing on disk. */
1132
+ ensureFsSync();
1122
1133
  void maybePromptJxsuiteUpdate(siteCtx.sitePath);
1123
1134
  }
1124
1135