visionary-image 1.0.4 → 1.1.0-pre.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.
package/README.md CHANGED
@@ -9,7 +9,7 @@ React image component with built-in Blurhash placeholders for better UX and Core
9
9
  - **Easy Blurhash:** Get started with Blurhash in 60 seconds.
10
10
  - **Layout stability**: Eliminates Cumulative Layout Shift (CLS) with true-to-size, responsive placeholders.
11
11
  - **Automatic lazy loading**: Off-screen images are deferred, reducing initial pageload size and optimizing Interaction to Next Paint (INP).
12
- - **Lighning-fast previews**: Renders placeholders early (by initial DOM layout) using URL-embedded Blurhash data, powered by [`visionary-url`](https://github.com/visionary-ux/visionary-url).
12
+ - **Lighning-fast previews**: Renders placeholders early (by initial DOM layout) using URL-embedded Blurhash data, powered by [`blurhash-url`](https://github.com/visionary-ux/blurhash-url).
13
13
  - **Framework tested**: Compatible with Remix, Next.js, and Vite and supports both client and server-side rendering (SSR, SSG).
14
14
  - **Additional features**: Prevent image dragging; prevent user selecting image
15
15
  - **Developer friendly**: Written in Typescript and [unit tested](./src/components/Image/__test__/).
@@ -32,45 +32,46 @@ npm install --save visionary-image
32
32
 
33
33
  ## Usage
34
34
 
35
- Begin by creating a Visionary image URL. This is then passed to the `src` prop of the Image component.
35
+ Begin by creating a Blurhash URL. This is then passed to the `src` prop of the Image component.
36
36
 
37
- ### Creating a Visionary Image URL
37
+ ### Creating a Blurhash URL
38
38
 
39
- There are several ways to create a Visionary URL.
39
+ There are several ways to create a Blurhash URL.
40
40
 
41
- 1. Use the [Visionary URL Maker](https://visionary.cloud/url-maker) for public image URLs
41
+ 1. Use the [Blurhash URL Maker](https://visionary.cloud/url-maker) for public image URLs
42
42
  2. Use the [Drag & Drop Blurhash Generator](https://visionary.cloud/image-to-blurhash) for local image files
43
- 3. Use [visionary-url](https://github.com/visionary-ux/visionary-url) to programmatically generate a URL
43
+ 3. Use [blurhash-url](https://github.com/visionary-ux/blurhash-url) to programmatically generate a URL
44
44
 
45
45
  ### Render Image
46
46
 
47
47
  ```tsx
48
48
  import { Image } from "visionary-image";
49
49
 
50
- const ImageDetails = () => <Image alt="..." src="<Visionary URL>" />;
50
+ const ImageDetails = () => <Image alt="..." src="<Blurhash URL>" />;
51
51
  ```
52
52
 
53
53
  ## Component Props
54
54
 
55
- | Name | Description |
56
- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
57
- | `alt` <br/> string | Image `alt` tag. Adding alt text to images is highly recommended to accommodate accessible devices and improve discoverability. |
58
- | `bgColorAlpha` <br/> number | Base layer (background color) alpha channel.<br /> Default: `0.7` |
59
- | `className` <br/> string | Classname applied to the container `div` or the fallback `img` element. |
60
- | `debug` <br/> boolean | Prints handy debug info to the console (Visionary URL data, render times). |
61
- | `disableBlurLayer` <br/> boolean | Disables rendering of the blur (canvas) layer. |
62
- | `disableImageLayer` <br/> boolean | Disables rendering of the image layer. |
63
- | `height` <br/>number, string | If set, will override internally computed image height. By default, Visionary renders optimally sized images, using the aspect-ratio and max-width placeholder data. |
64
- | `hideImageLayer` <br/> boolean | Hides the image layer, revealing the blur layer underneath. |
65
- | `lazy` <br/> boolean | Should image load lazily. <br/> Default: `true` |
66
- | `onClick` <br/> function | Callback function to invoke when the image is clicked. function. |
67
- | `onError` <br/> function | Error callback function. |
68
- | `onLoad` <br/> function | Image loaded callback function. |
69
- | `preventDrag` <br/>boolean | Prevents user from dragging the image element. |
70
- | `preventSelection` <br/>boolean | Prevents user from highlighting the image element. |
71
- | `punch` <br/>number | Blurhash punch parameter.<br /> Default: `1` |
72
- | `src` <br/>string | Visionary URL, Visionary Code, or ordinary image URL.<br/> If `src` contains Visionary data, placeholders will be rendered, otherwise falls back to an `img` element. <br/> **required** |
73
- | `width` <br/>number, string | If set, will override internally computed image width. By default, Visionary renders optimally sized images, using the aspect-ratio and max-width placeholder data. |
55
+ | Name | Description |
56
+ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
57
+ | `alt` <br/> string | Image `alt` tag. Adding alt text to images is highly recommended to accommodate accessible devices and improve discoverability. |
58
+ | `bgColorAlpha` <br/> number | Base layer (background color) alpha channel.<br /> Default: `0.7` |
59
+ | `className` <br/> string | Classname applied to the container `div` or the fallback `img` element. |
60
+ | `debug` <br/> boolean | Prints handy debug info to the console (Blurhash URL data, render times). |
61
+ | `disableBlurLayer` <br/> boolean | Disables rendering of the blur (canvas) layer. |
62
+ | `disableImageLayer` <br/> boolean | Disables rendering of the image layer. |
63
+ | `height` <br/>number, string | If set, will override internally computed image height. By default, Visionary renders optimally sized images, using the aspect-ratio and max-width placeholder data. |
64
+ | `hideImageLayer` <br/> boolean | Hides the image layer, revealing the blur layer underneath. |
65
+ | `lazy` <br/> boolean | Should image load lazily. <br/> Default: `true` |
66
+ | `onClick` <br/> function | Callback function to invoke when the image is clicked. function. |
67
+ | `onError` <br/> function | Error callback function. |
68
+ | `onLoad` <br/> function | Image loaded callback function. |
69
+ | `preventDrag` <br/>boolean | Prevents user from dragging the image element. |
70
+ | `preventSelection` <br/>boolean | Prevents user from highlighting the image element. |
71
+ | `priority` <br/>boolean | Mark as priority image (above-the-fold). Sets `fetchpriority="high"` and `loading="eager"`. Use for LCP images.<br /> Default: `false` |
72
+ | `punch` <br/>number | Blurhash punch parameter.<br /> Default: `1` |
73
+ | `src` <br/>string | Blurhash URL, Visionary Code, or ordinary image URL.<br/> If `src` contains Blurhash URL data, placeholders will be rendered, otherwise falls back to an `img` element. <br/> **required** |
74
+ | `width` <br/>number, string | If set, will override internally computed image width. By default, Visionary renders optimally sized images, using the aspect-ratio and max-width placeholder data. |
74
75
 
75
76
  ## Relevant Questions
76
77
 
@@ -85,3 +86,10 @@ Canvas operations are highly efficient in modern browsers. Rendering the 24x24 p
85
86
  ### What is Blurhash and where can I learn more?
86
87
 
87
88
  Blurhash uses Discrete Cosine Transforms to represent a color-accurate image placeholder as a compact string (in 20-30 characters). Check out the official [Blurhash docs](https://github.com/woltapp/blurhash) for more info.
89
+
90
+ ## Related packages
91
+
92
+ | Package | Use for |
93
+ | -------------------------------------------------------------------------- | ------------------------------------------------------------------ |
94
+ | **`visionary-image`** (this package) | React apps (`<Image />`), or the `<visionary-image>` web component |
95
+ | [`visionary-image-js`](https://github.com/visionary-ux/visionary-image-js) | Zero-config `<script>` / CDN, or framework-agnostic SSR HTML |
@@ -0,0 +1,100 @@
1
+ import { c as e, n as t, o as n, s as r } from "./canvas-D7cApRRm.js";
2
+ //#region src/lib/util.ts
3
+ var i = (e, t) => `rgba(${e.r},${e.g},${e.b},${t})`, a = (e) => {
4
+ let t = e.replace(/^#/, "");
5
+ if (t.length !== 3 && t.length !== 6) return null;
6
+ t.length === 3 && (t = `${t[0]}${t[0]}${t[1]}${t[1]}${t[2]}${t[2]}`);
7
+ let n = parseInt(t.slice(0, 2), 16), r = parseInt(t.slice(2, 4), 16);
8
+ return {
9
+ b: parseInt(t.slice(4, 6), 16),
10
+ g: r,
11
+ r: n
12
+ };
13
+ }, o = null;
14
+ function s() {
15
+ return o ||= new IntersectionObserver((e) => {
16
+ e.forEach((e) => {
17
+ if (e.isIntersecting) {
18
+ let t = e.target;
19
+ t.renderBlurhashNow(), o?.unobserve(t);
20
+ }
21
+ });
22
+ }, { rootMargin: "200px" }), o;
23
+ }
24
+ var c = typeof HTMLElement < "u" ? HTMLElement : class {}, l = class extends c {
25
+ canvas = null;
26
+ img = null;
27
+ container = null;
28
+ blurhash = null;
29
+ hasRenderedBlurhash = !1;
30
+ static get observedAttributes() {
31
+ return [
32
+ "src",
33
+ "alt",
34
+ "lazy",
35
+ "priority"
36
+ ];
37
+ }
38
+ connectedCallback() {
39
+ this.render();
40
+ }
41
+ disconnectedCallback() {
42
+ s().unobserve(this);
43
+ }
44
+ attributeChangedCallback() {
45
+ this.container && (this.hasRenderedBlurhash = !1, this.render());
46
+ }
47
+ renderBlurhashNow() {
48
+ this.hasRenderedBlurhash || !this.blurhash || !this.canvas || (this.renderBlurhashToCanvas(this.blurhash), this.hasRenderedBlurhash = !0);
49
+ }
50
+ render() {
51
+ let e = this.getAttribute("src");
52
+ if (!e) return;
53
+ let t = r(e);
54
+ if (!t) {
55
+ this.renderFallbackImage(e);
56
+ return;
57
+ }
58
+ let { fields: o } = t, { blurhash: c, sourceWidth: l, sourceHeight: u, bcc: d } = o, f = this.getAttribute("priority") === "true", p = !f && this.getAttribute("lazy") !== "false";
59
+ this.blurhash = c || null;
60
+ let m = l / u;
61
+ if (this.container = document.createElement("div"), this.container.style.cssText = `
62
+ position: relative;
63
+ width: 100%;
64
+ aspect-ratio: ${m};
65
+ overflow: hidden;
66
+ `, d) {
67
+ let e = a(d);
68
+ e && (this.container.style.backgroundColor = i(e, n));
69
+ }
70
+ c && (this.canvas = document.createElement("canvas"), this.canvas.width = 24, this.canvas.height = 24, this.canvas.style.cssText = "\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n ", this.container.appendChild(this.canvas), p ? s().observe(this) : (this.renderBlurhashToCanvas(c), this.hasRenderedBlurhash = !0)), this.img = document.createElement("img"), this.img.src = e, this.img.alt = this.getAttribute("alt") || "", this.img.loading = p ? "lazy" : "eager", f && (this.img.fetchPriority = "high"), this.img.style.cssText = "\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n ", this.img.onload = () => {
71
+ this.canvas && (this.canvas.style.opacity = "0", this.canvas.style.transition = "opacity 0.3s ease-out");
72
+ }, this.container.appendChild(this.img), this.innerHTML = "", this.appendChild(this.container);
73
+ }
74
+ renderBlurhashToCanvas(n) {
75
+ if (!this.canvas) return;
76
+ let r = this.canvas.getContext("2d");
77
+ if (!r) return;
78
+ let i = t(), a = `${n}:24:1`, o = i.get(a);
79
+ if (!o) try {
80
+ o = e(n, 24, 24, 1), i.set(a, o);
81
+ } catch (e) {
82
+ console.warn("Blurhash decode error:", e);
83
+ return;
84
+ }
85
+ let s = r.createImageData(24, 24);
86
+ s.data.set(o), r.putImageData(s, 0, 0);
87
+ }
88
+ renderFallbackImage(e) {
89
+ this.innerHTML = "";
90
+ let t = document.createElement("img");
91
+ t.src = e, t.alt = this.getAttribute("alt") || "";
92
+ let n = this.getAttribute("priority") === "true";
93
+ t.loading = n || this.getAttribute("lazy") === "false" ? "eager" : "lazy", n && (t.fetchPriority = "high"), t.style.cssText = "width: 100%; height: auto;", this.appendChild(t);
94
+ }
95
+ };
96
+ function u(e = "visionary-image") {
97
+ typeof HTMLElement > "u" || typeof customElements > "u" || customElements.get(e) || customElements.define(e, l);
98
+ }
99
+ //#endregion
100
+ export { u as n, l as t };
@@ -0,0 +1,17 @@
1
+ const e=require("./canvas-CnN_nKut.cjs");var t=(e,t)=>`rgba(${e.r},${e.g},${e.b},${t})`,n=e=>{let t=e.replace(/^#/,``);if(t.length!==3&&t.length!==6)return null;t.length===3&&(t=`${t[0]}${t[0]}${t[1]}${t[1]}${t[2]}${t[2]}`);let n=parseInt(t.slice(0,2),16),r=parseInt(t.slice(2,4),16);return{b:parseInt(t.slice(4,6),16),g:r,r:n}},r=null;function i(){return r||=new IntersectionObserver(e=>{e.forEach(e=>{if(e.isIntersecting){let t=e.target;t.renderBlurhashNow(),r?.unobserve(t)}})},{rootMargin:`200px`}),r}var a=typeof HTMLElement<`u`?HTMLElement:class{},o=class extends a{canvas=null;img=null;container=null;blurhash=null;hasRenderedBlurhash=!1;static get observedAttributes(){return[`src`,`alt`,`lazy`,`priority`]}connectedCallback(){this.render()}disconnectedCallback(){i().unobserve(this)}attributeChangedCallback(){this.container&&(this.hasRenderedBlurhash=!1,this.render())}renderBlurhashNow(){this.hasRenderedBlurhash||!this.blurhash||!this.canvas||(this.renderBlurhashToCanvas(this.blurhash),this.hasRenderedBlurhash=!0)}render(){let r=this.getAttribute(`src`);if(!r)return;let a=e.s(r);if(!a){this.renderFallbackImage(r);return}let{fields:o}=a,{blurhash:s,sourceWidth:c,sourceHeight:l,bcc:u}=o,d=this.getAttribute(`priority`)===`true`,f=!d&&this.getAttribute(`lazy`)!==`false`;this.blurhash=s||null;let p=c/l;if(this.container=document.createElement(`div`),this.container.style.cssText=`
2
+ position: relative;
3
+ width: 100%;
4
+ aspect-ratio: ${p};
5
+ overflow: hidden;
6
+ `,u){let r=n(u);r&&(this.container.style.backgroundColor=t(r,e.o))}s&&(this.canvas=document.createElement(`canvas`),this.canvas.width=24,this.canvas.height=24,this.canvas.style.cssText=`
7
+ position: absolute;
8
+ inset: 0;
9
+ width: 100%;
10
+ height: 100%;
11
+ `,this.container.appendChild(this.canvas),f?i().observe(this):(this.renderBlurhashToCanvas(s),this.hasRenderedBlurhash=!0)),this.img=document.createElement(`img`),this.img.src=r,this.img.alt=this.getAttribute(`alt`)||``,this.img.loading=f?`lazy`:`eager`,d&&(this.img.fetchPriority=`high`),this.img.style.cssText=`
12
+ position: absolute;
13
+ inset: 0;
14
+ width: 100%;
15
+ height: 100%;
16
+ object-fit: cover;
17
+ `,this.img.onload=()=>{this.canvas&&(this.canvas.style.opacity=`0`,this.canvas.style.transition=`opacity 0.3s ease-out`)},this.container.appendChild(this.img),this.innerHTML=``,this.appendChild(this.container)}renderBlurhashToCanvas(t){if(!this.canvas)return;let n=this.canvas.getContext(`2d`);if(!n)return;let r=e.n(),i=`${t}:24:1`,a=r.get(i);if(!a)try{a=e.c(t,24,24,1),r.set(i,a)}catch(e){console.warn(`Blurhash decode error:`,e);return}let o=n.createImageData(24,24);o.data.set(a),n.putImageData(o,0,0)}renderFallbackImage(e){this.innerHTML=``;let t=document.createElement(`img`);t.src=e,t.alt=this.getAttribute(`alt`)||``;let n=this.getAttribute(`priority`)===`true`;t.loading=n||this.getAttribute(`lazy`)===`false`?`eager`:`lazy`,n&&(t.fetchPriority=`high`),t.style.cssText=`width: 100%; height: auto;`,this.appendChild(t)}};function s(e=`visionary-image`){typeof HTMLElement>`u`||typeof customElements>`u`||customElements.get(e)||customElements.define(e,o)}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return o}});
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./canvas-CnN_nKut.cjs");exports.getOrDecodePixels=e.t,exports.getPixelCache=e.n,exports.getRenderedCanvasSet=e.r,exports.initBlurhashCanvases=e.i,exports.initOnDOMLoaded=e.a;
@@ -0,0 +1,50 @@
1
+ /** Get or decode blurhash pixels, using cache when available */
2
+ export declare function getOrDecodePixels(blurhash: string, size: number, punch: number): Uint8ClampedArray | null;
3
+
4
+ /** Returns the global pixel cache */
5
+ export declare function getPixelCache(): Map<string, Uint8ClampedArray>;
6
+
7
+ /** Returns the global set tracking rendered canvas keys */
8
+ export declare function getRenderedCanvasSet(): Set<string>;
9
+
10
+ /**
11
+ * Finds server-rendered canvas elements and renders blurhash to them.
12
+ * Uses IntersectionObserver: above-fold renders immediately, below-fold defers.
13
+ *
14
+ * Exported via `visionary-image/blurhash` for manual control:
15
+ * ```js
16
+ * import { initBlurhashCanvases } from 'visionary-image/blurhash';
17
+ * document.addEventListener('DOMContentLoaded', () => initBlurhashCanvases());
18
+ * ```
19
+ */
20
+ export declare function initBlurhashCanvases(debug?: boolean): void;
21
+
22
+ /**
23
+ * Runs initBlurhashCanvases() at DOMContentLoaded (or immediately if already loaded).
24
+ * Called by the loader entry point (`visionary-image/loader`).
25
+ *
26
+ * Usage:
27
+ * ```js
28
+ * import 'visionary-image/loader';
29
+ * ```
30
+ */
31
+ export declare function initOnDOMLoaded(debug?: boolean): void;
32
+
33
+ export { }
34
+
35
+ /**
36
+ * Blurhash rendering utilities shared across entry points:
37
+ *
38
+ * - `visionary-image` (React component) - uses getRenderedCanvasSet(), getOrDecodePixels()
39
+ * - `visionary-image/loader` (early loader) - calls initOnDOMLoaded()
40
+ * - `visionary-image/blurhash` (manual) - exports initBlurhashCanvases()
41
+ * - `visionary-image/web-component` - uses getPixelCache()
42
+ */
43
+ declare global {
44
+ interface Window {
45
+ /** Set of canvas keys that have been rendered */
46
+ V7Y_CANVAS_RENDERED?: Set<string>;
47
+ /** Cache of decoded blurhash pixels, keyed by "blurhash:size:punch" */
48
+ V7Y_PIXEL_CACHE?: Map<string, Uint8ClampedArray>;
49
+ }
50
+ }
@@ -0,0 +1,50 @@
1
+ /** Get or decode blurhash pixels, using cache when available */
2
+ export declare function getOrDecodePixels(blurhash: string, size: number, punch: number): Uint8ClampedArray | null;
3
+
4
+ /** Returns the global pixel cache */
5
+ export declare function getPixelCache(): Map<string, Uint8ClampedArray>;
6
+
7
+ /** Returns the global set tracking rendered canvas keys */
8
+ export declare function getRenderedCanvasSet(): Set<string>;
9
+
10
+ /**
11
+ * Finds server-rendered canvas elements and renders blurhash to them.
12
+ * Uses IntersectionObserver: above-fold renders immediately, below-fold defers.
13
+ *
14
+ * Exported via `visionary-image/blurhash` for manual control:
15
+ * ```js
16
+ * import { initBlurhashCanvases } from 'visionary-image/blurhash';
17
+ * document.addEventListener('DOMContentLoaded', () => initBlurhashCanvases());
18
+ * ```
19
+ */
20
+ export declare function initBlurhashCanvases(debug?: boolean): void;
21
+
22
+ /**
23
+ * Runs initBlurhashCanvases() at DOMContentLoaded (or immediately if already loaded).
24
+ * Called by the loader entry point (`visionary-image/loader`).
25
+ *
26
+ * Usage:
27
+ * ```js
28
+ * import 'visionary-image/loader';
29
+ * ```
30
+ */
31
+ export declare function initOnDOMLoaded(debug?: boolean): void;
32
+
33
+ export { }
34
+
35
+ /**
36
+ * Blurhash rendering utilities shared across entry points:
37
+ *
38
+ * - `visionary-image` (React component) - uses getRenderedCanvasSet(), getOrDecodePixels()
39
+ * - `visionary-image/loader` (early loader) - calls initOnDOMLoaded()
40
+ * - `visionary-image/blurhash` (manual) - exports initBlurhashCanvases()
41
+ * - `visionary-image/web-component` - uses getPixelCache()
42
+ */
43
+ declare global {
44
+ interface Window {
45
+ /** Set of canvas keys that have been rendered */
46
+ V7Y_CANVAS_RENDERED?: Set<string>;
47
+ /** Cache of decoded blurhash pixels, keyed by "blurhash:size:punch" */
48
+ V7Y_PIXEL_CACHE?: Map<string, Uint8ClampedArray>;
49
+ }
50
+ }
@@ -0,0 +1,2 @@
1
+ import { a as e, i as t, n, r, t as i } from "./canvas-D7cApRRm.js";
2
+ export { i as getOrDecodePixels, n as getPixelCache, r as getRenderedCanvasSet, t as initBlurhashCanvases, e as initOnDOMLoaded };
@@ -0,0 +1 @@
1
+ var e=(e,t,n)=>{let r=0;for(;t<n;)r=r*83+`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~`.indexOf(e[t++]);return r},t=Math.pow,n=Math.PI,r=3294.6,i=269.025,a=e=>e>10.31475?t(e/i+.052132,2.4):e/r,o=e=>~~(e>1227e-8?i*t(e,.416666)-13.025:e*r+1),s=4096,c=new Uint8ClampedArray(4097);for(let e=0;e<=s;e++)c[e]=o(e/s);var l=e=>e<=0?0:e>=1?255:c[e*s+.5|0],u=e=>(e<0?-1:1)*e*e,d=e=>{for(e+=n/2;e>n;)e-=n*2;let t=1.27323954*e-.405284735*u(e);return .225*(u(t)-t)+t};function f(t){let n=e(t,2,6);return[n>>16,n>>8&255,n&255]}function p(t,r,i,o){let s=e(t,0,1),c=s%9+1,p=~~(s/9)+1,m=c*p,h,g,_,v,y,b,x,S,C,w,T,E,D=(e(t,1,2)+1)/13446*(o|1),O=new Float64Array(m*3),k=f(t);for(h=0;h<3;h++)O[h]=a(k[h]);for(h=1;h<m;h++)E=e(t,4+h*2,6+h*2),O[h*3]=u(~~(E/361)-9)*D,O[h*3+1]=u(~~(E/19)%19-9)*D,O[h*3+2]=u(E%19-9)*D;let A=new Float64Array(p*i),j=new Float64Array(c*r);for(g=0;g<p;g++)for(v=0;v<i;v++)A[g*i+v]=d(n*v*g/i);for(h=0;h<c;h++)for(_=0;_<r;_++)j[h*r+_]=d(n*_*h/r);let M=r*4,N=new Uint8ClampedArray(M*i),P=new Float64Array(c*3);for(v=0;v<i;v++){for(h=0;h<c;h++){for(y=b=x=0,g=0;g<p;g++)C=A[g*i+v],w=(h+g*c)*3,y+=O[w]*C,b+=O[w+1]*C,x+=O[w+2]*C;P[h*3]=y,P[h*3+1]=b,P[h*3+2]=x}for(_=0;_<r;_++){for(y=b=x=0,h=0;h<c;h++)S=j[h*r+_],w=h*3,y+=P[w]*S,b+=P[w+1]*S,x+=P[w+2]*S;T=4*_+v*M,N[T]=l(y),N[T+1]=l(b),N[T+2]=l(x),N[T+3]=255}}return N}var m=(e=>(e.AUTO=`auto`,e.AVIF=`avif`,e.JPEG=`jpeg`,e.WEBP=`webp`,e))(m||{}),h=(e=>(e.xs=`xs`,e.sm=`sm`,e.md=`md`,e.lg=`lg`,e.xl=`xl`,e.xxl=`xxl`,e[`4k`]=`4k`,e[`5k`]=`5k`,e.full=`full`,e))(h||{}),g=(e=>(e.DEBUG=`debug`,e.DOWNLOAD=`download`,e.FOLLOW=`follow`,e))(g||{});m.AUTO,h.lg;var _={[h.xs]:160,[h.sm]:320,[h.md]:640,[h.lg]:1280,[h.xl]:1920,[h.xxl]:2560,[h[`4k`]]:3840,[h[`5k`]]:5120,[h.full]:0};Object.keys(_).reduce((e,t)=>{let n=t,r=_[n];return r&&(e[r]=n),e},{});var v=null,y=()=>{if(typeof Buffer<`u`&&typeof Buffer.from==`function`)return`buffer`;if(typeof TextEncoder<`u`&&typeof TextDecoder<`u`&&typeof btoa==`function`&&typeof atob==`function`)return`text-encoding`;throw Error(`No UTF-8 base64 implementation available`)},b=()=>(v===null&&(v=y()),v),x=e=>{let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t},S=e=>{let t=e.length%4;return t===0?e:e+`=`.repeat(4-t)},C=e=>Buffer.from(e,`base64`).toString(`utf8`),w=e=>new TextDecoder().decode(x(atob(S(e)))),T=e=>{switch(b()){case`buffer`:return C(e);case`text-encoding`:return w(e)}},E=e=>{if(typeof e!=`string`)throw Error(`decodeBase64Url: input must be a string`);return T(D(e))},D=e=>e.replace(/-/g,`+`).replace(/_/g,`/`),O=class extends Error{message=`invalid blurhash component dimensions`},k=e=>e===g.DEBUG,A=e=>e===g.DOWNLOAD,j=e=>e===g.FOLLOW,M=e=>Object.values(m).includes(e),N=e=>Object.values(h).includes(e),P=(e=[])=>{let t={};for(let n of e)N(n)?t.size=n:k(n)?t.debug=!0:A(n)?t.download=!0:j(n)?t.follow=!0:M(n)&&(t.format=n);return t},F=e=>e.filter(Boolean),I=(e=``)=>/^[A-Za-z0-9_-]*$/.test(e),L=e=>Number.isInteger(e)&&e>0,R=e=>{if(!e||e.length<6)throw new O;let t=z(e[0]);if(t<0)throw new O;let n=t%9+1,r=Math.floor(t/9)+1,i=4+2*n*r;if(e.length!==i)throw new O;return{xComponents:n,yComponents:r}},z=e=>`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~`.indexOf(e),B=e=>{if(typeof e!=`string`)return null;let t=e.trim();if(!t.length||!I(t))return null;let n=E(t);if(!n)return null;let r=n.split(`!`);if(r.length<3||r.length>6)return null;let[i,a,o,s,c,l]=r,u=i.trim();if(!u.length)return null;let d=Number(a.trim()),f=Number(o.trim());if(!L(d)||!L(f))return null;let p={sourceHeight:f,sourceWidth:d,url:u};if(s&&(p.bcc=s),c){p.blurhash=c;try{let e=R(c);p.blurhashX=e.xComponents,p.blurhashY=e.yComponents}catch{return null}}return l&&(p.altText=l),p},V=e=>{if(I(e)){let t=B(e);if(t)return{fields:t,options:{}}}return H(e)},H=e=>{let t=e?.trim();if(!t)return null;try{let e=U(t);if(!e)return null;let{code:n,optionTokens:r}=e,i=B(n);return i?{fields:i,options:P(r)}:null}catch{}return null},U=e=>{try{let t=F(new URL(e).pathname.split(`/`));if(t[0]!==`image`||![3,4].includes(t.length))throw Error(`Unrecognized URL`);let n=t[1].trim();if(!n.length||!I(n))throw Error(`URL is not formatted as base64url`);return t.length===4?{code:n,optionTokens:t[2].split(`,`)}:{code:n,optionTokens:[]}}catch{return null}return null},W=.7;h.lg,process.env.NODE_ENV;function G(){return typeof window>`u`?new Set:(window.V7Y_CANVAS_RENDERED||(window.V7Y_CANVAS_RENDERED=new Set),window.V7Y_CANVAS_RENDERED)}function K(){return typeof window>`u`?new Map:(window.V7Y_PIXEL_CACHE||(window.V7Y_PIXEL_CACHE=new Map),window.V7Y_PIXEL_CACHE)}function q(e,t,n){return`${e}:${t}:${n}`}function J(e,t,n){let r=q(e,t,n),i=K(),a=i.get(r);if(a)return a;try{let a=p(e,t,t,n);return i.set(r,a),a}catch(e){return console.warn(`Blurhash decode error:`,e),null}}var Y=null,X=!1;function Z(){return Y||=new IntersectionObserver(e=>{e.forEach(e=>{if(e.isIntersecting){let t=e.target;Q(t,X),Y?.unobserve(t)}})},{rootMargin:`200px`}),Y}function Q(e,t){let n=e.dataset.v7yKey;if(!n)return;let r=G();if(r.has(n)){t&&console.log(`[visionary-loader] Canvas already rendered, skipping`);return}let i=e.parentElement?.querySelector(`img`);if(!i?.src){t&&console.log(`[visionary-loader] Canvas has no sibling img, skipping`);return}let a=V(i.src);if(!a?.fields?.blurhash){t&&console.log(`[visionary-loader] Sibling img is not a Blurhash URL, skipping`);return}let{blurhash:o}=a.fields;t&&console.log(`[visionary-loader] Rendering canvas:`,{blurhash:o.slice(0,20)+`...`,punch:1,size:24});let s=J(o,24,1);if(!s)return;let c=e.getContext(`2d`);if(!c)return;let l=c.createImageData(24,24);l.data.set(s),c.putImageData(l,0,0),r.add(n),t&&console.log(`[visionary-loader] Canvas rendered at ${performance.now().toFixed(1)}ms`)}function $(e=!1){X=e;let t=document.querySelectorAll(`canvas[data-v7y-key]`);e&&console.log(`[visionary-loader] Found ${t.length} canvas(es) with data-v7y-key`);let n=Z();t.forEach(e=>{n.observe(e)})}function ee(e=!1){if(typeof document>`u`)return;let t=()=>{e&&console.log(`[visionary-loader] initOnDOMLoaded running at ${performance.now().toFixed(1)}ms, readyState: ${document.readyState}`),$(e)};document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,t):t()}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return ee}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return $}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return W}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return G}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return V}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return J}});
@@ -0,0 +1,245 @@
1
+ //#region node_modules/.pnpm/fast-blurhash@1.2.0/node_modules/fast-blurhash/index.js
2
+ var e = (e, t, n) => {
3
+ let r = 0;
4
+ for (; t < n;) r = r * 83 + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~".indexOf(e[t++]);
5
+ return r;
6
+ }, t = Math.pow, n = Math.PI, r = 3294.6, i = 269.025, a = (e) => e > 10.31475 ? t(e / i + .052132, 2.4) : e / r, o = (e) => ~~(e > 1227e-8 ? i * t(e, .416666) - 13.025 : e * r + 1), s = 4096, c = /* @__PURE__ */ new Uint8ClampedArray(4097);
7
+ for (let e = 0; e <= s; e++) c[e] = o(e / s);
8
+ var l = (e) => e <= 0 ? 0 : e >= 1 ? 255 : c[e * s + .5 | 0], u = (e) => (e < 0 ? -1 : 1) * e * e, d = (e) => {
9
+ for (e += n / 2; e > n;) e -= n * 2;
10
+ let t = 1.27323954 * e - .405284735 * u(e);
11
+ return .225 * (u(t) - t) + t;
12
+ };
13
+ function f(t) {
14
+ let n = e(t, 2, 6);
15
+ return [
16
+ n >> 16,
17
+ n >> 8 & 255,
18
+ n & 255
19
+ ];
20
+ }
21
+ function p(t, r, i, o) {
22
+ let s = e(t, 0, 1), c = s % 9 + 1, p = ~~(s / 9) + 1, m = c * p, h, g, _, v, y, b, x, S, C, w, T, E, D = (e(t, 1, 2) + 1) / 13446 * (o | 1), O = new Float64Array(m * 3), k = f(t);
23
+ for (h = 0; h < 3; h++) O[h] = a(k[h]);
24
+ for (h = 1; h < m; h++) E = e(t, 4 + h * 2, 6 + h * 2), O[h * 3] = u(~~(E / 361) - 9) * D, O[h * 3 + 1] = u(~~(E / 19) % 19 - 9) * D, O[h * 3 + 2] = u(E % 19 - 9) * D;
25
+ let A = new Float64Array(p * i), j = new Float64Array(c * r);
26
+ for (g = 0; g < p; g++) for (v = 0; v < i; v++) A[g * i + v] = d(n * v * g / i);
27
+ for (h = 0; h < c; h++) for (_ = 0; _ < r; _++) j[h * r + _] = d(n * _ * h / r);
28
+ let M = r * 4, N = new Uint8ClampedArray(M * i), P = new Float64Array(c * 3);
29
+ for (v = 0; v < i; v++) {
30
+ for (h = 0; h < c; h++) {
31
+ for (y = b = x = 0, g = 0; g < p; g++) C = A[g * i + v], w = (h + g * c) * 3, y += O[w] * C, b += O[w + 1] * C, x += O[w + 2] * C;
32
+ P[h * 3] = y, P[h * 3 + 1] = b, P[h * 3 + 2] = x;
33
+ }
34
+ for (_ = 0; _ < r; _++) {
35
+ for (y = b = x = 0, h = 0; h < c; h++) S = j[h * r + _], w = h * 3, y += P[w] * S, b += P[w + 1] * S, x += P[w + 2] * S;
36
+ T = 4 * _ + v * M, N[T] = l(y), N[T + 1] = l(b), N[T + 2] = l(x), N[T + 3] = 255;
37
+ }
38
+ }
39
+ return N;
40
+ }
41
+ //#endregion
42
+ //#region node_modules/.pnpm/blurhash-url@1.4.0/node_modules/blurhash-url/dist/constants.js
43
+ var m = /* @__PURE__ */ ((e) => (e.AUTO = "auto", e.AVIF = "avif", e.JPEG = "jpeg", e.WEBP = "webp", e))(m || {}), h = /* @__PURE__ */ ((e) => (e.xs = "xs", e.sm = "sm", e.md = "md", e.lg = "lg", e.xl = "xl", e.xxl = "xxl", e["4k"] = "4k", e["5k"] = "5k", e.full = "full", e))(h || {}), g = /* @__PURE__ */ ((e) => (e.DEBUG = "debug", e.DOWNLOAD = "download", e.FOLLOW = "follow", e))(g || {});
44
+ m.AUTO, h.lg;
45
+ var _ = {
46
+ [h.xs]: 160,
47
+ [h.sm]: 320,
48
+ [h.md]: 640,
49
+ [h.lg]: 1280,
50
+ [h.xl]: 1920,
51
+ [h.xxl]: 2560,
52
+ [h["4k"]]: 3840,
53
+ [h["5k"]]: 5120,
54
+ [h.full]: 0
55
+ };
56
+ Object.keys(_).reduce((e, t) => {
57
+ let n = t, r = _[n];
58
+ return r && (e[r] = n), e;
59
+ }, {});
60
+ //#endregion
61
+ //#region node_modules/.pnpm/visionary-base64url@0.1.4/node_modules/visionary-base64url/dist/index.js
62
+ var v = null, y = () => {
63
+ if (typeof Buffer < "u" && typeof Buffer.from == "function") return "buffer";
64
+ if (typeof TextEncoder < "u" && typeof TextDecoder < "u" && typeof btoa == "function" && typeof atob == "function") return "text-encoding";
65
+ throw Error("No UTF-8 base64 implementation available");
66
+ }, b = () => (v === null && (v = y()), v), x = (e) => {
67
+ let t = new Uint8Array(e.length);
68
+ for (let n = 0; n < e.length; n++) t[n] = e.charCodeAt(n);
69
+ return t;
70
+ }, S = (e) => {
71
+ let t = e.length % 4;
72
+ return t === 0 ? e : e + "=".repeat(4 - t);
73
+ }, C = (e) => Buffer.from(e, "base64").toString("utf8"), w = (e) => new TextDecoder().decode(x(atob(S(e)))), T = (e) => {
74
+ switch (b()) {
75
+ case "buffer": return C(e);
76
+ case "text-encoding": return w(e);
77
+ }
78
+ }, E = (e) => {
79
+ if (typeof e != "string") throw Error("decodeBase64Url: input must be a string");
80
+ return T(D(e));
81
+ }, D = (e) => e.replace(/-/g, "+").replace(/_/g, "/"), O = class extends Error {
82
+ message = "invalid blurhash component dimensions";
83
+ }, k = (e) => e === g.DEBUG, A = (e) => e === g.DOWNLOAD, j = (e) => e === g.FOLLOW, M = (e) => Object.values(m).includes(e), N = (e) => Object.values(h).includes(e), P = (e = []) => {
84
+ let t = {};
85
+ for (let n of e) N(n) ? t.size = n : k(n) ? t.debug = !0 : A(n) ? t.download = !0 : j(n) ? t.follow = !0 : M(n) && (t.format = n);
86
+ return t;
87
+ }, F = (e) => e.filter(Boolean), I = (e = "") => /^[A-Za-z0-9_-]*$/.test(e), L = (e) => Number.isInteger(e) && e > 0, R = (e) => {
88
+ if (!e || e.length < 6) throw new O();
89
+ let t = z(e[0]);
90
+ if (t < 0) throw new O();
91
+ let n = t % 9 + 1, r = Math.floor(t / 9) + 1, i = 4 + 2 * n * r;
92
+ if (e.length !== i) throw new O();
93
+ return {
94
+ xComponents: n,
95
+ yComponents: r
96
+ };
97
+ }, z = (e) => "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~".indexOf(e), B = (e) => {
98
+ if (typeof e != "string") return null;
99
+ let t = e.trim();
100
+ if (!t.length || !I(t)) return null;
101
+ let n = E(t);
102
+ if (!n) return null;
103
+ let r = n.split("!");
104
+ if (r.length < 3 || r.length > 6) return null;
105
+ let [i, a, o, s, c, l] = r, u = i.trim();
106
+ if (!u.length) return null;
107
+ let d = Number(a.trim()), f = Number(o.trim());
108
+ if (!L(d) || !L(f)) return null;
109
+ let p = {
110
+ sourceHeight: f,
111
+ sourceWidth: d,
112
+ url: u
113
+ };
114
+ if (s && (p.bcc = s), c) {
115
+ p.blurhash = c;
116
+ try {
117
+ let e = R(c);
118
+ p.blurhashX = e.xComponents, p.blurhashY = e.yComponents;
119
+ } catch {
120
+ return null;
121
+ }
122
+ }
123
+ return l && (p.altText = l), p;
124
+ }, V = (e) => {
125
+ if (I(e)) {
126
+ let t = B(e);
127
+ if (t) return {
128
+ fields: t,
129
+ options: {}
130
+ };
131
+ }
132
+ return H(e);
133
+ }, H = (e) => {
134
+ let t = e?.trim();
135
+ if (!t) return null;
136
+ try {
137
+ let e = U(t);
138
+ if (!e) return null;
139
+ let { code: n, optionTokens: r } = e, i = B(n);
140
+ return i ? {
141
+ fields: i,
142
+ options: P(r)
143
+ } : null;
144
+ } catch {}
145
+ return null;
146
+ }, U = (e) => {
147
+ try {
148
+ let t = F(new URL(e).pathname.split("/"));
149
+ if (t[0] !== "image" || ![3, 4].includes(t.length)) throw Error("Unrecognized URL");
150
+ let n = t[1].trim();
151
+ if (!n.length || !I(n)) throw Error("URL is not formatted as base64url");
152
+ return t.length === 4 ? {
153
+ code: n,
154
+ optionTokens: t[2].split(",")
155
+ } : {
156
+ code: n,
157
+ optionTokens: []
158
+ };
159
+ } catch {
160
+ return null;
161
+ }
162
+ return null;
163
+ }, W = .7;
164
+ h.lg, process.env.NODE_ENV;
165
+ //#endregion
166
+ //#region src/lib/canvas.ts
167
+ function G() {
168
+ return typeof window > "u" ? /* @__PURE__ */ new Set() : (window.V7Y_CANVAS_RENDERED || (window.V7Y_CANVAS_RENDERED = /* @__PURE__ */ new Set()), window.V7Y_CANVAS_RENDERED);
169
+ }
170
+ function K() {
171
+ return typeof window > "u" ? /* @__PURE__ */ new Map() : (window.V7Y_PIXEL_CACHE || (window.V7Y_PIXEL_CACHE = /* @__PURE__ */ new Map()), window.V7Y_PIXEL_CACHE);
172
+ }
173
+ function q(e, t, n) {
174
+ return `${e}:${t}:${n}`;
175
+ }
176
+ function J(e, t, n) {
177
+ let r = q(e, t, n), i = K(), a = i.get(r);
178
+ if (a) return a;
179
+ try {
180
+ let a = p(e, t, t, n);
181
+ return i.set(r, a), a;
182
+ } catch (e) {
183
+ return console.warn("Blurhash decode error:", e), null;
184
+ }
185
+ }
186
+ var Y = null, X = !1;
187
+ function Z() {
188
+ return Y ||= new IntersectionObserver((e) => {
189
+ e.forEach((e) => {
190
+ if (e.isIntersecting) {
191
+ let t = e.target;
192
+ Q(t, X), Y?.unobserve(t);
193
+ }
194
+ });
195
+ }, { rootMargin: "200px" }), Y;
196
+ }
197
+ function Q(e, t) {
198
+ let n = e.dataset.v7yKey;
199
+ if (!n) return;
200
+ let r = G();
201
+ if (r.has(n)) {
202
+ t && console.log("[visionary-loader] Canvas already rendered, skipping");
203
+ return;
204
+ }
205
+ let i = e.parentElement?.querySelector("img");
206
+ if (!i?.src) {
207
+ t && console.log("[visionary-loader] Canvas has no sibling img, skipping");
208
+ return;
209
+ }
210
+ let a = V(i.src);
211
+ if (!a?.fields?.blurhash) {
212
+ t && console.log("[visionary-loader] Sibling img is not a Blurhash URL, skipping");
213
+ return;
214
+ }
215
+ let { blurhash: o } = a.fields;
216
+ t && console.log("[visionary-loader] Rendering canvas:", {
217
+ blurhash: o.slice(0, 20) + "...",
218
+ punch: 1,
219
+ size: 24
220
+ });
221
+ let s = J(o, 24, 1);
222
+ if (!s) return;
223
+ let c = e.getContext("2d");
224
+ if (!c) return;
225
+ let l = c.createImageData(24, 24);
226
+ l.data.set(s), c.putImageData(l, 0, 0), r.add(n), t && console.log(`[visionary-loader] Canvas rendered at ${performance.now().toFixed(1)}ms`);
227
+ }
228
+ function $(e = !1) {
229
+ X = e;
230
+ let t = document.querySelectorAll("canvas[data-v7y-key]");
231
+ e && console.log(`[visionary-loader] Found ${t.length} canvas(es) with data-v7y-key`);
232
+ let n = Z();
233
+ t.forEach((e) => {
234
+ n.observe(e);
235
+ });
236
+ }
237
+ function ee(e = !1) {
238
+ if (typeof document > "u") return;
239
+ let t = () => {
240
+ e && console.log(`[visionary-loader] initOnDOMLoaded running at ${performance.now().toFixed(1)}ms, readyState: ${document.readyState}`), $(e);
241
+ };
242
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", t) : t();
243
+ }
244
+ //#endregion
245
+ export { ee as a, p as c, $ as i, K as n, W as o, G as r, V as s, J as t };
@@ -1,9 +1,9 @@
1
+ import { BlurhashUrlOptions } from 'blurhash-url';
1
2
  import { CSSProperties } from 'react';
2
- import { ImageSizeToken } from 'visionary-url';
3
- import { JSX as JSX_2 } from 'react/jsx-runtime';
4
- import { VisionaryImageOptions } from 'visionary-url';
3
+ import { ImageSizeToken } from 'blurhash-url/constants';
4
+ import { JSX } from 'react/jsx-runtime';
5
5
 
6
- declare const Image_2: ({ alt: altText, bgColorAlpha, className, debug, disableBlurLayer, disableImageLayer, endpoint, height: userHeight, hideImageLayer, lazy, onClick, onError, onLoad, preventDrag, preventSelection, punch, size, src, style: userStyles, width: userWidth, }: VisionaryImageProps) => JSX_2.Element;
6
+ declare const Image_2: ({ alt: altText, bgColorAlpha, className, debug, disableBlurLayer, disableImageLayer, endpoint, height: userHeight, hideImageLayer, lazy, priority, onClick, onError, onLoad, preventDrag, preventSelection, punch, size, src, style: userStyles, width: userWidth, }: VisionaryImageProps) => JSX.Element;
7
7
  export { Image_2 as Image }
8
8
 
9
9
  export declare interface VisionaryImageProps {
@@ -18,7 +18,7 @@ export declare interface VisionaryImageProps {
18
18
  /** Classname applied to the container `div` or the fallback `img` element. */
19
19
  className?: string;
20
20
  /**
21
- * Print debug info (Visionary data, render times) to the console
21
+ * Print debug info (Blurhash URL data, render times) to the console
22
22
  */
23
23
  debug?: boolean;
24
24
  /**
@@ -29,7 +29,7 @@ export declare interface VisionaryImageProps {
29
29
  * Disable rendering of image layer
30
30
  */
31
31
  disableImageLayer?: boolean;
32
- /** Custom endpoint for image URLs (when using `generateVisionaryUrl()`) */
32
+ /** Custom endpoint for image URLs (when using `generateBlurhashUrl()`) */
33
33
  endpoint?: string;
34
34
  height?: number | string;
35
35
  /**
@@ -52,7 +52,7 @@ export declare interface VisionaryImageProps {
52
52
  * Callback function to run after image load
53
53
  */
54
54
  onLoad?: () => void;
55
- options?: VisionaryImageOptions;
55
+ options?: BlurhashUrlOptions;
56
56
  /**
57
57
  * Prevents user from dragging the image element
58
58
  */
@@ -64,11 +64,16 @@ export declare interface VisionaryImageProps {
64
64
  /**
65
65
  * Blurhash punch parameter (default: 1)
66
66
  */
67
+ /**
68
+ * Mark as priority image (above-the-fold). Sets fetchpriority="high" and loading="eager".
69
+ * Use for LCP images to improve Core Web Vitals.
70
+ */
71
+ priority?: boolean;
67
72
  punch?: number;
68
- /** If specified, overrides the size specified in a Visionary URL */
73
+ /** If specified, overrides the size specified in a Blurhash URL */
69
74
  size?: ImageSizeToken;
70
75
  /**
71
- * Image `src` prop; if `src` contains a Visionary code, a Visionary image will be rendered, otherwise we fall back to a native `<img />` tag
76
+ * Image `src` prop; if `src` contains a Blurhash URL, a Visionary image is rendered, otherwise falls back to a native `<img />` tag
72
77
  */
73
78
  src: string;
74
79
  /** Styles are applied to the Visionary container (or the fallback <img> if a Visionary Image is not rendered) */