jazz-tools 0.18.16 → 0.18.17

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 (36) hide show
  1. package/.svelte-kit/__package__/media/image.svelte +104 -98
  2. package/.svelte-kit/__package__/media/image.svelte.d.ts.map +1 -1
  3. package/.svelte-kit/__package__/tests/media/image.svelte.test.js +16 -2
  4. package/.turbo/turbo-build.log +42 -42
  5. package/CHANGELOG.md +11 -0
  6. package/dist/{chunk-GRN6OAUX.js → chunk-OTWWOZMB.js} +73 -4
  7. package/dist/chunk-OTWWOZMB.js.map +1 -0
  8. package/dist/index.js +1 -1
  9. package/dist/react/index.js +2 -0
  10. package/dist/react/index.js.map +1 -1
  11. package/dist/react/media/image.d.ts.map +1 -1
  12. package/dist/react-native-core/index.js +3 -1
  13. package/dist/react-native-core/index.js.map +1 -1
  14. package/dist/react-native-core/media/image.d.ts.map +1 -1
  15. package/dist/svelte/media/image.svelte +104 -98
  16. package/dist/svelte/media/image.svelte.d.ts.map +1 -1
  17. package/dist/svelte/tests/media/image.svelte.test.js +16 -2
  18. package/dist/testing.js +1 -1
  19. package/dist/tools/implementation/refs.d.ts +1 -1
  20. package/dist/tools/implementation/refs.d.ts.map +1 -1
  21. package/dist/tools/subscribe/CoValueCoreSubscription.d.ts +4 -0
  22. package/dist/tools/subscribe/CoValueCoreSubscription.d.ts.map +1 -1
  23. package/dist/tools/subscribe/SubscriptionScope.d.ts +7 -0
  24. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  25. package/dist/tools/subscribe/index.d.ts.map +1 -1
  26. package/package.json +4 -4
  27. package/src/react/media/image.tsx +2 -0
  28. package/src/react/tests/media/image.test.tsx +20 -2
  29. package/src/react-native-core/media/image.tsx +4 -1
  30. package/src/svelte/media/image.svelte +104 -98
  31. package/src/svelte/tests/media/image.svelte.test.ts +18 -2
  32. package/src/tools/implementation/refs.ts +27 -3
  33. package/src/tools/subscribe/CoValueCoreSubscription.ts +14 -0
  34. package/src/tools/subscribe/SubscriptionScope.ts +62 -1
  35. package/src/tools/subscribe/index.ts +8 -0
  36. package/dist/chunk-GRN6OAUX.js.map +0 -1
@@ -1,118 +1,122 @@
1
1
  <script lang="ts">
2
- import { ImageDefinition } from "jazz-tools";
3
- import { highestResAvailable } from "jazz-tools/media";
4
- import { onDestroy } from "svelte";
5
- import { CoState } from "../jazz.class.svelte";
6
- import type { ImageProps } from "./image.types.js";
7
-
8
- const { imageId, width, height, ...rest }: ImageProps = $props();
9
-
10
- const imageState = new CoState(ImageDefinition, () => imageId);
11
- let lastBestImage: [string, string] | null = null;
12
-
13
- /**
14
- * For lazy loading, we use the browser's strategy for images with loading="lazy".
15
- * We use an empty image, and when the browser triggers the load event, we load the best available image.
16
- * On page loading, if the image url is already in browser's cache, the load event is triggered immediately.
17
- * This is why we need to use a different blob url for every image.
18
- */
19
- let waitingLazyLoading = $state(rest.loading === "lazy");
20
- const lazyPlaceholder = $derived.by(() =>
21
- waitingLazyLoading ? URL.createObjectURL(emptyPixelBlob) : undefined,
22
- );
23
-
24
- const dimensions = $derived.by<{
25
- width: number | undefined;
26
- height: number | undefined;
27
- }>(() => {
28
- const originalWidth = imageState.current?.originalSize?.[0];
29
- const originalHeight = imageState.current?.originalSize?.[1];
30
-
31
- // Both width and height are "original"
32
- if (width === "original" && height === "original") {
33
- return { width: originalWidth, height: originalHeight };
34
- }
2
+ import { ImageDefinition } from "jazz-tools";
3
+ import { highestResAvailable } from "jazz-tools/media";
4
+ import { onDestroy } from "svelte";
5
+ import { CoState } from "../jazz.class.svelte";
6
+ import type { ImageProps } from "./image.types.js";
7
+
8
+ const { imageId, width, height, ...rest }: ImageProps = $props();
9
+
10
+ const imageState = new CoState(ImageDefinition, () => imageId);
11
+ let lastBestImage: [string, string] | null = null;
12
+
13
+ /**
14
+ * For lazy loading, we use the browser's strategy for images with loading="lazy".
15
+ * We use an empty image, and when the browser triggers the load event, we load the best available image.
16
+ * On page loading, if the image url is already in browser's cache, the load event is triggered immediately.
17
+ * This is why we need to use a different blob url for every image.
18
+ */
19
+ let waitingLazyLoading = $state(rest.loading === "lazy");
20
+ const lazyPlaceholder = $derived.by(() =>
21
+ waitingLazyLoading ? URL.createObjectURL(emptyPixelBlob) : undefined,
22
+ );
23
+
24
+ const dimensions = $derived.by<{
25
+ width: number | undefined;
26
+ height: number | undefined;
27
+ }>(() => {
28
+ const originalWidth = imageState.current?.originalSize?.[0];
29
+ const originalHeight = imageState.current?.originalSize?.[1];
35
30
 
36
- // Width is "original", height is a number
37
- if (width === "original" && typeof height === "number") {
38
- if (originalWidth && originalHeight) {
39
- return {
40
- width: Math.round((height * originalWidth) / originalHeight),
41
- height,
42
- };
31
+ // Both width and height are "original"
32
+ if (width === "original" && height === "original") {
33
+ return { width: originalWidth, height: originalHeight };
43
34
  }
44
- return { width: undefined, height };
45
- }
46
35
 
47
- // Height is "original", width is a number
48
- if (height === "original" && typeof width === "number") {
49
- if (originalWidth && originalHeight) {
50
- return {
51
- width,
52
- height: Math.round((width * originalHeight) / originalWidth),
53
- };
36
+ // Width is "original", height is a number
37
+ if (width === "original" && typeof height === "number") {
38
+ if (originalWidth && originalHeight) {
39
+ return {
40
+ width: Math.round((height * originalWidth) / originalHeight),
41
+ height,
42
+ };
43
+ }
44
+ return { width: undefined, height };
54
45
  }
55
- return { width, height: undefined };
56
- }
57
46
 
58
- // In all other cases, use the property value:
59
- return {
60
- width: width === "original" ? originalWidth : width,
61
- height: height === "original" ? originalHeight : height,
62
- };
63
- });
47
+ // Height is "original", width is a number
48
+ if (height === "original" && typeof width === "number") {
49
+ if (originalWidth && originalHeight) {
50
+ return {
51
+ width,
52
+ height: Math.round((width * originalHeight) / originalWidth),
53
+ };
54
+ }
55
+ return { width, height: undefined };
56
+ }
64
57
 
65
- const src = $derived.by(() => {
66
- if (waitingLazyLoading) {
67
- return lazyPlaceholder;
68
- }
58
+ // In all other cases, use the property value:
59
+ return {
60
+ width: width === "original" ? originalWidth : width,
61
+ height: height === "original" ? originalHeight : height,
62
+ };
63
+ });
69
64
 
70
- const image = imageState.current;
71
- if (!image) return undefined;
65
+ const src = $derived.by(() => {
66
+ if (waitingLazyLoading) {
67
+ return lazyPlaceholder;
68
+ }
72
69
 
73
- const bestImage = highestResAvailable(
74
- image,
75
- dimensions.width || dimensions.height || 9999,
76
- dimensions.height || dimensions.width || 9999,
77
- );
70
+ const image = imageState.current;
71
+ if (image === undefined)
72
+ return "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
78
73
 
79
- if (!bestImage) return image.placeholderDataURL;
80
- if (lastBestImage?.[0] === bestImage.image.$jazz.id) return lastBestImage?.[1];
74
+ if (!image) return undefined;
81
75
 
82
- const blob = bestImage.image.toBlob();
76
+ const bestImage = highestResAvailable(
77
+ image,
78
+ dimensions.width || dimensions.height || 9999,
79
+ dimensions.height || dimensions.width || 9999,
80
+ );
83
81
 
84
- if (blob) {
85
- const url = URL.createObjectURL(blob);
86
- revokeObjectURL(lastBestImage?.[1]);
87
- lastBestImage = [bestImage.image.$jazz.id, url];
88
- return url;
89
- }
82
+ if (!bestImage) return image.placeholderDataURL;
83
+ if (lastBestImage?.[0] === bestImage.image.$jazz.id)
84
+ return lastBestImage?.[1];
85
+
86
+ const blob = bestImage.image.toBlob();
87
+
88
+ if (blob) {
89
+ const url = URL.createObjectURL(blob);
90
+ revokeObjectURL(lastBestImage?.[1]);
91
+ lastBestImage = [bestImage.image.$jazz.id, url];
92
+ return url;
93
+ }
90
94
 
91
- return image.placeholderDataURL;
92
- });
95
+ return image.placeholderDataURL;
96
+ });
93
97
 
94
- // Cleanup object URL on component destroy
95
- onDestroy(() => {
96
- revokeObjectURL(lastBestImage?.[1]);
97
- });
98
+ // Cleanup object URL on component destroy
99
+ onDestroy(() => {
100
+ revokeObjectURL(lastBestImage?.[1]);
101
+ });
98
102
 
99
- function revokeObjectURL(url: string | undefined) {
100
- if (url && url.startsWith("blob:")) {
101
- URL.revokeObjectURL(url);
103
+ function revokeObjectURL(url: string | undefined) {
104
+ if (url && url.startsWith("blob:")) {
105
+ URL.revokeObjectURL(url);
106
+ }
102
107
  }
103
- }
104
108
 
105
- const emptyPixelBlob = new Blob(
106
- [
107
- Uint8Array.from(
108
- atob(
109
- "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
109
+ const emptyPixelBlob = new Blob(
110
+ [
111
+ Uint8Array.from(
112
+ atob(
113
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
114
+ ),
115
+ (c) => c.charCodeAt(0),
110
116
  ),
111
- (c) => c.charCodeAt(0),
112
- ),
113
- ],
114
- { type: "image/png" },
115
- );
117
+ ],
118
+ { type: "image/png" },
119
+ );
116
120
  </script>
117
121
 
118
122
  <img
@@ -120,6 +124,8 @@ const emptyPixelBlob = new Blob(
120
124
  width={dimensions.width}
121
125
  height={dimensions.height}
122
126
  alt={rest.alt}
123
- onload={() => {waitingLazyLoading = false}}
127
+ onload={() => {
128
+ waitingLazyLoading = false;
129
+ }}
124
130
  {...rest}
125
131
  />
@@ -1 +1 @@
1
- {"version":3,"file":"image.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/media/image.svelte.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AA2HnD,QAAA,MAAM,KAAK,gDAAsC,CAAC;AAClD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"image.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/media/image.svelte.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAiInD,QAAA,MAAM,KAAK,gDAAsC,CAAC;AAClD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -10,7 +10,7 @@ describe("Image", async () => {
10
10
  });
11
11
  const renderWithAccount = (props) => render(Image, props, { account });
12
12
  describe("initial rendering", () => {
13
- it("should render nothing if coValue is not found", async () => {
13
+ it("should render a blank placeholder while waiting for the coValue to load", async () => {
14
14
  const { container } = renderWithAccount({
15
15
  imageId: "co_zMTubMby3QiKDYnW9e2BEXW7Xaq",
16
16
  alt: "test",
@@ -20,7 +20,21 @@ describe("Image", async () => {
20
20
  expect(img.getAttribute("width")).toBe(null);
21
21
  expect(img.getAttribute("height")).toBe(null);
22
22
  expect(img.alt).toBe("test");
23
- expect(img.src).toBe("");
23
+ expect(img.src).toBe("data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==");
24
+ });
25
+ it("should render nothing if coValue is not found", async () => {
26
+ const { container } = renderWithAccount({
27
+ imageId: "co_zMTubMby3QiKDYnW9e2BEXW7Xaq",
28
+ alt: "test",
29
+ });
30
+ await waitFor(() => {
31
+ const img = container.querySelector("img");
32
+ expect(img).toBeDefined();
33
+ expect(img.getAttribute("width")).toBe(null);
34
+ expect(img.getAttribute("height")).toBe(null);
35
+ expect(img.alt).toBe("test");
36
+ expect(img.src).toBe("");
37
+ });
24
38
  });
25
39
  it("should render an empty image if the image is not loaded yet", async () => {
26
40
  const original = FileStream.create({ owner: account.$jazz.owner });
package/dist/testing.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  createAnonymousJazzContext,
7
7
  createJazzContext,
8
8
  randomSessionProvider
9
- } from "./chunk-GRN6OAUX.js";
9
+ } from "./chunk-OTWWOZMB.js";
10
10
 
11
11
  // src/tools/testing.ts
12
12
  import { LocalNode } from "cojson";
@@ -1,5 +1,5 @@
1
1
  import { type Account } from "../coValues/account.js";
2
- import type { AnonymousJazzAgent, CoValue, ID, RefEncoded } from "../internal.js";
2
+ import { AnonymousJazzAgent, CoValue, ID, RefEncoded } from "../internal.js";
3
3
  export declare class Ref<out V extends CoValue> {
4
4
  readonly id: ID<V>;
5
5
  readonly controlledAccount: Account | AnonymousJazzAgent;
@@ -1 +1 @@
1
- {"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../../../src/tools/implementation/refs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EACV,kBAAkB,EAClB,OAAO,EACP,EAAE,EACF,UAAU,EACX,MAAM,gBAAgB,CAAC;AAOxB,qBAAa,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,OAAO;IAElC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAClB,QAAQ,CAAC,iBAAiB,EAAE,OAAO,GAAG,kBAAkB;IACxD,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO;gBAHf,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EACT,iBAAiB,EAAE,OAAO,GAAG,kBAAkB,EAC/C,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,EACrB,MAAM,EAAE,OAAO;IAOpB,IAAI,IAAI,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAiC/B,IAAI,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAEhC;CACF;AAED,wBAAgB,QAAQ,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EACnD,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,SAAS,EACnD,cAAc,EAAE,MAAM,IAAI,EAAE,EAC5B,iBAAiB,EAAE,OAAO,GAAG,kBAAkB,EAC/C,eAAe,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,UAAU,CAAC,OAAO,CAAC,GAClD;KAAG,CAAC,IAAI,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC;CAAE,GAAG;IACjC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,MAAM,EAAE,MAAM,CAAC;CAChB,CAgDA;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,SAAS,OAAO,GACxD,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GACnB,KAAK,CAAC"}
1
+ {"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../../../src/tools/implementation/refs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EACL,kBAAkB,EAClB,OAAO,EACP,EAAE,EACF,UAAU,EAEX,MAAM,gBAAgB,CAAC;AAOxB,qBAAa,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,OAAO;IAElC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAClB,QAAQ,CAAC,iBAAiB,EAAE,OAAO,GAAG,kBAAkB;IACxD,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO;gBAHf,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EACT,iBAAiB,EAAE,OAAO,GAAG,kBAAkB,EAC/C,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,EACrB,MAAM,EAAE,OAAO;IAOpB,IAAI,IAAI,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAwD/B,IAAI,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAEhC;CACF;AAED,wBAAgB,QAAQ,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EACnD,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,SAAS,EACnD,cAAc,EAAE,MAAM,IAAI,EAAE,EAC5B,iBAAiB,EAAE,OAAO,GAAG,kBAAkB,EAC/C,eAAe,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,UAAU,CAAC,OAAO,CAAC,GAClD;KAAG,CAAC,IAAI,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC;CAAE,GAAG;IACjC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,MAAM,EAAE,MAAM,CAAC;CAChB,CAgDA;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,SAAS,OAAO,GACxD,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GACnB,KAAK,CAAC"}
@@ -16,6 +16,10 @@ export declare class CoValueCoreSubscription {
16
16
  private listener;
17
17
  private skipRetry?;
18
18
  constructor(localNode: LocalNode, id: string, listener: (value: RawCoValue | "unavailable") => void, skipRetry?: boolean, branch?: BranchDefinition);
19
+ /**
20
+ * Rehydrates the subscription by resetting the unsubscribed flag and initializing the subscription again
21
+ */
22
+ pullValue(): void;
19
23
  /**
20
24
  * Main entry point for subscription initialization.
21
25
  * Determines the subscription strategy based on current availability and branch requirements.
@@ -1 +1 @@
1
- {"version":3,"file":"CoValueCoreSubscription.d.ts","sourceRoot":"","sources":["../../../src/tools/subscribe/CoValueCoreSubscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,SAAS,EAET,UAAU,EACX,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;GAKG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO,CAAC,aAAa,CAAC,CAAU;IAChC,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,QAAQ,CAA8C;IAC9D,OAAO,CAAC,SAAS,CAAC,CAAU;gBAG1B,SAAS,EAAE,SAAS,EACpB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,KAAK,IAAI,EACrD,SAAS,CAAC,EAAE,OAAO,EACnB,MAAM,CAAC,EAAE,gBAAgB;IAY3B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAmB9B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAuB7B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAqB5B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAY/B;;;OAGG;IACH,OAAO,CAAC,WAAW;IAsBnB;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IA6BpC;;;OAGG;IACH,OAAO,CAAC,SAAS;IASjB,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,GAAG,IAAI;IAM7C;;;OAGG;IACH,WAAW,IAAI,IAAI;CAKpB"}
1
+ {"version":3,"file":"CoValueCoreSubscription.d.ts","sourceRoot":"","sources":["../../../src/tools/subscribe/CoValueCoreSubscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,SAAS,EAET,UAAU,EACX,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;GAKG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO,CAAC,aAAa,CAAC,CAAU;IAChC,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,QAAQ,CAA8C;IAC9D,OAAO,CAAC,SAAS,CAAC,CAAU;gBAG1B,SAAS,EAAE,SAAS,EACpB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,KAAK,IAAI,EACrD,SAAS,CAAC,EAAE,OAAO,EACnB,MAAM,CAAC,EAAE,gBAAgB;IAY3B;;OAEG;IACH,SAAS;IAWT;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAmB9B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAuB7B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAqB5B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAY/B;;;OAGG;IACH,OAAO,CAAC,WAAW;IAsBnB;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IA6BpC;;;OAGG;IACH,OAAO,CAAC,SAAS;IASjB,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,GAAG,IAAI;IAM7C;;;OAGG;IACH,WAAW,IAAI,IAAI;CAKpB"}
@@ -34,6 +34,7 @@ export declare class SubscriptionScope<D extends CoValue> {
34
34
  totalValidTransactions: number;
35
35
  migrated: boolean;
36
36
  migrating: boolean;
37
+ closed: boolean;
37
38
  silenceUpdates: boolean;
38
39
  constructor(node: LocalNode, resolve: RefsToResolve<D>, id: ID<D>, schema: RefEncoded<D>, skipRetry?: boolean, bestEffortResolution?: boolean, unstable_branch?: BranchDefinition | undefined);
39
40
  updateValue(value: SubscriptionValue<D, any>): void;
@@ -50,6 +51,12 @@ export declare class SubscriptionScope<D extends CoValue> {
50
51
  setListener(listener: (value: SubscriptionValue<D, any>) => void): void;
51
52
  subscribeToKey(key: string): void;
52
53
  isSubscribedToId(id: string): boolean;
54
+ /**
55
+ * Checks if the currently unloaded value has got some updates
56
+ *
57
+ * Used to make the autoload work on closed subscription scopes
58
+ */
59
+ pullValue(listener: (value: SubscriptionValue<D, any>) => void): void;
53
60
  subscribeToId(id: string, descriptor: RefEncoded<any>): void;
54
61
  loadChildren(): boolean;
55
62
  loadCoMapKey(map: CoMap, key: string, depth: Record<string, any> | true): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"SubscriptionScope.d.ts","sourceRoot":"","sources":["../../../src/tools/subscribe/SubscriptionScope.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SubscriptionScope.d.ts","sourceRoot":"","sources":["../../../src/tools/subscribe/SubscriptionScope.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/subscribe/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,CAAC,qDAwB/D;AAED,yBAAyB;AAEzB;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAChD,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,OAeZ;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,EAC/C,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,OAa5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/subscribe/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,CAAC,qDA0B/D;AAED,yBAAyB;AAEzB;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAChD,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,OAqBZ;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,EAC/C,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,OAa5B"}
package/package.json CHANGED
@@ -177,7 +177,7 @@
177
177
  },
178
178
  "type": "module",
179
179
  "license": "MIT",
180
- "version": "0.18.16",
180
+ "version": "0.18.17",
181
181
  "dependencies": {
182
182
  "@manuscripts/prosemirror-recreate-steps": "^0.1.4",
183
183
  "@scure/base": "1.2.1",
@@ -194,9 +194,9 @@
194
194
  "prosemirror-transform": "^1.9.0",
195
195
  "use-sync-external-store": "^1.5.0",
196
196
  "zod": "3.25.76",
197
- "cojson": "0.18.16",
198
- "cojson-storage-indexeddb": "0.18.16",
199
- "cojson-transport-ws": "0.18.16"
197
+ "cojson": "0.18.17",
198
+ "cojson-storage-indexeddb": "0.18.17",
199
+ "cojson-transport-ws": "0.18.17"
200
200
  },
201
201
  "devDependencies": {
202
202
  "@scure/bip39": "^1.3.0",
@@ -140,6 +140,8 @@ export const Image = forwardRef<HTMLImageElement, ImageProps>(function Image(
140
140
  return lazyPlaceholder;
141
141
  }
142
142
 
143
+ if (image === undefined)
144
+ return "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
143
145
  if (!image) return undefined;
144
146
 
145
147
  const bestImage = highestResAvailable(
@@ -13,17 +13,35 @@ describe("Image", async () => {
13
13
  vi.spyOn(Account, "getMe").mockReturnValue(account);
14
14
 
15
15
  describe("initial rendering", () => {
16
- it("should render nothing if coValue is not found", async () => {
16
+ it("should render a blank placeholder while waiting for the coValue to load", async () => {
17
17
  const { container } = render(
18
18
  <Image imageId="co_zMTubMby3QiKDYnW9e2BEXW7Xaq" alt="test" />,
19
19
  { account },
20
20
  );
21
+
21
22
  const img = container.querySelector("img");
22
23
  expect(img).toBeDefined();
23
24
  expect(img!.getAttribute("width")).toBe(null);
24
25
  expect(img!.getAttribute("height")).toBe(null);
25
26
  expect(img!.alt).toBe("test");
26
- expect(img!.src).toBe("");
27
+ expect(img!.src).toBe(
28
+ "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==",
29
+ );
30
+ });
31
+
32
+ it("should render nothing if coValue is not found", async () => {
33
+ const { container } = render(
34
+ <Image imageId="co_zMTubMby3QiKDYnW9e2BEXW7Xaq" alt="test" />,
35
+ { account },
36
+ );
37
+ await waitFor(() => {
38
+ const img = container.querySelector("img");
39
+ expect(img).toBeDefined();
40
+ expect(img!.getAttribute("width")).toBe(null);
41
+ expect(img!.getAttribute("height")).toBe(null);
42
+ expect(img!.alt).toBe("test");
43
+ expect(img!.src).toBe("");
44
+ });
27
45
  });
28
46
 
29
47
  it("should render an empty image if the image is not loaded yet", async () => {
@@ -69,7 +69,10 @@ export const Image = forwardRef<RNImage, ImageProps>(function Image(
69
69
  ref,
70
70
  ) {
71
71
  const image = useCoState(ImageDefinition, imageId);
72
- const [src, setSrc] = useState<string | undefined>(image?.placeholderDataURL);
72
+ const [src, setSrc] = useState<string | undefined>(
73
+ image?.placeholderDataURL ??
74
+ "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==",
75
+ );
73
76
 
74
77
  const dimensions: { width: number | undefined; height: number | undefined } =
75
78
  useMemo(() => {