jazz-tools 0.16.5 → 0.17.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 (170) hide show
  1. package/.svelte-kit/__package__/index.d.ts +1 -0
  2. package/.svelte-kit/__package__/index.d.ts.map +1 -1
  3. package/.svelte-kit/__package__/index.js +1 -0
  4. package/.svelte-kit/__package__/media/image.svelte +131 -0
  5. package/.svelte-kit/__package__/media/image.svelte.d.ts +10 -0
  6. package/.svelte-kit/__package__/media/image.svelte.d.ts.map +1 -0
  7. package/.svelte-kit/__package__/media/index.d.ts +2 -0
  8. package/.svelte-kit/__package__/media/index.d.ts.map +1 -0
  9. package/.svelte-kit/__package__/media/index.js +1 -0
  10. package/.svelte-kit/__package__/tests/media/image.svelte.test.d.ts +2 -0
  11. package/.svelte-kit/__package__/tests/media/image.svelte.test.d.ts.map +1 -0
  12. package/.svelte-kit/__package__/tests/media/image.svelte.test.js +430 -0
  13. package/.svelte-kit/__package__/tests/testUtils.d.ts +11 -0
  14. package/.svelte-kit/__package__/tests/testUtils.d.ts.map +1 -0
  15. package/.svelte-kit/__package__/tests/testUtils.js +17 -0
  16. package/.svelte-kit/__package__/tests/types.d.ts +3 -0
  17. package/.turbo/turbo-build.log +44 -48
  18. package/CHANGELOG.md +28 -0
  19. package/dist/{chunk-H3BIFFQG.js → chunk-2SH44VLX.js} +35 -40
  20. package/dist/chunk-2SH44VLX.js.map +1 -0
  21. package/dist/index.js +1 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/inspector/{custom-element-TUXKXSZU.js → custom-element-I7L56H6B.js} +3 -5
  24. package/dist/inspector/{custom-element-TUXKXSZU.js.map → custom-element-I7L56H6B.js.map} +1 -1
  25. package/dist/inspector/index.js +2 -4
  26. package/dist/inspector/index.js.map +1 -1
  27. package/dist/inspector/register-custom-element.js +1 -1
  28. package/dist/inspector/viewer/co-plain-text-view.d.ts +1 -1
  29. package/dist/inspector/viewer/co-plain-text-view.d.ts.map +1 -1
  30. package/dist/inspector/viewer/role-display.d.ts.map +1 -1
  31. package/dist/media/chunk-BBSS3NEY.js +211 -0
  32. package/dist/media/chunk-BBSS3NEY.js.map +1 -0
  33. package/dist/media/create-image.d.ts +48 -0
  34. package/dist/media/create-image.d.ts.map +1 -0
  35. package/dist/media/create-image.test.d.ts +2 -0
  36. package/dist/media/create-image.test.d.ts.map +1 -0
  37. package/dist/media/index.browser.d.ts +15 -0
  38. package/dist/media/index.browser.d.ts.map +1 -0
  39. package/dist/media/index.browser.js +113 -0
  40. package/dist/media/index.browser.js.map +1 -0
  41. package/dist/media/index.d.ts +53 -0
  42. package/dist/media/index.d.ts.map +1 -0
  43. package/dist/media/index.js +13 -0
  44. package/dist/media/index.js.map +1 -0
  45. package/dist/media/index.native.d.ts +17 -0
  46. package/dist/media/index.native.d.ts.map +1 -0
  47. package/dist/media/index.native.js +126 -0
  48. package/dist/media/index.native.js.map +1 -0
  49. package/dist/media/utils.d.ts +17 -0
  50. package/dist/media/utils.d.ts.map +1 -0
  51. package/dist/media/utils.test.d.ts +2 -0
  52. package/dist/media/utils.test.d.ts.map +1 -0
  53. package/dist/react/index.d.ts +1 -2
  54. package/dist/react/index.d.ts.map +1 -1
  55. package/dist/react/index.js +176 -59
  56. package/dist/react/index.js.map +1 -1
  57. package/dist/react/media/image.d.ts +62 -0
  58. package/dist/react/media/image.d.ts.map +1 -0
  59. package/dist/react/ssr.d.ts.map +1 -1
  60. package/dist/react/ssr.js.map +1 -1
  61. package/dist/react/tests/media/image.test.d.ts +2 -0
  62. package/dist/react/tests/media/image.test.d.ts.map +1 -0
  63. package/dist/react/tests/testUtils.d.ts.map +1 -1
  64. package/dist/react-core/auth/PassphraseAuth.d.ts +1 -1
  65. package/dist/react-core/auth/PassphraseAuth.d.ts.map +1 -1
  66. package/dist/react-core/index.js +1 -3
  67. package/dist/react-core/index.js.map +1 -1
  68. package/dist/react-core/tests/testUtils.d.ts.map +1 -1
  69. package/dist/react-core/tests/useDemoAuth.test.d.ts +2 -0
  70. package/dist/react-core/tests/useDemoAuth.test.d.ts.map +1 -0
  71. package/dist/react-native-core/index.d.ts +1 -1
  72. package/dist/react-native-core/index.d.ts.map +1 -1
  73. package/dist/react-native-core/index.js +84 -66
  74. package/dist/react-native-core/index.js.map +1 -1
  75. package/dist/react-native-core/media/image.d.ts +93 -0
  76. package/dist/react-native-core/media/image.d.ts.map +1 -0
  77. package/dist/react-native-core/testing.d.ts +2 -0
  78. package/dist/react-native-core/testing.d.ts.map +1 -0
  79. package/dist/svelte/index.d.ts +1 -0
  80. package/dist/svelte/index.d.ts.map +1 -1
  81. package/dist/svelte/index.js +1 -0
  82. package/dist/svelte/media/image.svelte +131 -0
  83. package/dist/svelte/media/image.svelte.d.ts +10 -0
  84. package/dist/svelte/media/image.svelte.d.ts.map +1 -0
  85. package/dist/svelte/media/index.d.ts +2 -0
  86. package/dist/svelte/media/index.d.ts.map +1 -0
  87. package/dist/svelte/media/index.js +1 -0
  88. package/dist/svelte/tests/media/image.svelte.test.d.ts +2 -0
  89. package/dist/svelte/tests/media/image.svelte.test.d.ts.map +1 -0
  90. package/dist/svelte/tests/media/image.svelte.test.js +430 -0
  91. package/dist/svelte/tests/testUtils.d.ts +11 -0
  92. package/dist/svelte/tests/testUtils.d.ts.map +1 -0
  93. package/dist/svelte/tests/testUtils.js +17 -0
  94. package/dist/svelte/tests/types.d.ts +3 -0
  95. package/dist/testing.js +1 -1
  96. package/dist/testing.js.map +1 -1
  97. package/dist/tools/coValues/coFeed.d.ts +15 -0
  98. package/dist/tools/coValues/coFeed.d.ts.map +1 -1
  99. package/dist/tools/coValues/deepLoading.d.ts +10 -10
  100. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  101. package/dist/tools/coValues/extensions/imageDef.d.ts +3 -9
  102. package/dist/tools/coValues/extensions/imageDef.d.ts.map +1 -1
  103. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +1 -0
  104. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
  105. package/dist/tools/index.d.ts +1 -1
  106. package/dist/tools/index.d.ts.map +1 -1
  107. package/dist/tools/testing.d.ts.map +1 -1
  108. package/package.json +12 -12
  109. package/src/inspector/viewer/co-plain-text-view.tsx +1 -5
  110. package/src/inspector/viewer/co-stream-view.tsx +1 -1
  111. package/src/inspector/viewer/role-display.tsx +4 -1
  112. package/src/{browser-media-images/index.test.browser.ts → media/create-image.test.ts} +146 -24
  113. package/src/media/create-image.ts +180 -0
  114. package/src/media/index.browser.ts +150 -0
  115. package/src/media/index.native.ts +153 -0
  116. package/src/media/index.ts +61 -0
  117. package/src/media/utils.test.ts +327 -0
  118. package/src/media/utils.ts +202 -0
  119. package/src/react/index.ts +1 -2
  120. package/src/react/media/image.tsx +210 -0
  121. package/src/react/ssr.ts +1 -3
  122. package/src/react/tests/media/image.test.tsx +588 -0
  123. package/src/react/tests/testUtils.tsx +2 -10
  124. package/src/react-core/auth/PassphraseAuth.tsx +1 -5
  125. package/src/react-core/tests/testUtils.tsx +2 -10
  126. package/src/react-native-core/index.ts +1 -1
  127. package/src/react-native-core/media/image.tsx +159 -0
  128. package/src/svelte/index.ts +1 -0
  129. package/src/svelte/media/image.svelte +131 -0
  130. package/src/svelte/media/index.ts +1 -0
  131. package/src/svelte/tests/media/image.svelte.test.ts +583 -0
  132. package/src/svelte/tests/testUtils.ts +33 -0
  133. package/src/svelte/tests/types.d.ts +3 -0
  134. package/src/tools/coValues/coFeed.ts +40 -7
  135. package/src/tools/coValues/deepLoading.ts +46 -32
  136. package/src/tools/coValues/extensions/imageDef.ts +3 -49
  137. package/src/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +6 -0
  138. package/src/tools/index.ts +0 -1
  139. package/src/tools/testing.ts +3 -1
  140. package/src/tools/tests/coList.test.ts +1 -1
  141. package/src/tools/tests/coMap.record.test-d.ts +105 -0
  142. package/src/tools/tests/coMap.record.test.ts +48 -2
  143. package/src/tools/tests/coMap.test-d.ts +50 -0
  144. package/src/tools/tests/coOptional.test.ts +3 -1
  145. package/tsconfig.json +1 -0
  146. package/tsup.config.ts +4 -9
  147. package/vitest.config.ts +14 -21
  148. package/dist/browser-media-images/index.d.ts +0 -9
  149. package/dist/browser-media-images/index.d.ts.map +0 -1
  150. package/dist/browser-media-images/index.js +0 -72
  151. package/dist/browser-media-images/index.js.map +0 -1
  152. package/dist/browser-media-images/index.test.browser.d.ts +0 -2
  153. package/dist/browser-media-images/index.test.browser.d.ts.map +0 -1
  154. package/dist/chunk-H3BIFFQG.js.map +0 -1
  155. package/dist/react/media.d.ts +0 -24
  156. package/dist/react/media.d.ts.map +0 -1
  157. package/dist/react-native-core/media.d.ts +0 -24
  158. package/dist/react-native-core/media.d.ts.map +0 -1
  159. package/dist/react-native-media-images/index.d.ts +0 -7
  160. package/dist/react-native-media-images/index.d.ts.map +0 -1
  161. package/dist/react-native-media-images/index.js +0 -177
  162. package/dist/react-native-media-images/index.js.map +0 -1
  163. package/dist/tools/tests/imageDef.test.d.ts +0 -2
  164. package/dist/tools/tests/imageDef.test.d.ts.map +0 -1
  165. package/src/browser-media-images/index.ts +0 -131
  166. package/src/react/media.tsx +0 -74
  167. package/src/react/scratch.tsx +0 -50
  168. package/src/react-native-core/media.tsx +0 -79
  169. package/src/react-native-media-images/index.ts +0 -238
  170. package/src/tools/tests/imageDef.test.ts +0 -278
@@ -1,24 +0,0 @@
1
- import { ImageDefinition, Loaded } from "jazz-tools";
2
- import React from "react";
3
- /** @category Media */
4
- export declare function useProgressiveImg({ image, maxWidth, targetWidth, }: {
5
- image: Loaded<typeof ImageDefinition> | null | undefined;
6
- maxWidth?: number;
7
- targetWidth?: number;
8
- }): {
9
- src: string | undefined;
10
- res: `${number}x${number}` | "placeholder" | undefined;
11
- originalSize: [number, number] | undefined;
12
- };
13
- /** @category Media */
14
- export declare function ProgressiveImg({ children, image, maxWidth, targetWidth, }: {
15
- children: (result: {
16
- src: string | undefined;
17
- res: `${number}x${number}` | "placeholder" | undefined;
18
- originalSize: readonly [number, number] | undefined;
19
- }) => React.ReactNode;
20
- image: Loaded<typeof ImageDefinition> | null | undefined;
21
- maxWidth?: number;
22
- targetWidth?: number;
23
- }): React.ReactNode;
24
- //# sourceMappingURL=media.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/react/media.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,sBAAsB;AACtB,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;;;;EAyCA;AAED,sBAAsB;AACtB,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,WAAW,GACZ,EAAE;IACD,QAAQ,EAAE,CAAC,MAAM,EAAE;QACjB,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;QACxB,GAAG,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE,GAAG,aAAa,GAAG,SAAS,CAAC;QACvD,YAAY,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;KACrD,KAAK,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,KAAK,CAAC,SAAS,CAGlB"}
@@ -1,24 +0,0 @@
1
- import { ImageDefinition, Loaded } from "jazz-tools";
2
- import React from "react";
3
- /** @category Media */
4
- export declare function useProgressiveImgNative({ image, maxWidth, targetWidth, }: {
5
- image: Loaded<typeof ImageDefinition> | null | undefined;
6
- maxWidth?: number;
7
- targetWidth?: number;
8
- }): {
9
- src: string | undefined;
10
- res: `${number}x${number}` | "placeholder" | undefined;
11
- originalSize: [number, number] | undefined;
12
- };
13
- /** @category Media */
14
- export declare function ProgressiveImgNative({ children, image, maxWidth, targetWidth, }: {
15
- children: (result: {
16
- src: string | undefined;
17
- res: `${number}x${number}` | "placeholder" | undefined;
18
- originalSize: readonly [number, number] | undefined;
19
- }) => React.ReactNode;
20
- image: Loaded<typeof ImageDefinition> | null | undefined;
21
- maxWidth?: number;
22
- targetWidth?: number;
23
- }): React.ReactNode;
24
- //# sourceMappingURL=media.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/react-native-core/media.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,sBAAsB;AACtB,wBAAgB,uBAAuB,CAAC,EACtC,KAAK,EACL,QAAQ,EACR,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;;;;EA8CA;AAED,sBAAsB;AACtB,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,WAAW,GACZ,EAAE;IACD,QAAQ,EAAE,CAAC,MAAM,EAAE;QACjB,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;QACxB,GAAG,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE,GAAG,aAAa,GAAG,SAAS,CAAC;QACvD,YAAY,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;KACrD,KAAK,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,mBAGA"}
@@ -1,7 +0,0 @@
1
- import { Account, Group, ImageDefinition, Loaded } from "jazz-tools";
2
- /** @category Image creation */
3
- export declare function createImageNative(base64ImageDataURI: string, options?: {
4
- owner?: Group | Account;
5
- maxSize?: 256 | 1024 | 2048;
6
- }): Promise<Loaded<typeof ImageDefinition>>;
7
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react-native-media-images/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,OAAO,EAEP,KAAK,EACL,eAAe,EACf,MAAM,EACP,MAAM,YAAY,CAAC;AAwFpB,+BAA+B;AAC/B,wBAAsB,iBAAiB,CACrC,kBAAkB,EAAE,MAAM,EAC1B,OAAO,GAAE;IACP,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;CACxB,GACL,OAAO,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC,CAsIzC"}
@@ -1,177 +0,0 @@
1
- // src/react-native-media-images/index.ts
2
- import ImageResizer from "@bam.tech/react-native-image-resizer";
3
- import * as FileSystem from "expo-file-system";
4
- import {
5
- FileStream,
6
- ImageDefinition
7
- } from "jazz-tools";
8
- import { Image } from "react-native";
9
- function arrayBuffer(blob) {
10
- return new Promise((resolve, reject) => {
11
- const reader = new FileReader();
12
- reader.onloadend = () => {
13
- resolve(reader.result);
14
- };
15
- reader.onerror = (error) => {
16
- reject(error);
17
- };
18
- reader.readAsArrayBuffer(blob);
19
- });
20
- }
21
- async function fileUriToBlob(uri) {
22
- try {
23
- const response = await fetch(uri);
24
- const blob = await response.blob();
25
- blob.arrayBuffer = () => arrayBuffer(blob);
26
- return blob;
27
- } catch (error) {
28
- console.error("Failed to convert file URI to Blob:", error);
29
- throw new Error("Failed to convert file URI to Blob");
30
- }
31
- }
32
- async function convertFileContentsToBase64DataURI(fileUri, contentType) {
33
- try {
34
- const base64 = await FileSystem.readAsStringAsync(fileUri, {
35
- encoding: FileSystem.EncodingType.Base64
36
- });
37
- return `data:${contentType};base64,${base64}`;
38
- } catch (error) {
39
- console.error("Failed to convert file to base64:", error);
40
- return null;
41
- }
42
- }
43
- function base64DataURIToParts(base64Data) {
44
- const parts = base64Data.split(",");
45
- const contentType = parts[0]?.split(":")?.[1]?.split(";")?.[0] || "";
46
- const data = parts[1] || "";
47
- return { contentType, data };
48
- }
49
- function contentTypeToFormat(contentType) {
50
- if (contentType.includes("image/png")) return "PNG";
51
- if (contentType.includes("image/jpeg")) return "JPEG";
52
- if (contentType.includes("image/webp")) return "WEBP";
53
- return "PNG";
54
- }
55
- async function base64DataURIToBlob(base64Data) {
56
- const { contentType, data } = base64DataURIToParts(base64Data);
57
- const byteCharacters = atob(data);
58
- const byteNumbers = new Array(byteCharacters.length);
59
- for (let i = 0; i < byteCharacters.length; i++) {
60
- byteNumbers[i] = byteCharacters.charCodeAt(i);
61
- }
62
- const byteArray = new Uint8Array(byteNumbers);
63
- const blob = new Blob(byteArray, { type: contentType });
64
- blob.arrayBuffer = () => arrayBuffer(blob);
65
- return blob;
66
- }
67
- async function getImageDimensions(uri) {
68
- return new Promise((resolve, reject) => {
69
- Image.getSize(
70
- uri,
71
- (width, height) => resolve({ width, height }),
72
- (error) => {
73
- console.error("Failed to get image dimensions:", error);
74
- reject(new Error("Failed to get image dimensions"));
75
- }
76
- );
77
- });
78
- }
79
- async function createImageNative(base64ImageDataURI, options = {}) {
80
- try {
81
- const { contentType } = base64DataURIToParts(base64ImageDataURI);
82
- const format = contentTypeToFormat(contentType);
83
- let originalWidth, originalHeight;
84
- try {
85
- ({ width: originalWidth, height: originalHeight } = await getImageDimensions(base64ImageDataURI));
86
- } catch (error) {
87
- console.error("Error getting image dimensions:", error);
88
- throw new Error("Failed to get image dimensions");
89
- }
90
- let placeholderImage;
91
- try {
92
- placeholderImage = await ImageResizer.createResizedImage(
93
- base64ImageDataURI,
94
- 8,
95
- 8,
96
- format,
97
- 100,
98
- 0
99
- );
100
- } catch (error) {
101
- console.error("Error creating placeholder image:", error);
102
- throw new Error("Failed to create placeholder image");
103
- }
104
- const placeholderDataURL = await convertFileContentsToBase64DataURI(
105
- placeholderImage.uri,
106
- contentType
107
- );
108
- if (!placeholderDataURL) {
109
- throw new Error("Failed to create placeholder data URL");
110
- }
111
- const imageDefinition = ImageDefinition.create(
112
- {
113
- originalSize: [originalWidth, originalHeight],
114
- placeholderDataURL
115
- },
116
- options.owner
117
- );
118
- const addImageStream = async (width, height, label) => {
119
- try {
120
- const resizedImage = await ImageResizer.createResizedImage(
121
- base64ImageDataURI,
122
- width,
123
- height,
124
- format,
125
- 80,
126
- 0
127
- );
128
- const binaryStream = await FileStream.createFromBlob(
129
- await fileUriToBlob(resizedImage.uri),
130
- imageDefinition._owner
131
- );
132
- imageDefinition[label] = binaryStream;
133
- } catch (error) {
134
- console.error(`Error adding image stream for ${label}:`, error);
135
- throw new Error(`Failed to add image stream for ${label}`);
136
- }
137
- };
138
- if (originalWidth > 256 || originalHeight > 256) {
139
- const width = originalWidth > originalHeight ? 256 : Math.round(256 * (originalWidth / originalHeight));
140
- const height = originalHeight > originalWidth ? 256 : Math.round(256 * (originalHeight / originalWidth));
141
- await addImageStream(width, height, `${width}x${height}`);
142
- }
143
- if (options.maxSize === 256) return imageDefinition;
144
- if (originalWidth > 1024 || originalHeight > 1024) {
145
- const width = originalWidth > originalHeight ? 1024 : Math.round(1024 * (originalWidth / originalHeight));
146
- const height = originalHeight > originalWidth ? 1024 : Math.round(1024 * (originalHeight / originalWidth));
147
- await addImageStream(width, height, `${width}x${height}`);
148
- }
149
- if (options.maxSize === 1024) return imageDefinition;
150
- if (originalWidth > 2048 || originalHeight > 2048) {
151
- const width = originalWidth > originalHeight ? 2048 : Math.round(2048 * (originalWidth / originalHeight));
152
- const height = originalHeight > originalWidth ? 2048 : Math.round(2048 * (originalHeight / originalWidth));
153
- await addImageStream(width, height, `${width}x${height}`);
154
- }
155
- if (options.maxSize === 2048) return imageDefinition;
156
- if (options.maxSize === void 0 || options.maxSize > 2048) {
157
- try {
158
- const originalBinaryStream = await FileStream.createFromBlob(
159
- await base64DataURIToBlob(base64ImageDataURI),
160
- imageDefinition._owner
161
- );
162
- imageDefinition[`${originalWidth}x${originalHeight}`] = originalBinaryStream;
163
- } catch (error) {
164
- console.error("Error adding original image stream:", error);
165
- throw new Error("Failed to add original image stream");
166
- }
167
- }
168
- return imageDefinition;
169
- } catch (error) {
170
- console.error("Error in createImage:", error);
171
- throw error;
172
- }
173
- }
174
- export {
175
- createImageNative
176
- };
177
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/react-native-media-images/index.ts"],"sourcesContent":["import ImageResizer from \"@bam.tech/react-native-image-resizer\";\nimport * as FileSystem from \"expo-file-system\";\nimport {\n Account,\n FileStream,\n Group,\n ImageDefinition,\n Loaded,\n} from \"jazz-tools\";\nimport { Image } from \"react-native\";\n\nfunction arrayBuffer(blob: Blob): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n resolve(reader.result as ArrayBuffer);\n };\n reader.onerror = (error) => {\n reject(error);\n };\n reader.readAsArrayBuffer(blob);\n });\n}\n\nasync function fileUriToBlob(uri: string): Promise<Blob> {\n try {\n const response = await fetch(uri);\n const blob = await response.blob();\n blob.arrayBuffer = () => arrayBuffer(blob);\n return blob;\n } catch (error) {\n console.error(\"Failed to convert file URI to Blob:\", error);\n throw new Error(\"Failed to convert file URI to Blob\");\n }\n}\n\nasync function convertFileContentsToBase64DataURI(\n fileUri: string,\n contentType: string,\n) {\n try {\n const base64 = await FileSystem.readAsStringAsync(fileUri, {\n encoding: FileSystem.EncodingType.Base64,\n });\n return `data:${contentType};base64,${base64}`;\n } catch (error) {\n console.error(\"Failed to convert file to base64:\", error);\n return null;\n }\n}\n\nfunction base64DataURIToParts(base64Data: string) {\n const parts = base64Data.split(\",\");\n const contentType = parts[0]?.split(\":\")?.[1]?.split(\";\")?.[0] || \"\";\n const data = parts[1] || \"\";\n return { contentType, data };\n}\n\nfunction contentTypeToFormat(contentType: string) {\n if (contentType.includes(\"image/png\")) return \"PNG\";\n if (contentType.includes(\"image/jpeg\")) return \"JPEG\";\n if (contentType.includes(\"image/webp\")) return \"WEBP\";\n return \"PNG\";\n}\n\nasync function base64DataURIToBlob(base64Data: string) {\n const { contentType, data } = base64DataURIToParts(base64Data);\n const byteCharacters = atob(data);\n\n const byteNumbers = new Array(byteCharacters.length);\n for (let i = 0; i < byteCharacters.length; i++) {\n byteNumbers[i] = byteCharacters.charCodeAt(i);\n }\n const byteArray = new Uint8Array(byteNumbers);\n\n // @ts-expect-error byteArray has data\n const blob = new Blob(byteArray, { type: contentType });\n blob.arrayBuffer = () => arrayBuffer(blob);\n return blob;\n}\n\nasync function getImageDimensions(\n uri: string,\n): Promise<{ width: number; height: number }> {\n return new Promise((resolve, reject) => {\n Image.getSize(\n uri,\n (width, height) => resolve({ width, height }),\n (error) => {\n console.error(\"Failed to get image dimensions:\", error);\n reject(new Error(\"Failed to get image dimensions\"));\n },\n );\n });\n}\n\n/** @category Image creation */\nexport async function createImageNative(\n base64ImageDataURI: string,\n options: {\n owner?: Group | Account;\n maxSize?: 256 | 1024 | 2048;\n } = {},\n): Promise<Loaded<typeof ImageDefinition>> {\n try {\n const { contentType } = base64DataURIToParts(base64ImageDataURI);\n const format = contentTypeToFormat(contentType);\n\n let originalWidth, originalHeight;\n try {\n ({ width: originalWidth, height: originalHeight } =\n await getImageDimensions(base64ImageDataURI));\n } catch (error) {\n console.error(\"Error getting image dimensions:\", error);\n throw new Error(\"Failed to get image dimensions\");\n }\n\n let placeholderImage;\n try {\n placeholderImage = await ImageResizer.createResizedImage(\n base64ImageDataURI,\n 8,\n 8,\n format,\n 100,\n 0,\n );\n } catch (error) {\n console.error(\"Error creating placeholder image:\", error);\n throw new Error(\"Failed to create placeholder image\");\n }\n\n const placeholderDataURL = await convertFileContentsToBase64DataURI(\n placeholderImage.uri,\n contentType,\n );\n\n if (!placeholderDataURL) {\n throw new Error(\"Failed to create placeholder data URL\");\n }\n\n const imageDefinition = ImageDefinition.create(\n {\n originalSize: [originalWidth, originalHeight],\n placeholderDataURL,\n },\n options.owner,\n );\n\n const addImageStream = async (\n width: number,\n height: number,\n label: string,\n ) => {\n try {\n const resizedImage = await ImageResizer.createResizedImage(\n base64ImageDataURI,\n width,\n height,\n format,\n 80,\n 0,\n );\n\n const binaryStream = await FileStream.createFromBlob(\n await fileUriToBlob(resizedImage.uri),\n imageDefinition._owner,\n );\n\n imageDefinition[label] = binaryStream;\n } catch (error) {\n console.error(`Error adding image stream for ${label}:`, error);\n throw new Error(`Failed to add image stream for ${label}`);\n }\n };\n\n if (originalWidth > 256 || originalHeight > 256) {\n const width =\n originalWidth > originalHeight\n ? 256\n : Math.round(256 * (originalWidth / originalHeight));\n const height =\n originalHeight > originalWidth\n ? 256\n : Math.round(256 * (originalHeight / originalWidth));\n await addImageStream(width, height, `${width}x${height}`);\n }\n\n if (options.maxSize === 256) return imageDefinition;\n\n if (originalWidth > 1024 || originalHeight > 1024) {\n const width =\n originalWidth > originalHeight\n ? 1024\n : Math.round(1024 * (originalWidth / originalHeight));\n const height =\n originalHeight > originalWidth\n ? 1024\n : Math.round(1024 * (originalHeight / originalWidth));\n await addImageStream(width, height, `${width}x${height}`);\n }\n\n if (options.maxSize === 1024) return imageDefinition;\n\n if (originalWidth > 2048 || originalHeight > 2048) {\n const width =\n originalWidth > originalHeight\n ? 2048\n : Math.round(2048 * (originalWidth / originalHeight));\n const height =\n originalHeight > originalWidth\n ? 2048\n : Math.round(2048 * (originalHeight / originalWidth));\n await addImageStream(width, height, `${width}x${height}`);\n }\n\n if (options.maxSize === 2048) return imageDefinition;\n\n if (options.maxSize === undefined || options.maxSize > 2048) {\n try {\n const originalBinaryStream = await FileStream.createFromBlob(\n await base64DataURIToBlob(base64ImageDataURI),\n imageDefinition._owner,\n );\n imageDefinition[`${originalWidth}x${originalHeight}`] =\n originalBinaryStream;\n } catch (error) {\n console.error(\"Error adding original image stream:\", error);\n throw new Error(\"Failed to add original image stream\");\n }\n }\n\n return imageDefinition;\n } catch (error) {\n console.error(\"Error in createImage:\", error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=imageDef.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"imageDef.test.d.ts","sourceRoot":"","sources":["../../../src/tools/tests/imageDef.test.ts"],"names":[],"mappings":""}
@@ -1,131 +0,0 @@
1
- import ImageBlobReduce from "image-blob-reduce";
2
- import {
3
- Account,
4
- FileStream,
5
- Group,
6
- ImageDefinition,
7
- Loaded,
8
- } from "jazz-tools";
9
- import Pica from "pica";
10
-
11
- let reducer: ImageBlobReduce.ImageBlobReduce | undefined;
12
-
13
- /** @category Image creation */
14
- export async function createImage(
15
- imageBlobOrFile: Blob | File,
16
- options?: {
17
- owner?: Group | Account;
18
- maxSize?: 256 | 1024 | 2048;
19
- },
20
- ): Promise<Loaded<typeof ImageDefinition, { $each: true }>> {
21
- // Get the original size of the image
22
- const { width: originalWidth, height: originalHeight } =
23
- await getImageSize(imageBlobOrFile);
24
-
25
- const highestDimension = Math.max(originalWidth, originalHeight);
26
-
27
- // Calculate the sizes to resize the image to
28
- const resizes = [256, 1024, 2048, highestDimension]
29
- .filter((s) => s <= (options?.maxSize ?? highestDimension))
30
- .toSorted((a, b) => a - b);
31
-
32
- // Get the highest resolution to use as final original size
33
- // In case of options.maxSize, it's not the originalWidth/Height
34
- const { width: finalWidth, height: finalHeight } = getNewDimensions(
35
- originalWidth,
36
- originalHeight,
37
- resizes.at(-1)!,
38
- );
39
-
40
- const imageDefinition = ImageDefinition.create(
41
- { originalSize: [finalWidth, finalHeight] },
42
- options?.owner,
43
- );
44
- const owner = imageDefinition._owner;
45
-
46
- // Placeholder 8x8
47
- imageDefinition.placeholderDataURL =
48
- await getPlaceholderBase64(imageBlobOrFile);
49
-
50
- // Resizes for progressive loading
51
- for (let size of resizes) {
52
- // Calculate width and height respecting the aspect ratio
53
- const { width, height } = getNewDimensions(
54
- originalWidth,
55
- originalHeight,
56
- size,
57
- );
58
-
59
- const image = await resize(imageBlobOrFile, width, height);
60
-
61
- const binaryStream = await FileStream.createFromBlob(image, owner);
62
- imageDefinition[`${width}x${height}`] = binaryStream;
63
- }
64
-
65
- return imageDefinition;
66
- }
67
-
68
- async function getImageSize(
69
- imageBlobOrFile: Blob | File,
70
- ): Promise<{ width: number; height: number }> {
71
- const { width, height } = await new Promise<{
72
- width: number;
73
- height: number;
74
- }>((resolve, reject) => {
75
- const img = new Image();
76
- img.onload = () => {
77
- resolve({ width: img.width, height: img.height });
78
- URL.revokeObjectURL(img.src);
79
- };
80
- img.onerror = () => {
81
- reject(new Error("Failed to load image"));
82
- URL.revokeObjectURL(img.src);
83
- };
84
- img.src = URL.createObjectURL(imageBlobOrFile);
85
- });
86
-
87
- return { width, height };
88
- }
89
-
90
- async function getPlaceholderBase64(
91
- imageBlobOrFile: Blob | File,
92
- ): Promise<string> {
93
- // Inizialize Reducer here to not have module side effects
94
- if (!reducer) {
95
- reducer = new ImageBlobReduce({ pica: new Pica() });
96
- }
97
-
98
- const canvas = await reducer.toCanvas(imageBlobOrFile, { max: 8 });
99
- return canvas.toDataURL("image/png");
100
- }
101
-
102
- async function resize(
103
- imageBlobOrFile: Blob | File,
104
- width: number,
105
- height: number,
106
- ): Promise<Blob> {
107
- // Inizialize Reducer here to not have module side effects
108
- if (!reducer) {
109
- reducer = new ImageBlobReduce({ pica: new Pica() });
110
- }
111
-
112
- return reducer.toBlob(imageBlobOrFile, { max: Math.max(width, height) });
113
- }
114
-
115
- const getNewDimensions = (
116
- originalWidth: number,
117
- originalHeight: number,
118
- maxSize: number,
119
- ) => {
120
- const width =
121
- originalWidth > originalHeight
122
- ? maxSize
123
- : Math.round(maxSize * (originalWidth / originalHeight));
124
-
125
- const height =
126
- originalHeight > originalWidth
127
- ? maxSize
128
- : Math.round(maxSize * (originalHeight / originalWidth));
129
-
130
- return { width, height };
131
- };
@@ -1,74 +0,0 @@
1
- import { ImageDefinition, Loaded } from "jazz-tools";
2
- import React, { useEffect, useState } from "react";
3
-
4
- /** @category Media */
5
- export function useProgressiveImg({
6
- image,
7
- maxWidth,
8
- targetWidth,
9
- }: {
10
- image: Loaded<typeof ImageDefinition> | null | undefined;
11
- maxWidth?: number;
12
- targetWidth?: number;
13
- }) {
14
- const [current, setCurrent] = useState<
15
- { src?: string; res?: `${number}x${number}` | "placeholder" } | undefined
16
- >(undefined);
17
-
18
- useEffect(() => {
19
- let lastHighestRes: string | undefined;
20
- if (!image) return;
21
- const unsub = image.subscribe({}, (update) => {
22
- const highestRes = ImageDefinition.highestResAvailable(update, {
23
- maxWidth,
24
- targetWidth,
25
- });
26
- if (highestRes) {
27
- if (highestRes.res !== lastHighestRes) {
28
- lastHighestRes = highestRes.res;
29
- const blob = highestRes.stream.toBlob();
30
- if (blob) {
31
- const blobURI = URL.createObjectURL(blob);
32
- setCurrent({ src: blobURI, res: highestRes.res });
33
- return () => {
34
- setTimeout(() => URL.revokeObjectURL(blobURI), 200);
35
- };
36
- }
37
- }
38
- } else {
39
- setCurrent({
40
- src: update?.placeholderDataURL,
41
- res: "placeholder",
42
- });
43
- }
44
- });
45
-
46
- return unsub;
47
- }, [image?.id, maxWidth]);
48
-
49
- return {
50
- src: current?.src,
51
- res: current?.res,
52
- originalSize: image?.originalSize,
53
- };
54
- }
55
-
56
- /** @category Media */
57
- export function ProgressiveImg({
58
- children,
59
- image,
60
- maxWidth,
61
- targetWidth,
62
- }: {
63
- children: (result: {
64
- src: string | undefined;
65
- res: `${number}x${number}` | "placeholder" | undefined;
66
- originalSize: readonly [number, number] | undefined;
67
- }) => React.ReactNode;
68
- image: Loaded<typeof ImageDefinition> | null | undefined;
69
- maxWidth?: number;
70
- targetWidth?: number;
71
- }): React.ReactNode {
72
- const result = useProgressiveImg({ image, maxWidth, targetWidth });
73
- return result ? children(result) : null;
74
- }
@@ -1,50 +0,0 @@
1
- import { FileStream, ImageDefinition } from "jazz-tools";
2
- import { createJazzTestAccount } from "jazz-tools/testing";
3
-
4
- // Simple document environment
5
- global.document = {
6
- createElement: () =>
7
- ({ src: "", onload: null }) as unknown as HTMLImageElement,
8
- } as unknown as Document;
9
- global.window = { innerWidth: 1000 } as unknown as Window & typeof globalThis;
10
-
11
- const me = await createJazzTestAccount();
12
-
13
- const mediumSizeBlob = new Blob([], { type: "image/jpeg" });
14
- const image = ImageDefinition.create(
15
- {
16
- originalSize: [1920, 1080],
17
- },
18
- { owner: me },
19
- );
20
- image["100x100"] = await FileStream.createFromBlob(mediumSizeBlob, {
21
- owner: me,
22
- });
23
- image["1920x1080"] = await FileStream.createFromBlob(mediumSizeBlob, {
24
- owner: me,
25
- });
26
- const imageElement = document.createElement("img");
27
- // ---cut---
28
- // Start with placeholder for immediate display
29
- if (image.placeholderDataURL) {
30
- imageElement.src = image.placeholderDataURL;
31
- }
32
-
33
- // Then load the best resolution for the current display
34
- const screenWidth = window.innerWidth;
35
- const bestRes = ImageDefinition.highestResAvailable(image, {
36
- targetWidth: screenWidth,
37
- });
38
-
39
- if (bestRes) {
40
- const blob = bestRes.stream.toBlob();
41
- if (blob) {
42
- const url = URL.createObjectURL(blob);
43
- imageElement.src = url;
44
-
45
- // Remember to revoke the URL when no longer needed
46
- imageElement.onload = () => {
47
- URL.revokeObjectURL(url);
48
- };
49
- }
50
- }
@@ -1,79 +0,0 @@
1
- import { ImageDefinition, Loaded } from "jazz-tools";
2
- import React, { useEffect, useState } from "react";
3
-
4
- /** @category Media */
5
- export function useProgressiveImgNative({
6
- image,
7
- maxWidth,
8
- targetWidth,
9
- }: {
10
- image: Loaded<typeof ImageDefinition> | null | undefined;
11
- maxWidth?: number;
12
- targetWidth?: number;
13
- }) {
14
- const [current, setCurrent] = useState<
15
- { src?: string; res?: `${number}x${number}` | "placeholder" } | undefined
16
- >(undefined);
17
-
18
- useEffect(() => {
19
- let lastHighestRes: string | undefined;
20
- if (!image) return;
21
- const unsub = image.subscribe({}, (update) => {
22
- const highestRes = ImageDefinition.highestResAvailable(update, {
23
- maxWidth,
24
- targetWidth,
25
- });
26
- if (highestRes && highestRes.res !== lastHighestRes) {
27
- lastHighestRes = highestRes.res;
28
- // use the base64 data directly
29
- const dataUrl = highestRes.stream.asBase64({ dataURL: true });
30
- if (dataUrl) {
31
- setCurrent({
32
- src: dataUrl,
33
- res: highestRes.res,
34
- });
35
- } else {
36
- // Fallback to placeholder if chunks aren't available
37
- console.warn("No chunks available for image", image.id);
38
- setCurrent({
39
- src: update?.placeholderDataURL,
40
- res: "placeholder",
41
- });
42
- }
43
- } else if (!highestRes) {
44
- setCurrent({
45
- src: update?.placeholderDataURL,
46
- res: "placeholder",
47
- });
48
- }
49
- });
50
-
51
- return unsub;
52
- }, [image?.id, maxWidth]);
53
-
54
- return {
55
- src: current?.src,
56
- res: current?.res,
57
- originalSize: image?.originalSize,
58
- };
59
- }
60
-
61
- /** @category Media */
62
- export function ProgressiveImgNative({
63
- children,
64
- image,
65
- maxWidth,
66
- targetWidth,
67
- }: {
68
- children: (result: {
69
- src: string | undefined;
70
- res: `${number}x${number}` | "placeholder" | undefined;
71
- originalSize: readonly [number, number] | undefined;
72
- }) => React.ReactNode;
73
- image: Loaded<typeof ImageDefinition> | null | undefined;
74
- maxWidth?: number;
75
- targetWidth?: number;
76
- }) {
77
- const result = useProgressiveImgNative({ image, maxWidth, targetWidth });
78
- return result && children(result);
79
- }