visionary-image 1.0.1 → 1.0.3

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
@@ -2,18 +2,25 @@
2
2
 
3
3
  React image component with built-in Blurhash placeholders for better UX and Core Web Vitals.
4
4
 
5
- ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/visionary-ux/visionary-image/.github%2Fworkflows%2Fci-cd-workflow.yml?branch=master&style=flat-square) ![npm package size (minzipped, via Bundlephobia)](https://img.shields.io/bundlephobia/minzip/visionary-image?style=flat-square&color=blue)
5
+ ![GitHub Release](https://img.shields.io/github/v/release/visionary-ux/visionary-image?color=beige) [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/visionary-ux/visionary-image/.github%2Fworkflows%2Fci-cd-workflow.yml?branch=master&style=flat-square)](https://github.com/visionary-ux/visionary-image/actions/workflows/ci-cd-workflow.yml?query=branch%3Amaster) [![npm package size (minzipped, via Bundlephobia)](https://img.shields.io/bundlephobia/minzip/visionary-image?style=flat-square&color=blue)](https://bundlephobia.com/package/visionary-image) [![Storybook demo](https://img.shields.io/badge/-Storybook-FF4785?style=flat-square&logo=storybook&logoColor=white)](https://visionary-ux.github.io/visionary-image/)
6
6
 
7
- **Features:**
7
+ ## Features
8
8
 
9
- - Blurhash data encoded in the image URL via [visionary-url](https://github.com/visionary-ux/visionary-url) for instant image placeholders
10
- - Renders a true-to-size, responsive Blurhash placeholder while the image loads, eliminating Cumulative Layout Shift (CLS)
11
- - Images below the fold are lazily loaded, reducing initial page load size and request count, optimizing Interaction to Next Paint (INP)
12
- - Framework-tested (Remix, Next.js, Vite) with support for both client and server-side rendering (SSR, SSG) environments
13
- - Additional features: Prevent dragging, user-selection of image
14
- - Improves Core Web Vitals scores which Google notes as an important ranking signal in Search.
9
+ - **Easy Blurhash:** Get started with Blurhash in 60 seconds.
10
+ - **Layout stability**: Eliminates Cumulative Layout Shift (CLS) with true-to-size, responsive placeholders.
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).
13
+ - **Framework tested**: Compatible with Remix, Next.js, and Vite and supports both client and server-side rendering (SSR, SSG).
14
+ - **Additional features**: Prevent image dragging; prevent user selecting image
15
+ - **Developer friendly**: Written in Typescript and [unit tested](./src/components/Image/__test__/).
16
+ - Check out the [interactive Storybook sandbox](https://visionary-ux.github.io/visionary-image/)
17
+ - **Search performance**: Enhance search ranking potential by improving Core Web Vitals scores.
18
+ > "We highly recommend site owners achieve good Core Web Vitals for success with Search" — [Google Search Central](https://developers.google.com/search/docs/appearance/core-web-vitals)
15
19
 
16
- > "We highly recommend site owners achieve good Core Web Vitals for success with Search", [Google Search Central](https://developers.google.com/search/docs/appearance/core-web-vitals)
20
+ ### Lighthouse Performance
21
+
22
+ Lighthouse report filmstrip showing three-layer image loading process
23
+ ![Lighthouse report loading stage filmstrip](https://github.com/user-attachments/assets/20fd15ad-6801-4105-b75d-bf12cc8c704e)
17
24
 
18
25
  ## Installation
19
26
 
@@ -25,7 +32,7 @@ npm install --save visionary-image
25
32
 
26
33
  ## Usage
27
34
 
28
- Create a Visionary image URL to get started.
35
+ Begin by creating a Visionary image URL. This is then passed to the `src` prop of the Image component.
29
36
 
30
37
  ### Creating a Visionary Image URL
31
38
 
@@ -40,14 +47,7 @@ There are several ways to create a Visionary URL.
40
47
  ```tsx
41
48
  import { Image } from "visionary-image";
42
49
 
43
- const imageUrl = "<visionary url or code>";
44
- const altText = "Nighttime stroll in Tokyo, neon-lit with a purple glow";
45
-
46
- const App = () => {
47
- <div>
48
- <Image alt={altText} src={imageUrl} />
49
- </div>;
50
- };
50
+ const ImageDetails = () => <Image alt="..." src="<Visionary URL>" />;
51
51
  ```
52
52
 
53
53
  ## Component Props
@@ -60,8 +60,9 @@ const App = () => {
60
60
  | `debug` <br/> boolean | Prints handy debug info to the console (Visionary URL data, render times). |
61
61
  | `disableBlurLayer` <br/> boolean | Disables rendering of the blur (canvas) layer. |
62
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. |
63
64
  | `hideImageLayer` <br/> boolean | Hides the image layer, revealing the blur layer underneath. |
64
- | `lazy` <br/> boolean | Should image lazily load. <br/> Default: `true` |
65
+ | `lazy` <br/> boolean | Should image load lazily. <br/> Default: `true` |
65
66
  | `onClick` <br/> function | Callback function to invoke when the image is clicked. function. |
66
67
  | `onError` <br/> function | Error callback function. |
67
68
  | `onLoad` <br/> function | Image loaded callback function. |
@@ -69,9 +70,18 @@ const App = () => {
69
70
  | `preventSelection` <br/>boolean | Prevents user from highlighting the image element. |
70
71
  | `punch` <br/>number | Blurhash punch parameter.<br /> Default: `1` |
71
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. |
74
+
75
+ ## Relevant Questions
76
+
77
+ ### Do image placeholders render server-side?
78
+
79
+ Yes, Visionary Image supports server-side rendering (SSR) and static site generation (SSG), as well as client-side rendering. In server-rendered scenarios, the first layer (background color) renders immediately, followed by the Blurhash and image layers once the page loads in the client's browser.
80
+
81
+ ### How long does the Blurhash canvas take to load?
82
+
83
+ Canvas operations are highly efficient in modern browsers. Rendering the 24x24 pixel Blurhash placeholder typically takes around 1ms.
72
84
 
73
- ### More Props
85
+ ### What is Blurhash and where can I learn more?
74
86
 
75
- | | |
76
- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
77
- | `height`, `width` | If set, will override internally computed image dimensions. By default, Visionary renders optimally sized images, using the aspect-ratio and max-width placeholder data. |
87
+ 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.
@@ -1,7 +1,7 @@
1
1
  (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.id="v7y-styles",e.appendChild(document.createTextNode('.v7y_7587:before{content:"";display:block;padding-top:var(--v-ar)}.v7y_b8c0{-webkit-user-drag:none;pointer-events:none}.v7y_e0dd{-webkit-user-select:none;user-select:none}')),document.head.appendChild(e)}}catch(n){console.error("vite-plugin-css-injected-by-js",n)}})();
2
- import { jsx as G, jsxs as vt } from "react/jsx-runtime";
3
- import { useRef as Y, useCallback as q, useState as yt, useEffect as wt, useLayoutEffect as It, useMemo as xt } from "react";
4
- function Et(t) {
2
+ import { jsx as T, jsxs as wt } from "react/jsx-runtime";
3
+ import { useRef as Y, useCallback as q, useState as It, useEffect as Et, useLayoutEffect as Rt, useMemo as At } from "react";
4
+ function xt(t) {
5
5
  return t && t.__esModule && Object.prototype.hasOwnProperty.call(t, "default") ? t.default : t;
6
6
  }
7
7
  var et = { exports: {} };
@@ -12,11 +12,11 @@ var et = { exports: {} };
12
12
  */
13
13
  (function(t) {
14
14
  (function() {
15
- var e = {}.hasOwnProperty;
16
- function n() {
15
+ var n = {}.hasOwnProperty;
16
+ function e() {
17
17
  for (var r = "", s = 0; s < arguments.length; s++) {
18
- var a = arguments[s];
19
- a && (r = c(r, o(a)));
18
+ var u = arguments[s];
19
+ u && (r = i(r, o(u)));
20
20
  }
21
21
  return r;
22
22
  }
@@ -26,212 +26,214 @@ var et = { exports: {} };
26
26
  if (typeof r != "object")
27
27
  return "";
28
28
  if (Array.isArray(r))
29
- return n.apply(null, r);
29
+ return e.apply(null, r);
30
30
  if (r.toString !== Object.prototype.toString && !r.toString.toString().includes("[native code]"))
31
31
  return r.toString();
32
32
  var s = "";
33
- for (var a in r)
34
- e.call(r, a) && r[a] && (s = c(s, a));
33
+ for (var u in r)
34
+ n.call(r, u) && r[u] && (s = i(s, u));
35
35
  return s;
36
36
  }
37
- function c(r, s) {
37
+ function i(r, s) {
38
38
  return s ? r ? r + " " + s : r + s : r;
39
39
  }
40
- t.exports ? (n.default = n, t.exports = n) : window.classNames = n;
40
+ t.exports ? (e.default = e, t.exports = e) : window.classNames = e;
41
41
  })();
42
42
  })(et);
43
- var Rt = et.exports;
44
- const At = /* @__PURE__ */ Et(Rt), St = (t, { root: e, rootMargin: n, threshold: o } = {}, c = []) => {
43
+ var Ut = et.exports;
44
+ const Nt = /* @__PURE__ */ xt(Ut), Ot = (t, { root: n, rootMargin: e, threshold: o } = {}, i = []) => {
45
45
  const r = Y(null), s = Y(null);
46
- return q((i) => {
47
- r.current && s.current && (s.current.unobserve(r.current), s.current.disconnect(), s.current = null), i && (s.current = new IntersectionObserver(t, { root: e, rootMargin: n, threshold: o }), s.current.observe(i), r.current = i);
48
- }, [r, e, n, JSON.stringify(o), ...c]);
49
- }, Nt = ({ root: t, rootMargin: e, threshold: n, unobserveOnEnter: o, target: c, onEnter: r, onLeave: s, defaultInView: a } = {}, i = []) => {
50
- const [d, h] = yt({
51
- inView: a || !1,
46
+ return q((c) => {
47
+ r.current && s.current && (s.current.unobserve(r.current), s.current.disconnect(), s.current = null), c && (s.current = new IntersectionObserver(t, { root: n, rootMargin: e, threshold: o }), s.current.observe(c), r.current = c);
48
+ }, [r, n, e, JSON.stringify(o), ...i]);
49
+ }, Tt = ({ root: t, rootMargin: n, threshold: e, unobserveOnEnter: o, target: i, onEnter: r, onLeave: s, defaultInView: u } = {}, c = []) => {
50
+ const [a, p] = It({
51
+ inView: u || !1,
52
52
  entry: null,
53
53
  observer: null
54
- }), f = q(([p], l) => {
55
- const b = l.thresholds.some((g) => p.intersectionRatio >= g) && p.isIntersecting;
56
- h({
54
+ }), l = q(([h], d) => {
55
+ const b = d.thresholds.some((g) => h.intersectionRatio >= g) && h.isIntersecting;
56
+ p({
57
57
  inView: b,
58
- entry: p,
59
- observer: l
60
- }), b && o && (l.unobserve(p.target), l.disconnect()), b ? r == null || r(p, l) : s == null || s(p, l);
61
- }, [r, s, o]), m = St(f, { root: t, rootMargin: e, threshold: n }, [o, ...i]);
62
- return wt(() => {
63
- c != null && c.current && m(c.current);
64
- }, [c, m]), [m, d.inView, d.entry, d.observer];
65
- };
66
- var $ = /* @__PURE__ */ ((t) => (t.AUTO = "auto", t.AVIF = "avif", t.JPEG = "jpeg", t.WEBP = "webp", t))($ || {}), y = /* @__PURE__ */ ((t) => (t.xs = "xs", t.sm = "sm", t.md = "md", t.lg = "lg", t.xl = "xl", t.xxl = "xxl", t["4k"] = "4k", t["5k"] = "5k", t.full = "full", t))(y || {}), P = /* @__PURE__ */ ((t) => (t.DEBUG = "debug", t.DOWNLOAD = "download", t))(P || {});
67
- const Ot = "https://link.visionary.cloud";
68
- $.AUTO, y.lg;
58
+ entry: h,
59
+ observer: d
60
+ }), b && o && (d.unobserve(h.target), d.disconnect()), b ? r == null || r(h, d) : s == null || s(h, d);
61
+ }, [r, s, o]), m = Ot(l, { root: t, rootMargin: n, threshold: e }, [o, ...c]);
62
+ return Et(() => {
63
+ i != null && i.current && m(i.current);
64
+ }, [i, m]), [m, a.inView, a.entry, a.observer];
65
+ }, Ct = {
66
+ overflow: "hidden"
67
+ }, Dt = ({ aspectRatio: t, children: n }) => /* @__PURE__ */ T("div", { style: { aspectRatio: t, ...Ct }, children: n });
68
+ var $ = /* @__PURE__ */ ((t) => (t.AUTO = "auto", t.AVIF = "avif", t.JPEG = "jpeg", t.WEBP = "webp", t))($ || {}), w = /* @__PURE__ */ ((t) => (t.xs = "xs", t.sm = "sm", t.md = "md", t.lg = "lg", t.xl = "xl", t.xxl = "xxl", t["4k"] = "4k", t["5k"] = "5k", t.full = "full", t))(w || {}), D = /* @__PURE__ */ ((t) => (t.DEBUG = "debug", t.DOWNLOAD = "download", t))(D || {});
69
+ const Pt = "https://link.visionary.cloud";
70
+ $.AUTO, w.lg;
69
71
  const Z = {
70
- [y.xs]: 160,
71
- [y.sm]: 320,
72
- [y.md]: 640,
73
- [y.lg]: 1280,
74
- [y.xl]: 1920,
75
- [y.xxl]: 2560,
76
- [y["4k"]]: 3840,
77
- [y["5k"]]: 5120,
78
- [y.full]: 0
72
+ [w.xs]: 160,
73
+ [w.sm]: 320,
74
+ [w.md]: 640,
75
+ [w.lg]: 1280,
76
+ [w.xl]: 1920,
77
+ [w.xxl]: 2560,
78
+ [w["4k"]]: 3840,
79
+ [w["5k"]]: 5120,
80
+ [w.full]: 0
79
81
  };
80
82
  Object.keys(Z).reduce(
81
- (t, e) => {
82
- const n = e, o = Z[n];
83
- return o && (t[o] = n), t;
83
+ (t, n) => {
84
+ const e = n, o = Z[e];
85
+ return o && (t[o] = e), t;
84
86
  },
85
87
  {}
86
88
  );
87
- const nt = "!";
88
- var Ut = Object.defineProperty, Tt = (t, e, n) => e in t ? Ut(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n, Dt = (t, e, n) => Tt(t, typeof e != "symbol" ? e + "" : e, n), J = {}, L = {};
89
- Object.defineProperty(L, "__esModule", { value: !0 });
90
- function Pt(t) {
89
+ const rt = "!";
90
+ var St = Object.defineProperty, _t = (t, n, e) => n in t ? St(t, n, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[n] = e, Lt = (t, n, e) => _t(t, typeof n != "symbol" ? n + "" : n, e), J = {}, j = {};
91
+ Object.defineProperty(j, "__esModule", { value: !0 });
92
+ function Vt(t) {
91
93
  return String.fromCharCode(parseInt(t.slice(1), 16));
92
94
  }
93
- function _t(t) {
94
- return btoa(encodeURIComponent(t).replace(/%[0-9A-F]{2}/g, Pt));
95
+ function $t(t) {
96
+ return btoa(encodeURIComponent(t).replace(/%[0-9A-F]{2}/g, Vt));
95
97
  }
96
- L.encode = _t;
97
- function Ct(t) {
98
+ j.encode = $t;
99
+ function jt(t) {
98
100
  return `%${`00${t.charCodeAt(0).toString(16)}`.slice(-2)}`;
99
101
  }
100
- function Vt(t) {
101
- return decodeURIComponent(Array.from(atob(t), Ct).join(""));
102
+ function kt(t) {
103
+ return decodeURIComponent(Array.from(atob(t), jt).join(""));
102
104
  }
103
- L.decode = Vt;
105
+ j.decode = kt;
104
106
  Object.defineProperty(J, "__esModule", { value: !0 });
105
- const rt = L;
106
- function $t(t) {
107
- return rt.decode(t.replace(/\-/g, "+").replace(/_/g, "/"));
107
+ const ot = j;
108
+ function zt(t) {
109
+ return ot.decode(t.replace(/\-/g, "+").replace(/_/g, "/"));
108
110
  }
109
- var Lt = J.decode = $t;
110
- function jt(t) {
111
- return rt.encode(t).replace(/\//g, "_").replace(/\+/g, "-").replace(/=+$/, "");
111
+ var Bt = J.decode = zt;
112
+ function Mt(t) {
113
+ return ot.encode(t).replace(/\//g, "_").replace(/\+/g, "-").replace(/=+$/, "");
112
114
  }
113
- var kt = J.encode = jt;
114
- const zt = (t) => t.filter(Boolean), K = (t) => {
115
+ var Wt = J.encode = Mt;
116
+ const Gt = (t) => t.filter(Boolean), Q = (t) => {
115
117
  try {
116
118
  return new URL(t);
117
119
  } catch {
118
120
  return null;
119
121
  }
120
- }, j = (t = "") => /^[A-Za-z0-9_-]*$/.test(t), Bt = (t) => {
121
- const { altText: e, bcc: n, blurhash: o, blurhashX: c, blurhashY: r, sourceHeight: s, sourceWidth: a, url: i } = t;
122
- if (!i || !a || !s)
122
+ }, k = (t = "") => /^[A-Za-z0-9_-]*$/.test(t), Ft = (t) => {
123
+ const { altText: n, bcc: e, blurhash: o, blurhashX: i, blurhashY: r, sourceHeight: s, sourceWidth: u, url: c } = t;
124
+ if (!c || !u || !s)
123
125
  return new Error("Cannot construct visionary code: missing required url/width/height");
124
- const d = [i, a, s];
125
- return !n || (d.push(n), !o || !c || !r) || (d.push(o, c, r), e && e.length && d.push(e)), Mt(d);
126
- }, Mt = (t) => kt(t.join(nt)), ot = (t) => {
126
+ const a = [c, u, s];
127
+ return !e || (a.push(e), !o || !i || !r) || (a.push(o, i, r), n && n.length && a.push(n)), Ht(a);
128
+ }, Ht = (t) => Wt(t.join(rt)), st = (t) => {
127
129
  if (typeof t != "string")
128
130
  return null;
129
- const e = t.trim();
130
- if (!e.length || !j(e))
131
+ const n = t.trim();
132
+ if (!n.length || !k(n))
131
133
  return null;
132
- const n = Lt(e);
133
- if (!n)
134
+ const e = Bt(n);
135
+ if (!e)
134
136
  return null;
135
- const o = n.split(nt);
137
+ const o = e.split(rt);
136
138
  if (o.length < 3)
137
139
  return null;
138
- const [c, r, s, a, i, d, h, f] = o, m = c.trim();
140
+ const [i, r, s, u, c, a, p, l] = o, m = i.trim();
139
141
  if (!m.length)
140
142
  return console.error("Cannot parse code, empty file id"), null;
141
- const p = Number(r.trim()), l = Number(s.trim());
142
- if (isNaN(p) || isNaN(l) || !p || !l)
143
+ const h = Number(r.trim()), d = Number(s.trim());
144
+ if (isNaN(h) || isNaN(d) || !h || !d)
143
145
  return console.error("Cannot parse Visionary Code: invalid image dimensions", r, s), null;
144
- const v = Number(d) ?? 0, b = Number(h) ?? 0;
146
+ const v = Number(a) ?? 0, b = Number(p) ?? 0;
145
147
  return v < 1 || b < 1 ? (console.error(
146
148
  "Cannot parse Visionary Code: invalid blurhash x, y component dimensions",
147
149
  v,
148
150
  b
149
151
  ), null) : {
150
- altText: f,
151
- bcc: a,
152
- blurhash: i,
152
+ altText: l,
153
+ bcc: u,
154
+ blurhash: c,
153
155
  blurhashX: v,
154
156
  blurhashY: b,
155
- sourceHeight: l,
156
- sourceWidth: p,
157
+ sourceHeight: d,
158
+ sourceWidth: h,
157
159
  url: m
158
160
  };
159
161
  };
160
- class Gt extends Error {
162
+ class Xt extends Error {
161
163
  constructor() {
162
- super(...arguments), Dt(this, "message", "invalid endpoint URL (does it contain http/https?)");
164
+ super(...arguments), Lt(this, "message", "invalid endpoint URL (does it contain http/https?)");
163
165
  }
164
166
  }
165
- const Wt = (t) => t === P.DEBUG, Ft = (t) => t === P.DOWNLOAD, Ht = (t) => Object.values($).includes(t), st = (t) => Object.values(y).includes(t), Xt = (t = []) => {
166
- const e = {};
167
- for (const n of t)
168
- st(n) ? e.size = y[n] : Wt(n) ? e.debug = !0 : Ft(n) ? e.download = !0 : Ht(n) && (e.format = n);
169
- return e;
170
- }, Yt = (t) => {
167
+ const Yt = (t) => t === D.DEBUG, Zt = (t) => t === D.DOWNLOAD, qt = (t) => Object.values($).includes(t), ct = (t) => Object.values(w).includes(t), Jt = (t = []) => {
168
+ const n = {};
169
+ for (const e of t)
170
+ ct(e) ? n.size = w[e] : Yt(e) ? n.debug = !0 : Zt(e) ? n.download = !0 : qt(e) && (n.format = e);
171
+ return n;
172
+ }, Kt = (t) => {
171
173
  if (!t || typeof t != "object")
172
174
  return null;
173
- const e = [];
174
- return t.debug && e.push(P.DEBUG), t.download && e.push(P.DOWNLOAD), t.format && t.format !== $.AUTO && e.push(t.format), t.size && st(t.size) && e.push(t.size), e.length ? e.sort().join(",") : null;
175
- }, Zt = (t) => {
176
- if (j(t)) {
177
- const e = ot(t);
178
- if (e)
175
+ const n = [];
176
+ return t.debug && n.push(D.DEBUG), t.download && n.push(D.DOWNLOAD), t.format && t.format !== $.AUTO && n.push(t.format), t.size && ct(t.size) && n.push(t.size), n.length ? n.sort().join(",") : null;
177
+ }, Qt = (t) => {
178
+ if (k(t)) {
179
+ const n = st(t);
180
+ if (n)
179
181
  return {
180
- fields: e,
182
+ fields: n,
181
183
  options: {}
182
184
  };
183
185
  }
184
- return qt(t);
185
- }, qt = (t) => {
186
+ return tn(t);
187
+ }, tn = (t) => {
186
188
  if (!t)
187
189
  return null;
188
- const e = t.trim();
189
- if (!e)
190
+ const n = t.trim();
191
+ if (!n)
190
192
  return null;
191
193
  try {
192
- const n = Kt(e);
193
- if (!n)
194
+ const e = en(n);
195
+ if (!e)
194
196
  return null;
195
- const { code: o, optionTokens: c } = n, r = ot(o);
197
+ const { code: o, optionTokens: i } = e, r = st(o);
196
198
  if (!r)
197
199
  return null;
198
- const s = Xt(c);
200
+ const s = Jt(i);
199
201
  return {
200
202
  fields: r,
201
203
  options: s
202
204
  };
203
- } catch (n) {
204
- n instanceof Error ? console.error(`Error parsing URL: ${n.message}`, n) : console.error("uncaught error", n);
205
+ } catch (e) {
206
+ e instanceof Error ? console.error(`Error parsing URL: ${e.message}`, e) : console.error("uncaught error", e);
205
207
  }
206
208
  return null;
207
- }, Jt = (t, e) => {
208
- const n = Bt(t);
209
- if (n instanceof Error)
209
+ }, nn = (t, n) => {
210
+ const e = Ft(t);
211
+ if (e instanceof Error)
210
212
  return null;
211
213
  let o = null;
212
- if (e != null && e.endpoint && (o = K(e == null ? void 0 : e.endpoint), !o))
213
- throw new Gt(
214
+ if (n != null && n.endpoint && (o = Q(n == null ? void 0 : n.endpoint), !o))
215
+ throw new Xt(
214
216
  "Cannot construct URL: bad endpoint. Ensure endpoint starts with http:// or https://"
215
217
  );
216
- o || (o = K(Ot));
217
- const c = [o.origin, "image", n], r = e ? Yt(e) : null;
218
- return r && c.push(r), e != null && e.filename ? c.push(e.filename) : c.push("image.jpg"), c.join("/");
219
- }, Kt = (t) => {
218
+ o || (o = Q(Pt));
219
+ const i = [o.origin, "image", e], r = n ? Kt(n) : null;
220
+ return r && i.push(r), n != null && n.filename ? i.push(n.filename) : i.push("image.jpg"), i.join("/");
221
+ }, en = (t) => {
220
222
  try {
221
- const e = new URL(t), n = zt(e.pathname.split("/"));
222
- if (n[0] !== "image" || ![3, 4].includes(n.length))
223
+ const n = new URL(t), e = Gt(n.pathname.split("/"));
224
+ if (e[0] !== "image" || ![3, 4].includes(e.length))
223
225
  throw new Error("Unrecognized URL");
224
- const o = n[1].trim();
225
- if (!o.length || !j(o))
226
+ const o = e[1].trim();
227
+ if (!o.length || !k(o))
226
228
  throw new Error("URL is not formatted as base64url");
227
- if (n.length === 4) {
228
- const c = n[2].split(",");
229
+ if (e.length === 4) {
230
+ const i = e[2].split(",");
229
231
  return {
230
232
  code: o,
231
- optionTokens: c
233
+ optionTokens: i
232
234
  };
233
235
  }
234
- if (n.length === 3)
236
+ if (e.length === 3)
235
237
  return {
236
238
  code: o,
237
239
  optionTokens: []
@@ -240,39 +242,51 @@ const Wt = (t) => t === P.DEBUG, Ft = (t) => t === P.DOWNLOAD, Ht = (t) => Objec
240
242
  return null;
241
243
  }
242
244
  return null;
243
- }, ct = 0.7, it = 1, N = 24, Qt = y.lg, at = process.env.NODE_ENV, te = at === "development", lt = typeof document > "u", ee = at === "test", ne = lt ? () => {
244
- } : It, re = "<visionary>", S = (t, ...e) => {
245
- !console || typeof console.log != "function" || console.log(`${re} ${t}`, ...e);
246
- }, oe = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~", C = (t, e, n) => {
245
+ }, it = 0.7, at = 1, U = 24, rn = w.lg, lt = process.env.NODE_ENV, on = lt === "development", ut = typeof document > "u", sn = lt === "test", cn = ut ? () => {
246
+ } : Rt, an = "<visionary>", x = (t, ...n) => {
247
+ !console || typeof console.log != "function" || console.log(`${an} ${t}`, ...n);
248
+ }, dt = new Uint8Array(128);
249
+ for (let t = 0; t < 83; t++)
250
+ dt["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~".charCodeAt(
251
+ t
252
+ )] = t;
253
+ const L = (t, n, e) => {
247
254
  let o = 0;
248
- for (; e < n; )
249
- o *= 83, o += oe.indexOf(t[e++]);
255
+ for (; n < e; )
256
+ o *= 83, o += dt[t.charCodeAt(n++)];
250
257
  return o;
251
- }, ut = Math.pow, _ = Math.PI, se = _ * 2, dt = 3294.6, ft = 269.025, ce = (t) => t > 10.31475 ? ut(t / ft + 0.052132, 2.4) : t / dt, W = (t) => ~~(t > 1227e-8 ? ft * ut(t, 0.416666) - 13.025 : t * dt + 1), D = (t) => (t < 0 ? -1 : 1) * t * t, Q = (t) => {
252
- for (t += _ / 2; t > _; )
253
- t -= se;
254
- const e = 1.27323954 * t - 0.405284735 * D(t);
255
- return 0.225 * (D(e) - e) + e;
258
+ }, ft = Math.pow, P = Math.PI, ln = P * 2, pt = 3294.6, ht = 269.025, un = (t) => t > 10.31475 ? ft(t / ht + 0.052132, 2.4) : t / pt, G = (t) => ~~(t > 1227e-8 ? ht * ft(t, 0.416666) - 13.025 : t * pt + 1), C = (t) => (t < 0 ? -1 : 1) * t * t, tt = (t) => {
259
+ for (t += P / 2; t > P; )
260
+ t -= ln;
261
+ const n = 1.27323954 * t - 0.405284735 * C(t);
262
+ return 0.225 * (C(n) - n) + n;
256
263
  };
257
- function ie(t) {
258
- const e = C(t, 2, 6);
259
- return [e >> 16, e >> 8 & 255, e & 255];
264
+ function dn(t) {
265
+ const n = L(t, 2, 6);
266
+ return [n >> 16, n >> 8 & 255, n & 255];
260
267
  }
261
- function ae(t, e, n, o) {
262
- const c = C(t, 0, 1), r = c % 9 + 1, s = ~~(c / 9) + 1, a = r * s;
263
- let i = 0, d = 0, h = 0, f = 0, m = 0, p = 0, l = 0, v = 0, b = 0, g = 0, w = 0, x = 0, u = 0, E = 0;
264
- const O = (C(t, 1, 2) + 1) / 13446 * (o | 1), I = new Float64Array(a * 3), k = ie(t);
265
- for (i = 0; i < 3; i++)
266
- I[i] = ce(k[i]);
267
- for (i = 1; i < a; i++)
268
- E = C(t, 4 + i * 2, 6 + i * 2), I[i * 3] = D(~~(E / (19 * 19)) - 9) * O, I[i * 3 + 1] = D(~~(E / 19) % 19 - 9) * O, I[i * 3 + 2] = D(E % 19 - 9) * O;
269
- const U = e * 4, R = new Uint8ClampedArray(U * n);
270
- for (f = 0; f < n; f++)
271
- for (x = _ * f / n, h = 0; h < e; h++) {
272
- for (m = 0, p = 0, l = 0, u = _ * h / e, d = 0; d < s; d++)
273
- for (b = Q(x * d), i = 0; i < r; i++)
274
- v = Q(u * i) * b, g = (i + d * r) * 3, m += I[g] * v, p += I[g + 1] * v, l += I[g + 2] * v;
275
- w = 4 * h + f * U, R[w] = W(m), R[w + 1] = W(p), R[w + 2] = W(l), R[w + 3] = 255;
268
+ function fn(t, n, e, o) {
269
+ const i = L(t, 0, 1), r = i % 9 + 1, s = ~~(i / 9) + 1, u = r * s;
270
+ let c = 0, a = 0, p = 0, l = 0, m = 0, h = 0, d = 0, v = 0, b = 0, g = 0, y = 0, E = 0;
271
+ const f = (L(t, 1, 2) + 1) / 13446 * (o | 1), I = new Float64Array(u * 3), z = dn(t);
272
+ for (c = 0; c < 3; c++)
273
+ I[c] = un(z[c]);
274
+ for (c = 1; c < u; c++)
275
+ E = L(t, 4 + c * 2, 6 + c * 2), I[c * 3] = C(~~(E / 361) - 9) * f, I[c * 3 + 1] = C(~~(E / 19) % 19 - 9) * f, I[c * 3 + 2] = C(E % 19 - 9) * f;
276
+ const S = new Float64Array(s * e), _ = new Float64Array(r * n);
277
+ for (a = 0; a < s; a++)
278
+ for (l = 0; l < e; l++)
279
+ S[a * e + l] = tt(P * l * a / e);
280
+ for (c = 0; c < r; c++)
281
+ for (p = 0; p < n; p++)
282
+ _[c * n + p] = tt(P * p * c / n);
283
+ const N = n * 4, R = new Uint8ClampedArray(N * e);
284
+ for (l = 0; l < e; l++)
285
+ for (p = 0; p < n; p++) {
286
+ for (m = h = d = 0, a = 0; a < s; a++)
287
+ for (b = S[a * e + l], c = 0; c < r; c++)
288
+ v = _[c * n + p] * b, g = (c + a * r) * 3, m += I[g] * v, h += I[g + 1] * v, d += I[g + 2] * v;
289
+ y = 4 * p + l * N, R[y] = G(m), R[y + 1] = G(h), R[y + 2] = G(d), R[y + 3] = 255;
276
290
  }
277
291
  return R;
278
292
  }
@@ -282,225 +296,225 @@ const V = (t) => {
282
296
  } catch {
283
297
  return null;
284
298
  }
285
- }, le = (t, e) => `rgba(${t.r},${t.g},${t.b},${e})`, F = (t) => te || ee ? {
299
+ }, pn = (t, n) => `rgba(${t.r},${t.g},${t.b},${n})`, F = (t) => on || sn ? {
286
300
  "data-testid": t
287
- } : {}, ue = (t, e) => e ? {
301
+ } : {}, hn = (t, n) => n ? {
288
302
  "data-fileid": t
289
- } : {}, tt = (t, e) => Math.min(t, e), de = (t) => {
290
- let e = t.replace(/^#/, "");
291
- if (e.length !== 3 && e.length !== 6)
303
+ } : {}, nt = (t, n) => Math.min(t, n), mn = (t) => {
304
+ let n = t.replace(/^#/, "");
305
+ if (n.length !== 3 && n.length !== 6)
292
306
  return null;
293
- e.length === 3 && (e = `${e[0]}${e[0]}${e[1]}${e[1]}${e[2]}${e[2]}`);
294
- const n = parseInt(e.slice(0, 2), 16), o = parseInt(e.slice(2, 4), 16);
295
- return { b: parseInt(e.slice(4, 6), 16), g: o, r: n };
296
- }, A = (t, e = 0) => {
297
- const n = Math.pow(10, e);
298
- return Math.round(t * n) / n;
299
- }, fe = (t, e) => {
300
- const n = V(t), o = V(e);
301
- return !n || !o ? t : (o.pathname = n.pathname, o.search = n.search, o.toString());
302
- }, pe = (t, e = {}, n = ct, o = it) => {
307
+ n.length === 3 && (n = `${n[0]}${n[0]}${n[1]}${n[1]}${n[2]}${n[2]}`);
308
+ const e = parseInt(n.slice(0, 2), 16), o = parseInt(n.slice(2, 4), 16);
309
+ return { b: parseInt(n.slice(4, 6), 16), g: o, r: e };
310
+ }, A = (t, n = 0) => {
311
+ const e = Math.pow(10, n);
312
+ return Math.round(t * e) / e;
313
+ }, gn = (t, n) => {
314
+ const e = V(t), o = V(n);
315
+ return !e || !o ? t : (o.pathname = e.pathname, o.search = e.search, o.toString());
316
+ }, bn = (t, n = {}, e = it, o = at) => {
303
317
  if (!t)
304
318
  return null;
305
319
  try {
306
- e.debug && S("input imageSrc:", t);
307
- const c = Zt(t);
308
- if (e.debug && S("Visionary URL data: ", c), !c)
320
+ n.debug && x("input imageSrc:", t);
321
+ const i = Qt(t);
322
+ if (n.debug && x("Visionary URL data: ", i), !i)
309
323
  throw new Error("Could not parse Visionary URL");
310
- const { fields: r, options: s } = c;
324
+ const { fields: r, options: s } = i;
311
325
  if (r.sourceWidth < 1 || r.sourceHeight < 1)
312
326
  throw new Error("Invalid image dimensions");
313
- const a = r.sourceWidth / r.sourceHeight, i = (e == null ? void 0 : e.size) ?? s.size ?? Qt, d = Z[i];
314
- let h = 0, f = 0, m = 0;
315
- if (a >= 1) {
316
- f = h = tt(d, r.sourceWidth);
317
- const g = A(f / a);
318
- m = A(f / g, 6);
327
+ const u = r.sourceWidth / r.sourceHeight, c = (n == null ? void 0 : n.size) ?? s.size ?? rn, a = Z[c];
328
+ let p = 0, l = 0, m = 0;
329
+ if (u >= 1) {
330
+ l = p = nt(a, r.sourceWidth);
331
+ const g = A(l / u);
332
+ m = A(l / g, 6);
319
333
  } else
320
- h = tt(d, r.sourceHeight), f = A(h * a), m = A(f / h, 6);
321
- const p = A(100 / m, 6), l = {
334
+ p = nt(a, r.sourceHeight), l = A(p * u), m = A(l / p, 6);
335
+ const h = A(100 / m, 6), d = {
322
336
  ...r,
323
- arPaddingTop: `${p}%`,
337
+ arPaddingTop: `${h}%`,
324
338
  aspectRatio: m,
325
- maxWidth: f,
339
+ maxWidth: l,
326
340
  src: t
327
341
  }, v = V(r.url);
328
342
  if (v)
329
- l.src = v.toString();
330
- else if (!V(t) && j(r.url)) {
331
- const g = Jt(r, {
332
- endpoint: e.endpoint,
333
- size: i
343
+ d.src = v.toString();
344
+ else if (!V(t) && k(r.url)) {
345
+ const g = nn(r, {
346
+ endpoint: n.endpoint,
347
+ size: c
334
348
  });
335
- g && (l.src = g);
349
+ g && (d.src = g);
336
350
  }
337
- e.endpoint && (l.src = fe(l.src, e.endpoint));
338
- const b = r.bcc ? de(r.bcc) : null;
339
- if (b && (l.backgroundColor = le(b, n)), !lt && r.blurhash && !e.disableBlurLayer) {
340
- const g = performance.now(), w = ae(r.blurhash, N, N, o), x = performance.now() - g;
341
- e.debug && S(`Blurhash decode time: ${A(x, 1)} ms`), w && (l.pixels = w);
351
+ n.endpoint && (d.src = gn(d.src, n.endpoint));
352
+ const b = r.bcc ? mn(r.bcc) : null;
353
+ if (b && (d.backgroundColor = pn(b, e)), !ut && r.blurhash && !n.disableBlurLayer) {
354
+ const g = performance.now(), y = fn(r.blurhash, U, U, o), E = performance.now() - g;
355
+ n.debug && x(`Blurhash decode time: ${A(E, 1)} ms`), y && (d.pixels = y);
342
356
  }
343
- return e.debug && S("Visionary Image state: ", l), l;
357
+ return n.debug && x("Visionary Image state: ", d), d;
344
358
  } catch {
345
359
  return null;
346
360
  }
347
- }, pt = {
361
+ }, mt = {
348
362
  bottom: 0,
349
363
  left: 0,
350
364
  position: "absolute",
351
365
  right: 0,
352
366
  top: 0
353
- }, he = {
354
- ...pt,
367
+ }, vn = {
368
+ ...mt,
355
369
  maxHeight: "100%",
356
370
  maxWidth: "100%"
357
- }, me = {
358
- ...pt,
371
+ }, yn = {
372
+ ...mt,
359
373
  height: "100%",
360
374
  width: "100%"
361
- }, ge = (t) => {
362
- const e = {
363
- ...he
375
+ }, wn = (t) => {
376
+ const n = {
377
+ ...vn
364
378
  };
365
- return t && (e.display = "none"), e;
379
+ return t && (n.display = "none"), n;
366
380
  }, H = {
367
381
  CANVAS: "canvas",
368
382
  CONTAINER: "container",
369
383
  IMAGE: "image"
370
- }, be = "v7y_7587", ve = "v7y_b8c0", ye = "v7y_e0dd", X = {
371
- container: be,
372
- preventDrag: ve,
373
- preventSelection: ye
374
- }, Re = ({
384
+ }, In = "v7y_7587", En = "v7y_b8c0", Rn = "v7y_e0dd", X = {
385
+ container: In,
386
+ preventDrag: En,
387
+ preventSelection: Rn
388
+ }, On = ({
375
389
  alt: t,
376
- bgColorAlpha: e = ct,
377
- className: n,
390
+ bgColorAlpha: n = it,
391
+ className: e,
378
392
  debug: o = !1,
379
- disableBlurLayer: c = !1,
393
+ disableBlurLayer: i = !1,
380
394
  disableImageLayer: r = !1,
381
395
  endpoint: s,
382
- height: a,
383
- hideImageLayer: i = !1,
384
- lazy: d = !0,
385
- onClick: h,
386
- onError: f,
396
+ height: u,
397
+ hideImageLayer: c = !1,
398
+ lazy: a = !0,
399
+ onClick: p,
400
+ onError: l,
387
401
  onLoad: m,
388
- preventDrag: p = !1,
389
- preventSelection: l = !1,
390
- punch: v = it,
402
+ preventDrag: h = !1,
403
+ preventSelection: d = !1,
404
+ punch: v = at,
391
405
  size: b,
392
406
  src: g,
393
- style: w,
394
- width: x
407
+ style: y,
408
+ width: E
395
409
  }) => {
396
- const u = xt(() => pe(g, {
410
+ const f = At(() => bn(g, {
397
411
  debug: o,
398
- disableBlurLayer: c,
412
+ disableBlurLayer: i,
399
413
  endpoint: s,
400
414
  size: b
401
- }, e, v), [e, o, c, s, v, b, g]), E = Y(null), [O, I] = Nt();
402
- ne(
415
+ }, n, v), [n, o, i, s, v, b, g]), I = Y(null), [z, S] = Tt();
416
+ cn(
403
417
  function() {
404
- if (!E.current || !(u != null && u.blurhash))
418
+ if (!I.current || !(f != null && f.blurhash))
405
419
  return;
406
- if (!u.pixels) {
420
+ if (!f.pixels) {
407
421
  console.warn("No pixel data passed in, skipping");
408
422
  return;
409
423
  }
410
- const gt = performance.now(), B = E.current.getContext("2d");
411
- if (!B) {
424
+ const vt = performance.now(), M = I.current.getContext("2d");
425
+ if (!M) {
412
426
  console.warn("Cannot access canvasRenderingContext, skipping");
413
427
  return;
414
428
  }
415
- const M = B.createImageData(N, N);
416
- if (!M) {
429
+ const W = M.createImageData(U, U);
430
+ if (!W) {
417
431
  console.warn("Could not create ImageData on CanvasRenderingContext");
418
432
  return;
419
433
  }
420
- if (M.data.set(u.pixels), B.putImageData(M, 0, 0), o) {
421
- const bt = performance.now() - gt;
422
- S(`Canvas render time: ${A(bt, 1)} ms`);
434
+ if (W.data.set(f.pixels), M.putImageData(W, 0, 0), o) {
435
+ const yt = performance.now() - vt;
436
+ x(`Canvas render time: ${A(yt, 1)} ms`);
423
437
  }
424
438
  },
425
- [u == null ? void 0 : u.blurhash, u == null ? void 0 : u.pixels, o]
439
+ [f == null ? void 0 : f.blurhash, f == null ? void 0 : f.pixels, o]
426
440
  );
427
- const k = q(
428
- (T) => {
429
- o && S("Image load error ", T), f && f();
441
+ const _ = q(
442
+ (O) => {
443
+ o && x("Image load error ", O), l && l();
430
444
  },
431
- [o, f]
432
- ), U = {
445
+ [o, l]
446
+ ), N = {
433
447
  alt: t,
434
- loading: !d || I ? "eager" : "lazy",
448
+ loading: !a || S ? "eager" : "lazy",
435
449
  onLoad: m
436
450
  };
437
- if (!u) {
438
- o && S("Not a Visionary URL, rendering fallback <img />");
439
- const T = {
440
- ...U,
441
- className: n,
442
- height: a,
443
- onClick: h,
444
- onError: f,
451
+ if (!f) {
452
+ o && x("Not a Visionary URL, rendering fallback <img />");
453
+ const O = {
454
+ ...N,
455
+ className: e,
456
+ height: u,
457
+ onClick: p,
458
+ onError: l,
445
459
  src: g,
446
- style: w,
447
- width: x
460
+ style: y,
461
+ width: E
448
462
  };
449
- return /* @__PURE__ */ G("img", { ...T });
463
+ return /* @__PURE__ */ T("img", { ...O });
450
464
  }
451
- const R = At(X.container, n, {
452
- [X.preventDrag]: !!p,
453
- [X.preventSelection]: !!l
454
- }), z = {
465
+ const R = Nt(X.container, e, {
466
+ [X.preventDrag]: !!h,
467
+ [X.preventSelection]: !!d
468
+ }), B = {
455
469
  ...{
456
- "--v-ar": u.arPaddingTop
470
+ "--v-ar": f.arPaddingTop
457
471
  },
458
- aspectRatio: u.aspectRatio,
459
- backgroundColor: (u == null ? void 0 : u.backgroundColor) ?? void 0,
460
- maxWidth: u.maxWidth,
472
+ ...y,
473
+ aspectRatio: f.aspectRatio,
474
+ backgroundColor: (f == null ? void 0 : f.backgroundColor) ?? void 0,
475
+ maxWidth: f.maxWidth,
461
476
  position: "relative",
462
- width: "100%",
463
- ...w
477
+ width: "100%"
464
478
  };
465
- x && (z.width = x), a && (z.height = a);
466
- const ht = {
467
- onClick: h
468
- }, mt = ge(i);
469
- return /* @__PURE__ */ vt(
479
+ E && (B.width = E), u && (B.height = u);
480
+ const gt = {
481
+ onClick: p
482
+ }, bt = wn(c), K = /* @__PURE__ */ wt(
470
483
  "div",
471
484
  {
472
485
  className: R,
473
- ref: O,
474
- style: z,
475
- ...ue(u.url, o),
486
+ ref: z,
487
+ style: B,
488
+ ...hn(f.url, o),
476
489
  ...F(H.CONTAINER),
477
- ...ht,
490
+ ...gt,
478
491
  children: [
479
- !c && /* @__PURE__ */ G(
492
+ !i && /* @__PURE__ */ T(
480
493
  "canvas",
481
494
  {
482
- height: N,
483
- ref: E,
484
- style: me,
485
- width: N,
495
+ height: U,
496
+ ref: I,
497
+ style: yn,
498
+ width: U,
486
499
  ...F(H.CANVAS)
487
500
  }
488
501
  ),
489
502
  !r && // eslint-disable-next-line jsx-a11y/alt-text -- `sharedImgProps` includes alt tag
490
- /* @__PURE__ */ G(
503
+ /* @__PURE__ */ T(
491
504
  "img",
492
505
  {
493
- ...U,
506
+ ...N,
494
507
  ...F(H.IMAGE),
495
- onError: k,
496
- src: u.src,
497
- style: mt
508
+ onError: _,
509
+ src: f.src,
510
+ style: bt
498
511
  }
499
512
  )
500
513
  ]
501
514
  }
502
515
  );
516
+ return y != null && y.aspectRatio ? /* @__PURE__ */ T(Dt, { aspectRatio: y.aspectRatio, children: K }) : K;
503
517
  };
504
518
  export {
505
- Re as Image
519
+ On as Image
506
520
  };
@@ -1,6 +1,6 @@
1
1
  (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.id="v7y-styles",e.appendChild(document.createTextNode('.v7y_7587:before{content:"";display:block;padding-top:var(--v-ar)}.v7y_b8c0{-webkit-user-drag:none;pointer-events:none}.v7y_e0dd{-webkit-user-select:none;user-select:none}')),document.head.appendChild(e)}}catch(n){console.error("vite-plugin-css-injected-by-js",n)}})();
2
- (function(E,R){typeof exports=="object"&&typeof module<"u"?R(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],R):(E=typeof globalThis<"u"?globalThis:E||self,R(E.VisionaryImage={},E.jsxRuntime,E.React))})(this,function(E,R,I){"use strict";function ht(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var K={exports:{}};/*!
2
+ (function(R,x){typeof exports=="object"&&typeof module<"u"?x(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],x):(R=typeof globalThis<"u"?globalThis:R||self,x(R.VisionaryImage={},R.jsxRuntime,R.React))})(this,function(R,x,E){"use strict";function gt(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var K={exports:{}};/*!
3
3
  Copyright (c) 2018 Jed Watson.
4
4
  Licensed under the MIT License (MIT), see
5
5
  http://jedwatson.github.io/classnames
6
- */(function(t){(function(){var e={}.hasOwnProperty;function n(){for(var r="",s=0;s<arguments.length;s++){var a=arguments[s];a&&(r=i(r,o(a)))}return r}function o(r){if(typeof r=="string"||typeof r=="number")return r;if(typeof r!="object")return"";if(Array.isArray(r))return n.apply(null,r);if(r.toString!==Object.prototype.toString&&!r.toString.toString().includes("[native code]"))return r.toString();var s="";for(var a in r)e.call(r,a)&&r[a]&&(s=i(s,a));return s}function i(r,s){return s?r?r+" "+s:r+s:r}t.exports?(n.default=n,t.exports=n):window.classNames=n})()})(K);var gt=K.exports;const mt=ht(gt),bt=(t,{root:e,rootMargin:n,threshold:o}={},i=[])=>{const r=I.useRef(null),s=I.useRef(null);return I.useCallback(c=>{r.current&&s.current&&(s.current.unobserve(r.current),s.current.disconnect(),s.current=null),c&&(s.current=new IntersectionObserver(t,{root:e,rootMargin:n,threshold:o}),s.current.observe(c),r.current=c)},[r,e,n,JSON.stringify(o),...i])},yt=({root:t,rootMargin:e,threshold:n,unobserveOnEnter:o,target:i,onEnter:r,onLeave:s,defaultInView:a}={},c=[])=>{const[d,h]=I.useState({inView:a||!1,entry:null,observer:null}),f=I.useCallback(([p],l)=>{const b=l.thresholds.some(m=>p.intersectionRatio>=m)&&p.isIntersecting;h({inView:b,entry:p,observer:l}),b&&o&&(l.unobserve(p.target),l.disconnect()),b?r==null||r(p,l):s==null||s(p,l)},[r,s,o]),g=bt(f,{root:t,rootMargin:e,threshold:n},[o,...c]);return I.useEffect(()=>{i!=null&&i.current&&g(i.current)},[i,g]),[g,d.inView,d.entry,d.observer]};var $=(t=>(t.AUTO="auto",t.AVIF="avif",t.JPEG="jpeg",t.WEBP="webp",t))($||{}),v=(t=>(t.xs="xs",t.sm="sm",t.md="md",t.lg="lg",t.xl="xl",t.xxl="xxl",t["4k"]="4k",t["5k"]="5k",t.full="full",t))(v||{}),C=(t=>(t.DEBUG="debug",t.DOWNLOAD="download",t))(C||{});const vt="https://link.visionary.cloud";$.AUTO,v.lg;const M={[v.xs]:160,[v.sm]:320,[v.md]:640,[v.lg]:1280,[v.xl]:1920,[v.xxl]:2560,[v["4k"]]:3840,[v["5k"]]:5120,[v.full]:0};Object.keys(M).reduce((t,e)=>{const n=e,o=M[n];return o&&(t[o]=n),t},{});const Q="!";var wt=Object.defineProperty,It=(t,e,n)=>e in t?wt(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,xt=(t,e,n)=>It(t,typeof e!="symbol"?e+"":e,n),G={},L={};Object.defineProperty(L,"__esModule",{value:!0});function Et(t){return String.fromCharCode(parseInt(t.slice(1),16))}function Rt(t){return btoa(encodeURIComponent(t).replace(/%[0-9A-F]{2}/g,Et))}L.encode=Rt;function At(t){return`%${`00${t.charCodeAt(0).toString(16)}`.slice(-2)}`}function St(t){return decodeURIComponent(Array.from(atob(t),At).join(""))}L.decode=St,Object.defineProperty(G,"__esModule",{value:!0});const tt=L;function Tt(t){return tt.decode(t.replace(/\-/g,"+").replace(/_/g,"/"))}var Ot=G.decode=Tt;function Nt(t){return tt.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=+$/,"")}var Ut=G.encode=Nt;const Ct=t=>t.filter(Boolean),et=t=>{try{return new URL(t)}catch{return null}},k=(t="")=>/^[A-Za-z0-9_-]*$/.test(t),Dt=t=>{const{altText:e,bcc:n,blurhash:o,blurhashX:i,blurhashY:r,sourceHeight:s,sourceWidth:a,url:c}=t;if(!c||!a||!s)return new Error("Cannot construct visionary code: missing required url/width/height");const d=[c,a,s];return!n||(d.push(n),!o||!i||!r)||(d.push(o,i,r),e&&e.length&&d.push(e)),Pt(d)},Pt=t=>Ut(t.join(Q)),nt=t=>{if(typeof t!="string")return null;const e=t.trim();if(!e.length||!k(e))return null;const n=Ot(e);if(!n)return null;const o=n.split(Q);if(o.length<3)return null;const[i,r,s,a,c,d,h,f]=o,g=i.trim();if(!g.length)return console.error("Cannot parse code, empty file id"),null;const p=Number(r.trim()),l=Number(s.trim());if(isNaN(p)||isNaN(l)||!p||!l)return console.error("Cannot parse Visionary Code: invalid image dimensions",r,s),null;const y=Number(d)??0,b=Number(h)??0;return y<1||b<1?(console.error("Cannot parse Visionary Code: invalid blurhash x, y component dimensions",y,b),null):{altText:f,bcc:a,blurhash:c,blurhashX:y,blurhashY:b,sourceHeight:l,sourceWidth:p,url:g}};class _t extends Error{constructor(){super(...arguments),xt(this,"message","invalid endpoint URL (does it contain http/https?)")}}const jt=t=>t===C.DEBUG,Vt=t=>t===C.DOWNLOAD,$t=t=>Object.values($).includes(t),rt=t=>Object.values(v).includes(t),Lt=(t=[])=>{const e={};for(const n of t)rt(n)?e.size=v[n]:jt(n)?e.debug=!0:Vt(n)?e.download=!0:$t(n)&&(e.format=n);return e},kt=t=>{if(!t||typeof t!="object")return null;const e=[];return t.debug&&e.push(C.DEBUG),t.download&&e.push(C.DOWNLOAD),t.format&&t.format!==$.AUTO&&e.push(t.format),t.size&&rt(t.size)&&e.push(t.size),e.length?e.sort().join(","):null},zt=t=>{if(k(t)){const e=nt(t);if(e)return{fields:e,options:{}}}return Bt(t)},Bt=t=>{if(!t)return null;const e=t.trim();if(!e)return null;try{const n=Gt(e);if(!n)return null;const{code:o,optionTokens:i}=n,r=nt(o);if(!r)return null;const s=Lt(i);return{fields:r,options:s}}catch(n){n instanceof Error?console.error(`Error parsing URL: ${n.message}`,n):console.error("uncaught error",n)}return null},Mt=(t,e)=>{const n=Dt(t);if(n instanceof Error)return null;let o=null;if(e!=null&&e.endpoint&&(o=et(e==null?void 0:e.endpoint),!o))throw new _t("Cannot construct URL: bad endpoint. Ensure endpoint starts with http:// or https://");o||(o=et(vt));const i=[o.origin,"image",n],r=e?kt(e):null;return r&&i.push(r),e!=null&&e.filename?i.push(e.filename):i.push("image.jpg"),i.join("/")},Gt=t=>{try{const e=new URL(t),n=Ct(e.pathname.split("/"));if(n[0]!=="image"||![3,4].includes(n.length))throw new Error("Unrecognized URL");const o=n[1].trim();if(!o.length||!k(o))throw new Error("URL is not formatted as base64url");if(n.length===4){const i=n[2].split(",");return{code:o,optionTokens:i}}if(n.length===3)return{code:o,optionTokens:[]}}catch{return null}return null},ot=.7,st=1,U=24,Wt=v.lg,it=process.env.NODE_ENV,Ft=it==="development",ct=typeof document>"u",Ht=it==="test",qt=ct?()=>{}:I.useLayoutEffect,Xt="<visionary>",T=(t,...e)=>{!console||typeof console.log!="function"||console.log(`${Xt} ${t}`,...e)},Yt="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~",z=(t,e,n)=>{let o=0;for(;e<n;)o*=83,o+=Yt.indexOf(t[e++]);return o},at=Math.pow,D=Math.PI,Zt=D*2,lt=3294.6,ut=269.025,Jt=t=>t>10.31475?at(t/ut+.052132,2.4):t/lt,W=t=>~~(t>1227e-8?ut*at(t,.416666)-13.025:t*lt+1),P=t=>(t<0?-1:1)*t*t,dt=t=>{for(t+=D/2;t>D;)t-=Zt;const e=1.27323954*t-.405284735*P(t);return .225*(P(e)-e)+e};function Kt(t){const e=z(t,2,6);return[e>>16,e>>8&255,e&255]}function Qt(t,e,n,o){const i=z(t,0,1),r=i%9+1,s=~~(i/9)+1,a=r*s;let c=0,d=0,h=0,f=0,g=0,p=0,l=0,y=0,b=0,m=0,w=0,A=0,u=0,S=0;const _=(z(t,1,2)+1)/13446*(o|1),x=new Float64Array(a*3),X=Kt(t);for(c=0;c<3;c++)x[c]=Jt(X[c]);for(c=1;c<a;c++)S=z(t,4+c*2,6+c*2),x[c*3]=P(~~(S/(19*19))-9)*_,x[c*3+1]=P(~~(S/19)%19-9)*_,x[c*3+2]=P(S%19-9)*_;const j=e*4,N=new Uint8ClampedArray(j*n);for(f=0;f<n;f++)for(A=D*f/n,h=0;h<e;h++){for(g=0,p=0,l=0,u=D*h/e,d=0;d<s;d++)for(b=dt(A*d),c=0;c<r;c++)y=dt(u*c)*b,m=(c+d*r)*3,g+=x[m]*y,p+=x[m+1]*y,l+=x[m+2]*y;w=4*h+f*j,N[w]=W(g),N[w+1]=W(p),N[w+2]=W(l),N[w+3]=255}return N}const B=t=>{try{return new URL(t)}catch{return null}},te=(t,e)=>`rgba(${t.r},${t.g},${t.b},${e})`,F=t=>Ft||Ht?{"data-testid":t}:{},ee=(t,e)=>e?{"data-fileid":t}:{},ft=(t,e)=>Math.min(t,e),ne=t=>{let e=t.replace(/^#/,"");if(e.length!==3&&e.length!==6)return null;e.length===3&&(e=`${e[0]}${e[0]}${e[1]}${e[1]}${e[2]}${e[2]}`);const n=parseInt(e.slice(0,2),16),o=parseInt(e.slice(2,4),16);return{b:parseInt(e.slice(4,6),16),g:o,r:n}},O=(t,e=0)=>{const n=Math.pow(10,e);return Math.round(t*n)/n},re=(t,e)=>{const n=B(t),o=B(e);return!n||!o?t:(o.pathname=n.pathname,o.search=n.search,o.toString())},oe=(t,e={},n=ot,o=st)=>{if(!t)return null;try{e.debug&&T("input imageSrc:",t);const i=zt(t);if(e.debug&&T("Visionary URL data: ",i),!i)throw new Error("Could not parse Visionary URL");const{fields:r,options:s}=i;if(r.sourceWidth<1||r.sourceHeight<1)throw new Error("Invalid image dimensions");const a=r.sourceWidth/r.sourceHeight,c=(e==null?void 0:e.size)??s.size??Wt,d=M[c];let h=0,f=0,g=0;if(a>=1){f=h=ft(d,r.sourceWidth);const m=O(f/a);g=O(f/m,6)}else h=ft(d,r.sourceHeight),f=O(h*a),g=O(f/h,6);const p=O(100/g,6),l={...r,arPaddingTop:`${p}%`,aspectRatio:g,maxWidth:f,src:t},y=B(r.url);if(y)l.src=y.toString();else if(!B(t)&&k(r.url)){const m=Mt(r,{endpoint:e.endpoint,size:c});m&&(l.src=m)}e.endpoint&&(l.src=re(l.src,e.endpoint));const b=r.bcc?ne(r.bcc):null;if(b&&(l.backgroundColor=te(b,n)),!ct&&r.blurhash&&!e.disableBlurLayer){const m=performance.now(),w=Qt(r.blurhash,U,U,o),A=performance.now()-m;e.debug&&T(`Blurhash decode time: ${O(A,1)} ms`),w&&(l.pixels=w)}return e.debug&&T("Visionary Image state: ",l),l}catch{return null}},pt={bottom:0,left:0,position:"absolute",right:0,top:0},se={...pt,maxHeight:"100%",maxWidth:"100%"},ie={...pt,height:"100%",width:"100%"},ce=t=>{const e={...se};return t&&(e.display="none"),e},H={CANVAS:"canvas",CONTAINER:"container",IMAGE:"image"},q={container:"v7y_7587",preventDrag:"v7y_b8c0",preventSelection:"v7y_e0dd"},ae=({alt:t,bgColorAlpha:e=ot,className:n,debug:o=!1,disableBlurLayer:i=!1,disableImageLayer:r=!1,endpoint:s,height:a,hideImageLayer:c=!1,lazy:d=!0,onClick:h,onError:f,onLoad:g,preventDrag:p=!1,preventSelection:l=!1,punch:y=st,size:b,src:m,style:w,width:A})=>{const u=I.useMemo(()=>oe(m,{debug:o,disableBlurLayer:i,endpoint:s,size:b},e,y),[e,o,i,s,y,b,m]),S=I.useRef(null),[_,x]=yt();qt(function(){if(!S.current||!(u!=null&&u.blurhash))return;if(!u.pixels){console.warn("No pixel data passed in, skipping");return}const de=performance.now(),Z=S.current.getContext("2d");if(!Z){console.warn("Cannot access canvasRenderingContext, skipping");return}const J=Z.createImageData(U,U);if(!J){console.warn("Could not create ImageData on CanvasRenderingContext");return}if(J.data.set(u.pixels),Z.putImageData(J,0,0),o){const fe=performance.now()-de;T(`Canvas render time: ${O(fe,1)} ms`)}},[u==null?void 0:u.blurhash,u==null?void 0:u.pixels,o]);const X=I.useCallback(V=>{o&&T("Image load error ",V),f&&f()},[o,f]),j={alt:t,loading:!d||x?"eager":"lazy",onLoad:g};if(!u){o&&T("Not a Visionary URL, rendering fallback <img />");const V={...j,className:n,height:a,onClick:h,onError:f,src:m,style:w,width:A};return R.jsx("img",{...V})}const N=mt(q.container,n,{[q.preventDrag]:!!p,[q.preventSelection]:!!l}),Y={...{"--v-ar":u.arPaddingTop},aspectRatio:u.aspectRatio,backgroundColor:(u==null?void 0:u.backgroundColor)??void 0,maxWidth:u.maxWidth,position:"relative",width:"100%",...w};A&&(Y.width=A),a&&(Y.height=a);const le={onClick:h},ue=ce(c);return R.jsxs("div",{className:N,ref:_,style:Y,...ee(u.url,o),...F(H.CONTAINER),...le,children:[!i&&R.jsx("canvas",{height:U,ref:S,style:ie,width:U,...F(H.CANVAS)}),!r&&R.jsx("img",{...j,...F(H.IMAGE),onError:X,src:u.src,style:ue})]})};E.Image=ae,Object.defineProperty(E,Symbol.toStringTag,{value:"Module"})});
6
+ */(function(t){(function(){var e={}.hasOwnProperty;function n(){for(var r="",s=0;s<arguments.length;s++){var u=arguments[s];u&&(r=i(r,o(u)))}return r}function o(r){if(typeof r=="string"||typeof r=="number")return r;if(typeof r!="object")return"";if(Array.isArray(r))return n.apply(null,r);if(r.toString!==Object.prototype.toString&&!r.toString.toString().includes("[native code]"))return r.toString();var s="";for(var u in r)e.call(r,u)&&r[u]&&(s=i(s,u));return s}function i(r,s){return s?r?r+" "+s:r+s:r}t.exports?(n.default=n,t.exports=n):window.classNames=n})()})(K);var bt=K.exports;const vt=gt(bt),yt=(t,{root:e,rootMargin:n,threshold:o}={},i=[])=>{const r=E.useRef(null),s=E.useRef(null);return E.useCallback(c=>{r.current&&s.current&&(s.current.unobserve(r.current),s.current.disconnect(),s.current=null),c&&(s.current=new IntersectionObserver(t,{root:e,rootMargin:n,threshold:o}),s.current.observe(c),r.current=c)},[r,e,n,JSON.stringify(o),...i])},wt=({root:t,rootMargin:e,threshold:n,unobserveOnEnter:o,target:i,onEnter:r,onLeave:s,defaultInView:u}={},c=[])=>{const[a,p]=E.useState({inView:u||!1,entry:null,observer:null}),l=E.useCallback(([h],f)=>{const b=f.thresholds.some(g=>h.intersectionRatio>=g)&&h.isIntersecting;p({inView:b,entry:h,observer:f}),b&&o&&(f.unobserve(h.target),f.disconnect()),b?r==null||r(h,f):s==null||s(h,f)},[r,s,o]),m=yt(l,{root:t,rootMargin:e,threshold:n},[o,...c]);return E.useEffect(()=>{i!=null&&i.current&&m(i.current)},[i,m]),[m,a.inView,a.entry,a.observer]},It={overflow:"hidden"},xt=({aspectRatio:t,children:e})=>x.jsx("div",{style:{aspectRatio:t,...It},children:e});var j=(t=>(t.AUTO="auto",t.AVIF="avif",t.JPEG="jpeg",t.WEBP="webp",t))(j||{}),w=(t=>(t.xs="xs",t.sm="sm",t.md="md",t.lg="lg",t.xl="xl",t.xxl="xxl",t["4k"]="4k",t["5k"]="5k",t.full="full",t))(w||{}),O=(t=>(t.DEBUG="debug",t.DOWNLOAD="download",t))(O||{});const Et="https://link.visionary.cloud";j.AUTO,w.lg;const M={[w.xs]:160,[w.sm]:320,[w.md]:640,[w.lg]:1280,[w.xl]:1920,[w.xxl]:2560,[w["4k"]]:3840,[w["5k"]]:5120,[w.full]:0};Object.keys(M).reduce((t,e)=>{const n=e,o=M[n];return o&&(t[o]=n),t},{});const Q="!";var At=Object.defineProperty,Rt=(t,e,n)=>e in t?At(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Tt=(t,e,n)=>Rt(t,typeof e!="symbol"?e+"":e,n),W={},V={};Object.defineProperty(V,"__esModule",{value:!0});function Ut(t){return String.fromCharCode(parseInt(t.slice(1),16))}function Ct(t){return btoa(encodeURIComponent(t).replace(/%[0-9A-F]{2}/g,Ut))}V.encode=Ct;function Nt(t){return`%${`00${t.charCodeAt(0).toString(16)}`.slice(-2)}`}function Ot(t){return decodeURIComponent(Array.from(atob(t),Nt).join(""))}V.decode=Ot,Object.defineProperty(W,"__esModule",{value:!0});const tt=V;function St(t){return tt.decode(t.replace(/\-/g,"+").replace(/_/g,"/"))}var Dt=W.decode=St;function Pt(t){return tt.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=+$/,"")}var _t=W.encode=Pt;const jt=t=>t.filter(Boolean),et=t=>{try{return new URL(t)}catch{return null}},L=(t="")=>/^[A-Za-z0-9_-]*$/.test(t),Vt=t=>{const{altText:e,bcc:n,blurhash:o,blurhashX:i,blurhashY:r,sourceHeight:s,sourceWidth:u,url:c}=t;if(!c||!u||!s)return new Error("Cannot construct visionary code: missing required url/width/height");const a=[c,u,s];return!n||(a.push(n),!o||!i||!r)||(a.push(o,i,r),e&&e.length&&a.push(e)),Lt(a)},Lt=t=>_t(t.join(Q)),nt=t=>{if(typeof t!="string")return null;const e=t.trim();if(!e.length||!L(e))return null;const n=Dt(e);if(!n)return null;const o=n.split(Q);if(o.length<3)return null;const[i,r,s,u,c,a,p,l]=o,m=i.trim();if(!m.length)return console.error("Cannot parse code, empty file id"),null;const h=Number(r.trim()),f=Number(s.trim());if(isNaN(h)||isNaN(f)||!h||!f)return console.error("Cannot parse Visionary Code: invalid image dimensions",r,s),null;const v=Number(a)??0,b=Number(p)??0;return v<1||b<1?(console.error("Cannot parse Visionary Code: invalid blurhash x, y component dimensions",v,b),null):{altText:l,bcc:u,blurhash:c,blurhashX:v,blurhashY:b,sourceHeight:f,sourceWidth:h,url:m}};class $t extends Error{constructor(){super(...arguments),Tt(this,"message","invalid endpoint URL (does it contain http/https?)")}}const kt=t=>t===O.DEBUG,zt=t=>t===O.DOWNLOAD,Bt=t=>Object.values(j).includes(t),rt=t=>Object.values(w).includes(t),Mt=(t=[])=>{const e={};for(const n of t)rt(n)?e.size=w[n]:kt(n)?e.debug=!0:zt(n)?e.download=!0:Bt(n)&&(e.format=n);return e},Wt=t=>{if(!t||typeof t!="object")return null;const e=[];return t.debug&&e.push(O.DEBUG),t.download&&e.push(O.DOWNLOAD),t.format&&t.format!==j.AUTO&&e.push(t.format),t.size&&rt(t.size)&&e.push(t.size),e.length?e.sort().join(","):null},Gt=t=>{if(L(t)){const e=nt(t);if(e)return{fields:e,options:{}}}return Ft(t)},Ft=t=>{if(!t)return null;const e=t.trim();if(!e)return null;try{const n=Xt(e);if(!n)return null;const{code:o,optionTokens:i}=n,r=nt(o);if(!r)return null;const s=Mt(i);return{fields:r,options:s}}catch(n){n instanceof Error?console.error(`Error parsing URL: ${n.message}`,n):console.error("uncaught error",n)}return null},Ht=(t,e)=>{const n=Vt(t);if(n instanceof Error)return null;let o=null;if(e!=null&&e.endpoint&&(o=et(e==null?void 0:e.endpoint),!o))throw new $t("Cannot construct URL: bad endpoint. Ensure endpoint starts with http:// or https://");o||(o=et(Et));const i=[o.origin,"image",n],r=e?Wt(e):null;return r&&i.push(r),e!=null&&e.filename?i.push(e.filename):i.push("image.jpg"),i.join("/")},Xt=t=>{try{const e=new URL(t),n=jt(e.pathname.split("/"));if(n[0]!=="image"||![3,4].includes(n.length))throw new Error("Unrecognized URL");const o=n[1].trim();if(!o.length||!L(o))throw new Error("URL is not formatted as base64url");if(n.length===4){const i=n[2].split(",");return{code:o,optionTokens:i}}if(n.length===3)return{code:o,optionTokens:[]}}catch{return null}return null},ot=.7,st=1,N=24,Yt=w.lg,ct=process.env.NODE_ENV,qt=ct==="development",it=typeof document>"u",Zt=ct==="test",Jt=it?()=>{}:E.useLayoutEffect,Kt="<visionary>",T=(t,...e)=>{!console||typeof console.log!="function"||console.log(`${Kt} ${t}`,...e)},at=new Uint8Array(128);for(let t=0;t<83;t++)at["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~".charCodeAt(t)]=t;const $=(t,e,n)=>{let o=0;for(;e<n;)o*=83,o+=at[t.charCodeAt(e++)];return o},lt=Math.pow,S=Math.PI,Qt=S*2,ut=3294.6,ft=269.025,te=t=>t>10.31475?lt(t/ft+.052132,2.4):t/ut,G=t=>~~(t>1227e-8?ft*lt(t,.416666)-13.025:t*ut+1),D=t=>(t<0?-1:1)*t*t,dt=t=>{for(t+=S/2;t>S;)t-=Qt;const e=1.27323954*t-.405284735*D(t);return .225*(D(e)-e)+e};function ee(t){const e=$(t,2,6);return[e>>16,e>>8&255,e&255]}function ne(t,e,n,o){const i=$(t,0,1),r=i%9+1,s=~~(i/9)+1,u=r*s;let c=0,a=0,p=0,l=0,m=0,h=0,f=0,v=0,b=0,g=0,y=0,A=0;const d=($(t,1,2)+1)/13446*(o|1),I=new Float64Array(u*3),Y=ee(t);for(c=0;c<3;c++)I[c]=te(Y[c]);for(c=1;c<u;c++)A=$(t,4+c*2,6+c*2),I[c*3]=D(~~(A/361)-9)*d,I[c*3+1]=D(~~(A/19)%19-9)*d,I[c*3+2]=D(A%19-9)*d;const z=new Float64Array(s*n),B=new Float64Array(r*e);for(a=0;a<s;a++)for(l=0;l<n;l++)z[a*n+l]=dt(S*l*a/n);for(c=0;c<r;c++)for(p=0;p<e;p++)B[c*e+p]=dt(S*p*c/e);const P=e*4,C=new Uint8ClampedArray(P*n);for(l=0;l<n;l++)for(p=0;p<e;p++){for(m=h=f=0,a=0;a<s;a++)for(b=z[a*n+l],c=0;c<r;c++)v=B[c*e+p]*b,g=(c+a*r)*3,m+=I[g]*v,h+=I[g+1]*v,f+=I[g+2]*v;y=4*p+l*P,C[y]=G(m),C[y+1]=G(h),C[y+2]=G(f),C[y+3]=255}return C}const k=t=>{try{return new URL(t)}catch{return null}},re=(t,e)=>`rgba(${t.r},${t.g},${t.b},${e})`,F=t=>qt||Zt?{"data-testid":t}:{},oe=(t,e)=>e?{"data-fileid":t}:{},pt=(t,e)=>Math.min(t,e),se=t=>{let e=t.replace(/^#/,"");if(e.length!==3&&e.length!==6)return null;e.length===3&&(e=`${e[0]}${e[0]}${e[1]}${e[1]}${e[2]}${e[2]}`);const n=parseInt(e.slice(0,2),16),o=parseInt(e.slice(2,4),16);return{b:parseInt(e.slice(4,6),16),g:o,r:n}},U=(t,e=0)=>{const n=Math.pow(10,e);return Math.round(t*n)/n},ce=(t,e)=>{const n=k(t),o=k(e);return!n||!o?t:(o.pathname=n.pathname,o.search=n.search,o.toString())},ie=(t,e={},n=ot,o=st)=>{if(!t)return null;try{e.debug&&T("input imageSrc:",t);const i=Gt(t);if(e.debug&&T("Visionary URL data: ",i),!i)throw new Error("Could not parse Visionary URL");const{fields:r,options:s}=i;if(r.sourceWidth<1||r.sourceHeight<1)throw new Error("Invalid image dimensions");const u=r.sourceWidth/r.sourceHeight,c=(e==null?void 0:e.size)??s.size??Yt,a=M[c];let p=0,l=0,m=0;if(u>=1){l=p=pt(a,r.sourceWidth);const g=U(l/u);m=U(l/g,6)}else p=pt(a,r.sourceHeight),l=U(p*u),m=U(l/p,6);const h=U(100/m,6),f={...r,arPaddingTop:`${h}%`,aspectRatio:m,maxWidth:l,src:t},v=k(r.url);if(v)f.src=v.toString();else if(!k(t)&&L(r.url)){const g=Ht(r,{endpoint:e.endpoint,size:c});g&&(f.src=g)}e.endpoint&&(f.src=ce(f.src,e.endpoint));const b=r.bcc?se(r.bcc):null;if(b&&(f.backgroundColor=re(b,n)),!it&&r.blurhash&&!e.disableBlurLayer){const g=performance.now(),y=ne(r.blurhash,N,N,o),A=performance.now()-g;e.debug&&T(`Blurhash decode time: ${U(A,1)} ms`),y&&(f.pixels=y)}return e.debug&&T("Visionary Image state: ",f),f}catch{return null}},ht={bottom:0,left:0,position:"absolute",right:0,top:0},ae={...ht,maxHeight:"100%",maxWidth:"100%"},le={...ht,height:"100%",width:"100%"},ue=t=>{const e={...ae};return t&&(e.display="none"),e},H={CANVAS:"canvas",CONTAINER:"container",IMAGE:"image"},X={container:"v7y_7587",preventDrag:"v7y_b8c0",preventSelection:"v7y_e0dd"},fe=({alt:t,bgColorAlpha:e=ot,className:n,debug:o=!1,disableBlurLayer:i=!1,disableImageLayer:r=!1,endpoint:s,height:u,hideImageLayer:c=!1,lazy:a=!0,onClick:p,onError:l,onLoad:m,preventDrag:h=!1,preventSelection:f=!1,punch:v=st,size:b,src:g,style:y,width:A})=>{const d=E.useMemo(()=>ie(g,{debug:o,disableBlurLayer:i,endpoint:s,size:b},e,v),[e,o,i,s,v,b,g]),I=E.useRef(null),[Y,z]=wt();Jt(function(){if(!I.current||!(d!=null&&d.blurhash))return;if(!d.pixels){console.warn("No pixel data passed in, skipping");return}const he=performance.now(),Z=I.current.getContext("2d");if(!Z){console.warn("Cannot access canvasRenderingContext, skipping");return}const J=Z.createImageData(N,N);if(!J){console.warn("Could not create ImageData on CanvasRenderingContext");return}if(J.data.set(d.pixels),Z.putImageData(J,0,0),o){const me=performance.now()-he;T(`Canvas render time: ${U(me,1)} ms`)}},[d==null?void 0:d.blurhash,d==null?void 0:d.pixels,o]);const B=E.useCallback(_=>{o&&T("Image load error ",_),l&&l()},[o,l]),P={alt:t,loading:!a||z?"eager":"lazy",onLoad:m};if(!d){o&&T("Not a Visionary URL, rendering fallback <img />");const _={...P,className:n,height:u,onClick:p,onError:l,src:g,style:y,width:A};return x.jsx("img",{..._})}const C=vt(X.container,n,{[X.preventDrag]:!!h,[X.preventSelection]:!!f}),q={...{"--v-ar":d.arPaddingTop},...y,aspectRatio:d.aspectRatio,backgroundColor:(d==null?void 0:d.backgroundColor)??void 0,maxWidth:d.maxWidth,position:"relative",width:"100%"};A&&(q.width=A),u&&(q.height=u);const de={onClick:p},pe=ue(c),mt=x.jsxs("div",{className:C,ref:Y,style:q,...oe(d.url,o),...F(H.CONTAINER),...de,children:[!i&&x.jsx("canvas",{height:N,ref:I,style:le,width:N,...F(H.CANVAS)}),!r&&x.jsx("img",{...P,...F(H.IMAGE),onError:B,src:d.src,style:pe})]});return y!=null&&y.aspectRatio?x.jsx(xt,{aspectRatio:y.aspectRatio,children:mt}):mt};R.Image=fe,Object.defineProperty(R,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "visionary-image",
3
3
  "description": "React image component with built-in Blurhash placeholders for better UX and Core Web Vitals.",
4
- "version": "1.0.1",
4
+ "version": "1.0.3",
5
+ "homepage": "https://visionary.cloud",
5
6
  "type": "module",
6
7
  "main": "./dist/visionary-image.umd.js",
7
8
  "module": "./dist/visionary-image.es.js",
@@ -17,14 +18,14 @@
17
18
  "license": "ISC",
18
19
  "scripts": {
19
20
  "build": "tsc && npm run clean && vite build",
21
+ "build-storybook": "storybook build -o storybook-static",
20
22
  "clean": "rimraf dist/",
21
23
  "dev": "vite",
22
24
  "lint": "tsc --noEmit; eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
23
25
  "preview": "vite preview",
24
- "test": "vitest",
25
- "test:coverage": "vitest run --coverage",
26
26
  "storybook": "storybook dev -p 6006 --no-open",
27
- "build-storybook": "storybook build"
27
+ "test": "vitest",
28
+ "test:coverage": "vitest run --coverage"
28
29
  },
29
30
  "files": [
30
31
  "dist/",
@@ -37,7 +38,7 @@
37
38
  },
38
39
  "dependencies": {
39
40
  "classnames": "2.5.1",
40
- "fast-blurhash": "1.1.2",
41
+ "fast-blurhash": "1.1.4",
41
42
  "react-hook-inview": "4.5.1",
42
43
  "visionary-url": "1.3.1"
43
44
  },