glasskit-js 1.0.1 → 1.0.2

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/LiquidGlass.mjs CHANGED
@@ -19,7 +19,7 @@ import LG from "./liquid-glass.js";
19
19
  const GLASS_KEYS = [
20
20
  "mode", "frost", "refraction", "depth", "dispersion", "splay",
21
21
  "lightAngle", "lightIntensity", "curvature", "convexity",
22
- "tint", "tintOpacity", "sheen", "sheenColor", "saturate", "brightness", "radius", "background",
22
+ "tint", "tintOpacity", "sheen", "sheenColor", "saturate", "brightness", "shadow", "radius", "background",
23
23
  ];
24
24
 
25
25
  export default function LiquidGlass({ as: Tag = "div", children, ...props }) {
package/liquid-glass.d.ts CHANGED
@@ -43,6 +43,8 @@ export interface LiquidGlassOptions {
43
43
  saturate?: number;
44
44
  /** Backdrop brightness (css mode). @default 1.04 */
45
45
  brightness?: number;
46
+ /** Outer drop shadow as any CSS box-shadow value; "none" or "" removes it. The inner light border/bezel are controlled by `lightIntensity`. @default "0 8px 30px rgba(0,0,0,0.18)" */
47
+ shadow?: string;
46
48
  /** Override corner radius (px). null = read element's border-radius. @default null */
47
49
  radius?: number | null;
48
50
  /** Element or selector to refract. Required for `svg-clone` and `webgl`. */
package/liquid-glass.js CHANGED
@@ -42,6 +42,7 @@
42
42
  sheenColor: '255,255,255', // "r,g,b" — recolor the gloss
43
43
  saturate: 1.4,
44
44
  brightness: 1.04,
45
+ shadow: '0 8px 30px rgba(0,0,0,0.18)', // outer drop shadow; 'none'/'' removes it, or pass any CSS box-shadow
45
46
  radius: null, // null = read element border-radius
46
47
  background: null // Element|selector — required for 'svg-clone' & 'webgl'
47
48
  };
@@ -58,6 +59,11 @@
58
59
  function clamp8(v) { return v < 0 ? 0 : v > 255 ? 255 : Math.round(v); }
59
60
  // only ever emit a clean "r,g,b" triplet into inline CSS — blocks url()/expression smuggling
60
61
  function safeRGB(v) { return (typeof v === 'string' && /^\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*$/.test(v)) ? v.replace(/\s+/g, '') : '255,255,255'; }
62
+ // allow only box-shadow-shaped CSS (lengths/colors); reject url()/expression/extra declarations
63
+ function safeShadow(v) {
64
+ if (typeof v !== 'string' || !v || v === 'none') return '';
65
+ return /url\(|expression|javascript:|[;{}<>]/i.test(v) ? '' : v;
66
+ }
61
67
  function num(v, d) { var n = parseFloat(v); return isFinite(n) ? n : d; }
62
68
  function resolveEl(x) { return typeof x === 'string' ? document.querySelector(x) : x; }
63
69
  function readRadius(el) { return parseFloat(getComputedStyle(el).borderRadius) || 0; }
@@ -251,11 +257,13 @@
251
257
  overlay.style.background = sh <= 0 ? 'none' :
252
258
  'linear-gradient(' + (num(o.lightAngle, -45) + 90) + 'deg,rgba(' + sc + ',' + (0.6 * sh).toFixed(3) +
253
259
  ') 0%,rgba(' + sc + ',0) 30%,rgba(' + sc + ',0) 70%,rgba(' + sc + ',' + (0.14 * sh).toFixed(3) + ') 100%)';
254
- overlay.style.boxShadow =
260
+ // inset light border + bezel (scale with lightIntensity) and a separately controllable outer drop shadow
261
+ var insets =
255
262
  'inset 0 0 0 1px rgba(255,255,255,' + (0.30 * li) + '),' +
256
263
  'inset ' + (Math.cos(a) * 2).toFixed(1) + 'px ' + (Math.sin(a) * 2).toFixed(1) + 'px 2px rgba(255,255,255,' + (0.5 * li) + '),' +
257
- 'inset ' + (-Math.cos(a) * 2).toFixed(1) + 'px ' + (-Math.sin(a) * 2).toFixed(1) + 'px 6px rgba(0,0,0,.15),' +
258
- '0 8px 30px rgba(0,0,0,.18)';
264
+ 'inset ' + (-Math.cos(a) * 2).toFixed(1) + 'px ' + (-Math.sin(a) * 2).toFixed(1) + 'px 6px rgba(0,0,0,.15)';
265
+ var drop = safeShadow(o.shadow);
266
+ overlay.style.boxShadow = drop ? insets + ',' + drop : insets;
259
267
  }
260
268
 
261
269
  /* ------------------------------ WebGL ------------------------------ */
@@ -389,7 +397,7 @@
389
397
  /* ===================== <glass-kit> web component ===================== */
390
398
  var ATTRS = ['mode', 'frost', 'refraction', 'depth', 'dispersion', 'splay', 'light-angle',
391
399
  'light-intensity', 'curvature', 'convexity', 'tint', 'tint-opacity', 'sheen', 'sheen-color',
392
- 'radius', 'background'];
400
+ 'shadow', 'radius', 'background'];
393
401
  function camel(s) { return s.replace(/-([a-z])/g, function (_, c) { return c.toUpperCase(); }); }
394
402
  function defineElement() {
395
403
  if (typeof customElements === 'undefined' || customElements.get('glass-kit')) return;
@@ -399,7 +407,7 @@
399
407
  ATTRS.forEach(function (a) {
400
408
  if (!node.hasAttribute(a)) return;
401
409
  var v = node.getAttribute(a), key = camel(a);
402
- opts[key] = (a === 'mode' || a === 'tint' || a === 'sheen-color' || a === 'background') ? v : parseFloat(v);
410
+ opts[key] = (a === 'mode' || a === 'tint' || a === 'sheen-color' || a === 'shadow' || a === 'background') ? v : parseFloat(v);
403
411
  });
404
412
  return opts;
405
413
  }
@@ -416,5 +424,5 @@
416
424
  }
417
425
  if (typeof window !== 'undefined') { if (document.readyState !== 'loading') defineElement(); else document.addEventListener('DOMContentLoaded', defineElement); }
418
426
 
419
- return { apply: apply, defineElement: defineElement, isChromium: isChromium, pickMode: pickMode, DEFAULTS: DEFAULTS, version: '1.0.1' };
427
+ return { apply: apply, defineElement: defineElement, isChromium: isChromium, pickMode: pickMode, DEFAULTS: DEFAULTS, version: '1.0.2' };
420
428
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glasskit-js",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Drop-in Apple/Figma 'Liquid Glass' for any element — switch between pure CSS, SVG displacement (live backdrop), cross-browser clone-mode, or WebGL. Real refraction, chromatic aberration, specular highlight. Zero dependencies. Class + <liquid-glass> web component.",
5
5
  "keywords": [
6
6
  "liquid-glass",