@substrate-system/blur-hash 0.0.35 → 0.0.39

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.
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var decode_dimensions_exports = {};
21
+ __export(decode_dimensions_exports, {
22
+ decodeDimensions: () => decodeDimensions
23
+ });
24
+ module.exports = __toCommonJS(decode_dimensions_exports);
25
+ function decodeDimensions(width, height, cap = 32) {
26
+ const longEdge = Math.max(width, height);
27
+ if (longEdge <= cap) {
28
+ return { width, height };
29
+ }
30
+ const scale = cap / longEdge;
31
+ return {
32
+ width: Math.max(1, Math.round(width * scale)),
33
+ height: Math.max(1, Math.round(height * scale))
34
+ };
35
+ }
36
+ __name(decodeDimensions, "decodeDimensions");
37
+ //# sourceMappingURL=decode-dimensions.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/decode-dimensions.ts"],
4
+ "sourcesContent": ["/**\n * Compute the resolution to decode a BlurHash placeholder at.\n *\n * A placeholder is a low-frequency blur, and decode cost is\n * O(width * height * componentsX * componentsY). Decoding above a small\n * size wastes work with no visible benefit, because the canvas is stretched\n * to fill its host via CSS (`blur-hash canvas { width:100%; height:100% }`).\n *\n * This caps the long edge to `cap` pixels, preserves the aspect ratio, floors\n * each edge at 1px, and never upscales a source that is already small.\n *\n * @param width The layout/source width in pixels.\n * @param height The layout/source height in pixels.\n * @param cap Maximum pixels on the long edge. Default 32.\n * @returns The decode dimensions to pass to `decode` and `createImageData`.\n */\nexport function decodeDimensions (\n width:number,\n height:number,\n cap:number = 32\n):{ width:number; height:number } {\n const longEdge = Math.max(width, height)\n\n // Never upscale: a source at or below the cap decodes as-is.\n if (longEdge <= cap) {\n return { width, height }\n }\n\n const scale = cap / longEdge\n return {\n width: Math.max(1, Math.round(width * scale)),\n height: Math.max(1, Math.round(height * scale))\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBO,SAAS,iBACZ,OACA,QACA,MAAa,IACiB;AAC9B,QAAM,WAAW,KAAK,IAAI,OAAO,MAAM;AAGvC,MAAI,YAAY,KAAK;AACjB,WAAO,EAAE,OAAO,OAAO;AAAA,EAC3B;AAEA,QAAM,QAAQ,MAAM;AACpB,SAAO;AAAA,IACH,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,KAAK,CAAC;AAAA,IAC5C,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,KAAK,CAAC;AAAA,EAClD;AACJ;AAjBgB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,18 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ function decodeDimensions(width, height, cap = 32) {
4
+ const longEdge = Math.max(width, height);
5
+ if (longEdge <= cap) {
6
+ return { width, height };
7
+ }
8
+ const scale = cap / longEdge;
9
+ return {
10
+ width: Math.max(1, Math.round(width * scale)),
11
+ height: Math.max(1, Math.round(height * scale))
12
+ };
13
+ }
14
+ __name(decodeDimensions, "decodeDimensions");
15
+ export {
16
+ decodeDimensions
17
+ };
18
+ //# sourceMappingURL=decode-dimensions.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/decode-dimensions.ts"],
4
+ "sourcesContent": ["/**\n * Compute the resolution to decode a BlurHash placeholder at.\n *\n * A placeholder is a low-frequency blur, and decode cost is\n * O(width * height * componentsX * componentsY). Decoding above a small\n * size wastes work with no visible benefit, because the canvas is stretched\n * to fill its host via CSS (`blur-hash canvas { width:100%; height:100% }`).\n *\n * This caps the long edge to `cap` pixels, preserves the aspect ratio, floors\n * each edge at 1px, and never upscales a source that is already small.\n *\n * @param width The layout/source width in pixels.\n * @param height The layout/source height in pixels.\n * @param cap Maximum pixels on the long edge. Default 32.\n * @returns The decode dimensions to pass to `decode` and `createImageData`.\n */\nexport function decodeDimensions (\n width:number,\n height:number,\n cap:number = 32\n):{ width:number; height:number } {\n const longEdge = Math.max(width, height)\n\n // Never upscale: a source at or below the cap decodes as-is.\n if (longEdge <= cap) {\n return { width, height }\n }\n\n const scale = cap / longEdge\n return {\n width: Math.max(1, Math.round(width * scale)),\n height: Math.max(1, Math.round(height * scale))\n }\n}\n"],
5
+ "mappings": ";;AAgBO,SAAS,iBACZ,OACA,QACA,MAAa,IACiB;AAC9B,QAAM,WAAW,KAAK,IAAI,OAAO,MAAM;AAGvC,MAAI,YAAY,KAAK;AACjB,WAAO,EAAE,OAAO,OAAO;AAAA,EAC3B;AAEA,QAAM,QAAQ,MAAM;AACpB,SAAO;AAAA,IACH,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,KAAK,CAAC;AAAA,IAC5C,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,KAAK,CAAC;AAAA,EAClD;AACJ;AAjBgB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ var o=Object.defineProperty;var m=(n,e)=>o(n,"name",{value:e,configurable:!0});function b(n,e,r=32){let t=Math.max(n,e);if(t<=r)return{width:n,height:e};let u=r/t;return{width:Math.max(1,Math.round(n*u)),height:Math.max(1,Math.round(e*u))}}m(b,"decodeDimensions");export{b as decodeDimensions};
2
+ //# sourceMappingURL=decode-dimensions.min.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/decode-dimensions.ts"],
4
+ "sourcesContent": ["/**\n * Compute the resolution to decode a BlurHash placeholder at.\n *\n * A placeholder is a low-frequency blur, and decode cost is\n * O(width * height * componentsX * componentsY). Decoding above a small\n * size wastes work with no visible benefit, because the canvas is stretched\n * to fill its host via CSS (`blur-hash canvas { width:100%; height:100% }`).\n *\n * This caps the long edge to `cap` pixels, preserves the aspect ratio, floors\n * each edge at 1px, and never upscales a source that is already small.\n *\n * @param width The layout/source width in pixels.\n * @param height The layout/source height in pixels.\n * @param cap Maximum pixels on the long edge. Default 32.\n * @returns The decode dimensions to pass to `decode` and `createImageData`.\n */\nexport function decodeDimensions (\n width:number,\n height:number,\n cap:number = 32\n):{ width:number; height:number } {\n const longEdge = Math.max(width, height)\n\n // Never upscale: a source at or below the cap decodes as-is.\n if (longEdge <= cap) {\n return { width, height }\n }\n\n const scale = cap / longEdge\n return {\n width: Math.max(1, Math.round(width * scale)),\n height: Math.max(1, Math.round(height * scale))\n }\n}\n"],
5
+ "mappings": "+EAgBO,SAASA,EACZC,EACAC,EACAC,EAAa,GACiB,CAC9B,IAAMC,EAAW,KAAK,IAAIH,EAAOC,CAAM,EAGvC,GAAIE,GAAYD,EACZ,MAAO,CAAE,MAAAF,EAAO,OAAAC,CAAO,EAG3B,IAAMG,EAAQF,EAAMC,EACpB,MAAO,CACH,MAAO,KAAK,IAAI,EAAG,KAAK,MAAMH,EAAQI,CAAK,CAAC,EAC5C,OAAQ,KAAK,IAAI,EAAG,KAAK,MAAMH,EAASG,CAAK,CAAC,CAClD,CACJ,CAjBgBC,EAAAN,EAAA",
6
+ "names": ["decodeDimensions", "width", "height", "cap", "longEdge", "scale", "__name"]
7
+ }
package/dist/html.cjs CHANGED
@@ -24,6 +24,7 @@ __export(html_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(html_exports);
26
26
  var import_attributes = require("@substrate-system/web-component/attributes");
27
+ var import_decode_dimensions = require("./decode-dimensions.js");
27
28
  function render(attrs) {
28
29
  const {
29
30
  width,
@@ -38,13 +39,14 @@ function render(attrs) {
38
39
  src
39
40
  } = attrs;
40
41
  if (!placeholder) throw new Error("not placeholder");
42
+ const decodeWidth = typeof width === "string" ? parseInt(width, 10) : width;
43
+ const decodeHeight = typeof height === "string" ? parseInt(height, 10) : height;
44
+ const decodeSize = (0, import_decode_dimensions.decodeDimensions)(decodeWidth, decodeHeight);
41
45
  const htmlString = `<canvas
42
46
  alt="${alt}"
43
- width=${width}
44
- height=${height}
47
+ width=${decodeSize.width}
48
+ height=${decodeSize.height}
45
49
  class="blurry"
46
- width=${width}
47
- height=${height}
48
50
  ></canvas>
49
51
 
50
52
  <img class="blurry"
package/dist/html.cjs.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/html.ts"],
4
- "sourcesContent": ["import { toAttributes } from '@substrate-system/web-component/attributes'\nimport type { ImgAttrs } from './index.js'\n\nexport type SSRAttrs = ImgAttrs & { classes?:string }\n\nexport function render (attrs:SSRAttrs) {\n const {\n width,\n height,\n alt,\n contentVisibility,\n placeholder,\n decoding,\n loading,\n srcset,\n sizes,\n src\n } = attrs\n\n if (!placeholder) throw new Error('not placeholder')\n\n const htmlString = `<canvas\n alt=\"${alt}\"\n width=${width}\n height=${height}\n class=\"blurry\"\n width=${width}\n height=${height}\n ></canvas>\n\n <img class=\"blurry\"\n alt=\"${alt}\"\n content-visibility=\"${contentVisibility || 'auto'}\"\n decoding=\"${decoding || 'async'}\"\n loading=\"${loading || 'lazy'}\"\n ${srcset ? `srcset=\"${srcset}\"` : ''}\n ${sizes ? `sizes=\"${sizes}\"` : ''}\n src=\"${src}\"\n />`\n\n const attributeString = toAttributes(attrs)\n\n // running in node?\n return typeof window === 'undefined' ?\n `<blur-hash ${attributeString}>\n ${htmlString}\n </blur-hash>` :\n htmlString\n}\n\nexport const outerHTML = (attrs:SSRAttrs) => {\n return `<blur-hash>${render(attrs)}</blur-hash>`\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAA6B;AAKtB,SAAS,OAAQ,OAAgB;AACpC,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,IAAI;AAEJ,MAAI,CAAC,YAAa,OAAM,IAAI,MAAM,iBAAiB;AAEnD,QAAM,aAAa;AAAA,eACR,GAAG;AAAA,gBACF,KAAK;AAAA,iBACJ,MAAM;AAAA;AAAA,gBAEP,KAAK;AAAA,iBACJ,MAAM;AAAA;AAAA;AAAA;AAAA,eAIR,GAAG;AAAA,8BACY,qBAAqB,MAAM;AAAA,oBACrC,YAAY,OAAO;AAAA,mBACpB,WAAW,MAAM;AAAA,UAC1B,SAAS,WAAW,MAAM,MAAM,EAAE;AAAA,UAClC,QAAQ,UAAU,KAAK,MAAM,EAAE;AAAA,eAC1B,GAAG;AAAA;AAGd,QAAM,sBAAkB,gCAAa,KAAK;AAG1C,SAAO,OAAO,WAAW,cACrB,cAAc,eAAe;AAAA,cACvB,UAAU;AAAA,wBAEhB;AACR;AA3CgB;AA6CT,MAAM,YAAY,wBAAC,UAAmB;AACzC,SAAO,cAAc,OAAO,KAAK,CAAC;AACtC,GAFyB;",
4
+ "sourcesContent": ["import { toAttributes } from '@substrate-system/web-component/attributes'\nimport type { ImgAttrs } from './index.js'\nimport { decodeDimensions } from './decode-dimensions.js'\n\nexport type SSRAttrs = ImgAttrs & { classes?:string }\n\nexport function render (attrs:SSRAttrs) {\n const {\n width,\n height,\n alt,\n contentVisibility,\n placeholder,\n decoding,\n loading,\n srcset,\n sizes,\n src\n } = attrs\n\n if (!placeholder) throw new Error('not placeholder')\n\n const decodeWidth = typeof width === 'string' ? parseInt(width, 10) : width\n const decodeHeight = typeof height === 'string' ?\n parseInt(height, 10) :\n height\n const decodeSize = decodeDimensions(decodeWidth, decodeHeight)\n\n const htmlString = `<canvas\n alt=\"${alt}\"\n width=${decodeSize.width}\n height=${decodeSize.height}\n class=\"blurry\"\n ></canvas>\n\n <img class=\"blurry\"\n alt=\"${alt}\"\n content-visibility=\"${contentVisibility || 'auto'}\"\n decoding=\"${decoding || 'async'}\"\n loading=\"${loading || 'lazy'}\"\n ${srcset ? `srcset=\"${srcset}\"` : ''}\n ${sizes ? `sizes=\"${sizes}\"` : ''}\n src=\"${src}\"\n />`\n\n const attributeString = toAttributes(attrs)\n\n // running in node?\n return typeof window === 'undefined' ?\n `<blur-hash ${attributeString}>\n ${htmlString}\n </blur-hash>` :\n htmlString\n}\n\nexport const outerHTML = (attrs:SSRAttrs) => {\n return `<blur-hash>${render(attrs)}</blur-hash>`\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAA6B;AAE7B,+BAAiC;AAI1B,SAAS,OAAQ,OAAgB;AACpC,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,IAAI;AAEJ,MAAI,CAAC,YAAa,OAAM,IAAI,MAAM,iBAAiB;AAEnD,QAAM,cAAc,OAAO,UAAU,WAAW,SAAS,OAAO,EAAE,IAAI;AACtE,QAAM,eAAe,OAAO,WAAW,WACnC,SAAS,QAAQ,EAAE,IACnB;AACJ,QAAM,iBAAa,2CAAiB,aAAa,YAAY;AAE7D,QAAM,aAAa;AAAA,eACR,GAAG;AAAA,gBACF,WAAW,KAAK;AAAA,iBACf,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,eAKnB,GAAG;AAAA,8BACY,qBAAqB,MAAM;AAAA,oBACrC,YAAY,OAAO;AAAA,mBACpB,WAAW,MAAM;AAAA,UAC1B,SAAS,WAAW,MAAM,MAAM,EAAE;AAAA,UAClC,QAAQ,UAAU,KAAK,MAAM,EAAE;AAAA,eAC1B,GAAG;AAAA;AAGd,QAAM,sBAAkB,gCAAa,KAAK;AAG1C,SAAO,OAAO,WAAW,cACrB,cAAc,eAAe;AAAA,cACvB,UAAU;AAAA,wBAEhB;AACR;AA/CgB;AAiDT,MAAM,YAAY,wBAAC,UAAmB;AACzC,SAAO,cAAc,OAAO,KAAK,CAAC;AACtC,GAFyB;",
6
6
  "names": []
7
7
  }
package/dist/html.js CHANGED
@@ -1,6 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
  import { toAttributes } from "@substrate-system/web-component/attributes";
4
+ import { decodeDimensions } from "./decode-dimensions.js";
4
5
  function render(attrs) {
5
6
  const {
6
7
  width,
@@ -15,13 +16,14 @@ function render(attrs) {
15
16
  src
16
17
  } = attrs;
17
18
  if (!placeholder) throw new Error("not placeholder");
19
+ const decodeWidth = typeof width === "string" ? parseInt(width, 10) : width;
20
+ const decodeHeight = typeof height === "string" ? parseInt(height, 10) : height;
21
+ const decodeSize = decodeDimensions(decodeWidth, decodeHeight);
18
22
  const htmlString = `<canvas
19
23
  alt="${alt}"
20
- width=${width}
21
- height=${height}
24
+ width=${decodeSize.width}
25
+ height=${decodeSize.height}
22
26
  class="blurry"
23
- width=${width}
24
- height=${height}
25
27
  ></canvas>
26
28
 
27
29
  <img class="blurry"
package/dist/html.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/html.ts"],
4
- "sourcesContent": ["import { toAttributes } from '@substrate-system/web-component/attributes'\nimport type { ImgAttrs } from './index.js'\n\nexport type SSRAttrs = ImgAttrs & { classes?:string }\n\nexport function render (attrs:SSRAttrs) {\n const {\n width,\n height,\n alt,\n contentVisibility,\n placeholder,\n decoding,\n loading,\n srcset,\n sizes,\n src\n } = attrs\n\n if (!placeholder) throw new Error('not placeholder')\n\n const htmlString = `<canvas\n alt=\"${alt}\"\n width=${width}\n height=${height}\n class=\"blurry\"\n width=${width}\n height=${height}\n ></canvas>\n\n <img class=\"blurry\"\n alt=\"${alt}\"\n content-visibility=\"${contentVisibility || 'auto'}\"\n decoding=\"${decoding || 'async'}\"\n loading=\"${loading || 'lazy'}\"\n ${srcset ? `srcset=\"${srcset}\"` : ''}\n ${sizes ? `sizes=\"${sizes}\"` : ''}\n src=\"${src}\"\n />`\n\n const attributeString = toAttributes(attrs)\n\n // running in node?\n return typeof window === 'undefined' ?\n `<blur-hash ${attributeString}>\n ${htmlString}\n </blur-hash>` :\n htmlString\n}\n\nexport const outerHTML = (attrs:SSRAttrs) => {\n return `<blur-hash>${render(attrs)}</blur-hash>`\n}\n"],
5
- "mappings": ";;AAAA,SAAS,oBAAoB;AAKtB,SAAS,OAAQ,OAAgB;AACpC,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,IAAI;AAEJ,MAAI,CAAC,YAAa,OAAM,IAAI,MAAM,iBAAiB;AAEnD,QAAM,aAAa;AAAA,eACR,GAAG;AAAA,gBACF,KAAK;AAAA,iBACJ,MAAM;AAAA;AAAA,gBAEP,KAAK;AAAA,iBACJ,MAAM;AAAA;AAAA;AAAA;AAAA,eAIR,GAAG;AAAA,8BACY,qBAAqB,MAAM;AAAA,oBACrC,YAAY,OAAO;AAAA,mBACpB,WAAW,MAAM;AAAA,UAC1B,SAAS,WAAW,MAAM,MAAM,EAAE;AAAA,UAClC,QAAQ,UAAU,KAAK,MAAM,EAAE;AAAA,eAC1B,GAAG;AAAA;AAGd,QAAM,kBAAkB,aAAa,KAAK;AAG1C,SAAO,OAAO,WAAW,cACrB,cAAc,eAAe;AAAA,cACvB,UAAU;AAAA,wBAEhB;AACR;AA3CgB;AA6CT,MAAM,YAAY,wBAAC,UAAmB;AACzC,SAAO,cAAc,OAAO,KAAK,CAAC;AACtC,GAFyB;",
4
+ "sourcesContent": ["import { toAttributes } from '@substrate-system/web-component/attributes'\nimport type { ImgAttrs } from './index.js'\nimport { decodeDimensions } from './decode-dimensions.js'\n\nexport type SSRAttrs = ImgAttrs & { classes?:string }\n\nexport function render (attrs:SSRAttrs) {\n const {\n width,\n height,\n alt,\n contentVisibility,\n placeholder,\n decoding,\n loading,\n srcset,\n sizes,\n src\n } = attrs\n\n if (!placeholder) throw new Error('not placeholder')\n\n const decodeWidth = typeof width === 'string' ? parseInt(width, 10) : width\n const decodeHeight = typeof height === 'string' ?\n parseInt(height, 10) :\n height\n const decodeSize = decodeDimensions(decodeWidth, decodeHeight)\n\n const htmlString = `<canvas\n alt=\"${alt}\"\n width=${decodeSize.width}\n height=${decodeSize.height}\n class=\"blurry\"\n ></canvas>\n\n <img class=\"blurry\"\n alt=\"${alt}\"\n content-visibility=\"${contentVisibility || 'auto'}\"\n decoding=\"${decoding || 'async'}\"\n loading=\"${loading || 'lazy'}\"\n ${srcset ? `srcset=\"${srcset}\"` : ''}\n ${sizes ? `sizes=\"${sizes}\"` : ''}\n src=\"${src}\"\n />`\n\n const attributeString = toAttributes(attrs)\n\n // running in node?\n return typeof window === 'undefined' ?\n `<blur-hash ${attributeString}>\n ${htmlString}\n </blur-hash>` :\n htmlString\n}\n\nexport const outerHTML = (attrs:SSRAttrs) => {\n return `<blur-hash>${render(attrs)}</blur-hash>`\n}\n"],
5
+ "mappings": ";;AAAA,SAAS,oBAAoB;AAE7B,SAAS,wBAAwB;AAI1B,SAAS,OAAQ,OAAgB;AACpC,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,IAAI;AAEJ,MAAI,CAAC,YAAa,OAAM,IAAI,MAAM,iBAAiB;AAEnD,QAAM,cAAc,OAAO,UAAU,WAAW,SAAS,OAAO,EAAE,IAAI;AACtE,QAAM,eAAe,OAAO,WAAW,WACnC,SAAS,QAAQ,EAAE,IACnB;AACJ,QAAM,aAAa,iBAAiB,aAAa,YAAY;AAE7D,QAAM,aAAa;AAAA,eACR,GAAG;AAAA,gBACF,WAAW,KAAK;AAAA,iBACf,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,eAKnB,GAAG;AAAA,8BACY,qBAAqB,MAAM;AAAA,oBACrC,YAAY,OAAO;AAAA,mBACpB,WAAW,MAAM;AAAA,UAC1B,SAAS,WAAW,MAAM,MAAM,EAAE;AAAA,UAClC,QAAQ,UAAU,KAAK,MAAM,EAAE;AAAA,eAC1B,GAAG;AAAA;AAGd,QAAM,kBAAkB,aAAa,KAAK;AAG1C,SAAO,OAAO,WAAW,cACrB,cAAc,eAAe;AAAA,cACvB,UAAU;AAAA,wBAEhB;AACR;AA/CgB;AAiDT,MAAM,YAAY,wBAAC,UAAmB;AACzC,SAAO,cAAc,OAAO,KAAK,CAAC;AACtC,GAFyB;",
6
6
  "names": []
7
7
  }
package/dist/html.min.js CHANGED
@@ -1,21 +1,19 @@
1
- var f=Object.defineProperty;var n=(r,t)=>f(r,"name",{value:t,configurable:!0});var g=Object.defineProperty,p=n((r,t)=>g(r,"name",{value:t,configurable:!0}),"__name");function s(r){return Object.keys(r).reduce((t,i)=>{let e=r[i];return e?typeof e=="boolean"?e?(t+` ${i}`).trim():t:Array.isArray(e)?t+` ${i}="${e.join(" ")}"`:(t+` ${i}="${e}"`).trim():t},"")}n(s,"toAttributes");p(s,"toAttributes");function y(r){let{width:t,height:i,alt:e,contentVisibility:l,placeholder:$,decoding:h,loading:c,srcset:o,sizes:u,src:d}=r;if(!$)throw new Error("not placeholder");let a=`<canvas
1
+ var y=Object.defineProperty;var o=(r,t)=>y(r,"name",{value:t,configurable:!0});var A=Object.defineProperty,x=o((r,t)=>A(r,"name",{value:t,configurable:!0}),"__name");function s(r){return Object.keys(r).reduce((t,n)=>{let e=r[n];return e?typeof e=="boolean"?e?(t+` ${n}`).trim():t:Array.isArray(e)?t+` ${n}="${e.join(" ")}"`:(t+` ${n}="${e}"`).trim():t},"")}o(s,"toAttributes");x(s,"toAttributes");function h(r,t,n=32){let e=Math.max(r,t);if(e<=n)return{width:r,height:t};let i=n/e;return{width:Math.max(1,Math.round(r*i)),height:Math.max(1,Math.round(t*i))}}o(h,"decodeDimensions");function S(r){let{width:t,height:n,alt:e,contentVisibility:i,placeholder:l,decoding:m,loading:b,srcset:u,sizes:a,src:f}=r;if(!l)throw new Error("not placeholder");let $=typeof t=="string"?parseInt(t,10):t,g=typeof n=="string"?parseInt(n,10):n,d=h($,g),c=`<canvas
2
2
  alt="${e}"
3
- width=${t}
4
- height=${i}
3
+ width=${d.width}
4
+ height=${d.height}
5
5
  class="blurry"
6
- width=${t}
7
- height=${i}
8
6
  ></canvas>
9
7
 
10
8
  <img class="blurry"
11
9
  alt="${e}"
12
- content-visibility="${l||"auto"}"
13
- decoding="${h||"async"}"
14
- loading="${c||"lazy"}"
15
- ${o?`srcset="${o}"`:""}
16
- ${u?`sizes="${u}"`:""}
17
- src="${d}"
18
- />`,b=s(r);return typeof window>"u"?`<blur-hash ${b}>
19
- ${a}
20
- </blur-hash>`:a}n(y,"render");var v=n(r=>`<blur-hash>${y(r)}</blur-hash>`,"outerHTML");export{v as outerHTML,y as render};
10
+ content-visibility="${i||"auto"}"
11
+ decoding="${m||"async"}"
12
+ loading="${b||"lazy"}"
13
+ ${u?`srcset="${u}"`:""}
14
+ ${a?`sizes="${a}"`:""}
15
+ src="${f}"
16
+ />`,p=s(r);return typeof window>"u"?`<blur-hash ${p}>
17
+ ${c}
18
+ </blur-hash>`:c}o(S,"render");var R=o(r=>`<blur-hash>${S(r)}</blur-hash>`,"outerHTML");export{R as outerHTML,S as render};
21
19
  //# sourceMappingURL=html.min.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../node_modules/@substrate-system/web-component/src/attributes.ts", "../src/html.ts"],
4
- "sourcesContent": ["export type Attrs = Record<string, undefined|null|string|number|boolean|(string|number)[]>\n\n/**\n * Transform an object into an HTML attributes string. The object should be\n * like `{ attributeName: value }`.\n *\n * @param attrs An object for the attributes.\n * @returns {string} A string suitable for use as HTML attributes.\n */\nexport function toAttributes (attrs:Attrs):string {\n return Object.keys(attrs).reduce((acc, k) => {\n const value = attrs[k]\n if (!value) return acc\n\n if (typeof value === 'boolean') {\n if (value) return (acc + ` ${k}`).trim()\n return acc\n }\n\n if (Array.isArray(value)) {\n return (acc + ` ${k}=\"${value.join(' ')}\"`)\n }\n\n return (acc + ` ${k}=\"${value}\"`).trim()\n }, '')\n}\n", "import { toAttributes } from '@substrate-system/web-component/attributes'\nimport type { ImgAttrs } from './index.js'\n\nexport type SSRAttrs = ImgAttrs & { classes?:string }\n\nexport function render (attrs:SSRAttrs) {\n const {\n width,\n height,\n alt,\n contentVisibility,\n placeholder,\n decoding,\n loading,\n srcset,\n sizes,\n src\n } = attrs\n\n if (!placeholder) throw new Error('not placeholder')\n\n const htmlString = `<canvas\n alt=\"${alt}\"\n width=${width}\n height=${height}\n class=\"blurry\"\n width=${width}\n height=${height}\n ></canvas>\n\n <img class=\"blurry\"\n alt=\"${alt}\"\n content-visibility=\"${contentVisibility || 'auto'}\"\n decoding=\"${decoding || 'async'}\"\n loading=\"${loading || 'lazy'}\"\n ${srcset ? `srcset=\"${srcset}\"` : ''}\n ${sizes ? `sizes=\"${sizes}\"` : ''}\n src=\"${src}\"\n />`\n\n const attributeString = toAttributes(attrs)\n\n // running in node?\n return typeof window === 'undefined' ?\n `<blur-hash ${attributeString}>\n ${htmlString}\n </blur-hash>` :\n htmlString\n}\n\nexport const outerHTML = (attrs:SSRAttrs) => {\n return `<blur-hash>${render(attrs)}</blur-hash>`\n}\n"],
5
- "mappings": "sKASO,SAASA,EAAcC,EAAoB,CAC9C,OAAO,OAAO,KAAKA,CAAK,EAAE,OAAO,CAACC,EAAKC,IAAM,CACzC,IAAMC,EAAQH,EAAME,CAAC,EACrB,OAAKC,EAED,OAAOA,GAAU,UACbA,GAAeF,EAAM,IAAIC,CAAC,IAAI,KAAK,EAChCD,EAGP,MAAM,QAAQE,CAAK,EACXF,EAAM,IAAIC,CAAC,KAAKC,EAAM,KAAK,GAAG,CAAC,KAGnCF,EAAM,IAAIC,CAAC,KAAKC,CAAK,KAAK,KAAK,EAXpBF,CAYvB,EAAG,EAAE,CACT,CAhBgBG,EAAAL,EAAA,gBAAAK,EAAAL,EAAA,cAAA,ECJT,SAASM,EAAQC,EAAgB,CACpC,GAAM,CACF,MAAAC,EACA,OAAAC,EACA,IAAAC,EACA,kBAAAC,EACA,YAAAC,EACA,SAAAC,EACA,QAAAC,EACA,OAAAC,EACA,MAAAC,EACA,IAAAC,CACJ,EAAIV,EAEJ,GAAI,CAACK,EAAa,MAAM,IAAI,MAAM,iBAAiB,EAEnD,IAAMM,EAAa;AAAA,eACRR,CAAG;AAAA,gBACFF,CAAK;AAAA,iBACJC,CAAM;AAAA;AAAA,gBAEPD,CAAK;AAAA,iBACJC,CAAM;AAAA;AAAA;AAAA;AAAA,eAIRC,CAAG;AAAA,8BACYC,GAAqB,MAAM;AAAA,oBACrCE,GAAY,OAAO;AAAA,mBACpBC,GAAW,MAAM;AAAA,UAC1BC,EAAS,WAAWA,CAAM,IAAM,EAAE;AAAA,UAClCC,EAAQ,UAAUA,CAAK,IAAM,EAAE;AAAA,eAC1BC,CAAG;AAAA,QAGRE,EAAkBC,EAAab,CAAK,EAG1C,OAAO,OAAO,OAAW,IACrB,cAAcY,CAAe;AAAA,cACvBD,CAAU;AAAA,sBAEhBA,CACR,CA3CgBG,EAAAf,EAAA,UA6CT,IAAMgB,EAAYD,EAACd,GACf,cAAcD,EAAOC,CAAK,CAAC,eADb",
6
- "names": ["toAttributes", "attrs", "acc", "k", "value", "__name", "render", "attrs", "width", "height", "alt", "contentVisibility", "placeholder", "decoding", "loading", "srcset", "sizes", "src", "htmlString", "attributeString", "toAttributes", "__name", "outerHTML"]
3
+ "sources": ["../node_modules/@substrate-system/web-component/src/attributes.ts", "../src/decode-dimensions.ts", "../src/html.ts"],
4
+ "sourcesContent": ["export type Attrs = Record<string, undefined|null|string|number|boolean|(string|number)[]>\n\n/**\n * Transform an object into an HTML attributes string. The object should be\n * like `{ attributeName: value }`.\n *\n * @param attrs An object for the attributes.\n * @returns {string} A string suitable for use as HTML attributes.\n */\nexport function toAttributes (attrs:Attrs):string {\n return Object.keys(attrs).reduce((acc, k) => {\n const value = attrs[k]\n if (!value) return acc\n\n if (typeof value === 'boolean') {\n if (value) return (acc + ` ${k}`).trim()\n return acc\n }\n\n if (Array.isArray(value)) {\n return (acc + ` ${k}=\"${value.join(' ')}\"`)\n }\n\n return (acc + ` ${k}=\"${value}\"`).trim()\n }, '')\n}\n", "/**\n * Compute the resolution to decode a BlurHash placeholder at.\n *\n * A placeholder is a low-frequency blur, and decode cost is\n * O(width * height * componentsX * componentsY). Decoding above a small\n * size wastes work with no visible benefit, because the canvas is stretched\n * to fill its host via CSS (`blur-hash canvas { width:100%; height:100% }`).\n *\n * This caps the long edge to `cap` pixels, preserves the aspect ratio, floors\n * each edge at 1px, and never upscales a source that is already small.\n *\n * @param width The layout/source width in pixels.\n * @param height The layout/source height in pixels.\n * @param cap Maximum pixels on the long edge. Default 32.\n * @returns The decode dimensions to pass to `decode` and `createImageData`.\n */\nexport function decodeDimensions (\n width:number,\n height:number,\n cap:number = 32\n):{ width:number; height:number } {\n const longEdge = Math.max(width, height)\n\n // Never upscale: a source at or below the cap decodes as-is.\n if (longEdge <= cap) {\n return { width, height }\n }\n\n const scale = cap / longEdge\n return {\n width: Math.max(1, Math.round(width * scale)),\n height: Math.max(1, Math.round(height * scale))\n }\n}\n", "import { toAttributes } from '@substrate-system/web-component/attributes'\nimport type { ImgAttrs } from './index.js'\nimport { decodeDimensions } from './decode-dimensions.js'\n\nexport type SSRAttrs = ImgAttrs & { classes?:string }\n\nexport function render (attrs:SSRAttrs) {\n const {\n width,\n height,\n alt,\n contentVisibility,\n placeholder,\n decoding,\n loading,\n srcset,\n sizes,\n src\n } = attrs\n\n if (!placeholder) throw new Error('not placeholder')\n\n const decodeWidth = typeof width === 'string' ? parseInt(width, 10) : width\n const decodeHeight = typeof height === 'string' ?\n parseInt(height, 10) :\n height\n const decodeSize = decodeDimensions(decodeWidth, decodeHeight)\n\n const htmlString = `<canvas\n alt=\"${alt}\"\n width=${decodeSize.width}\n height=${decodeSize.height}\n class=\"blurry\"\n ></canvas>\n\n <img class=\"blurry\"\n alt=\"${alt}\"\n content-visibility=\"${contentVisibility || 'auto'}\"\n decoding=\"${decoding || 'async'}\"\n loading=\"${loading || 'lazy'}\"\n ${srcset ? `srcset=\"${srcset}\"` : ''}\n ${sizes ? `sizes=\"${sizes}\"` : ''}\n src=\"${src}\"\n />`\n\n const attributeString = toAttributes(attrs)\n\n // running in node?\n return typeof window === 'undefined' ?\n `<blur-hash ${attributeString}>\n ${htmlString}\n </blur-hash>` :\n htmlString\n}\n\nexport const outerHTML = (attrs:SSRAttrs) => {\n return `<blur-hash>${render(attrs)}</blur-hash>`\n}\n"],
5
+ "mappings": "sKASO,SAASA,EAAcC,EAAoB,CAC9C,OAAO,OAAO,KAAKA,CAAK,EAAE,OAAO,CAACC,EAAKC,IAAM,CACzC,IAAMC,EAAQH,EAAME,CAAC,EACrB,OAAKC,EAED,OAAOA,GAAU,UACbA,GAAeF,EAAM,IAAIC,CAAC,IAAI,KAAK,EAChCD,EAGP,MAAM,QAAQE,CAAK,EACXF,EAAM,IAAIC,CAAC,KAAKC,EAAM,KAAK,GAAG,CAAC,KAGnCF,EAAM,IAAIC,CAAC,KAAKC,CAAK,KAAK,KAAK,EAXpBF,CAYvB,EAAG,EAAE,CACT,CAhBgBG,EAAAL,EAAA,gBAAAK,EAAAL,EAAA,cAAA,ECOT,SAASM,EACZC,EACAC,EACAC,EAAa,GACiB,CAC9B,IAAMC,EAAW,KAAK,IAAIH,EAAOC,CAAM,EAGvC,GAAIE,GAAYD,EACZ,MAAO,CAAE,MAAAF,EAAO,OAAAC,CAAO,EAG3B,IAAMG,EAAQF,EAAMC,EACpB,MAAO,CACH,MAAO,KAAK,IAAI,EAAG,KAAK,MAAMH,EAAQI,CAAK,CAAC,EAC5C,OAAQ,KAAK,IAAI,EAAG,KAAK,MAAMH,EAASG,CAAK,CAAC,CAClD,CACJ,CAjBgBC,EAAAN,EAAA,oBCVT,SAASO,EAAQC,EAAgB,CACpC,GAAM,CACF,MAAAC,EACA,OAAAC,EACA,IAAAC,EACA,kBAAAC,EACA,YAAAC,EACA,SAAAC,EACA,QAAAC,EACA,OAAAC,EACA,MAAAC,EACA,IAAAC,CACJ,EAAIV,EAEJ,GAAI,CAACK,EAAa,MAAM,IAAI,MAAM,iBAAiB,EAEnD,IAAMM,EAAc,OAAOV,GAAU,SAAW,SAASA,EAAO,EAAE,EAAIA,EAChEW,EAAe,OAAOV,GAAW,SACnC,SAASA,EAAQ,EAAE,EACnBA,EACEW,EAAaC,EAAiBH,EAAaC,CAAY,EAEvDG,EAAa;AAAA,eACRZ,CAAG;AAAA,gBACFU,EAAW,KAAK;AAAA,iBACfA,EAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,eAKnBV,CAAG;AAAA,8BACYC,GAAqB,MAAM;AAAA,oBACrCE,GAAY,OAAO;AAAA,mBACpBC,GAAW,MAAM;AAAA,UAC1BC,EAAS,WAAWA,CAAM,IAAM,EAAE;AAAA,UAClCC,EAAQ,UAAUA,CAAK,IAAM,EAAE;AAAA,eAC1BC,CAAG;AAAA,QAGRM,EAAkBC,EAAajB,CAAK,EAG1C,OAAO,OAAO,OAAW,IACrB,cAAcgB,CAAe;AAAA,cACvBD,CAAU;AAAA,sBAEhBA,CACR,CA/CgBG,EAAAnB,EAAA,UAiDT,IAAMoB,EAAYD,EAAClB,GACf,cAAcD,EAAOC,CAAK,CAAC,eADb",
6
+ "names": ["toAttributes", "attrs", "acc", "k", "value", "__name", "decodeDimensions", "width", "height", "cap", "longEdge", "scale", "__name", "render", "attrs", "width", "height", "alt", "contentVisibility", "placeholder", "decoding", "loading", "srcset", "sizes", "src", "decodeWidth", "decodeHeight", "decodeSize", "decodeDimensions", "htmlString", "attributeString", "toAttributes", "__name", "outerHTML"]
7
7
  }
package/dist/index.cjs CHANGED
@@ -25,11 +25,13 @@ module.exports = __toCommonJS(index_exports);
25
25
  var import_web_component = require("@substrate-system/web-component");
26
26
  var import_blurhash = require("blurhash");
27
27
  var import_html = require("./html.js");
28
+ var import_decode_dimensions = require("./decode-dimensions.js");
28
29
  class BlurHash extends import_web_component.WebComponent.create("blur-hash") {
29
30
  static {
30
31
  __name(this, "BlurHash");
31
32
  }
32
33
  time;
34
+ rafId = null;
33
35
  constructor() {
34
36
  super();
35
37
  const w = this.getAttribute("width");
@@ -50,16 +52,11 @@ class BlurHash extends import_web_component.WebComponent.create("blur-hash") {
50
52
  reset(attrs) {
51
53
  if (attrs.width) this.style.width = "" + attrs.width;
52
54
  if (attrs.height) this.style.height = "" + attrs.height;
53
- const width = attrs.width ? typeof attrs.width === "string" ? parseInt(attrs.width) : attrs.width : parseInt(this.style.width);
54
- const height = attrs.height ? typeof attrs.height === "string" ? parseInt(attrs.height) : attrs.height : parseInt(this.style.height);
55
+ const width = attrs.width ? typeof attrs.width === "string" ? parseInt(attrs.width, 10) : attrs.width : parseInt(this.style.width, 10);
56
+ const height = attrs.height ? typeof attrs.height === "string" ? parseInt(attrs.height, 10) : attrs.height : parseInt(this.style.height, 10);
55
57
  this.innerHTML = BlurHash.html(Object.assign(attrs, { width, height }));
56
58
  const { placeholder, src: newSrc } = attrs;
57
- const pixels = (0, import_blurhash.decode)(placeholder, width, height);
58
- const canvas = this.querySelector("canvas");
59
- const ctx = canvas.getContext("2d");
60
- const imageData = ctx.createImageData(width, height);
61
- imageData.data.set(pixels);
62
- ctx.putImageData(imageData, 0, 0);
59
+ this.scheduleDecode(placeholder, width, height);
63
60
  this.setAttribute("src", newSrc);
64
61
  this.setAttribute("placeholder", placeholder);
65
62
  const img = this.querySelector("img");
@@ -67,6 +64,34 @@ class BlurHash extends import_web_component.WebComponent.create("blur-hash") {
67
64
  if (attrs.sizes) img.setAttribute("sizes", attrs.sizes);
68
65
  this.sharpen();
69
66
  }
67
+ /**
68
+ * Decode the placeholder and paint it to the canvas on the next frame.
69
+ * Cancels any pending frame first, so a rapid re-call (e.g. a second
70
+ * `reset`) never leaves a stale decode running. Bails if the element has
71
+ * detached before the frame fires.
72
+ */
73
+ scheduleDecode(placeholder, width, height) {
74
+ if (this.rafId !== null) cancelAnimationFrame(this.rafId);
75
+ const { width: dw, height: dh } = (0, import_decode_dimensions.decodeDimensions)(width, height);
76
+ this.rafId = requestAnimationFrame(() => {
77
+ this.rafId = null;
78
+ if (!this.isConnected) return;
79
+ const canvas = this.querySelector("canvas");
80
+ if (!canvas) return;
81
+ const ctx = canvas.getContext("2d");
82
+ if (!ctx) return;
83
+ const pixels = (0, import_blurhash.decode)(placeholder, dw, dh);
84
+ const imageData = ctx.createImageData(dw, dh);
85
+ imageData.data.set(pixels);
86
+ ctx.putImageData(imageData, 0, 0);
87
+ });
88
+ }
89
+ disconnectedCallback() {
90
+ if (this.rafId !== null) {
91
+ cancelAnimationFrame(this.rafId);
92
+ this.rafId = null;
93
+ }
94
+ }
70
95
  sharpen() {
71
96
  const img = this.qs("img");
72
97
  if (img.complete && img.naturalWidth > 0) {
@@ -89,12 +114,7 @@ class BlurHash extends import_web_component.WebComponent.create("blur-hash") {
89
114
  if (!this.innerHTML) {
90
115
  this.innerHTML = this.render();
91
116
  }
92
- const pixels = (0, import_blurhash.decode)(placeholder, width, height);
93
- const canvas = this.querySelector("canvas");
94
- const ctx = canvas.getContext("2d");
95
- const imageData = ctx.createImageData(width, height);
96
- imageData.data.set(pixels);
97
- ctx.putImageData(imageData, 0, 0);
117
+ this.scheduleDecode(placeholder, width, height);
98
118
  this.sharpen();
99
119
  }
100
120
  static html(attrs) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { WebComponent } from '@substrate-system/web-component'\nimport { decode } from 'blurhash'\nimport { render } from './html.js'\n\n// for docuement.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'blur-hash': BlurHash\n }\n}\n\nexport type ImgAttrs = {\n alt:string;\n width:string|number;\n height:string|number;\n placeholder:string;\n src:string;\n srcset?:string|null;\n sizes?:string|null;\n time?:number;\n contentVisibility?:'visible'|'auto'|'hidden'|null;\n decoding?:'sync'|'async'|'auto'|null;\n loading?:'lazy'|'eager'|'auto'|null;\n}\n\nexport class BlurHash extends WebComponent.create('blur-hash') {\n time:number\n\n constructor () {\n super()\n const w = this.getAttribute('width')\n const h = this.getAttribute('height')\n const time = this.getAttribute('time')\n this.time = time ? parseInt(time) : 800\n\n this.style.width = '' + w\n this.style.height = '' + h\n\n document.body.style.setProperty('--blur-hash-time',\n time ? '.' + (parseInt(time) / 1000 + 's') : '0.8s')\n }\n\n /**\n * Change the image, and do the blur-up thing again.\n * Will use the existing width & height if they are not passed in.\n */\n reset (attrs:(Omit<Omit<ImgAttrs, 'width'>, 'height'> & {\n width?:string|number;\n height?:string|number;\n })):void {\n if (attrs.width) this.style.width = '' + attrs.width\n if (attrs.height) this.style.height = '' + attrs.height\n\n const width = (attrs.width ?\n (typeof attrs.width === 'string' ? parseInt(attrs.width) : attrs.width) :\n parseInt(this.style.width))\n const height = (attrs.height ?\n (typeof attrs.height === 'string' ? parseInt(attrs.height) : attrs.height) :\n parseInt(this.style.height))\n\n this.innerHTML = BlurHash.html(Object.assign(attrs, { width, height }))\n\n const { placeholder, src: newSrc } = attrs\n\n const pixels = decode(placeholder, width, height)\n const canvas = this.querySelector('canvas') as HTMLCanvasElement\n const ctx = canvas.getContext('2d')!\n const imageData = ctx.createImageData(width, height)\n imageData.data.set(pixels)\n ctx.putImageData(imageData, 0, 0)\n\n this.setAttribute('src', newSrc)\n this.setAttribute('placeholder', placeholder)\n\n const img = this.querySelector('img')!\n if (attrs.srcset) img.setAttribute('srcset', attrs.srcset)\n if (attrs.sizes) img.setAttribute('sizes', attrs.sizes)\n\n this.sharpen()\n }\n\n sharpen () {\n const img = this.qs('img')!\n if (img.complete && img.naturalWidth > 0) {\n img.classList.remove('blurry')\n img.classList.add('sharp')\n } else {\n img.addEventListener('load', () => {\n img.classList.remove('blurry')\n img.classList.add('sharp')\n })\n }\n }\n\n connectedCallback () {\n const width = parseInt(this.getAttribute('width') ?? '')\n const height = parseInt(this.getAttribute('height') ?? '')\n const placeholder = this.getAttribute('placeholder')\n if (!placeholder) throw new Error('Missing placeholder')\n if (!width) throw new Error('Missing width')\n if (!height) throw new Error('Missing height')\n\n // don't render again if we dont have to\n if (!this.innerHTML) {\n this.innerHTML = this.render()\n }\n\n const pixels = decode(placeholder, width, height)\n const canvas = this.querySelector('canvas') as HTMLCanvasElement\n const ctx = canvas.getContext('2d')!\n const imageData = ctx.createImageData(width, height)\n imageData.data.set(pixels)\n ctx.putImageData(imageData, 0, 0)\n\n this.sharpen()\n }\n\n static html (attrs:ImgAttrs & { classes?:string }) {\n return render(attrs)\n }\n\n /**\n * Use the attributes to create HTML.\n */\n render ():string {\n const srcset = this.getAttribute('srcset')\n const width = this.getAttribute('width')\n const height = this.getAttribute('height')\n const time = this.getAttribute('time')\n const classes = this.classList.toString()\n const placeholder = this.getAttribute('placeholder')\n this.time = time ? parseInt(time) : 800\n const src = this.getAttribute('src')\n const alt = this.getAttribute('alt')\n if (!placeholder) throw new Error('not placeholder')\n if (!width || !height) throw new Error('not width or not height')\n if (!src) throw new Error('Not src')\n if (!alt) throw new Error('Not alt')\n\n return BlurHash.html({ classes, srcset, width, height, src, alt, placeholder })\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { WebComponent } from '@substrate-system/web-component'\nimport { decode } from 'blurhash'\nimport { render } from './html.js'\nimport { decodeDimensions } from './decode-dimensions.js'\n\n// for docuement.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'blur-hash': BlurHash\n }\n}\n\nexport type ImgAttrs = {\n alt:string;\n width:string|number;\n height:string|number;\n placeholder:string;\n src:string;\n srcset?:string|null;\n sizes?:string|null;\n time?:number;\n contentVisibility?:'visible'|'auto'|'hidden'|null;\n decoding?:'sync'|'async'|'auto'|null;\n loading?:'lazy'|'eager'|'auto'|null;\n}\n\nexport class BlurHash extends WebComponent.create('blur-hash') {\n time:number\n rafId:number|null = null\n\n constructor () {\n super()\n const w = this.getAttribute('width')\n const h = this.getAttribute('height')\n const time = this.getAttribute('time')\n this.time = time ? parseInt(time) : 800\n\n this.style.width = '' + w\n this.style.height = '' + h\n\n document.body.style.setProperty('--blur-hash-time',\n time ? '.' + (parseInt(time) / 1000 + 's') : '0.8s')\n }\n\n /**\n * Change the image, and do the blur-up thing again.\n * Will use the existing width & height if they are not passed in.\n */\n reset (attrs:(Omit<Omit<ImgAttrs, 'width'>, 'height'> & {\n width?:string|number;\n height?:string|number;\n })):void {\n if (attrs.width) this.style.width = '' + attrs.width\n if (attrs.height) this.style.height = '' + attrs.height\n\n const width = (attrs.width ?\n (typeof attrs.width === 'string' ? parseInt(attrs.width, 10) : attrs.width) :\n parseInt(this.style.width, 10))\n const height = (attrs.height ?\n (typeof attrs.height === 'string' ? parseInt(attrs.height, 10) : attrs.height) :\n parseInt(this.style.height, 10))\n\n this.innerHTML = BlurHash.html(Object.assign(attrs, { width, height }))\n\n const { placeholder, src: newSrc } = attrs\n\n this.scheduleDecode(placeholder, width, height)\n\n this.setAttribute('src', newSrc)\n this.setAttribute('placeholder', placeholder)\n\n const img = this.querySelector('img')!\n if (attrs.srcset) img.setAttribute('srcset', attrs.srcset)\n if (attrs.sizes) img.setAttribute('sizes', attrs.sizes)\n\n this.sharpen()\n }\n\n /**\n * Decode the placeholder and paint it to the canvas on the next frame.\n * Cancels any pending frame first, so a rapid re-call (e.g. a second\n * `reset`) never leaves a stale decode running. Bails if the element has\n * detached before the frame fires.\n */\n scheduleDecode (placeholder:string, width:number, height:number):void {\n if (this.rafId !== null) cancelAnimationFrame(this.rafId)\n\n const { width: dw, height: dh } = decodeDimensions(width, height)\n\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null\n if (!this.isConnected) return\n const canvas = this.querySelector<HTMLCanvasElement>('canvas')\n if (!canvas) return\n const ctx = canvas.getContext('2d')\n if (!ctx) return\n const pixels = decode(placeholder, dw, dh)\n const imageData = ctx.createImageData(dw, dh)\n imageData.data.set(pixels)\n ctx.putImageData(imageData, 0, 0)\n })\n }\n\n disconnectedCallback ():void {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n }\n\n sharpen () {\n const img = this.qs('img')!\n if (img.complete && img.naturalWidth > 0) {\n img.classList.remove('blurry')\n img.classList.add('sharp')\n } else {\n img.addEventListener('load', () => {\n img.classList.remove('blurry')\n img.classList.add('sharp')\n })\n }\n }\n\n connectedCallback () {\n const width = parseInt(this.getAttribute('width') ?? '')\n const height = parseInt(this.getAttribute('height') ?? '')\n const placeholder = this.getAttribute('placeholder')\n if (!placeholder) throw new Error('Missing placeholder')\n if (!width) throw new Error('Missing width')\n if (!height) throw new Error('Missing height')\n\n // don't render again if we dont have to\n if (!this.innerHTML) {\n this.innerHTML = this.render()\n }\n\n this.scheduleDecode(placeholder, width, height)\n this.sharpen()\n }\n\n static html (attrs:ImgAttrs & { classes?:string }) {\n return render(attrs)\n }\n\n /**\n * Use the attributes to create HTML.\n */\n render ():string {\n const srcset = this.getAttribute('srcset')\n const width = this.getAttribute('width')\n const height = this.getAttribute('height')\n const time = this.getAttribute('time')\n const classes = this.classList.toString()\n const placeholder = this.getAttribute('placeholder')\n this.time = time ? parseInt(time) : 800\n const src = this.getAttribute('src')\n const alt = this.getAttribute('alt')\n if (!placeholder) throw new Error('not placeholder')\n if (!width || !height) throw new Error('not width or not height')\n if (!src) throw new Error('Not src')\n if (!alt) throw new Error('Not alt')\n\n return BlurHash.html({ classes, srcset, width, height, src, alt, placeholder })\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.js CHANGED
@@ -3,11 +3,13 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
3
3
  import { WebComponent } from "@substrate-system/web-component";
4
4
  import { decode } from "blurhash";
5
5
  import { render } from "./html.js";
6
+ import { decodeDimensions } from "./decode-dimensions.js";
6
7
  class BlurHash extends WebComponent.create("blur-hash") {
7
8
  static {
8
9
  __name(this, "BlurHash");
9
10
  }
10
11
  time;
12
+ rafId = null;
11
13
  constructor() {
12
14
  super();
13
15
  const w = this.getAttribute("width");
@@ -28,16 +30,11 @@ class BlurHash extends WebComponent.create("blur-hash") {
28
30
  reset(attrs) {
29
31
  if (attrs.width) this.style.width = "" + attrs.width;
30
32
  if (attrs.height) this.style.height = "" + attrs.height;
31
- const width = attrs.width ? typeof attrs.width === "string" ? parseInt(attrs.width) : attrs.width : parseInt(this.style.width);
32
- const height = attrs.height ? typeof attrs.height === "string" ? parseInt(attrs.height) : attrs.height : parseInt(this.style.height);
33
+ const width = attrs.width ? typeof attrs.width === "string" ? parseInt(attrs.width, 10) : attrs.width : parseInt(this.style.width, 10);
34
+ const height = attrs.height ? typeof attrs.height === "string" ? parseInt(attrs.height, 10) : attrs.height : parseInt(this.style.height, 10);
33
35
  this.innerHTML = BlurHash.html(Object.assign(attrs, { width, height }));
34
36
  const { placeholder, src: newSrc } = attrs;
35
- const pixels = decode(placeholder, width, height);
36
- const canvas = this.querySelector("canvas");
37
- const ctx = canvas.getContext("2d");
38
- const imageData = ctx.createImageData(width, height);
39
- imageData.data.set(pixels);
40
- ctx.putImageData(imageData, 0, 0);
37
+ this.scheduleDecode(placeholder, width, height);
41
38
  this.setAttribute("src", newSrc);
42
39
  this.setAttribute("placeholder", placeholder);
43
40
  const img = this.querySelector("img");
@@ -45,6 +42,34 @@ class BlurHash extends WebComponent.create("blur-hash") {
45
42
  if (attrs.sizes) img.setAttribute("sizes", attrs.sizes);
46
43
  this.sharpen();
47
44
  }
45
+ /**
46
+ * Decode the placeholder and paint it to the canvas on the next frame.
47
+ * Cancels any pending frame first, so a rapid re-call (e.g. a second
48
+ * `reset`) never leaves a stale decode running. Bails if the element has
49
+ * detached before the frame fires.
50
+ */
51
+ scheduleDecode(placeholder, width, height) {
52
+ if (this.rafId !== null) cancelAnimationFrame(this.rafId);
53
+ const { width: dw, height: dh } = decodeDimensions(width, height);
54
+ this.rafId = requestAnimationFrame(() => {
55
+ this.rafId = null;
56
+ if (!this.isConnected) return;
57
+ const canvas = this.querySelector("canvas");
58
+ if (!canvas) return;
59
+ const ctx = canvas.getContext("2d");
60
+ if (!ctx) return;
61
+ const pixels = decode(placeholder, dw, dh);
62
+ const imageData = ctx.createImageData(dw, dh);
63
+ imageData.data.set(pixels);
64
+ ctx.putImageData(imageData, 0, 0);
65
+ });
66
+ }
67
+ disconnectedCallback() {
68
+ if (this.rafId !== null) {
69
+ cancelAnimationFrame(this.rafId);
70
+ this.rafId = null;
71
+ }
72
+ }
48
73
  sharpen() {
49
74
  const img = this.qs("img");
50
75
  if (img.complete && img.naturalWidth > 0) {
@@ -67,12 +92,7 @@ class BlurHash extends WebComponent.create("blur-hash") {
67
92
  if (!this.innerHTML) {
68
93
  this.innerHTML = this.render();
69
94
  }
70
- const pixels = decode(placeholder, width, height);
71
- const canvas = this.querySelector("canvas");
72
- const ctx = canvas.getContext("2d");
73
- const imageData = ctx.createImageData(width, height);
74
- imageData.data.set(pixels);
75
- ctx.putImageData(imageData, 0, 0);
95
+ this.scheduleDecode(placeholder, width, height);
76
96
  this.sharpen();
77
97
  }
78
98
  static html(attrs) {
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { WebComponent } from '@substrate-system/web-component'\nimport { decode } from 'blurhash'\nimport { render } from './html.js'\n\n// for docuement.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'blur-hash': BlurHash\n }\n}\n\nexport type ImgAttrs = {\n alt:string;\n width:string|number;\n height:string|number;\n placeholder:string;\n src:string;\n srcset?:string|null;\n sizes?:string|null;\n time?:number;\n contentVisibility?:'visible'|'auto'|'hidden'|null;\n decoding?:'sync'|'async'|'auto'|null;\n loading?:'lazy'|'eager'|'auto'|null;\n}\n\nexport class BlurHash extends WebComponent.create('blur-hash') {\n time:number\n\n constructor () {\n super()\n const w = this.getAttribute('width')\n const h = this.getAttribute('height')\n const time = this.getAttribute('time')\n this.time = time ? parseInt(time) : 800\n\n this.style.width = '' + w\n this.style.height = '' + h\n\n document.body.style.setProperty('--blur-hash-time',\n time ? '.' + (parseInt(time) / 1000 + 's') : '0.8s')\n }\n\n /**\n * Change the image, and do the blur-up thing again.\n * Will use the existing width & height if they are not passed in.\n */\n reset (attrs:(Omit<Omit<ImgAttrs, 'width'>, 'height'> & {\n width?:string|number;\n height?:string|number;\n })):void {\n if (attrs.width) this.style.width = '' + attrs.width\n if (attrs.height) this.style.height = '' + attrs.height\n\n const width = (attrs.width ?\n (typeof attrs.width === 'string' ? parseInt(attrs.width) : attrs.width) :\n parseInt(this.style.width))\n const height = (attrs.height ?\n (typeof attrs.height === 'string' ? parseInt(attrs.height) : attrs.height) :\n parseInt(this.style.height))\n\n this.innerHTML = BlurHash.html(Object.assign(attrs, { width, height }))\n\n const { placeholder, src: newSrc } = attrs\n\n const pixels = decode(placeholder, width, height)\n const canvas = this.querySelector('canvas') as HTMLCanvasElement\n const ctx = canvas.getContext('2d')!\n const imageData = ctx.createImageData(width, height)\n imageData.data.set(pixels)\n ctx.putImageData(imageData, 0, 0)\n\n this.setAttribute('src', newSrc)\n this.setAttribute('placeholder', placeholder)\n\n const img = this.querySelector('img')!\n if (attrs.srcset) img.setAttribute('srcset', attrs.srcset)\n if (attrs.sizes) img.setAttribute('sizes', attrs.sizes)\n\n this.sharpen()\n }\n\n sharpen () {\n const img = this.qs('img')!\n if (img.complete && img.naturalWidth > 0) {\n img.classList.remove('blurry')\n img.classList.add('sharp')\n } else {\n img.addEventListener('load', () => {\n img.classList.remove('blurry')\n img.classList.add('sharp')\n })\n }\n }\n\n connectedCallback () {\n const width = parseInt(this.getAttribute('width') ?? '')\n const height = parseInt(this.getAttribute('height') ?? '')\n const placeholder = this.getAttribute('placeholder')\n if (!placeholder) throw new Error('Missing placeholder')\n if (!width) throw new Error('Missing width')\n if (!height) throw new Error('Missing height')\n\n // don't render again if we dont have to\n if (!this.innerHTML) {\n this.innerHTML = this.render()\n }\n\n const pixels = decode(placeholder, width, height)\n const canvas = this.querySelector('canvas') as HTMLCanvasElement\n const ctx = canvas.getContext('2d')!\n const imageData = ctx.createImageData(width, height)\n imageData.data.set(pixels)\n ctx.putImageData(imageData, 0, 0)\n\n this.sharpen()\n }\n\n static html (attrs:ImgAttrs & { classes?:string }) {\n return render(attrs)\n }\n\n /**\n * Use the attributes to create HTML.\n */\n render ():string {\n const srcset = this.getAttribute('srcset')\n const width = this.getAttribute('width')\n const height = this.getAttribute('height')\n const time = this.getAttribute('time')\n const classes = this.classList.toString()\n const placeholder = this.getAttribute('placeholder')\n this.time = time ? parseInt(time) : 800\n const src = this.getAttribute('src')\n const alt = this.getAttribute('alt')\n if (!placeholder) throw new Error('not placeholder')\n if (!width || !height) throw new Error('not width or not height')\n if (!src) throw new Error('Not src')\n if (!alt) throw new Error('Not alt')\n\n return BlurHash.html({ classes, srcset, width, height, src, alt, placeholder })\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { WebComponent } from '@substrate-system/web-component'\nimport { decode } from 'blurhash'\nimport { render } from './html.js'\nimport { decodeDimensions } from './decode-dimensions.js'\n\n// for docuement.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'blur-hash': BlurHash\n }\n}\n\nexport type ImgAttrs = {\n alt:string;\n width:string|number;\n height:string|number;\n placeholder:string;\n src:string;\n srcset?:string|null;\n sizes?:string|null;\n time?:number;\n contentVisibility?:'visible'|'auto'|'hidden'|null;\n decoding?:'sync'|'async'|'auto'|null;\n loading?:'lazy'|'eager'|'auto'|null;\n}\n\nexport class BlurHash extends WebComponent.create('blur-hash') {\n time:number\n rafId:number|null = null\n\n constructor () {\n super()\n const w = this.getAttribute('width')\n const h = this.getAttribute('height')\n const time = this.getAttribute('time')\n this.time = time ? parseInt(time) : 800\n\n this.style.width = '' + w\n this.style.height = '' + h\n\n document.body.style.setProperty('--blur-hash-time',\n time ? '.' + (parseInt(time) / 1000 + 's') : '0.8s')\n }\n\n /**\n * Change the image, and do the blur-up thing again.\n * Will use the existing width & height if they are not passed in.\n */\n reset (attrs:(Omit<Omit<ImgAttrs, 'width'>, 'height'> & {\n width?:string|number;\n height?:string|number;\n })):void {\n if (attrs.width) this.style.width = '' + attrs.width\n if (attrs.height) this.style.height = '' + attrs.height\n\n const width = (attrs.width ?\n (typeof attrs.width === 'string' ? parseInt(attrs.width, 10) : attrs.width) :\n parseInt(this.style.width, 10))\n const height = (attrs.height ?\n (typeof attrs.height === 'string' ? parseInt(attrs.height, 10) : attrs.height) :\n parseInt(this.style.height, 10))\n\n this.innerHTML = BlurHash.html(Object.assign(attrs, { width, height }))\n\n const { placeholder, src: newSrc } = attrs\n\n this.scheduleDecode(placeholder, width, height)\n\n this.setAttribute('src', newSrc)\n this.setAttribute('placeholder', placeholder)\n\n const img = this.querySelector('img')!\n if (attrs.srcset) img.setAttribute('srcset', attrs.srcset)\n if (attrs.sizes) img.setAttribute('sizes', attrs.sizes)\n\n this.sharpen()\n }\n\n /**\n * Decode the placeholder and paint it to the canvas on the next frame.\n * Cancels any pending frame first, so a rapid re-call (e.g. a second\n * `reset`) never leaves a stale decode running. Bails if the element has\n * detached before the frame fires.\n */\n scheduleDecode (placeholder:string, width:number, height:number):void {\n if (this.rafId !== null) cancelAnimationFrame(this.rafId)\n\n const { width: dw, height: dh } = decodeDimensions(width, height)\n\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null\n if (!this.isConnected) return\n const canvas = this.querySelector<HTMLCanvasElement>('canvas')\n if (!canvas) return\n const ctx = canvas.getContext('2d')\n if (!ctx) return\n const pixels = decode(placeholder, dw, dh)\n const imageData = ctx.createImageData(dw, dh)\n imageData.data.set(pixels)\n ctx.putImageData(imageData, 0, 0)\n })\n }\n\n disconnectedCallback ():void {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n }\n\n sharpen () {\n const img = this.qs('img')!\n if (img.complete && img.naturalWidth > 0) {\n img.classList.remove('blurry')\n img.classList.add('sharp')\n } else {\n img.addEventListener('load', () => {\n img.classList.remove('blurry')\n img.classList.add('sharp')\n })\n }\n }\n\n connectedCallback () {\n const width = parseInt(this.getAttribute('width') ?? '')\n const height = parseInt(this.getAttribute('height') ?? '')\n const placeholder = this.getAttribute('placeholder')\n if (!placeholder) throw new Error('Missing placeholder')\n if (!width) throw new Error('Missing width')\n if (!height) throw new Error('Missing height')\n\n // don't render again if we dont have to\n if (!this.innerHTML) {\n this.innerHTML = this.render()\n }\n\n this.scheduleDecode(placeholder, width, height)\n this.sharpen()\n }\n\n static html (attrs:ImgAttrs & { classes?:string }) {\n return render(attrs)\n }\n\n /**\n * Use the attributes to create HTML.\n */\n render ():string {\n const srcset = this.getAttribute('srcset')\n const width = this.getAttribute('width')\n const height = this.getAttribute('height')\n const time = this.getAttribute('time')\n const classes = this.classList.toString()\n const placeholder = this.getAttribute('placeholder')\n this.time = time ? parseInt(time) : 800\n const src = this.getAttribute('src')\n const alt = this.getAttribute('alt')\n if (!placeholder) throw new Error('not placeholder')\n if (!width || !height) throw new Error('not width or not height')\n if (!src) throw new Error('Not src')\n if (!alt) throw new Error('Not alt')\n\n return BlurHash.html({ classes, srcset, width, height, src, alt, placeholder })\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }