takumi-js 2.13.7 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -11
- package/dist/index.cjs +2 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{render-B2cdtVWB.cjs → render-BmM58jcW.cjs} +47 -22
- package/dist/{render-C-wS8FET.d.mts → render-D36x-iF4.d.mts} +17 -1
- package/dist/{render-B1HYpcq6.mjs → render-DNAu8Luv.mjs} +42 -23
- package/dist/{render-BIjyc8uU.d.cts → render-DRoDMAA1.d.cts} +17 -1
- package/dist/response.cjs +27 -29
- package/dist/response.d.cts +1 -1
- package/dist/response.d.mts +1 -1
- package/dist/response.mjs +27 -29
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
# takumi-js
|
|
5
5
|
|
|
6
|
-
**
|
|
6
|
+
**Generate Open Graph images from JSX, HTML, and CSS without a headless browser.**
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Create social cards, banners, PNG, JPEG, WebP, SVG, and animations. The package provides an `ImageResponse` API compatible with `next/og`.
|
|
9
9
|
|
|
10
10
|
[Documentation](https://takumi.kane.tw/docs/) · [Playground](https://takumi.kane.tw/playground)
|
|
11
11
|
|
|
@@ -21,12 +21,14 @@ npm install takumi-js
|
|
|
21
21
|
|
|
22
22
|
## Quick start
|
|
23
23
|
|
|
24
|
+
Save this example as `image.tsx` and run it with `bun image.tsx`. In Node.js, compile JSX before running it.
|
|
25
|
+
|
|
24
26
|
```tsx
|
|
25
27
|
import { render } from "takumi-js";
|
|
26
28
|
import { writeFile } from "node:fs/promises";
|
|
27
29
|
|
|
28
30
|
const image = await render(
|
|
29
|
-
<div tw="w-full h-full flex items-center justify-center bg-
|
|
31
|
+
<div tw="w-full h-full flex items-center justify-center bg-linear-to-b from-blue-100 to-red-50">
|
|
30
32
|
<h1 tw="text-6xl font-bold">Hello from Takumi</h1>
|
|
31
33
|
</div>,
|
|
32
34
|
{ width: 1200, height: 630 },
|
|
@@ -35,13 +37,13 @@ const image = await render(
|
|
|
35
37
|
await writeFile("./output.png", image);
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
##
|
|
40
|
+
## Migrate from another renderer
|
|
39
41
|
|
|
40
|
-
| You are using | What changes
|
|
41
|
-
| :------------------------ |
|
|
42
|
-
| `satori` | Replace `satori()` with `renderSvg()`, or call `render()` for encoded image bytes. [Compare the renderers](https://takumi.kane.tw/docs/comparison-to-satori).
|
|
43
|
-
| `next/og` | Swap the `ImageResponse` import.
|
|
44
|
-
| Puppeteer for screenshots | Pass a JSX or HTML tree to `render()`. Scripts do not run, and Takumi supports less CSS than Chrome.
|
|
42
|
+
| You are using | What changes |
|
|
43
|
+
| :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `satori` | Replace `satori()` with `renderSvg()`, or call `render()` for encoded image bytes. [Compare the renderers](https://takumi.kane.tw/docs/comparison-to-satori). |
|
|
45
|
+
| `next/og` | Swap the `ImageResponse` import. Keep explicit Flexbox styles and compare the rendered output. [Read the migration guide](https://takumi.kane.tw/docs/comparison-to-satori#migrate-from-nextog). |
|
|
46
|
+
| Puppeteer for screenshots | Pass a JSX or HTML tree to `render()`. Scripts do not run, and Takumi supports less CSS than Chrome. |
|
|
45
47
|
|
|
46
48
|
## Runtime detection
|
|
47
49
|
|
|
@@ -61,7 +63,7 @@ import { ImageResponse } from "takumi-js/response";
|
|
|
61
63
|
|
|
62
64
|
export function GET() {
|
|
63
65
|
return new ImageResponse(
|
|
64
|
-
<div tw="w-full h-full flex items-center justify-center bg-
|
|
66
|
+
<div tw="w-full h-full flex items-center justify-center bg-linear-to-b from-blue-100 to-red-50">
|
|
65
67
|
<h1 tw="text-6xl font-bold">Hello from Takumi</h1>
|
|
66
68
|
</div>,
|
|
67
69
|
{ width: 1200, height: 630 },
|
|
@@ -76,7 +78,7 @@ import { renderSvg } from "takumi-js";
|
|
|
76
78
|
import { writeFile } from "node:fs/promises";
|
|
77
79
|
|
|
78
80
|
const svg = await renderSvg(
|
|
79
|
-
<div tw="w-full h-full flex items-center justify-center bg-
|
|
81
|
+
<div tw="w-full h-full flex items-center justify-center bg-linear-to-b from-blue-100 to-red-50">
|
|
80
82
|
<h1 tw="text-6xl font-bold">Hello from Takumi</h1>
|
|
81
83
|
</div>,
|
|
82
84
|
{ width: 1200, height: 630 },
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_render = require("./render-
|
|
2
|
+
const require_render = require("./render-BmM58jcW.cjs");
|
|
3
|
+
exports.measure = require_render.measure;
|
|
3
4
|
exports.render = require_render.render;
|
|
4
5
|
exports.renderAnimation = require_render.renderAnimation;
|
|
5
6
|
exports.renderSvg = require_render.renderSvg;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as RenderOptions, c as
|
|
1
|
+
import { a as RenderOptions, c as render, i as RenderInput, l as renderAnimation, n as ImagesInput, o as RenderSvgOptions, r as RenderAnimationOptions, s as measure, t as AnimationScene, u as renderSvg } from "./render-DRoDMAA1.cjs";
|
|
2
2
|
import { AnimationOutputFormat, DitheringAlgorithm, Font, FontDetails, FontLoader, ImageSource, Keyframes, KeyframesMap, KeyframesRuleList, MeasuredNode, MeasuredTextRun, OutputFormat } from "@takumi-rs/core";
|
|
3
3
|
import { AnimationRule, ContainerNode, CssInput, Declarations, FetchOptions, ImageNode, LayerRule, MediaRule, Node, NodeAttributes, NodeMetadata, ReactElementLike, RgbaImage, StyleRule, SupportsRule, TextNode } from "@takumi-rs/helpers";
|
|
4
4
|
//#region src/glyph-cache.d.ts
|
|
@@ -24,4 +24,4 @@ declare module "react" {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
//#endregion
|
|
27
|
-
export { type AnimationOutputFormat, type AnimationRule, type AnimationScene, type ContainerNode, type CssInput, type Declarations, type DitheringAlgorithm, type FetchOptions, type Font, type FontDetails, type FontLoader, type ImageNode, type ImageSource, type ImagesInput, type Keyframes, type KeyframesMap, type KeyframesRuleList, type LayerRule, type MeasuredNode, type MeasuredTextRun, type MediaRule, type Node, type NodeAttributes, type NodeMetadata, type OutputFormat, type ReactElementLike, type RenderAnimationOptions, type RenderInput, type RenderOptions, type RenderSvgOptions, type RgbaImage, type StyleRule, type SupportsRule, type TextNode, render, renderAnimation, renderSvg, setGlyphCacheMaxBytes };
|
|
27
|
+
export { type AnimationOutputFormat, type AnimationRule, type AnimationScene, type ContainerNode, type CssInput, type Declarations, type DitheringAlgorithm, type FetchOptions, type Font, type FontDetails, type FontLoader, type ImageNode, type ImageSource, type ImagesInput, type Keyframes, type KeyframesMap, type KeyframesRuleList, type LayerRule, type MeasuredNode, type MeasuredTextRun, type MediaRule, type Node, type NodeAttributes, type NodeMetadata, type OutputFormat, type ReactElementLike, type RenderAnimationOptions, type RenderInput, type RenderOptions, type RenderSvgOptions, type RgbaImage, type StyleRule, type SupportsRule, type TextNode, measure, render, renderAnimation, renderSvg, setGlyphCacheMaxBytes };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as RenderOptions, c as
|
|
1
|
+
import { a as RenderOptions, c as render, i as RenderInput, l as renderAnimation, n as ImagesInput, o as RenderSvgOptions, r as RenderAnimationOptions, s as measure, t as AnimationScene, u as renderSvg } from "./render-D36x-iF4.mjs";
|
|
2
2
|
import { AnimationRule, ContainerNode, CssInput, Declarations, FetchOptions, ImageNode, LayerRule, MediaRule, Node, NodeAttributes, NodeMetadata, ReactElementLike, RgbaImage, StyleRule, SupportsRule, TextNode } from "@takumi-rs/helpers";
|
|
3
3
|
import { AnimationOutputFormat, DitheringAlgorithm, Font, FontDetails, FontLoader, ImageSource, Keyframes, KeyframesMap, KeyframesRuleList, MeasuredNode, MeasuredTextRun, OutputFormat } from "@takumi-rs/core";
|
|
4
4
|
//#region src/glyph-cache.d.ts
|
|
@@ -24,4 +24,4 @@ declare module "react" {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
//#endregion
|
|
27
|
-
export { type AnimationOutputFormat, type AnimationRule, type AnimationScene, type ContainerNode, type CssInput, type Declarations, type DitheringAlgorithm, type FetchOptions, type Font, type FontDetails, type FontLoader, type ImageNode, type ImageSource, type ImagesInput, type Keyframes, type KeyframesMap, type KeyframesRuleList, type LayerRule, type MeasuredNode, type MeasuredTextRun, type MediaRule, type Node, type NodeAttributes, type NodeMetadata, type OutputFormat, type ReactElementLike, type RenderAnimationOptions, type RenderInput, type RenderOptions, type RenderSvgOptions, type RgbaImage, type StyleRule, type SupportsRule, type TextNode, render, renderAnimation, renderSvg, setGlyphCacheMaxBytes };
|
|
27
|
+
export { type AnimationOutputFormat, type AnimationRule, type AnimationScene, type ContainerNode, type CssInput, type Declarations, type DitheringAlgorithm, type FetchOptions, type Font, type FontDetails, type FontLoader, type ImageNode, type ImageSource, type ImagesInput, type Keyframes, type KeyframesMap, type KeyframesRuleList, type LayerRule, type MeasuredNode, type MeasuredTextRun, type MediaRule, type Node, type NodeAttributes, type NodeMetadata, type OutputFormat, type ReactElementLike, type RenderAnimationOptions, type RenderInput, type RenderOptions, type RenderSvgOptions, type RgbaImage, type StyleRule, type SupportsRule, type TextNode, measure, render, renderAnimation, renderSvg, setGlyphCacheMaxBytes };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { render, renderAnimation, renderSvg, setGlyphCacheMaxBytes };
|
|
1
|
+
import { a as setGlyphCacheMaxBytes, i as renderSvg, n as render, r as renderAnimation, t as measure } from "./render-DNAu8Luv.mjs";
|
|
2
|
+
export { measure, render, renderAnimation, renderSvg, setGlyphCacheMaxBytes };
|
|
@@ -113,6 +113,24 @@ function mergeCss(options, extra) {
|
|
|
113
113
|
if (options?.stylesheets !== void 0) warnStylesheetsDeprecated();
|
|
114
114
|
return [...options?.css !== void 0 ? isCssList(options.css) ? options.css : [options.css] : options?.stylesheets ?? [], ...extra];
|
|
115
115
|
}
|
|
116
|
+
/** Resolves the renderer, node tree, and backend options, images and CSS merged in, a single scene needs. */
|
|
117
|
+
async function prepareScene(element, options) {
|
|
118
|
+
options?.signal?.throwIfAborted();
|
|
119
|
+
const renderer = await resolveRenderer(options);
|
|
120
|
+
const { node, css } = await resolveContent(element, options);
|
|
121
|
+
const images = await collectImages(node, options);
|
|
122
|
+
options?.signal?.throwIfAborted();
|
|
123
|
+
const { css: _, stylesheets: _alias, ...forward } = options ?? {};
|
|
124
|
+
return {
|
|
125
|
+
renderer,
|
|
126
|
+
node,
|
|
127
|
+
options: {
|
|
128
|
+
...forward,
|
|
129
|
+
images,
|
|
130
|
+
css: mergeCss(options, css)
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
116
134
|
/**
|
|
117
135
|
* Renders a React element, HTML string, or Takumi node tree into an image.
|
|
118
136
|
*
|
|
@@ -134,17 +152,27 @@ function mergeCss(options, extra) {
|
|
|
134
152
|
* @returns A promise that resolves to the rendered image data (Buffer/Uint8Array).
|
|
135
153
|
*/
|
|
136
154
|
async function render(element, options) {
|
|
137
|
-
options
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
155
|
+
const scene = await prepareScene(element, options);
|
|
156
|
+
return scene.renderer.render(scene.node, scene.options);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Lays out a React element, HTML string, or Takumi node tree without painting it.
|
|
160
|
+
*
|
|
161
|
+
* Same input handling, CSS, emoji, and image pipeline as {@link render}, on the same default
|
|
162
|
+
* renderer, so fonts registered for rendering measure too.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```tsx
|
|
166
|
+
* import { measure } from "takumi-js";
|
|
167
|
+
*
|
|
168
|
+
* const { width, height } = await measure(<span tw="text-xl">Hello World</span>);
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @returns A promise that resolves to the measured node tree.
|
|
172
|
+
*/
|
|
173
|
+
async function measure(element, options) {
|
|
174
|
+
const scene = await prepareScene(element, options);
|
|
175
|
+
return scene.renderer.measure(scene.node, scene.options);
|
|
148
176
|
}
|
|
149
177
|
/**
|
|
150
178
|
* Renders a React element, HTML string, or Takumi node tree into a vector SVG
|
|
@@ -167,17 +195,8 @@ async function render(element, options) {
|
|
|
167
195
|
* @returns A promise that resolves to the SVG document string.
|
|
168
196
|
*/
|
|
169
197
|
async function renderSvg(element, options) {
|
|
170
|
-
options
|
|
171
|
-
|
|
172
|
-
const { node, css: extractedCss } = await resolveContent(element, options);
|
|
173
|
-
const images = await collectImages(node, options);
|
|
174
|
-
options?.signal?.throwIfAborted();
|
|
175
|
-
const { css: _, stylesheets: _alias, ...forward } = options ?? {};
|
|
176
|
-
return renderer.renderSvg(node, {
|
|
177
|
-
...forward,
|
|
178
|
-
images,
|
|
179
|
-
css: mergeCss(options, extractedCss)
|
|
180
|
-
});
|
|
198
|
+
const scene = await prepareScene(element, options);
|
|
199
|
+
return scene.renderer.renderSvg(scene.node, scene.options);
|
|
181
200
|
}
|
|
182
201
|
/**
|
|
183
202
|
* Renders a sequence of scenes into an animated image (WebP / APNG / GIF).
|
|
@@ -229,6 +248,12 @@ async function renderAnimation(options) {
|
|
|
229
248
|
});
|
|
230
249
|
}
|
|
231
250
|
//#endregion
|
|
251
|
+
Object.defineProperty(exports, "measure", {
|
|
252
|
+
enumerable: true,
|
|
253
|
+
get: function() {
|
|
254
|
+
return measure;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
232
257
|
Object.defineProperty(exports, "render", {
|
|
233
258
|
enumerable: true,
|
|
234
259
|
get: function() {
|
|
@@ -99,6 +99,22 @@ type RenderInput = ReactNode | ReactElementLike | Node | string;
|
|
|
99
99
|
* @returns A promise that resolves to the rendered image data (Buffer/Uint8Array).
|
|
100
100
|
*/
|
|
101
101
|
declare function render(element: RenderInput, options?: RenderOptions): Promise<Buffer<ArrayBuffer> | Uint8Array<ArrayBuffer>>;
|
|
102
|
+
/**
|
|
103
|
+
* Lays out a React element, HTML string, or Takumi node tree without painting it.
|
|
104
|
+
*
|
|
105
|
+
* Same input handling, CSS, emoji, and image pipeline as {@link render}, on the same default
|
|
106
|
+
* renderer, so fonts registered for rendering measure too.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```tsx
|
|
110
|
+
* import { measure } from "takumi-js";
|
|
111
|
+
*
|
|
112
|
+
* const { width, height } = await measure(<span tw="text-xl">Hello World</span>);
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* @returns A promise that resolves to the measured node tree.
|
|
116
|
+
*/
|
|
117
|
+
declare function measure(element: RenderInput, options?: RenderOptions): Promise<napi.MeasuredNode>;
|
|
102
118
|
/**
|
|
103
119
|
* Renders a React element, HTML string, or Takumi node tree into a vector SVG
|
|
104
120
|
* document string.
|
|
@@ -146,4 +162,4 @@ declare function renderSvg(element: RenderInput, options?: RenderSvgOptions): Pr
|
|
|
146
162
|
*/
|
|
147
163
|
declare function renderAnimation(options: RenderAnimationOptions): Promise<Buffer<ArrayBuffer> | Uint8Array<ArrayBuffer>>;
|
|
148
164
|
//#endregion
|
|
149
|
-
export { RenderOptions as a,
|
|
165
|
+
export { RenderOptions as a, render as c, RenderInput as i, renderAnimation as l, ImagesInput as n, RenderSvgOptions as o, RenderAnimationOptions as r, measure as s, AnimationScene as t, renderSvg as u };
|
|
@@ -113,6 +113,24 @@ function mergeCss(options, extra) {
|
|
|
113
113
|
if (options?.stylesheets !== void 0) warnStylesheetsDeprecated();
|
|
114
114
|
return [...options?.css !== void 0 ? isCssList(options.css) ? options.css : [options.css] : options?.stylesheets ?? [], ...extra];
|
|
115
115
|
}
|
|
116
|
+
/** Resolves the renderer, node tree, and backend options, images and CSS merged in, a single scene needs. */
|
|
117
|
+
async function prepareScene(element, options) {
|
|
118
|
+
options?.signal?.throwIfAborted();
|
|
119
|
+
const renderer = await resolveRenderer(options);
|
|
120
|
+
const { node, css } = await resolveContent(element, options);
|
|
121
|
+
const images = await collectImages(node, options);
|
|
122
|
+
options?.signal?.throwIfAborted();
|
|
123
|
+
const { css: _, stylesheets: _alias, ...forward } = options ?? {};
|
|
124
|
+
return {
|
|
125
|
+
renderer,
|
|
126
|
+
node,
|
|
127
|
+
options: {
|
|
128
|
+
...forward,
|
|
129
|
+
images,
|
|
130
|
+
css: mergeCss(options, css)
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
116
134
|
/**
|
|
117
135
|
* Renders a React element, HTML string, or Takumi node tree into an image.
|
|
118
136
|
*
|
|
@@ -134,17 +152,27 @@ function mergeCss(options, extra) {
|
|
|
134
152
|
* @returns A promise that resolves to the rendered image data (Buffer/Uint8Array).
|
|
135
153
|
*/
|
|
136
154
|
async function render(element, options) {
|
|
137
|
-
options
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
155
|
+
const scene = await prepareScene(element, options);
|
|
156
|
+
return scene.renderer.render(scene.node, scene.options);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Lays out a React element, HTML string, or Takumi node tree without painting it.
|
|
160
|
+
*
|
|
161
|
+
* Same input handling, CSS, emoji, and image pipeline as {@link render}, on the same default
|
|
162
|
+
* renderer, so fonts registered for rendering measure too.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```tsx
|
|
166
|
+
* import { measure } from "takumi-js";
|
|
167
|
+
*
|
|
168
|
+
* const { width, height } = await measure(<span tw="text-xl">Hello World</span>);
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @returns A promise that resolves to the measured node tree.
|
|
172
|
+
*/
|
|
173
|
+
async function measure(element, options) {
|
|
174
|
+
const scene = await prepareScene(element, options);
|
|
175
|
+
return scene.renderer.measure(scene.node, scene.options);
|
|
148
176
|
}
|
|
149
177
|
/**
|
|
150
178
|
* Renders a React element, HTML string, or Takumi node tree into a vector SVG
|
|
@@ -167,17 +195,8 @@ async function render(element, options) {
|
|
|
167
195
|
* @returns A promise that resolves to the SVG document string.
|
|
168
196
|
*/
|
|
169
197
|
async function renderSvg(element, options) {
|
|
170
|
-
options
|
|
171
|
-
|
|
172
|
-
const { node, css: extractedCss } = await resolveContent(element, options);
|
|
173
|
-
const images = await collectImages(node, options);
|
|
174
|
-
options?.signal?.throwIfAborted();
|
|
175
|
-
const { css: _, stylesheets: _alias, ...forward } = options ?? {};
|
|
176
|
-
return renderer.renderSvg(node, {
|
|
177
|
-
...forward,
|
|
178
|
-
images,
|
|
179
|
-
css: mergeCss(options, extractedCss)
|
|
180
|
-
});
|
|
198
|
+
const scene = await prepareScene(element, options);
|
|
199
|
+
return scene.renderer.renderSvg(scene.node, scene.options);
|
|
181
200
|
}
|
|
182
201
|
/**
|
|
183
202
|
* Renders a sequence of scenes into an animated image (WebP / APNG / GIF).
|
|
@@ -229,4 +248,4 @@ async function renderAnimation(options) {
|
|
|
229
248
|
});
|
|
230
249
|
}
|
|
231
250
|
//#endregion
|
|
232
|
-
export { setGlyphCacheMaxBytes as i,
|
|
251
|
+
export { setGlyphCacheMaxBytes as a, renderSvg as i, render as n, renderAnimation as r, measure as t };
|
|
@@ -99,6 +99,22 @@ type RenderInput = ReactNode | ReactElementLike | Node | string;
|
|
|
99
99
|
* @returns A promise that resolves to the rendered image data (Buffer/Uint8Array).
|
|
100
100
|
*/
|
|
101
101
|
declare function render(element: RenderInput, options?: RenderOptions): Promise<Buffer<ArrayBuffer> | Uint8Array<ArrayBuffer>>;
|
|
102
|
+
/**
|
|
103
|
+
* Lays out a React element, HTML string, or Takumi node tree without painting it.
|
|
104
|
+
*
|
|
105
|
+
* Same input handling, CSS, emoji, and image pipeline as {@link render}, on the same default
|
|
106
|
+
* renderer, so fonts registered for rendering measure too.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```tsx
|
|
110
|
+
* import { measure } from "takumi-js";
|
|
111
|
+
*
|
|
112
|
+
* const { width, height } = await measure(<span tw="text-xl">Hello World</span>);
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* @returns A promise that resolves to the measured node tree.
|
|
116
|
+
*/
|
|
117
|
+
declare function measure(element: RenderInput, options?: RenderOptions): Promise<napi.MeasuredNode>;
|
|
102
118
|
/**
|
|
103
119
|
* Renders a React element, HTML string, or Takumi node tree into a vector SVG
|
|
104
120
|
* document string.
|
|
@@ -146,4 +162,4 @@ declare function renderSvg(element: RenderInput, options?: RenderSvgOptions): Pr
|
|
|
146
162
|
*/
|
|
147
163
|
declare function renderAnimation(options: RenderAnimationOptions): Promise<Buffer<ArrayBuffer> | Uint8Array<ArrayBuffer>>;
|
|
148
164
|
//#endregion
|
|
149
|
-
export { RenderOptions as a,
|
|
165
|
+
export { RenderOptions as a, render as c, RenderInput as i, renderAnimation as l, ImagesInput as n, RenderSvgOptions as o, RenderAnimationOptions as r, measure as s, AnimationScene as t, renderSvg as u };
|
package/dist/response.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_render = require("./render-
|
|
5
|
+
const require_render = require("./render-BmM58jcW.cjs");
|
|
6
6
|
//#region src/response/index.ts
|
|
7
7
|
const contentTypeMap = {
|
|
8
8
|
png: "image/png",
|
|
@@ -15,7 +15,8 @@ function defaultErrorHandler(error) {
|
|
|
15
15
|
console.error("Failed to render image.");
|
|
16
16
|
console.error(error);
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
/** Streams the rendered image; `ready` settles once the render finishes or fails. */
|
|
19
|
+
function renderStream(element, options) {
|
|
19
20
|
let resolveReady;
|
|
20
21
|
let rejectReady;
|
|
21
22
|
const ready = new Promise((resolve, reject) => {
|
|
@@ -23,30 +24,21 @@ function buildImageResponse(element, options) {
|
|
|
23
24
|
rejectReady = reject;
|
|
24
25
|
});
|
|
25
26
|
ready.catch(() => {});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
headers,
|
|
42
|
-
status: options?.status,
|
|
43
|
-
statusText: options?.statusText
|
|
44
|
-
});
|
|
45
|
-
return Object.defineProperty(response, "ready", {
|
|
46
|
-
enumerable: false,
|
|
47
|
-
value: ready,
|
|
48
|
-
writable: false
|
|
49
|
-
});
|
|
27
|
+
return {
|
|
28
|
+
stream: new ReadableStream({ async start(controller) {
|
|
29
|
+
try {
|
|
30
|
+
const image = await require_render.render(element, options);
|
|
31
|
+
controller.enqueue(image);
|
|
32
|
+
controller.close();
|
|
33
|
+
resolveReady();
|
|
34
|
+
} catch (error) {
|
|
35
|
+
controller.error(error);
|
|
36
|
+
rejectReady(error);
|
|
37
|
+
await (options?.onError ?? defaultErrorHandler)(error);
|
|
38
|
+
}
|
|
39
|
+
} }),
|
|
40
|
+
ready
|
|
41
|
+
};
|
|
50
42
|
}
|
|
51
43
|
/**
|
|
52
44
|
* A universal ImageResponse class for generating images in API routes.
|
|
@@ -74,9 +66,15 @@ function buildImageResponse(element, options) {
|
|
|
74
66
|
var ImageResponse = class extends Response {
|
|
75
67
|
ready;
|
|
76
68
|
constructor(component, options) {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
const { stream, ready } = renderStream(component, options);
|
|
70
|
+
const headers = new Headers(options?.headers);
|
|
71
|
+
if (!headers.get("content-type")) headers.set("content-type", contentTypeMap[options?.format ?? "png"]);
|
|
72
|
+
super(stream, {
|
|
73
|
+
headers,
|
|
74
|
+
status: options?.status,
|
|
75
|
+
statusText: options?.statusText
|
|
76
|
+
});
|
|
77
|
+
this.ready = ready;
|
|
80
78
|
}
|
|
81
79
|
};
|
|
82
80
|
//#endregion
|
package/dist/response.d.cts
CHANGED
package/dist/response.d.mts
CHANGED
package/dist/response.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as render } from "./render-DNAu8Luv.mjs";
|
|
2
2
|
//#region src/response/index.ts
|
|
3
3
|
const contentTypeMap = {
|
|
4
4
|
png: "image/png",
|
|
@@ -11,7 +11,8 @@ function defaultErrorHandler(error) {
|
|
|
11
11
|
console.error("Failed to render image.");
|
|
12
12
|
console.error(error);
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
/** Streams the rendered image; `ready` settles once the render finishes or fails. */
|
|
15
|
+
function renderStream(element, options) {
|
|
15
16
|
let resolveReady;
|
|
16
17
|
let rejectReady;
|
|
17
18
|
const ready = new Promise((resolve, reject) => {
|
|
@@ -19,30 +20,21 @@ function buildImageResponse(element, options) {
|
|
|
19
20
|
rejectReady = reject;
|
|
20
21
|
});
|
|
21
22
|
ready.catch(() => {});
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
headers,
|
|
38
|
-
status: options?.status,
|
|
39
|
-
statusText: options?.statusText
|
|
40
|
-
});
|
|
41
|
-
return Object.defineProperty(response, "ready", {
|
|
42
|
-
enumerable: false,
|
|
43
|
-
value: ready,
|
|
44
|
-
writable: false
|
|
45
|
-
});
|
|
23
|
+
return {
|
|
24
|
+
stream: new ReadableStream({ async start(controller) {
|
|
25
|
+
try {
|
|
26
|
+
const image = await render(element, options);
|
|
27
|
+
controller.enqueue(image);
|
|
28
|
+
controller.close();
|
|
29
|
+
resolveReady();
|
|
30
|
+
} catch (error) {
|
|
31
|
+
controller.error(error);
|
|
32
|
+
rejectReady(error);
|
|
33
|
+
await (options?.onError ?? defaultErrorHandler)(error);
|
|
34
|
+
}
|
|
35
|
+
} }),
|
|
36
|
+
ready
|
|
37
|
+
};
|
|
46
38
|
}
|
|
47
39
|
/**
|
|
48
40
|
* A universal ImageResponse class for generating images in API routes.
|
|
@@ -70,9 +62,15 @@ function buildImageResponse(element, options) {
|
|
|
70
62
|
var ImageResponse = class extends Response {
|
|
71
63
|
ready;
|
|
72
64
|
constructor(component, options) {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
65
|
+
const { stream, ready } = renderStream(component, options);
|
|
66
|
+
const headers = new Headers(options?.headers);
|
|
67
|
+
if (!headers.get("content-type")) headers.set("content-type", contentTypeMap[options?.format ?? "png"]);
|
|
68
|
+
super(stream, {
|
|
69
|
+
headers,
|
|
70
|
+
status: options?.status,
|
|
71
|
+
statusText: options?.statusText
|
|
72
|
+
});
|
|
73
|
+
this.ready = ready;
|
|
76
74
|
}
|
|
77
75
|
};
|
|
78
76
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "takumi-js",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"description": "Render OG images from JSX, HTML, and CSS. No headless browser.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"animated-webp",
|
|
@@ -238,15 +238,15 @@
|
|
|
238
238
|
"publish-lint": "attw --pack . && publint --strict ."
|
|
239
239
|
},
|
|
240
240
|
"dependencies": {
|
|
241
|
-
"@takumi-rs/core": "2.
|
|
242
|
-
"@takumi-rs/helpers": "2.
|
|
243
|
-
"@takumi-rs/wasm": "2.
|
|
241
|
+
"@takumi-rs/core": "2.15.0",
|
|
242
|
+
"@takumi-rs/helpers": "2.15.0",
|
|
243
|
+
"@takumi-rs/wasm": "2.15.0"
|
|
244
244
|
},
|
|
245
245
|
"devDependencies": {
|
|
246
|
-
"@types/bun": "^1.4.
|
|
246
|
+
"@types/bun": "^1.4.1",
|
|
247
247
|
"@types/react": "19.2.18",
|
|
248
248
|
"react": "^19.2.8",
|
|
249
|
-
"tsdown": "0.
|
|
249
|
+
"tsdown": "0.23.0",
|
|
250
250
|
"unrun": "^0.3.1"
|
|
251
251
|
},
|
|
252
252
|
"engines": {
|