@altano/satori-fit-text 2.0.1 → 2.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.
@@ -1,7 +1,8 @@
1
- import log_default from "../log.js";
1
+ import log from "../log.js";
2
2
  import { TextMeasurer } from "./TextMeasurer.js";
3
3
 
4
4
  //#region src/TextMeasurer/BrowserTextMeasurer.ts
5
+ /* v8 ignore start */
5
6
  var BrowserTextMeasurer = class extends TextMeasurer {
6
7
  #createSvgElement(svgXML) {
7
8
  const wrapper = document.createElement("div");
@@ -18,7 +19,7 @@ var BrowserTextMeasurer = class extends TextMeasurer {
18
19
  const dimensions = svg.getBBox();
19
20
  const width = dimensions.width + Math.min(dimensions.x, 0);
20
21
  const height = dimensions.height + Math.min(dimensions.y, 0);
21
- log_default({
22
+ log({
22
23
  fontSize,
23
24
  width: `${width}px`,
24
25
  height: `${height}px`,
@@ -1 +1 @@
1
- {"version":3,"file":"BrowserTextMeasurer.js","names":["svgXML: string","fontSize: number","#createSvgElement"],"sources":["../../src/TextMeasurer/BrowserTextMeasurer.ts"],"sourcesContent":["/// <reference lib=\"dom\" />\n\n// TODO Factor this out to a separate project so it doesn't infect the whole\n// project with the dom lib\n\n/* v8 ignore start */\nimport log from \"../log.js\";\nimport { TextMeasurer } from \"./TextMeasurer.js\";\nimport type { Dimensions } from \"../types.js\";\n\nexport default class BrowserTextMeasurer extends TextMeasurer {\n #createSvgElement(svgXML: string): SVGSVGElement {\n const wrapper = document.createElement(\"div\");\n wrapper.innerHTML = svgXML;\n const svg = wrapper.firstElementChild;\n if (svg == null || !(svg instanceof SVGSVGElement)) {\n throw new Error(`Child should be svg element`);\n }\n return svg;\n }\n\n async getDimensions(fontSize: number): Promise<Dimensions> {\n const svgXML = await this.createSvgXmlString(fontSize);\n const svg = this.#createSvgElement(svgXML);\n\n try {\n document.body.appendChild(svg);\n const dimensions = svg.getBBox();\n const width = dimensions.width + Math.min(dimensions.x, 0);\n const height = dimensions.height + Math.min(dimensions.y, 0);\n\n log({\n fontSize,\n width: `${width}px`,\n height: `${height}px`,\n widthFits: `${width}px ${width <= this.maxWidth ? \"DOES\" : \"does NOT\"} fit in ${this.maxWidth}`,\n heightFits: `${height}px ${height <= this.maxHeight ? \"DOES\" : \"does NOT\"} fit in ${this.maxHeight}`,\n });\n\n return { width, height };\n } finally {\n svg.parentElement?.removeChild?.(svg);\n }\n }\n}\n/* v8 ignore stop */\n"],"mappings":";;;;AAUA,IAAqB,sBAArB,cAAiD,aAAa;CAC5D,kBAAkBA,QAA+B;EAC/C,MAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,UAAQ,YAAY;EACpB,MAAM,MAAM,QAAQ;AACpB,MAAI,OAAO,UAAU,eAAe,eAClC,OAAM,IAAI,OAAO;AAEnB,SAAO;CACR;CAED,MAAM,cAAcC,UAAuC;EACzD,MAAM,SAAS,MAAM,KAAK,mBAAmB,SAAS;EACtD,MAAM,MAAM,KAAKC,kBAAkB,OAAO;AAE1C,MAAI;AACF,YAAS,KAAK,YAAY,IAAI;GAC9B,MAAM,aAAa,IAAI,SAAS;GAChC,MAAM,QAAQ,WAAW,QAAQ,KAAK,IAAI,WAAW,GAAG,EAAE;GAC1D,MAAM,SAAS,WAAW,SAAS,KAAK,IAAI,WAAW,GAAG,EAAE;AAE5D,eAAI;IACF;IACA,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,OAAO;IAClB,YAAY,EAAE,MAAM,KAAK,SAAS,KAAK,WAAW,SAAS,WAAW,UAAU,KAAK,SAAS;IAC9F,aAAa,EAAE,OAAO,KAAK,UAAU,KAAK,YAAY,SAAS,WAAW,UAAU,KAAK,UAAU;GACpG,EAAC;AAEF,UAAO;IAAE;IAAO;GAAQ;EACzB,UAAS;AACR,OAAI,eAAe,cAAc,IAAI;EACtC;CACF;AACF"}
1
+ {"version":3,"file":"BrowserTextMeasurer.js","names":["#createSvgElement"],"sources":["../../src/TextMeasurer/BrowserTextMeasurer.ts"],"sourcesContent":["/// <reference lib=\"dom\" />\n\n// TODO Factor this out to a separate project so it doesn't infect the whole\n// project with the dom lib\n\n/* v8 ignore start */\nimport log from \"../log.js\";\nimport { TextMeasurer } from \"./TextMeasurer.js\";\nimport type { Dimensions } from \"../types.js\";\n\nexport default class BrowserTextMeasurer extends TextMeasurer {\n #createSvgElement(svgXML: string): SVGSVGElement {\n const wrapper = document.createElement(\"div\");\n wrapper.innerHTML = svgXML;\n const svg = wrapper.firstElementChild;\n if (svg == null || !(svg instanceof SVGSVGElement)) {\n throw new Error(`Child should be svg element`);\n }\n return svg;\n }\n\n async getDimensions(fontSize: number): Promise<Dimensions> {\n const svgXML = await this.createSvgXmlString(fontSize);\n const svg = this.#createSvgElement(svgXML);\n\n try {\n document.body.appendChild(svg);\n const dimensions = svg.getBBox();\n const width = dimensions.width + Math.min(dimensions.x, 0);\n const height = dimensions.height + Math.min(dimensions.y, 0);\n\n log({\n fontSize,\n width: `${width}px`,\n height: `${height}px`,\n widthFits: `${width}px ${width <= this.maxWidth ? \"DOES\" : \"does NOT\"} fit in ${this.maxWidth}`,\n heightFits: `${height}px ${height <= this.maxHeight ? \"DOES\" : \"does NOT\"} fit in ${this.maxHeight}`,\n });\n\n return { width, height };\n } finally {\n svg.parentElement?.removeChild?.(svg);\n }\n }\n}\n/* v8 ignore stop */\n"],"mappings":";;;;;AAUA,IAAqB,sBAArB,cAAiD,aAAa;CAC5D,kBAAkB,QAA+B;EAC/C,MAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,UAAQ,YAAY;EACpB,MAAM,MAAM,QAAQ;AACpB,MAAI,OAAO,QAAQ,EAAE,eAAe,eAClC,OAAM,IAAI,MAAM,8BAA8B;AAEhD,SAAO;;CAGT,MAAM,cAAc,UAAuC;EACzD,MAAM,SAAS,MAAM,KAAK,mBAAmB,SAAS;EACtD,MAAM,MAAM,MAAKA,iBAAkB,OAAO;AAE1C,MAAI;AACF,YAAS,KAAK,YAAY,IAAI;GAC9B,MAAM,aAAa,IAAI,SAAS;GAChC,MAAM,QAAQ,WAAW,QAAQ,KAAK,IAAI,WAAW,GAAG,EAAE;GAC1D,MAAM,SAAS,WAAW,SAAS,KAAK,IAAI,WAAW,GAAG,EAAE;AAE5D,OAAI;IACF;IACA,OAAO,GAAG,MAAM;IAChB,QAAQ,GAAG,OAAO;IAClB,WAAW,GAAG,MAAM,KAAK,SAAS,KAAK,WAAW,SAAS,WAAW,UAAU,KAAK;IACrF,YAAY,GAAG,OAAO,KAAK,UAAU,KAAK,YAAY,SAAS,WAAW,UAAU,KAAK;IAC1F,CAAC;AAEF,UAAO;IAAE;IAAO;IAAQ;YAChB;AACR,OAAI,eAAe,cAAc,IAAI"}
@@ -1,4 +1,4 @@
1
- import log_default from "../log.js";
1
+ import log from "../log.js";
2
2
  import { TextMeasurer } from "./TextMeasurer.js";
3
3
  import { SVG, registerWindow } from "@svgdotjs/svg.js";
4
4
  import { createSVGWindow } from "svgdom";
@@ -18,7 +18,7 @@ var HeadlessTextMeasurer = class extends TextMeasurer {
18
18
  const dimensions = this.#canvas.bbox();
19
19
  const width = dimensions.width + Math.min(dimensions.x, 0);
20
20
  const height = dimensions.height + Math.min(dimensions.y, 0);
21
- log_default({
21
+ log({
22
22
  fontSize,
23
23
  width: `${width}px`,
24
24
  height: `${height}px`,
@@ -1 +1 @@
1
- {"version":3,"file":"HeadlessTextMeasurer.js","names":["text: string","font: Font","maxWidth: number","maxHeight: number","lineHeight: number | \"normal\"","#canvas","fontSize: number","#setFontSize"],"sources":["../../src/TextMeasurer/HeadlessTextMeasurer.ts"],"sourcesContent":["/// <reference no-default-lib=\"true\"/>\n\nimport { SVG, registerWindow, type Svg } from \"@svgdotjs/svg.js\";\nimport { createSVGWindow } from \"svgdom\";\nimport log from \"../log.js\";\nimport type { Dimensions, Font } from \"../types.js\";\nimport { TextMeasurer } from \"./TextMeasurer.js\";\n\nexport default class HeadlessTextMeasurer extends TextMeasurer {\n #canvas: Svg;\n\n constructor(\n text: string,\n font: Font,\n maxWidth: number,\n maxHeight: number,\n lineHeight: number | \"normal\",\n ) {\n super(text, font, maxWidth, maxHeight, lineHeight);\n\n // register window and document\n const window = createSVGWindow();\n const document = window.document;\n registerWindow(window, document);\n\n // create canvas\n this.#canvas = SVG<SVGSVGElement>(document.documentElement);\n }\n\n async getDimensions(fontSize: number): Promise<Dimensions> {\n await this.#setFontSize(fontSize);\n const dimensions = this.#canvas.bbox();\n const width = dimensions.width + Math.min(dimensions.x, 0);\n const height = dimensions.height + Math.min(dimensions.y, 0);\n\n log({\n fontSize,\n width: `${width}px`,\n height: `${height}px`,\n widthFits: `${width}px ${\n width <= this.maxWidth ? \"DOES\" : \"does NOT\"\n } fit in ${this.maxWidth}`,\n heightFits: `${height}px ${\n height <= this.maxHeight ? \"DOES\" : \"does NOT\"\n } fit in ${this.maxHeight}`,\n });\n\n return { width, height };\n }\n\n async #setFontSize(fontSize: number): Promise<void> {\n const svgXML = await this.createSvgXmlString(fontSize);\n this.#canvas.clear();\n this.#canvas.svg(svgXML);\n }\n}\n"],"mappings":";;;;;;AAQA,IAAqB,uBAArB,cAAkD,aAAa;CAC7D;CAEA,YACEA,MACAC,MACAC,UACAC,WACAC,YACA;AACA,QAAM,MAAM,MAAM,UAAU,WAAW,WAAW;EAGlD,MAAM,SAAS,iBAAiB;EAChC,MAAM,WAAW,OAAO;AACxB,iBAAe,QAAQ,SAAS;AAGhC,OAAKC,UAAU,IAAmB,SAAS,gBAAgB;CAC5D;CAED,MAAM,cAAcC,UAAuC;AACzD,QAAM,KAAKC,aAAa,SAAS;EACjC,MAAM,aAAa,KAAKF,QAAQ,MAAM;EACtC,MAAM,QAAQ,WAAW,QAAQ,KAAK,IAAI,WAAW,GAAG,EAAE;EAC1D,MAAM,SAAS,WAAW,SAAS,KAAK,IAAI,WAAW,GAAG,EAAE;AAE5D,cAAI;GACF;GACA,QAAQ,EAAE,MAAM;GAChB,SAAS,EAAE,OAAO;GAClB,YAAY,EAAE,MAAM,KAClB,SAAS,KAAK,WAAW,SAAS,WACnC,UAAU,KAAK,SAAS;GACzB,aAAa,EAAE,OAAO,KACpB,UAAU,KAAK,YAAY,SAAS,WACrC,UAAU,KAAK,UAAU;EAC3B,EAAC;AAEF,SAAO;GAAE;GAAO;EAAQ;CACzB;CAED,MAAME,aAAaD,UAAiC;EAClD,MAAM,SAAS,MAAM,KAAK,mBAAmB,SAAS;AACtD,OAAKD,QAAQ,OAAO;AACpB,OAAKA,QAAQ,IAAI,OAAO;CACzB;AACF"}
1
+ {"version":3,"file":"HeadlessTextMeasurer.js","names":["#canvas","#setFontSize"],"sources":["../../src/TextMeasurer/HeadlessTextMeasurer.ts"],"sourcesContent":["/// <reference no-default-lib=\"true\"/>\n\nimport { SVG, registerWindow, type Svg } from \"@svgdotjs/svg.js\";\nimport { createSVGWindow } from \"svgdom\";\nimport log from \"../log.js\";\nimport type { Dimensions, Font } from \"../types.js\";\nimport { TextMeasurer } from \"./TextMeasurer.js\";\n\nexport default class HeadlessTextMeasurer extends TextMeasurer {\n #canvas: Svg;\n\n constructor(\n text: string,\n font: Font,\n maxWidth: number,\n maxHeight: number,\n lineHeight: number | \"normal\",\n ) {\n super(text, font, maxWidth, maxHeight, lineHeight);\n\n // register window and document\n const window = createSVGWindow();\n const document = window.document;\n registerWindow(window, document);\n\n // create canvas\n this.#canvas = SVG<SVGSVGElement>(document.documentElement);\n }\n\n async getDimensions(fontSize: number): Promise<Dimensions> {\n await this.#setFontSize(fontSize);\n const dimensions = this.#canvas.bbox();\n const width = dimensions.width + Math.min(dimensions.x, 0);\n const height = dimensions.height + Math.min(dimensions.y, 0);\n\n log({\n fontSize,\n width: `${width}px`,\n height: `${height}px`,\n widthFits: `${width}px ${\n width <= this.maxWidth ? \"DOES\" : \"does NOT\"\n } fit in ${this.maxWidth}`,\n heightFits: `${height}px ${\n height <= this.maxHeight ? \"DOES\" : \"does NOT\"\n } fit in ${this.maxHeight}`,\n });\n\n return { width, height };\n }\n\n async #setFontSize(fontSize: number): Promise<void> {\n const svgXML = await this.createSvgXmlString(fontSize);\n this.#canvas.clear();\n this.#canvas.svg(svgXML);\n }\n}\n"],"mappings":";;;;;;AAQA,IAAqB,uBAArB,cAAkD,aAAa;CAC7D;CAEA,YACE,MACA,MACA,UACA,WACA,YACA;AACA,QAAM,MAAM,MAAM,UAAU,WAAW,WAAW;EAGlD,MAAM,SAAS,iBAAiB;EAChC,MAAM,WAAW,OAAO;AACxB,iBAAe,QAAQ,SAAS;AAGhC,QAAKA,SAAU,IAAmB,SAAS,gBAAgB;;CAG7D,MAAM,cAAc,UAAuC;AACzD,QAAM,MAAKC,YAAa,SAAS;EACjC,MAAM,aAAa,MAAKD,OAAQ,MAAM;EACtC,MAAM,QAAQ,WAAW,QAAQ,KAAK,IAAI,WAAW,GAAG,EAAE;EAC1D,MAAM,SAAS,WAAW,SAAS,KAAK,IAAI,WAAW,GAAG,EAAE;AAE5D,MAAI;GACF;GACA,OAAO,GAAG,MAAM;GAChB,QAAQ,GAAG,OAAO;GAClB,WAAW,GAAG,MAAM,KAClB,SAAS,KAAK,WAAW,SAAS,WACnC,UAAU,KAAK;GAChB,YAAY,GAAG,OAAO,KACpB,UAAU,KAAK,YAAY,SAAS,WACrC,UAAU,KAAK;GACjB,CAAC;AAEF,SAAO;GAAE;GAAO;GAAQ;;CAG1B,OAAMC,YAAa,UAAiC;EAClD,MAAM,SAAS,MAAM,KAAK,mBAAmB,SAAS;AACtD,QAAKD,OAAQ,OAAO;AACpB,QAAKA,OAAQ,IAAI,OAAO"}
@@ -17,7 +17,7 @@ var TextMeasurer = class {
17
17
  return width - epsilon <= this.maxWidth && height - epsilon <= this.maxHeight;
18
18
  }
19
19
  async createSvgXmlString(fontSize) {
20
- const node = {
20
+ return satori({
21
21
  type: "div",
22
22
  key: "satori-fit-text-measure-node",
23
23
  props: {
@@ -36,8 +36,7 @@ var TextMeasurer = class {
36
36
  },
37
37
  children: this.text
38
38
  }
39
- };
40
- return satori(node, {
39
+ }, {
41
40
  fonts: this.#fonts,
42
41
  width: this.maxWidth * 2,
43
42
  height: this.maxHeight * 2
@@ -1 +1 @@
1
- {"version":3,"file":"TextMeasurer.js","names":["text: string","font: Font","maxWidth: number","maxHeight: number","lineHeight: number | \"normal\"","#fonts","fontSize: number","node: React.ReactElement"],"sources":["../../src/TextMeasurer/TextMeasurer.ts"],"sourcesContent":["import satori from \"satori\";\n\nimport type React from \"react\";\nimport type { Dimensions, Font } from \"../types.js\";\n\n// getBBox seems to be off by a very tiny fraction with certain versions of\n// Inter. Maybe that makes sense... maybe there's a better way of measuring\n// things. But for now, fudge it...\nconst epsilon = 0.0001;\n\nexport abstract class TextMeasurer {\n #fonts: Font[];\n constructor(\n protected text: string,\n protected font: Font,\n protected maxWidth: number,\n protected maxHeight: number,\n protected lineHeight: number | \"normal\",\n ) {\n // Satori keeps a WeakMap of fonts arrays. Adding a new font is very\n // expensive, so let's make sure we always return the (referentially) same\n // array if the font is the same, to improve performance.\n this.#fonts = [this.font];\n }\n\n abstract getDimensions(fontSize: number): Promise<Dimensions>;\n\n async doesSizeFit(fontSize: number): Promise<boolean> {\n const { width, height } = await this.getDimensions(fontSize);\n return (\n width - epsilon <= this.maxWidth && height - epsilon <= this.maxHeight\n );\n }\n\n protected async createSvgXmlString(fontSize: number): Promise<string> {\n const node: React.ReactElement = {\n type: \"div\",\n key: \"satori-fit-text-measure-node\",\n props: {\n style: {\n // Static styles\n background: \"white\",\n color: \"black\",\n display: \"flex\",\n flex: 1,\n boxSizing: \"border-box\",\n margin: 0,\n padding: 0,\n\n // Dynamic styles based on input\n fontSize,\n fontFamily: this.font.name,\n maxWidth: this.maxWidth,\n lineHeight: this.lineHeight,\n },\n children: this.text,\n },\n } as const;\n\n // vnode => svg\n return satori(node, {\n fonts: this.#fonts,\n width: this.maxWidth * 2,\n height: this.maxHeight * 2,\n });\n }\n}\n"],"mappings":";;;AAQA,MAAM,UAAU;AAEhB,IAAsB,eAAtB,MAAmC;CACjC;CACA,YACYA,MACAC,MACAC,UACAC,WACAC,YACV;EALU;EACA;EACA;EACA;EACA;AAKV,OAAKC,SAAS,CAAC,KAAK,IAAK;CAC1B;CAID,MAAM,YAAYC,UAAoC;EACpD,MAAM,EAAE,OAAO,QAAQ,GAAG,MAAM,KAAK,cAAc,SAAS;AAC5D,SACE,QAAQ,WAAW,KAAK,YAAY,SAAS,WAAW,KAAK;CAEhE;CAED,MAAgB,mBAAmBA,UAAmC;EACpE,MAAMC,OAA2B;GAC/B,MAAM;GACN,KAAK;GACL,OAAO;IACL,OAAO;KAEL,YAAY;KACZ,OAAO;KACP,SAAS;KACT,MAAM;KACN,WAAW;KACX,QAAQ;KACR,SAAS;KAGT;KACA,YAAY,KAAK,KAAK;KACtB,UAAU,KAAK;KACf,YAAY,KAAK;IAClB;IACD,UAAU,KAAK;GAChB;EACF;AAGD,SAAO,OAAO,MAAM;GAClB,OAAO,KAAKF;GACZ,OAAO,KAAK,WAAW;GACvB,QAAQ,KAAK,YAAY;EAC1B,EAAC;CACH;AACF"}
1
+ {"version":3,"file":"TextMeasurer.js","names":["#fonts"],"sources":["../../src/TextMeasurer/TextMeasurer.ts"],"sourcesContent":["import satori from \"satori\";\n\nimport type React from \"react\";\nimport type { Dimensions, Font } from \"../types.js\";\n\n// getBBox seems to be off by a very tiny fraction with certain versions of\n// Inter. Maybe that makes sense... maybe there's a better way of measuring\n// things. But for now, fudge it...\nconst epsilon = 0.0001;\n\nexport abstract class TextMeasurer {\n #fonts: Font[];\n constructor(\n protected text: string,\n protected font: Font,\n protected maxWidth: number,\n protected maxHeight: number,\n protected lineHeight: number | \"normal\",\n ) {\n // Satori keeps a WeakMap of fonts arrays. Adding a new font is very\n // expensive, so let's make sure we always return the (referentially) same\n // array if the font is the same, to improve performance.\n this.#fonts = [this.font];\n }\n\n abstract getDimensions(fontSize: number): Promise<Dimensions>;\n\n async doesSizeFit(fontSize: number): Promise<boolean> {\n const { width, height } = await this.getDimensions(fontSize);\n return (\n width - epsilon <= this.maxWidth && height - epsilon <= this.maxHeight\n );\n }\n\n protected async createSvgXmlString(fontSize: number): Promise<string> {\n const node: React.ReactElement = {\n type: \"div\",\n key: \"satori-fit-text-measure-node\",\n props: {\n style: {\n // Static styles\n background: \"white\",\n color: \"black\",\n display: \"flex\",\n flex: 1,\n boxSizing: \"border-box\",\n margin: 0,\n padding: 0,\n\n // Dynamic styles based on input\n fontSize,\n fontFamily: this.font.name,\n maxWidth: this.maxWidth,\n lineHeight: this.lineHeight,\n },\n children: this.text,\n },\n } as const;\n\n // vnode => svg\n return satori(node, {\n fonts: this.#fonts,\n width: this.maxWidth * 2,\n height: this.maxHeight * 2,\n });\n }\n}\n"],"mappings":";;;AAQA,MAAM,UAAU;AAEhB,IAAsB,eAAtB,MAAmC;CACjC;CACA,YACE,AAAU,MACV,AAAU,MACV,AAAU,UACV,AAAU,WACV,AAAU,YACV;EALU;EACA;EACA;EACA;EACA;AAKV,QAAKA,QAAS,CAAC,KAAK,KAAK;;CAK3B,MAAM,YAAY,UAAoC;EACpD,MAAM,EAAE,OAAO,WAAW,MAAM,KAAK,cAAc,SAAS;AAC5D,SACE,QAAQ,WAAW,KAAK,YAAY,SAAS,WAAW,KAAK;;CAIjE,MAAgB,mBAAmB,UAAmC;AA0BpE,SAAO,OAzB0B;GAC/B,MAAM;GACN,KAAK;GACL,OAAO;IACL,OAAO;KAEL,YAAY;KACZ,OAAO;KACP,SAAS;KACT,MAAM;KACN,WAAW;KACX,QAAQ;KACR,SAAS;KAGT;KACA,YAAY,KAAK,KAAK;KACtB,UAAU,KAAK;KACf,YAAY,KAAK;KAClB;IACD,UAAU,KAAK;IAChB;GACF,EAGmB;GAClB,OAAO,MAAKA;GACZ,OAAO,KAAK,WAAW;GACvB,QAAQ,KAAK,YAAY;GAC1B,CAAC"}
@@ -1,13 +1,8 @@
1
1
  //#region src/TextMeasurer/getTextMeasurer.ts
2
2
  async function getTextMeasurer(...args) {
3
3
  /* v8 ignore next 3 */
4
- if (typeof window !== "undefined") {
5
- const Measurer = await import("./BrowserTextMeasurer.js");
6
- return new Measurer.default(...args);
7
- } else {
8
- const Measurer = await import("./HeadlessTextMeasurer.js");
9
- return new Measurer.default(...args);
10
- }
4
+ if (typeof window !== "undefined") return new (await (import("./BrowserTextMeasurer.js"))).default(...args);
5
+ else return new (await (import("./HeadlessTextMeasurer.js"))).default(...args);
11
6
  }
12
7
 
13
8
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"getTextMeasurer.js","names":[],"sources":["../../src/TextMeasurer/getTextMeasurer.ts"],"sourcesContent":["import type { TextMeasurer } from \"./TextMeasurer.js\";\n\nexport async function getTextMeasurer(\n ...args: ConstructorParameters<typeof TextMeasurer>\n): Promise<TextMeasurer> {\n // TODO Get browser testing working\n /* v8 ignore next 3 */\n if (typeof window !== \"undefined\") {\n const Measurer = await import(\"./BrowserTextMeasurer.js\");\n return new Measurer.default(...args);\n } else {\n const Measurer = await import(\"./HeadlessTextMeasurer.js\");\n return new Measurer.default(...args);\n }\n}\n"],"mappings":";AAEA,eAAsB,gBACpB,GAAG,MACoB;;AAGvB,YAAW,WAAW,aAAa;EACjC,MAAM,WAAW,MAAM,OAAO;AAC9B,SAAO,IAAI,SAAS,QAAQ,GAAG;CAChC,OAAM;EACL,MAAM,WAAW,MAAM,OAAO;AAC9B,SAAO,IAAI,SAAS,QAAQ,GAAG;CAChC;AACF"}
1
+ {"version":3,"file":"getTextMeasurer.js","names":[],"sources":["../../src/TextMeasurer/getTextMeasurer.ts"],"sourcesContent":["import type { TextMeasurer } from \"./TextMeasurer.js\";\n\nexport async function getTextMeasurer(\n ...args: ConstructorParameters<typeof TextMeasurer>\n): Promise<TextMeasurer> {\n // TODO Get browser testing working\n /* v8 ignore next 3 */\n if (typeof window !== \"undefined\") {\n const Measurer = await import(\"./BrowserTextMeasurer.js\");\n return new Measurer.default(...args);\n } else {\n const Measurer = await import(\"./HeadlessTextMeasurer.js\");\n return new Measurer.default(...args);\n }\n}\n"],"mappings":";AAEA,eAAsB,gBACpB,GAAG,MACoB;;AAGvB,KAAI,OAAO,WAAW,YAEpB,QAAO,KADU,OAAM,OAAO,8BACV,QAAQ,GAAG,KAAK;KAGpC,QAAO,KADU,OAAM,OAAO,+BACV,QAAQ,GAAG,KAAK"}
package/dist/fitText.js CHANGED
@@ -12,8 +12,7 @@ async function findLargestUsableFontSize({ text, font, maxWidth, maxHeight, line
12
12
  const searchCutoffThreshold = Math.min(1, lower);
13
13
  if (upper - lower <= searchCutoffThreshold) return Math.floor(lower);
14
14
  const sizeCandidate = Math.floor(lower + (upper - lower) / 2);
15
- const doesFit = await textMeasurer.doesSizeFit(sizeCandidate);
16
- if (doesFit) lower = sizeCandidate;
15
+ if (await textMeasurer.doesSizeFit(sizeCandidate)) lower = sizeCandidate;
17
16
  else upper = sizeCandidate;
18
17
  }
19
18
  throw new Error(`Could not find a valid font size in ${maxTries - 1} attempts. Giving up. Please try again after constraining the search space, e.g. by restricting the min/max font size difference.`);
@@ -1 +1 @@
1
- {"version":3,"file":"fitText.js","names":[],"sources":["../src/fitText.ts"],"sourcesContent":["import { getTextMeasurer } from \"./TextMeasurer/getTextMeasurer.js\";\n\nimport type { Font } from \"./types.js\";\n\nexport type FindOptions = {\n /**\n * The text you want to fit\n */\n text: string;\n /**\n * The font of your text. Options are the same as [those taken by\n * Satori](https://github.com/vercel/satori#fonts), but only one font and not\n * an array of fonts is accepted here.\n */\n font: Font;\n /**\n * The max width the text must be contained in\n */\n maxWidth: number;\n /**\n * The max height the text must be contained in\n */\n maxHeight: number;\n /**\n * Optional: the CSS line height factor to use, e.g. 1.1\n */\n lineHeight?: number | \"normal\";\n /**\n * The minimum font size that should be returned, even if smaller fonts fit\n */\n minFontSize?: number;\n /**\n * The maximum font size that should be returned, even if larger fonts fit\n */\n maxFontSize?: number;\n /**\n * The maximum number of font sizes to try before giving up. Defaults to 1000.\n */\n maxTries?: number;\n};\n\n/**\n * Given text, dimensions, and some options, returns the largest font size that\n * would keep the text contained within the dimensions.\n */\nexport async function findLargestUsableFontSize({\n text,\n font,\n maxWidth,\n maxHeight,\n lineHeight = \"normal\",\n minFontSize = 1,\n maxFontSize = 1000,\n maxTries = 1000,\n}: FindOptions): Promise<number> {\n if (maxTries < 2) {\n throw new Error(\"`maxTries` must be >= 2\");\n }\n\n const textMeasurer = await getTextMeasurer(\n text,\n font,\n maxWidth,\n maxHeight,\n lineHeight,\n );\n\n for (\n let tries = 1, lower = minFontSize, upper = maxFontSize;\n tries < maxTries;\n ++tries\n ) {\n const searchCutoffThreshold = Math.min(1, lower);\n if (upper - lower <= searchCutoffThreshold) {\n return Math.floor(lower);\n }\n\n const sizeCandidate = Math.floor(lower + (upper - lower) / 2);\n const doesFit = await textMeasurer.doesSizeFit(sizeCandidate);\n\n if (doesFit) {\n lower = sizeCandidate;\n } else {\n upper = sizeCandidate;\n }\n }\n\n throw new Error(\n `Could not find a valid font size in ${\n maxTries - 1\n } attempts. Giving up. Please try again after constraining the search space, e.g. by restricting the min/max font size difference.`,\n );\n}\n"],"mappings":";;;;;;;AA6CA,eAAsB,0BAA0B,EAC9C,MACA,MACA,UACA,WACA,aAAa,UACb,cAAc,GACd,cAAc,KACd,WAAW,KACC,EAAmB;AAC/B,KAAI,WAAW,EACb,OAAM,IAAI,MAAM;CAGlB,MAAM,eAAe,MAAM,gBACzB,MACA,MACA,UACA,WACA,WACD;AAED,MACE,IAAI,QAAQ,GAAG,QAAQ,aAAa,QAAQ,aAC5C,QAAQ,UACR,EAAE,OACF;EACA,MAAM,wBAAwB,KAAK,IAAI,GAAG,MAAM;AAChD,MAAI,QAAQ,SAAS,sBACnB,QAAO,KAAK,MAAM,MAAM;EAG1B,MAAM,gBAAgB,KAAK,MAAM,SAAS,QAAQ,SAAS,EAAE;EAC7D,MAAM,UAAU,MAAM,aAAa,YAAY,cAAc;AAE7D,MAAI,QACF,SAAQ;MAER,SAAQ;CAEX;AAED,OAAM,IAAI,OACP,sCACC,WAAW,EACZ;AAEJ"}
1
+ {"version":3,"file":"fitText.js","names":[],"sources":["../src/fitText.ts"],"sourcesContent":["import { getTextMeasurer } from \"./TextMeasurer/getTextMeasurer.js\";\n\nimport type { Font } from \"./types.js\";\n\nexport type FindOptions = {\n /**\n * The text you want to fit\n */\n text: string;\n /**\n * The font of your text. Options are the same as [those taken by\n * Satori](https://github.com/vercel/satori#fonts), but only one font and not\n * an array of fonts is accepted here.\n */\n font: Font;\n /**\n * The max width the text must be contained in\n */\n maxWidth: number;\n /**\n * The max height the text must be contained in\n */\n maxHeight: number;\n /**\n * Optional: the CSS line height factor to use, e.g. 1.1\n */\n lineHeight?: number | \"normal\";\n /**\n * The minimum font size that should be returned, even if smaller fonts fit\n */\n minFontSize?: number;\n /**\n * The maximum font size that should be returned, even if larger fonts fit\n */\n maxFontSize?: number;\n /**\n * The maximum number of font sizes to try before giving up. Defaults to 1000.\n */\n maxTries?: number;\n};\n\n/**\n * Given text, dimensions, and some options, returns the largest font size that\n * would keep the text contained within the dimensions.\n */\nexport async function findLargestUsableFontSize({\n text,\n font,\n maxWidth,\n maxHeight,\n lineHeight = \"normal\",\n minFontSize = 1,\n maxFontSize = 1000,\n maxTries = 1000,\n}: FindOptions): Promise<number> {\n if (maxTries < 2) {\n throw new Error(\"`maxTries` must be >= 2\");\n }\n\n const textMeasurer = await getTextMeasurer(\n text,\n font,\n maxWidth,\n maxHeight,\n lineHeight,\n );\n\n for (\n let tries = 1, lower = minFontSize, upper = maxFontSize;\n tries < maxTries;\n ++tries\n ) {\n const searchCutoffThreshold = Math.min(1, lower);\n if (upper - lower <= searchCutoffThreshold) {\n return Math.floor(lower);\n }\n\n const sizeCandidate = Math.floor(lower + (upper - lower) / 2);\n const doesFit = await textMeasurer.doesSizeFit(sizeCandidate);\n\n if (doesFit) {\n lower = sizeCandidate;\n } else {\n upper = sizeCandidate;\n }\n }\n\n throw new Error(\n `Could not find a valid font size in ${\n maxTries - 1\n } attempts. Giving up. Please try again after constraining the search space, e.g. by restricting the min/max font size difference.`,\n );\n}\n"],"mappings":";;;;;;;AA6CA,eAAsB,0BAA0B,EAC9C,MACA,MACA,UACA,WACA,aAAa,UACb,cAAc,GACd,cAAc,KACd,WAAW,OACoB;AAC/B,KAAI,WAAW,EACb,OAAM,IAAI,MAAM,0BAA0B;CAG5C,MAAM,eAAe,MAAM,gBACzB,MACA,MACA,UACA,WACA,WACD;AAED,MACE,IAAI,QAAQ,GAAG,QAAQ,aAAa,QAAQ,aAC5C,QAAQ,UACR,EAAE,OACF;EACA,MAAM,wBAAwB,KAAK,IAAI,GAAG,MAAM;AAChD,MAAI,QAAQ,SAAS,sBACnB,QAAO,KAAK,MAAM,MAAM;EAG1B,MAAM,gBAAgB,KAAK,MAAM,SAAS,QAAQ,SAAS,EAAE;AAG7D,MAFgB,MAAM,aAAa,YAAY,cAAc,CAG3D,SAAQ;MAER,SAAQ;;AAIZ,OAAM,IAAI,MACR,uCACE,WAAW,EACZ,mIACF"}
package/dist/log.js CHANGED
@@ -2,8 +2,7 @@ import debug from "debug";
2
2
 
3
3
  //#region src/log.ts
4
4
  const log = debug("satori-text-fit");
5
- var log_default = log;
6
5
 
7
6
  //#endregion
8
- export { log_default as default };
7
+ export { log as default };
9
8
  //# sourceMappingURL=log.js.map
package/dist/log.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"log.js","names":["log: debug.Debugger"],"sources":["../src/log.ts"],"sourcesContent":["import debug from \"debug\";\n\nconst log: debug.Debugger = debug(\"satori-text-fit\");\n\nexport default log;\n"],"mappings":";;;AAEA,MAAMA,MAAsB,MAAM,kBAAkB;AAEpD,kBAAe"}
1
+ {"version":3,"file":"log.js","names":[],"sources":["../src/log.ts"],"sourcesContent":["import debug from \"debug\";\n\nconst log: debug.Debugger = debug(\"satori-text-fit\");\n\nexport default log;\n"],"mappings":";;;AAEA,MAAM,MAAsB,MAAM,kBAAkB"}
package/dist/types.js CHANGED
@@ -0,0 +1 @@
1
+ export { };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@altano/satori-fit-text",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Fit text to a bounding box in Node or the browser",
5
5
  "keywords": [
6
6
  "fit-text",
@@ -31,43 +31,46 @@
31
31
  "dist/**/*.d.ts"
32
32
  ],
33
33
  "dependencies": {
34
- "@svgdotjs/svg.js": "^3.2.4",
35
- "debug": "^4.4.0",
34
+ "@svgdotjs/svg.js": "^3.2.5",
35
+ "debug": "^4.4.3",
36
36
  "satori": "^0.12.2",
37
- "svgdom": "^0.1.21"
37
+ "svgdom": "^0.1.23"
38
38
  },
39
39
  "devDependencies": {
40
- "@arethetypeswrong/cli": "^0.17.4",
40
+ "@arethetypeswrong/cli": "^0.18.2",
41
41
  "@fontsource-variable/inter": "5.2.6",
42
42
  "@fontsource/inter": "5.2.6",
43
- "@playwright/test": "1.51.1",
43
+ "@playwright/test": "1.58.2",
44
44
  "@resvg/resvg-js": "^2.6.2",
45
45
  "@types/debug": "^4.1.12",
46
46
  "@types/he": "^1.2.3",
47
- "@types/jest-image-snapshot": "^6.4.0",
48
- "@types/node": "^22.13.10",
49
- "@types/react": "^19.0.12",
50
- "@types/react-dom": "^19.0.4",
47
+ "@types/jest-image-snapshot": "^6.4.1",
48
+ "@types/node": "^25.5.0",
49
+ "@types/react": "^19.2.10",
50
+ "@types/react-dom": "^19.2.3",
51
51
  "@types/svgdom": "^0.1.2",
52
- "@vitest/coverage-v8": "^3.1.4",
52
+ "@vitest/coverage-v8": "^4.1.0",
53
53
  "depcheck": "^1.4.7",
54
- "jest-image-snapshot": "^6.4.0",
55
- "prettier": "^3.5.3",
56
- "react": "^19.1.0",
57
- "tsdown": "^0.12.9",
58
- "typescript": "^5.8.2",
59
- "vite": "^6.2.6",
60
- "vitest": "^3.1.4",
54
+ "jest-image-snapshot": "^6.5.1",
55
+ "prettier": "^3.8.1",
56
+ "react": "^19.2.4",
57
+ "tsdown": "^0.21.4",
58
+ "typescript": "^5.9.3",
59
+ "vite": "^7.3.1",
60
+ "vitest": "^4.1.0",
61
61
  "@altano/assets": "0.0.1",
62
62
  "@altano/build-config": "0.0.1",
63
63
  "@altano/testing": "0.0.1",
64
64
  "@altano/tsconfig": "0.0.1"
65
65
  },
66
+ "peerDependencies": {
67
+ "@types/react": "19.x.x"
68
+ },
66
69
  "publishConfig": {
67
70
  "access": "public"
68
71
  },
69
72
  "scripts": {
70
- "build": "tsdown --config ../build-config/tsdown.config.node.ts",
73
+ "build": "tsdown --config-loader unrun --config ../build-config/tsdown.config.node.ts",
71
74
  "check:exports": "attw --pack . --profile esm-only --quiet",
72
75
  "check:types:src": "tsc --noEmit",
73
76
  "check:types:test": "tsc --noEmit --project ./tests/tsconfig.json",
@@ -79,7 +82,7 @@
79
82
  "lint": "eslint",
80
83
  "lint:fix": "TIMING=1 pnpm lint --fix",
81
84
  "lint:timing": "TIMING=1 pnpm lint",
82
- "test:e2e": "playwright test",
85
+ "test:e2e": "NODE_OPTIONS='--no-experimental-strip-types' playwright test",
83
86
  "test:e2e:server": "pnpm --dir ../../examples/satori-fit-text-playground start",
84
87
  "test:e2e:ui": "playwright test --ui",
85
88
  "test:unit": "vitest --run",