@zappie/foundations 0.1.8 → 0.1.9

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @zappie/foundations
2
2
 
3
+ ## 0.1.9
4
+
5
+ ### Patch Changes
6
+
7
+ - c1ffb88: Images resize only from `RESIZE_HOSTS` (or your `resizeHosts`), never as `.avif`, `.jxl` or `.svg`. `Image` falls back once to the original when a resized image fails.
8
+ - Updated dependencies [c1ffb88]
9
+ - @zappie/sdk@0.1.22
10
+
3
11
  ## 0.1.8
4
12
 
5
13
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -686,9 +686,11 @@ type ImageProps = Omit<ImgHTMLAttributes<HTMLImageElement>, "src" | "srcSet"> &
686
686
  priority?: boolean;
687
687
  quality?: number;
688
688
  mode?: "resize" | "direct";
689
+ /** Lowercase hosts your zone resizes. Defaults to `RESIZE_HOSTS` from `@zappie/sdk/template`. */
690
+ resizeHosts?: readonly string[];
689
691
  };
690
- /** Render an image through same-origin resizing, or directly when unavailable. */
691
- declare function Image({ src, sizes, priority, quality, mode, alt, ...props }: ImageProps): react.JSX.Element;
692
+ /** Render an image through same-origin resizing, falling back once to `src` if that fails. */
693
+ declare function Image({ src, sizes, priority, quality, mode, resizeHosts, alt, onError, ...props }: ImageProps): react.JSX.Element;
692
694
 
693
695
  /**
694
696
  * Render formatted SDK money in a data element, with the minor-unit amount as its value.
@@ -1,5 +1,6 @@
1
1
  // src/media/image.tsx
2
- import { resized, srcSet } from "@zappie/sdk/template";
2
+ import { canResize, resized, srcSet } from "@zappie/sdk/template";
3
+ import { useCallback, useState } from "react";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  function Image({
5
6
  src,
@@ -7,20 +8,38 @@ function Image({
7
8
  priority = false,
8
9
  quality,
9
10
  mode = "resize",
11
+ resizeHosts,
10
12
  alt,
13
+ onError,
11
14
  ...props
12
15
  }) {
13
- const responsive = mode === "resize" && /^https?:\/\//.test(src);
16
+ const [failed, setFailed] = useState(null);
17
+ const responsive = mode === "resize" && failed !== src && canResize(src, resizeHosts);
18
+ const checkLoaded = useCallback(
19
+ (image) => {
20
+ if (responsive && image?.complete && image.naturalWidth === 0) {
21
+ setFailed(src);
22
+ }
23
+ },
24
+ [responsive, src]
25
+ );
14
26
  return /* @__PURE__ */ jsx(
15
27
  "img",
16
28
  {
17
29
  ...props,
30
+ ref: checkLoaded,
18
31
  alt,
19
- src: responsive ? resized(src, 960, quality) : src,
20
- ...responsive ? { srcSet: srcSet(src, quality), sizes } : {},
32
+ src: responsive ? resized(src, 960, quality, resizeHosts) : src,
33
+ ...responsive ? { srcSet: srcSet(src, quality, resizeHosts), sizes } : {},
21
34
  loading: priority ? "eager" : "lazy",
22
35
  decoding: priority ? "sync" : "async",
23
- ...priority ? { fetchPriority: "high" } : {}
36
+ ...priority ? { fetchPriority: "high" } : {},
37
+ onError: (event) => {
38
+ if (responsive) {
39
+ setFailed(src);
40
+ }
41
+ onError?.(event);
42
+ }
24
43
  }
25
44
  );
26
45
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/media/image.tsx"],
4
- "sourcesContent": ["import { resized, srcSet } from \"@zappie/sdk/template\";\nimport type { ImgHTMLAttributes } from \"react\";\n\n/** Props for a responsive storefront image. */\nexport type ImageProps = Omit<\n ImgHTMLAttributes<HTMLImageElement>,\n \"src\" | \"srcSet\"\n> & {\n src: string;\n alt: string;\n sizes?: string;\n priority?: boolean;\n quality?: number;\n mode?: \"resize\" | \"direct\";\n};\n\n/** Render an image through same-origin resizing, or directly when unavailable. */\nexport function Image({\n src,\n sizes = \"100vw\",\n priority = false,\n quality,\n mode = \"resize\",\n alt,\n ...props\n}: ImageProps) {\n const responsive = mode === \"resize\" && /^https?:\\/\\//.test(src);\n return (\n <img\n {...props}\n alt={alt}\n src={responsive ? resized(src, 960, quality) : src}\n {...(responsive ? { srcSet: srcSet(src, quality), sizes } : {})}\n loading={priority ? \"eager\" : \"lazy\"}\n decoding={priority ? \"sync\" : \"async\"}\n {...(priority ? { fetchPriority: \"high\" as const } : {})}\n />\n );\n}\n"],
5
- "mappings": ";AAAA,SAAS,SAAS,cAAc;AA4B5B;AAXG,SAAS,MAAM;AAAA,EACpB;AAAA,EACA,QAAQ;AAAA,EACR,WAAW;AAAA,EACX;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA,GAAG;AACL,GAAe;AACb,QAAM,aAAa,SAAS,YAAY,eAAe,KAAK,GAAG;AAC/D,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,KAAK,aAAa,QAAQ,KAAK,KAAK,OAAO,IAAI;AAAA,MAC9C,GAAI,aAAa,EAAE,QAAQ,OAAO,KAAK,OAAO,GAAG,MAAM,IAAI,CAAC;AAAA,MAC7D,SAAS,WAAW,UAAU;AAAA,MAC9B,UAAU,WAAW,SAAS;AAAA,MAC7B,GAAI,WAAW,EAAE,eAAe,OAAgB,IAAI,CAAC;AAAA;AAAA,EACxD;AAEJ;",
4
+ "sourcesContent": ["import { canResize, resized, srcSet } from \"@zappie/sdk/template\";\nimport { useCallback, useState, type ImgHTMLAttributes } from \"react\";\n\n/** Props for a responsive storefront image. */\nexport type ImageProps = Omit<\n ImgHTMLAttributes<HTMLImageElement>,\n \"src\" | \"srcSet\"\n> & {\n src: string;\n alt: string;\n sizes?: string;\n priority?: boolean;\n quality?: number;\n mode?: \"resize\" | \"direct\";\n /** Lowercase hosts your zone resizes. Defaults to `RESIZE_HOSTS` from `@zappie/sdk/template`. */\n resizeHosts?: readonly string[];\n};\n\n/** Render an image through same-origin resizing, falling back once to `src` if that fails. */\nexport function Image({\n src,\n sizes = \"100vw\",\n priority = false,\n quality,\n mode = \"resize\",\n resizeHosts,\n alt,\n onError,\n ...props\n}: ImageProps) {\n const [failed, setFailed] = useState<string | null>(null);\n const responsive =\n mode === \"resize\" && failed !== src && canResize(src, resizeHosts);\n // Catches an error that fired before hydration.\n const checkLoaded = useCallback(\n (image: HTMLImageElement | null) => {\n if (responsive && image?.complete && image.naturalWidth === 0) {\n setFailed(src);\n }\n },\n [responsive, src],\n );\n return (\n <img\n {...props}\n ref={checkLoaded}\n alt={alt}\n src={responsive ? resized(src, 960, quality, resizeHosts) : src}\n {...(responsive\n ? { srcSet: srcSet(src, quality, resizeHosts), sizes }\n : {})}\n loading={priority ? \"eager\" : \"lazy\"}\n decoding={priority ? \"sync\" : \"async\"}\n {...(priority ? { fetchPriority: \"high\" as const } : {})}\n onError={(event) => {\n if (responsive) {\n setFailed(src);\n }\n onError?.(event);\n }}\n />\n );\n}\n"],
5
+ "mappings": ";AAAA,SAAS,WAAW,SAAS,cAAc;AAC3C,SAAS,aAAa,gBAAwC;AA0C1D;AAxBG,SAAS,MAAM;AAAA,EACpB;AAAA,EACA,QAAQ;AAAA,EACR,WAAW;AAAA,EACX;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAe;AACb,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAwB,IAAI;AACxD,QAAM,aACJ,SAAS,YAAY,WAAW,OAAO,UAAU,KAAK,WAAW;AAEnE,QAAM,cAAc;AAAA,IAClB,CAAC,UAAmC;AAClC,UAAI,cAAc,OAAO,YAAY,MAAM,iBAAiB,GAAG;AAC7D,kBAAU,GAAG;AAAA,MACf;AAAA,IACF;AAAA,IACA,CAAC,YAAY,GAAG;AAAA,EAClB;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,KAAK;AAAA,MACL;AAAA,MACA,KAAK,aAAa,QAAQ,KAAK,KAAK,SAAS,WAAW,IAAI;AAAA,MAC3D,GAAI,aACD,EAAE,QAAQ,OAAO,KAAK,SAAS,WAAW,GAAG,MAAM,IACnD,CAAC;AAAA,MACL,SAAS,WAAW,UAAU;AAAA,MAC9B,UAAU,WAAW,SAAS;AAAA,MAC7B,GAAI,WAAW,EAAE,eAAe,OAAgB,IAAI,CAAC;AAAA,MACtD,SAAS,CAAC,UAAU;AAClB,YAAI,YAAY;AACd,oBAAU,GAAG;AAAA,QACf;AACA,kBAAU,KAAK;AAAA,MACjB;AAAA;AAAA,EACF;AAEJ;",
6
6
  "names": []
7
7
  }
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var PACKAGE_VERSION = true ? "0.1.8" : "0.0.0-development";
2
+ var PACKAGE_VERSION = true ? "0.1.9" : "0.0.0-development";
3
3
  export {
4
4
  PACKAGE_VERSION
5
5
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zappie/foundations",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "UI-less React primitives for Zappie storefronts: behaviour, state and accessibility without styles.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -33,7 +33,7 @@
33
33
  "dependencies": {
34
34
  "@base-ui/react": "^1.9.0",
35
35
  "@googlemaps/markerclusterer": "^2.6.2",
36
- "@zappie/sdk": "^0.1.13"
36
+ "@zappie/sdk": "^0.1.22"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "react": "^18.2.0 || ^19.0.0",