@creativoma/liquid-glass 1.1.2 → 1.2.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/CHANGELOG.md CHANGED
@@ -7,14 +7,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [1.1.2] - 2026-03-06
10
+ ## [1.2.0] - 2026-03-07
11
+
12
+ ### Added
13
+
14
+ - Full test suite with Vitest and jsdom:
15
+ - `src/components/LiquidGlass.test.tsx` — 27 tests covering rendering, wrapper styles, props, default values, Safari simplified filter, and layer structure
16
+ - `src/hooks/useBrowserDetection.test.ts` — 8 tests covering Chrome, Firefox, Edge, Safari macOS, iPhone, iPad, iPod, and render stability
17
+ - `src/test/setup.ts` — global test setup with `@testing-library/jest-dom`
18
+ - `vitest.config.ts` — Vitest configuration with jsdom environment and v8 coverage
19
+ - Static HTML demo pages:
20
+ - `demo/component.html` — standalone showcase of component variants
21
+ - `demo/filters.html` — interactive SVG filter debugger
22
+
23
+ ### Changed
24
+
25
+ - Interactive demo app (`src/App.tsx`): added live sliders to control `backdropBlur` and `tintColor` opacity in real time, with a code preview that updates dynamically
26
+
27
+ ## [1.1.3] - 2026-03-06
11
28
 
12
29
  ### Security
13
30
 
14
31
  - Updated `ajv` to `>=8.18.0` via pnpm overrides to fix vulnerability
15
32
  - Updated `minimatch` to `>=9.0.7` and `>=10.2.3` via pnpm overrides to fix vulnerability
16
33
  - Updated `rollup` to `>=4.59.0` via pnpm overrides to fix vulnerability
17
- - Bumped dev dependencies: `eslint` `^9` → `^10`, `tailwindcss` `^4.1` → `^4.2`, `@tailwindcss/postcss` `^4.1` → `^4.2`, `globals`, `postcss`, `eslint-plugin-react-refresh`, `typescript-eslint`, `@types/node`
34
+ - Bumped dev dependencies: `tailwindcss` `^4.1` → `^4.2`, `@tailwindcss/postcss` `^4.1` → `^4.2`, `globals`, `postcss`, `eslint-plugin-react-refresh`, `typescript-eslint`, `@types/node`
35
+
36
+ ### Fixed
37
+
38
+ - Reverted `eslint` to `^9.x` for compatibility with `eslint-plugin-react-hooks@7`
39
+
40
+ ## [1.1.2] - 2026-03-06
41
+
42
+ ### Yanked
43
+
44
+ - Published with eslint@10 which breaks peer dependency with eslint-plugin-react-hooks
18
45
 
19
46
  ## [1.1.1] - 2026-02-14
20
47
 
@@ -1 +1 @@
1
- {"version":3,"file":"LiquidGlass.d.ts","sourceRoot":"","sources":["../../src/components/LiquidGlass.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAS,MAAM,OAAO,CAAA;AACjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAG/C,QAAA,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CA6IrC,CAAA;AAED,eAAe,WAAW,CAAA"}
1
+ {"version":3,"file":"LiquidGlass.d.ts","sourceRoot":"","sources":["../../src/components/LiquidGlass.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAS,MAAM,OAAO,CAAA;AACjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAG/C,QAAA,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAoJrC,CAAA;AAED,eAAe,WAAW,CAAA"}
package/dist/index.esm.js CHANGED
@@ -5,24 +5,24 @@ function ne() {
5
5
  if (D) return v;
6
6
  D = 1;
7
7
  var s = /* @__PURE__ */ Symbol.for("react.transitional.element"), c = /* @__PURE__ */ Symbol.for("react.fragment");
8
- function u(d, l, i) {
8
+ function u(d, i, l) {
9
9
  var f = null;
10
- if (i !== void 0 && (f = "" + i), l.key !== void 0 && (f = "" + l.key), "key" in l) {
11
- i = {};
12
- for (var m in l)
13
- m !== "key" && (i[m] = l[m]);
14
- } else i = l;
15
- return l = i.ref, {
10
+ if (l !== void 0 && (f = "" + l), i.key !== void 0 && (f = "" + i.key), "key" in i) {
11
+ l = {};
12
+ for (var p in i)
13
+ p !== "key" && (l[p] = i[p]);
14
+ } else l = i;
15
+ return i = l.ref, {
16
16
  $$typeof: s,
17
17
  type: d,
18
18
  key: f,
19
- ref: l !== void 0 ? l : null,
20
- props: i
19
+ ref: i !== void 0 ? i : null,
20
+ props: l
21
21
  };
22
22
  }
23
23
  return v.Fragment = c, v.jsx = u, v.jsxs = u, v;
24
24
  }
25
- var _ = {};
25
+ var x = {};
26
26
  var L;
27
27
  function ae() {
28
28
  return L || (L = 1, process.env.NODE_ENV !== "production" && (function() {
@@ -100,23 +100,23 @@ function ae() {
100
100
  return "<...>";
101
101
  }
102
102
  }
103
- function l() {
103
+ function i() {
104
104
  var e = S.A;
105
105
  return e === null ? null : e.getOwner();
106
106
  }
107
- function i() {
107
+ function l() {
108
108
  return Error("react-stack-top-frame");
109
109
  }
110
110
  function f(e) {
111
- if (N.call(e, "key")) {
111
+ if (C.call(e, "key")) {
112
112
  var r = Object.getOwnPropertyDescriptor(e, "key").get;
113
113
  if (r && r.isReactWarning) return !1;
114
114
  }
115
115
  return e.key !== void 0;
116
116
  }
117
- function m(e, r) {
117
+ function p(e, r) {
118
118
  function n() {
119
- C || (C = !0, console.error(
119
+ N || (N = !0, console.error(
120
120
  "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
121
121
  r
122
122
  ));
@@ -171,14 +171,14 @@ function ae() {
171
171
  if (a)
172
172
  if (Q(o)) {
173
173
  for (a = 0; a < o.length; a++)
174
- p(o[a]);
174
+ m(o[a]);
175
175
  Object.freeze && Object.freeze(o);
176
176
  } else
177
177
  console.error(
178
178
  "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
179
179
  );
180
- else p(o);
181
- if (N.call(r, "key")) {
180
+ else m(o);
181
+ if (C.call(r, "key")) {
182
182
  o = s(e);
183
183
  var b = Object.keys(r).filter(function(K) {
184
184
  return K !== "key";
@@ -201,37 +201,37 @@ React keys must be passed directly to JSX without using spread:
201
201
  for (var A in r)
202
202
  A !== "key" && (n[A] = r[A]);
203
203
  } else n = r;
204
- return o && m(
204
+ return o && p(
205
205
  n,
206
206
  typeof e == "function" ? e.displayName || e.name || "Unknown" : e
207
207
  ), g(
208
208
  e,
209
209
  o,
210
210
  n,
211
- l(),
211
+ i(),
212
212
  R,
213
213
  O
214
214
  );
215
215
  }
216
- function p(e) {
216
+ function m(e) {
217
217
  E(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === k && (e._payload.status === "fulfilled" ? E(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
218
218
  }
219
219
  function E(e) {
220
220
  return typeof e == "object" && e !== null && e.$$typeof === P;
221
221
  }
222
- var x = ee, P = /* @__PURE__ */ Symbol.for("react.transitional.element"), G = /* @__PURE__ */ Symbol.for("react.portal"), y = /* @__PURE__ */ Symbol.for("react.fragment"), W = /* @__PURE__ */ Symbol.for("react.strict_mode"), U = /* @__PURE__ */ Symbol.for("react.profiler"), q = /* @__PURE__ */ Symbol.for("react.consumer"), z = /* @__PURE__ */ Symbol.for("react.context"), B = /* @__PURE__ */ Symbol.for("react.forward_ref"), J = /* @__PURE__ */ Symbol.for("react.suspense"), V = /* @__PURE__ */ Symbol.for("react.suspense_list"), X = /* @__PURE__ */ Symbol.for("react.memo"), k = /* @__PURE__ */ Symbol.for("react.lazy"), H = /* @__PURE__ */ Symbol.for("react.activity"), Z = /* @__PURE__ */ Symbol.for("react.client.reference"), S = x.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, N = Object.prototype.hasOwnProperty, Q = Array.isArray, w = console.createTask ? console.createTask : function() {
222
+ var _ = ee, P = /* @__PURE__ */ Symbol.for("react.transitional.element"), G = /* @__PURE__ */ Symbol.for("react.portal"), y = /* @__PURE__ */ Symbol.for("react.fragment"), W = /* @__PURE__ */ Symbol.for("react.strict_mode"), U = /* @__PURE__ */ Symbol.for("react.profiler"), q = /* @__PURE__ */ Symbol.for("react.consumer"), z = /* @__PURE__ */ Symbol.for("react.context"), B = /* @__PURE__ */ Symbol.for("react.forward_ref"), J = /* @__PURE__ */ Symbol.for("react.suspense"), V = /* @__PURE__ */ Symbol.for("react.suspense_list"), X = /* @__PURE__ */ Symbol.for("react.memo"), k = /* @__PURE__ */ Symbol.for("react.lazy"), H = /* @__PURE__ */ Symbol.for("react.activity"), Z = /* @__PURE__ */ Symbol.for("react.client.reference"), S = _.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, C = Object.prototype.hasOwnProperty, Q = Array.isArray, w = console.createTask ? console.createTask : function() {
223
223
  return null;
224
224
  };
225
- x = {
225
+ _ = {
226
226
  react_stack_bottom_frame: function(e) {
227
227
  return e();
228
228
  }
229
229
  };
230
- var C, F = {}, I = x.react_stack_bottom_frame.bind(
231
- x,
232
- i
233
- )(), $ = w(d(i)), Y = {};
234
- _.Fragment = y, _.jsx = function(e, r, n) {
230
+ var N, F = {}, I = _.react_stack_bottom_frame.bind(
231
+ _,
232
+ l
233
+ )(), $ = w(d(l)), Y = {};
234
+ x.Fragment = y, x.jsx = function(e, r, n) {
235
235
  var a = 1e4 > S.recentlyCreatedOwnerStacks++;
236
236
  return j(
237
237
  e,
@@ -241,7 +241,7 @@ React keys must be passed directly to JSX without using spread:
241
241
  a ? Error("react-stack-top-frame") : I,
242
242
  a ? w(d(e)) : $
243
243
  );
244
- }, _.jsxs = function(e, r, n) {
244
+ }, x.jsxs = function(e, r, n) {
245
245
  var a = 1e4 > S.recentlyCreatedOwnerStacks++;
246
246
  return j(
247
247
  e,
@@ -252,40 +252,41 @@ React keys must be passed directly to JSX without using spread:
252
252
  a ? w(d(e)) : $
253
253
  );
254
254
  };
255
- })()), _;
255
+ })()), x;
256
256
  }
257
257
  var M;
258
258
  function oe() {
259
259
  return M || (M = 1, process.env.NODE_ENV === "production" ? h.exports = ne() : h.exports = ae()), h.exports;
260
260
  }
261
261
  var t = oe();
262
- const se = /iPad|iPhone|iPod/, le = /^((?!chrome|android).)*safari/i, ie = () => {
262
+ const se = /iPad|iPhone|iPod/, ie = /^((?!chrome|android).)*safari/i, le = () => {
263
263
  if (typeof window > "u") return !1;
264
- const s = window.navigator.userAgent, c = se.test(s), u = le.test(s);
264
+ const s = window.navigator.userAgent, c = se.test(s), u = ie.test(s);
265
265
  return c || u;
266
266
  }, ue = () => {
267
- const [s] = re(() => ie());
267
+ const [s] = re(() => le());
268
268
  return { useSimplifiedFilter: s };
269
269
  }, fe = ({
270
270
  children: s,
271
271
  className: c = "",
272
272
  backdropBlur: u = 2,
273
273
  tintColor: d = "rgba(255, 255, 255, .2)",
274
- displacementScale: l = 150,
275
- turbulenceBaseFrequency: i = "0.008 0.008",
274
+ displacementScale: i = 150,
275
+ turbulenceBaseFrequency: l = "0.008 0.008",
276
276
  turbulenceSeed: f = 1.5,
277
- as: m = "div",
277
+ as: p = "div",
278
278
  style: T,
279
279
  ...g
280
280
  }) => {
281
- const p = `liquid-glass-${te().replace(/:/g, "-")}`, { useSimplifiedFilter: E } = ue();
281
+ const m = `liquid-glass-${te().replace(/:/g, "-")}`, { useSimplifiedFilter: E } = ue();
282
282
  return /* @__PURE__ */ t.jsxs(t.Fragment, { children: [
283
283
  /* @__PURE__ */ t.jsx("svg", { style: { display: "none" }, suppressHydrationWarning: !0, children: E ? (
284
284
  // Simplified filter for Safari/iOS - uses only well-supported primitives
285
+ // Note: displacementScale has no effect in this filter path
285
286
  /* @__PURE__ */ t.jsxs(
286
287
  "filter",
287
288
  {
288
- id: p,
289
+ id: m,
289
290
  x: "-20%",
290
291
  y: "-20%",
291
292
  width: "140%",
@@ -296,7 +297,7 @@ const se = /iPad|iPhone|iPod/, le = /^((?!chrome|android).)*safari/i, ie = () =>
296
297
  "feTurbulence",
297
298
  {
298
299
  type: "fractalNoise",
299
- baseFrequency: i,
300
+ baseFrequency: l,
300
301
  numOctaves: 2,
301
302
  seed: f,
302
303
  result: "turbulence"
@@ -324,7 +325,7 @@ const se = /iPad|iPhone|iPod/, le = /^((?!chrome|android).)*safari/i, ie = () =>
324
325
  /* @__PURE__ */ t.jsxs(
325
326
  "filter",
326
327
  {
327
- id: p,
328
+ id: m,
328
329
  x: "0%",
329
330
  y: "0%",
330
331
  width: "100%",
@@ -335,7 +336,7 @@ const se = /iPad|iPhone|iPod/, le = /^((?!chrome|android).)*safari/i, ie = () =>
335
336
  "feTurbulence",
336
337
  {
337
338
  type: "fractalNoise",
338
- baseFrequency: i,
339
+ baseFrequency: l,
339
340
  numOctaves: 1,
340
341
  seed: f,
341
342
  result: "turbulence"
@@ -376,7 +377,7 @@ const se = /iPad|iPhone|iPod/, le = /^((?!chrome|android).)*safari/i, ie = () =>
376
377
  {
377
378
  in: "SourceGraphic",
378
379
  in2: "softMap",
379
- scale: l,
380
+ scale: i,
380
381
  xChannelSelector: "R",
381
382
  yChannelSelector: "G"
382
383
  }
@@ -386,10 +387,12 @@ const se = /iPad|iPhone|iPod/, le = /^((?!chrome|android).)*safari/i, ie = () =>
386
387
  )
387
388
  ) }),
388
389
  /* @__PURE__ */ t.jsxs(
389
- m,
390
+ p,
390
391
  {
391
- className: `relative overflow-hidden ${c}`,
392
+ className: c,
392
393
  style: {
394
+ position: "relative",
395
+ overflow: "hidden",
393
396
  boxShadow: "0 6px 6px rgba(0, 0, 0, 0.2), 0 0 20px rgba(0, 0, 0, 0.1)",
394
397
  ...T
395
398
  },
@@ -398,14 +401,16 @@ const se = /iPad|iPhone|iPod/, le = /^((?!chrome|android).)*safari/i, ie = () =>
398
401
  /* @__PURE__ */ t.jsx(
399
402
  "div",
400
403
  {
401
- className: "absolute inset-0 z-0 overflow-hidden",
402
404
  style: {
405
+ position: "absolute",
406
+ inset: 0,
407
+ zIndex: 0,
408
+ overflow: "hidden",
403
409
  backdropFilter: `blur(${u}px)`,
404
410
  WebkitBackdropFilter: `blur(${u}px)`,
405
- filter: `url(#${p})`,
411
+ filter: `url(#${m})`,
406
412
  isolation: "isolate",
407
413
  ...E && {
408
- // Additional CSS-based effects for Safari/iOS to enhance the liquid glass appearance
409
414
  transform: "translateZ(0)",
410
415
  willChange: "transform"
411
416
  }
@@ -415,13 +420,15 @@ const se = /iPad|iPhone|iPod/, le = /^((?!chrome|android).)*safari/i, ie = () =>
415
420
  /* @__PURE__ */ t.jsx(
416
421
  "div",
417
422
  {
418
- className: "absolute inset-0 z-[1]",
419
423
  style: {
424
+ position: "absolute",
425
+ inset: 0,
426
+ zIndex: 1,
420
427
  background: d
421
428
  }
422
429
  }
423
430
  ),
424
- /* @__PURE__ */ t.jsx("div", { className: "relative z-[2]", children: s })
431
+ /* @__PURE__ */ t.jsx("div", { style: { position: "relative", zIndex: 2 }, children: s })
425
432
  ]
426
433
  }
427
434
  )
package/dist/index.umd.js CHANGED
@@ -1,9 +1,9 @@
1
- (function(c,m){typeof exports=="object"&&typeof module<"u"?m(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],m):(c=typeof globalThis<"u"?globalThis:c||self,m(c.LiquidGlass={},c.React))})(this,(function(c,m){"use strict";var h={exports:{}},_={};var C;function q(){if(C)return _;C=1;var o=Symbol.for("react.transitional.element"),f=Symbol.for("react.fragment");function u(p,i,l){var d=null;if(l!==void 0&&(d=""+l),i.key!==void 0&&(d=""+i.key),"key"in i){l={};for(var b in i)b!=="key"&&(l[b]=i[b])}else l=i;return i=l.ref,{$$typeof:o,type:p,key:d,ref:i!==void 0?i:null,props:l}}return _.Fragment=f,_.jsx=u,_.jsxs=u,_}var x={};var F;function z(){return F||(F=1,process.env.NODE_ENV!=="production"&&(function(){function o(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ie?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case k:return"Fragment";case K:return"Profiler";case Q:return"StrictMode";case ne:return"Suspense";case ae:return"SuspenseList";case oe:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case Z:return"Portal";case re:return e.displayName||"Context";case ee:return(e._context.displayName||"Context")+".Consumer";case te:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case se:return r=e.displayName||null,r!==null?r:o(e.type)||"Memo";case w:r=e._payload,e=e._init;try{return o(e(r))}catch{}}return null}function f(e){return""+e}function u(e){try{f(e);var r=!1}catch{r=!0}if(r){r=console;var n=r.error,a=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return n.call(r,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",a),f(e)}}function p(e){if(e===k)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===w)return"<...>";try{var r=o(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function i(){var e=O.A;return e===null?null:e.getOwner()}function l(){return Error("react-stack-top-frame")}function d(e){if(D.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function b(e,r){function n(){G||(G=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",r))}n.isReactWarning=!0,Object.defineProperty(e,"key",{get:n,configurable:!0})}function j(){var e=o(this.type);return M[e]||(M[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function y(e,r,n,a,g,P){var s=n.ref;return e={$$typeof:L,type:e,key:r,props:n,_owner:a},(s!==void 0?s:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:j}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:g}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:P}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function S(e,r,n,a,g,P){var s=r.children;if(s!==void 0)if(a)if(le(s)){for(a=0;a<s.length;a++)E(s[a]);Object.freeze&&Object.freeze(s)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else E(s);if(D.call(r,"key")){s=o(e);var v=Object.keys(r).filter(function(ue){return ue!=="key"});a=0<v.length?"{key: someKey, "+v.join(": ..., ")+": ...}":"{key: someKey}",U[s+a]||(v=0<v.length?"{"+v.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
1
+ (function(c,p){typeof exports=="object"&&typeof module<"u"?p(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],p):(c=typeof globalThis<"u"?globalThis:c||self,p(c.LiquidGlass={},c.React))})(this,(function(c,p){"use strict";var h={exports:{}},x={};var N;function q(){if(N)return x;N=1;var s=Symbol.for("react.transitional.element"),f=Symbol.for("react.fragment");function u(m,i,l){var d=null;if(l!==void 0&&(d=""+l),i.key!==void 0&&(d=""+i.key),"key"in i){l={};for(var b in i)b!=="key"&&(l[b]=i[b])}else l=i;return i=l.ref,{$$typeof:s,type:m,key:d,ref:i!==void 0?i:null,props:l}}return x.Fragment=f,x.jsx=u,x.jsxs=u,x}var _={};var F;function z(){return F||(F=1,process.env.NODE_ENV!=="production"&&(function(){function s(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ie?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case k:return"Fragment";case K:return"Profiler";case Q:return"StrictMode";case ne:return"Suspense";case ae:return"SuspenseList";case se:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case Z:return"Portal";case re:return e.displayName||"Context";case ee:return(e._context.displayName||"Context")+".Consumer";case te:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case oe:return r=e.displayName||null,r!==null?r:s(e.type)||"Memo";case w:r=e._payload,e=e._init;try{return s(e(r))}catch{}}return null}function f(e){return""+e}function u(e){try{f(e);var r=!1}catch{r=!0}if(r){r=console;var n=r.error,a=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return n.call(r,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",a),f(e)}}function m(e){if(e===k)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===w)return"<...>";try{var r=s(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function i(){var e=O.A;return e===null?null:e.getOwner()}function l(){return Error("react-stack-top-frame")}function d(e){if(D.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function b(e,r){function n(){G||(G=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",r))}n.isReactWarning=!0,Object.defineProperty(e,"key",{get:n,configurable:!0})}function y(){var e=s(this.type);return M[e]||(M[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function j(e,r,n,a,g,P){var o=n.ref;return e={$$typeof:L,type:e,key:r,props:n,_owner:a},(o!==void 0?o:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:y}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:g}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:P}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function S(e,r,n,a,g,P){var o=r.children;if(o!==void 0)if(a)if(le(o)){for(a=0;a<o.length;a++)E(o[a]);Object.freeze&&Object.freeze(o)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else E(o);if(D.call(r,"key")){o=s(e);var v=Object.keys(r).filter(function(ue){return ue!=="key"});a=0<v.length?"{key: someKey, "+v.join(": ..., ")+": ...}":"{key: someKey}",U[o+a]||(v=0<v.length?"{"+v.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
2
2
  let props = %s;
3
3
  <%s {...props} />
4
4
  React keys must be passed directly to JSX without using spread:
5
5
  let props = %s;
6
- <%s key={someKey} {...props} />`,a,s,v,s),U[s+a]=!0)}if(s=null,n!==void 0&&(u(n),s=""+n),d(r)&&(u(r.key),s=""+r.key),"key"in r){n={};for(var N in r)N!=="key"&&(n[N]=r[N])}else n=r;return s&&b(n,typeof e=="function"?e.displayName||e.name||"Unknown":e),y(e,s,n,i(),g,P)}function E(e){R(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===w&&(e._payload.status==="fulfilled"?R(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function R(e){return typeof e=="object"&&e!==null&&e.$$typeof===L}var T=m,L=Symbol.for("react.transitional.element"),Z=Symbol.for("react.portal"),k=Symbol.for("react.fragment"),Q=Symbol.for("react.strict_mode"),K=Symbol.for("react.profiler"),ee=Symbol.for("react.consumer"),re=Symbol.for("react.context"),te=Symbol.for("react.forward_ref"),ne=Symbol.for("react.suspense"),ae=Symbol.for("react.suspense_list"),se=Symbol.for("react.memo"),w=Symbol.for("react.lazy"),oe=Symbol.for("react.activity"),ie=Symbol.for("react.client.reference"),O=T.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,D=Object.prototype.hasOwnProperty,le=Array.isArray,A=console.createTask?console.createTask:function(){return null};T={react_stack_bottom_frame:function(e){return e()}};var G,M={},$=T.react_stack_bottom_frame.bind(T,l)(),W=A(p(l)),U={};x.Fragment=k,x.jsx=function(e,r,n){var a=1e4>O.recentlyCreatedOwnerStacks++;return S(e,r,n,!1,a?Error("react-stack-top-frame"):$,a?A(p(e)):W)},x.jsxs=function(e,r,n){var a=1e4>O.recentlyCreatedOwnerStacks++;return S(e,r,n,!0,a?Error("react-stack-top-frame"):$,a?A(p(e)):W)}})()),x}var I;function B(){return I||(I=1,process.env.NODE_ENV==="production"?h.exports=q():h.exports=z()),h.exports}var t=B();const J=/iPad|iPhone|iPod/,V=/^((?!chrome|android).)*safari/i,X=()=>{if(typeof window>"u")return!1;const o=window.navigator.userAgent,f=J.test(o),u=V.test(o);return f||u},Y=()=>{const[o]=m.useState(()=>X());return{useSimplifiedFilter:o}},H=({children:o,className:f="",backdropBlur:u=2,tintColor:p="rgba(255, 255, 255, .2)",displacementScale:i=150,turbulenceBaseFrequency:l="0.008 0.008",turbulenceSeed:d=1.5,as:b="div",style:j,...y})=>{const E=`liquid-glass-${m.useId().replace(/:/g,"-")}`,{useSimplifiedFilter:R}=Y();return t.jsxs(t.Fragment,{children:[t.jsx("svg",{style:{display:"none"},suppressHydrationWarning:!0,children:R?t.jsxs("filter",{id:E,x:"-20%",y:"-20%",width:"140%",height:"140%",filterUnits:"objectBoundingBox",children:[t.jsx("feTurbulence",{type:"fractalNoise",baseFrequency:l,numOctaves:2,seed:d,result:"turbulence"}),t.jsx("feGaussianBlur",{in:"turbulence",stdDeviation:"2",result:"blur"}),t.jsx("feColorMatrix",{in:"blur",type:"matrix",values:`1 0 0 0 0
6
+ <%s key={someKey} {...props} />`,a,o,v,o),U[o+a]=!0)}if(o=null,n!==void 0&&(u(n),o=""+n),d(r)&&(u(r.key),o=""+r.key),"key"in r){n={};for(var C in r)C!=="key"&&(n[C]=r[C])}else n=r;return o&&b(n,typeof e=="function"?e.displayName||e.name||"Unknown":e),j(e,o,n,i(),g,P)}function E(e){R(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===w&&(e._payload.status==="fulfilled"?R(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function R(e){return typeof e=="object"&&e!==null&&e.$$typeof===L}var T=p,L=Symbol.for("react.transitional.element"),Z=Symbol.for("react.portal"),k=Symbol.for("react.fragment"),Q=Symbol.for("react.strict_mode"),K=Symbol.for("react.profiler"),ee=Symbol.for("react.consumer"),re=Symbol.for("react.context"),te=Symbol.for("react.forward_ref"),ne=Symbol.for("react.suspense"),ae=Symbol.for("react.suspense_list"),oe=Symbol.for("react.memo"),w=Symbol.for("react.lazy"),se=Symbol.for("react.activity"),ie=Symbol.for("react.client.reference"),O=T.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,D=Object.prototype.hasOwnProperty,le=Array.isArray,A=console.createTask?console.createTask:function(){return null};T={react_stack_bottom_frame:function(e){return e()}};var G,M={},$=T.react_stack_bottom_frame.bind(T,l)(),W=A(m(l)),U={};_.Fragment=k,_.jsx=function(e,r,n){var a=1e4>O.recentlyCreatedOwnerStacks++;return S(e,r,n,!1,a?Error("react-stack-top-frame"):$,a?A(m(e)):W)},_.jsxs=function(e,r,n){var a=1e4>O.recentlyCreatedOwnerStacks++;return S(e,r,n,!0,a?Error("react-stack-top-frame"):$,a?A(m(e)):W)}})()),_}var I;function B(){return I||(I=1,process.env.NODE_ENV==="production"?h.exports=q():h.exports=z()),h.exports}var t=B();const J=/iPad|iPhone|iPod/,V=/^((?!chrome|android).)*safari/i,X=()=>{if(typeof window>"u")return!1;const s=window.navigator.userAgent,f=J.test(s),u=V.test(s);return f||u},Y=()=>{const[s]=p.useState(()=>X());return{useSimplifiedFilter:s}},H=({children:s,className:f="",backdropBlur:u=2,tintColor:m="rgba(255, 255, 255, .2)",displacementScale:i=150,turbulenceBaseFrequency:l="0.008 0.008",turbulenceSeed:d=1.5,as:b="div",style:y,...j})=>{const E=`liquid-glass-${p.useId().replace(/:/g,"-")}`,{useSimplifiedFilter:R}=Y();return t.jsxs(t.Fragment,{children:[t.jsx("svg",{style:{display:"none"},suppressHydrationWarning:!0,children:R?t.jsxs("filter",{id:E,x:"-20%",y:"-20%",width:"140%",height:"140%",filterUnits:"objectBoundingBox",children:[t.jsx("feTurbulence",{type:"fractalNoise",baseFrequency:l,numOctaves:2,seed:d,result:"turbulence"}),t.jsx("feGaussianBlur",{in:"turbulence",stdDeviation:"2",result:"blur"}),t.jsx("feColorMatrix",{in:"blur",type:"matrix",values:`1 0 0 0 0
7
7
  0 1 0 0 0
8
8
  0 0 1 0 0
9
- 0 0 0 0.15 0`,result:"transparency"}),t.jsx("feBlend",{in:"SourceGraphic",in2:"transparency",mode:"normal"})]}):t.jsxs("filter",{id:E,x:"0%",y:"0%",width:"100%",height:"100%",filterUnits:"objectBoundingBox",children:[t.jsx("feTurbulence",{type:"fractalNoise",baseFrequency:l,numOctaves:1,seed:d,result:"turbulence"}),t.jsxs("feComponentTransfer",{in:"turbulence",result:"mapped",children:[t.jsx("feFuncR",{type:"gamma",amplitude:1,exponent:10,offset:.5}),t.jsx("feFuncG",{type:"gamma",amplitude:0,exponent:1,offset:0}),t.jsx("feFuncB",{type:"gamma",amplitude:0,exponent:1,offset:.5})]}),t.jsx("feGaussianBlur",{in:"turbulence",stdDeviation:3,result:"softMap"}),t.jsx("feSpecularLighting",{in:"softMap",surfaceScale:5,specularConstant:1,specularExponent:100,lightingColor:"white",result:"specLight",children:t.jsx("fePointLight",{x:-200,y:-200,z:300})}),t.jsx("feComposite",{in:"specLight",operator:"arithmetic",k1:0,k2:1,k3:1,k4:0,result:"litImage"}),t.jsx("feDisplacementMap",{in:"SourceGraphic",in2:"softMap",scale:i,xChannelSelector:"R",yChannelSelector:"G"})]})}),t.jsxs(b,{className:`relative overflow-hidden ${f}`,style:{boxShadow:"0 6px 6px rgba(0, 0, 0, 0.2), 0 0 20px rgba(0, 0, 0, 0.1)",...j},...y,children:[t.jsx("div",{className:"absolute inset-0 z-0 overflow-hidden",style:{backdropFilter:`blur(${u}px)`,WebkitBackdropFilter:`blur(${u}px)`,filter:`url(#${E})`,isolation:"isolate",...R&&{transform:"translateZ(0)",willChange:"transform"}}}),t.jsx("div",{className:"absolute inset-0 z-[1]",style:{background:p}}),t.jsx("div",{className:"relative z-[2]",children:o})]})]})};c.LiquidGlass=H,c.useBrowserDetection=Y,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
9
+ 0 0 0 0.15 0`,result:"transparency"}),t.jsx("feBlend",{in:"SourceGraphic",in2:"transparency",mode:"normal"})]}):t.jsxs("filter",{id:E,x:"0%",y:"0%",width:"100%",height:"100%",filterUnits:"objectBoundingBox",children:[t.jsx("feTurbulence",{type:"fractalNoise",baseFrequency:l,numOctaves:1,seed:d,result:"turbulence"}),t.jsxs("feComponentTransfer",{in:"turbulence",result:"mapped",children:[t.jsx("feFuncR",{type:"gamma",amplitude:1,exponent:10,offset:.5}),t.jsx("feFuncG",{type:"gamma",amplitude:0,exponent:1,offset:0}),t.jsx("feFuncB",{type:"gamma",amplitude:0,exponent:1,offset:.5})]}),t.jsx("feGaussianBlur",{in:"turbulence",stdDeviation:3,result:"softMap"}),t.jsx("feSpecularLighting",{in:"softMap",surfaceScale:5,specularConstant:1,specularExponent:100,lightingColor:"white",result:"specLight",children:t.jsx("fePointLight",{x:-200,y:-200,z:300})}),t.jsx("feComposite",{in:"specLight",operator:"arithmetic",k1:0,k2:1,k3:1,k4:0,result:"litImage"}),t.jsx("feDisplacementMap",{in:"SourceGraphic",in2:"softMap",scale:i,xChannelSelector:"R",yChannelSelector:"G"})]})}),t.jsxs(b,{className:f,style:{position:"relative",overflow:"hidden",boxShadow:"0 6px 6px rgba(0, 0, 0, 0.2), 0 0 20px rgba(0, 0, 0, 0.1)",...y},...j,children:[t.jsx("div",{style:{position:"absolute",inset:0,zIndex:0,overflow:"hidden",backdropFilter:`blur(${u}px)`,WebkitBackdropFilter:`blur(${u}px)`,filter:`url(#${E})`,isolation:"isolate",...R&&{transform:"translateZ(0)",willChange:"transform"}}}),t.jsx("div",{style:{position:"absolute",inset:0,zIndex:1,background:m}}),t.jsx("div",{style:{position:"relative",zIndex:2},children:s})]})]})};c.LiquidGlass=H,c.useBrowserDetection=Y,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@creativoma/liquid-glass",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "A React wrapper component with liquid frosted glass effect using TailwindCSS",
6
6
  "main": "./dist/index.js",
@@ -32,6 +32,9 @@
32
32
  "build:lib": "tsc && vite build --config vite.config.lib.ts",
33
33
  "lint": "eslint . --ext .ts,.tsx",
34
34
  "format": "prettier --write .",
35
+ "test": "vitest",
36
+ "test:run": "vitest run",
37
+ "test:coverage": "vitest run --coverage",
35
38
  "prepublishOnly": "npm run build:lib"
36
39
  },
37
40
  "keywords": [
@@ -57,17 +60,21 @@
57
60
  "react-dom": ">=18.0.0"
58
61
  },
59
62
  "devDependencies": {
60
- "@eslint/js": "^10.0.1",
63
+ "@eslint/js": "^9.39.2",
61
64
  "@tailwindcss/postcss": "^4.2.1",
65
+ "@testing-library/jest-dom": "^6.9.1",
66
+ "@testing-library/react": "^16.3.2",
62
67
  "@types/node": "^25.3.5",
63
68
  "@types/react": "^19.2.14",
64
69
  "@types/react-dom": "^19.2.3",
65
70
  "@vitejs/plugin-react": "^5.1.4",
71
+ "@vitest/coverage-v8": "^4.0.18",
66
72
  "autoprefixer": "^10.4.27",
67
- "eslint": "^10.0.2",
73
+ "eslint": "^9.39.2",
68
74
  "eslint-plugin-react-hooks": "^7.0.1",
69
75
  "eslint-plugin-react-refresh": "^0.5.2",
70
76
  "globals": "^17.4.0",
77
+ "jsdom": "^28.1.0",
71
78
  "postcss": "^8.5.8",
72
79
  "prettier": "^3.8.1",
73
80
  "prettier-plugin-tailwindcss": "^0.7.2",
@@ -77,7 +84,8 @@
77
84
  "typescript": "^5.9.3",
78
85
  "typescript-eslint": "^8.56.1",
79
86
  "vite": "^7.3.1",
80
- "vite-plugin-dts": "^4.5.4"
87
+ "vite-plugin-dts": "^4.5.4",
88
+ "vitest": "^4.0.18"
81
89
  },
82
90
  "publishConfig": {
83
91
  "registry": "https://registry.npmjs.org/",