takumi-js 1.8.7 → 2.0.0-beta.1

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/dist/index.cjs CHANGED
@@ -1,3 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_render = require("./render-BkAfi_5a.cjs");
2
+ const require_render = require("./render-BWrJI7_9.cjs");
3
3
  exports.render = require_render.render;
4
+ exports.renderAnimation = require_render.renderAnimation;
5
+ exports.renderSvg = require_render.renderSvg;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { n as RenderOptions, r as render } from "./render-lU4_qVw3.cjs";
1
+ import { a as RenderSvgOptions, c as renderSvg, i as RenderOptions, n as RenderAnimationScene, o as render, r as RenderInput, s as renderAnimation, t as RenderAnimationOptions } from "./render-DJjKHz2l.cjs";
2
2
  import { ContainerNode, FetchResourcesOptions, ImageNode, Node, NodeAttributes, NodeMetadata, ReactElementLike, TextNode } from "@takumi-rs/helpers";
3
- import { AnimationFrameSource, AnimationOutputFormat, AnimationSceneSource, ConstructRendererOptions, DitheringAlgorithm, EncodeFramesOptions, Font, FontDetails, FontLoader, FontLoaderSync, ImageSource, ImageSourceLoader, ImageSourceLoaderSync, Keyframes, KeyframesMap, KeyframesRuleList, MeasuredNode, MeasuredTextRun, OutputFormat, RenderAnimationOptions } from "@takumi-rs/core";
3
+ import { AnimationFrameSource, AnimationOutputFormat, AnimationSceneSource, DitheringAlgorithm, EncodeFramesOptions, Font, FontDetails, FontLoader, ImageSource, Keyframes, KeyframesMap, KeyframesRuleList, MeasuredNode, MeasuredTextRun, OutputFormat } from "@takumi-rs/core";
4
4
 
5
5
  //#region src/index.d.ts
6
6
  declare module "react" {
@@ -9,4 +9,4 @@ declare module "react" {
9
9
  }
10
10
  }
11
11
  //#endregion
12
- export { type AnimationFrameSource, type AnimationOutputFormat, type AnimationSceneSource, type ConstructRendererOptions, type ContainerNode, type DitheringAlgorithm, type EncodeFramesOptions, type FetchResourcesOptions, type Font, type FontDetails, type FontLoader, type FontLoaderSync, type ImageNode, type ImageSource, type ImageSourceLoader, type ImageSourceLoaderSync, type Keyframes, type KeyframesMap, type KeyframesRuleList, type MeasuredNode, type MeasuredTextRun, type Node, type NodeAttributes, type NodeMetadata, type OutputFormat, type ReactElementLike, type RenderAnimationOptions, type RenderOptions, type TextNode, render };
12
+ export { type AnimationFrameSource, type AnimationOutputFormat, type AnimationSceneSource, type ContainerNode, type DitheringAlgorithm, type EncodeFramesOptions, type FetchResourcesOptions, type Font, type FontDetails, type FontLoader, type ImageNode, type ImageSource, type Keyframes, type KeyframesMap, type KeyframesRuleList, type MeasuredNode, type MeasuredTextRun, type Node, type NodeAttributes, type NodeMetadata, type OutputFormat, type ReactElementLike, type RenderAnimationOptions, type RenderAnimationScene, type RenderInput, type RenderOptions, type RenderSvgOptions, type TextNode, render, renderAnimation, renderSvg };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { n as RenderOptions, r as render } from "./render-lU4_qVw3.mjs";
1
+ import { a as RenderSvgOptions, c as renderSvg, i as RenderOptions, n as RenderAnimationScene, o as render, r as RenderInput, s as renderAnimation, t as RenderAnimationOptions } from "./render-DJjKHz2l.mjs";
2
2
  import { ContainerNode, FetchResourcesOptions, ImageNode, Node, NodeAttributes, NodeMetadata, ReactElementLike, TextNode } from "@takumi-rs/helpers";
3
- import { AnimationFrameSource, AnimationOutputFormat, AnimationSceneSource, ConstructRendererOptions, DitheringAlgorithm, EncodeFramesOptions, Font, FontDetails, FontLoader, FontLoaderSync, ImageSource, ImageSourceLoader, ImageSourceLoaderSync, Keyframes, KeyframesMap, KeyframesRuleList, MeasuredNode, MeasuredTextRun, OutputFormat, RenderAnimationOptions } from "@takumi-rs/core";
3
+ import { AnimationFrameSource, AnimationOutputFormat, AnimationSceneSource, DitheringAlgorithm, EncodeFramesOptions, Font, FontDetails, FontLoader, ImageSource, Keyframes, KeyframesMap, KeyframesRuleList, MeasuredNode, MeasuredTextRun, OutputFormat } from "@takumi-rs/core";
4
4
 
5
5
  //#region src/index.d.ts
6
6
  declare module "react" {
@@ -9,4 +9,4 @@ declare module "react" {
9
9
  }
10
10
  }
11
11
  //#endregion
12
- export { type AnimationFrameSource, type AnimationOutputFormat, type AnimationSceneSource, type ConstructRendererOptions, type ContainerNode, type DitheringAlgorithm, type EncodeFramesOptions, type FetchResourcesOptions, type Font, type FontDetails, type FontLoader, type FontLoaderSync, type ImageNode, type ImageSource, type ImageSourceLoader, type ImageSourceLoaderSync, type Keyframes, type KeyframesMap, type KeyframesRuleList, type MeasuredNode, type MeasuredTextRun, type Node, type NodeAttributes, type NodeMetadata, type OutputFormat, type ReactElementLike, type RenderAnimationOptions, type RenderOptions, type TextNode, render };
12
+ export { type AnimationFrameSource, type AnimationOutputFormat, type AnimationSceneSource, type ContainerNode, type DitheringAlgorithm, type EncodeFramesOptions, type FetchResourcesOptions, type Font, type FontDetails, type FontLoader, type ImageNode, type ImageSource, type Keyframes, type KeyframesMap, type KeyframesRuleList, type MeasuredNode, type MeasuredTextRun, type Node, type NodeAttributes, type NodeMetadata, type OutputFormat, type ReactElementLike, type RenderAnimationOptions, type RenderAnimationScene, type RenderInput, type RenderOptions, type RenderSvgOptions, type TextNode, render, renderAnimation, renderSvg };
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as render } from "./render-BKqYuN_7.mjs";
2
- export { render };
1
+ import { n as renderAnimation, r as renderSvg, t as render } from "./render-1w0Pei0G.mjs";
2
+ export { render, renderAnimation, renderSvg };
@@ -2,22 +2,6 @@ import { extractEmojis } from "@takumi-rs/helpers/emoji";
2
2
  import { extractResourceUrls, fetchResources } from "@takumi-rs/helpers";
3
3
  import { fromJsx } from "@takumi-rs/helpers/jsx";
4
4
  import { fromHtml } from "@takumi-rs/helpers/html";
5
- //#region src/renderer.ts
6
- /**
7
- * Mirrors the renderer constructor behavior: when custom fonts are provided,
8
- * default fonts are disabled so they can't shadow user fonts through generic
9
- * family resolution (e.g. `sans-serif` resolving to the embedded font).
10
- */
11
- function shouldLoadDefaultFonts(options) {
12
- return options?.loadDefaultFonts ?? (options?.fonts?.length ? false : void 0);
13
- }
14
- async function loadRendererResources(renderer, options) {
15
- const tasks = [];
16
- if (options?.fonts && options.fonts.length > 0) tasks.push(renderer.loadFonts(options.fonts));
17
- if (options?.persistentImages && options.persistentImages.length > 0) tasks.push(...options.persistentImages.map((image) => Promise.resolve(renderer.putPersistentImage(image, options.signal))));
18
- if (tasks.length > 0) await Promise.all(tasks);
19
- }
20
- //#endregion
21
5
  //#region src/import.ts
22
6
  let importPromise = null;
23
7
  function getImports(module) {
@@ -106,6 +90,31 @@ async function transformElement(element, options) {
106
90
  if (typeof element === "string") return fromHtml(element);
107
91
  return fromJsx(element, options?.jsx);
108
92
  }
93
+ /** Resolves the renderer to use: a caller-supplied one, or the shared global. */
94
+ async function resolveRenderer(options) {
95
+ if (options && "renderer" in options && options.renderer) return options.renderer;
96
+ const imports = await getImports(options?.module);
97
+ return globalRenderer ??= new imports.Renderer();
98
+ }
99
+ /** Transforms an input into a node tree and extracts its emojis. */
100
+ async function resolveContent(element, options) {
101
+ const { node: originalNode, stylesheets } = await transformElement(element, options);
102
+ const emojiType = options?.emoji ?? "twemoji";
103
+ return {
104
+ node: emojiType !== "from-font" ? extractEmojis(originalNode, emojiType) : originalNode,
105
+ stylesheets
106
+ };
107
+ }
108
+ /** Merges caller-supplied images with the resources fetched from the nodes. */
109
+ async function collectImages(nodes, options) {
110
+ const providedImages = /* @__PURE__ */ new Map();
111
+ for (const image of options?.images ?? []) providedImages.set(image.src, image);
112
+ const fetched = await fetchResources([...new Set(nodes.flatMap((node) => extractResourceUrls(node)))].filter((url) => !providedImages.has(url)), options?.resourcesOptions);
113
+ return [...providedImages.values(), ...fetched];
114
+ }
115
+ function mergeStylesheets(options, extra) {
116
+ return [...options?.stylesheets ?? [], ...extra];
117
+ }
109
118
  /**
110
119
  * Renders a React element, HTML string, or Takumi node tree into an image.
111
120
  *
@@ -128,21 +137,95 @@ async function transformElement(element, options) {
128
137
  */
129
138
  async function render(element, options) {
130
139
  options?.signal?.throwIfAborted();
131
- const imports = await getImports(options && "module" in options ? options.module : void 0);
132
- const isExternalRenderer = options && "renderer" in options;
133
- const renderer = isExternalRenderer ? options.renderer : globalRenderer ??= new imports.Renderer({ loadDefaultFonts: shouldLoadDefaultFonts(options) });
134
- if (!isExternalRenderer) await loadRendererResources(renderer, options);
135
- const { node: originalNode, stylesheets } = await transformElement(element, options);
136
- const emojiType = options?.emoji ?? "twemoji";
137
- const node = emojiType !== "from-font" ? extractEmojis(originalNode, emojiType) : originalNode;
138
- const fetchedResources = options?.fetchedResources ?? await fetchResources(extractResourceUrls(node), options?.resourcesOptions);
139
- const renderOptions = {
140
+ const renderer = await resolveRenderer(options);
141
+ const { node, stylesheets } = await resolveContent(element, options);
142
+ const images = await collectImages([node], options);
143
+ options?.signal?.throwIfAborted();
144
+ return renderer.render(node, {
140
145
  ...options,
141
- fetchedResources,
142
- stylesheets: [...options?.stylesheets ?? [], ...stylesheets]
143
- };
146
+ images,
147
+ stylesheets: mergeStylesheets(options, stylesheets)
148
+ });
149
+ }
150
+ /**
151
+ * Renders a React element, HTML string, or Takumi node tree into a vector SVG
152
+ * document string.
153
+ *
154
+ * Same input handling and resource pipeline as {@link render}, but emits real SVG
155
+ * (`<rect>`, `<path>`, gradients, glyph outlines, embedded images) instead of a
156
+ * raster bitmap.
157
+ *
158
+ * @example
159
+ * ```tsx
160
+ * import { renderSvg } from "takumi-js";
161
+ *
162
+ * const svg = await renderSvg(
163
+ * <div tw="bg-blue-500 text-white p-4">Hello World</div>,
164
+ * { width: 1200, height: 630 }
165
+ * );
166
+ * ```
167
+ *
168
+ * @returns A promise that resolves to the SVG document string.
169
+ */
170
+ async function renderSvg(element, options) {
171
+ options?.signal?.throwIfAborted();
172
+ const renderer = await resolveRenderer(options);
173
+ const { node, stylesheets } = await resolveContent(element, options);
174
+ const images = await collectImages([node], options);
144
175
  options?.signal?.throwIfAborted();
145
- return renderer.render(node, renderOptions, options?.signal);
176
+ return renderer.renderSvg(node, {
177
+ ...options,
178
+ images,
179
+ stylesheets: mergeStylesheets(options, stylesheets)
180
+ });
181
+ }
182
+ /**
183
+ * Renders a sequence of scenes into an animated image (WebP / APNG / GIF).
184
+ *
185
+ * Each scene's content goes through the same input handling and resource pipeline
186
+ * as {@link render}; resources are fetched once across all scenes.
187
+ *
188
+ * @example
189
+ * ```tsx
190
+ * import { renderAnimation } from "takumi-js";
191
+ *
192
+ * const webp = await renderAnimation({
193
+ * width: 600,
194
+ * height: 400,
195
+ * fps: 30,
196
+ * format: "webp",
197
+ * scenes: [
198
+ * { node: <div tw="bg-red-500 w-full h-full" />, durationMs: 500 },
199
+ * { node: <div tw="bg-blue-500 w-full h-full" />, durationMs: 500 },
200
+ * ],
201
+ * });
202
+ * ```
203
+ *
204
+ * @returns A promise that resolves to the encoded animation (Buffer/Uint8Array).
205
+ */
206
+ async function renderAnimation(options) {
207
+ options.signal?.throwIfAborted();
208
+ const renderer = await resolveRenderer(options);
209
+ const scenes = await Promise.all(options.scenes.map(async (scene) => {
210
+ const { node, stylesheets } = await resolveContent(scene.node, options);
211
+ return {
212
+ node,
213
+ durationMs: scene.durationMs,
214
+ stylesheets
215
+ };
216
+ }));
217
+ const images = await collectImages(scenes.map((scene) => scene.node), options);
218
+ const stylesheets = mergeStylesheets(options, scenes.flatMap((scene) => scene.stylesheets));
219
+ options.signal?.throwIfAborted();
220
+ return renderer.renderAnimation({
221
+ ...options,
222
+ scenes: scenes.map(({ node, durationMs }) => ({
223
+ node,
224
+ durationMs
225
+ })),
226
+ images,
227
+ stylesheets
228
+ });
146
229
  }
147
230
  //#endregion
148
- export { render as t };
231
+ export { renderAnimation as n, renderSvg as r, render as t };
@@ -2,22 +2,6 @@ let _takumi_rs_helpers_emoji = require("@takumi-rs/helpers/emoji");
2
2
  let _takumi_rs_helpers = require("@takumi-rs/helpers");
3
3
  let _takumi_rs_helpers_jsx = require("@takumi-rs/helpers/jsx");
4
4
  let _takumi_rs_helpers_html = require("@takumi-rs/helpers/html");
5
- //#region src/renderer.ts
6
- /**
7
- * Mirrors the renderer constructor behavior: when custom fonts are provided,
8
- * default fonts are disabled so they can't shadow user fonts through generic
9
- * family resolution (e.g. `sans-serif` resolving to the embedded font).
10
- */
11
- function shouldLoadDefaultFonts(options) {
12
- return options?.loadDefaultFonts ?? (options?.fonts?.length ? false : void 0);
13
- }
14
- async function loadRendererResources(renderer, options) {
15
- const tasks = [];
16
- if (options?.fonts && options.fonts.length > 0) tasks.push(renderer.loadFonts(options.fonts));
17
- if (options?.persistentImages && options.persistentImages.length > 0) tasks.push(...options.persistentImages.map((image) => Promise.resolve(renderer.putPersistentImage(image, options.signal))));
18
- if (tasks.length > 0) await Promise.all(tasks);
19
- }
20
- //#endregion
21
5
  //#region src/import.ts
22
6
  let importPromise = null;
23
7
  function getImports(module) {
@@ -106,6 +90,31 @@ async function transformElement(element, options) {
106
90
  if (typeof element === "string") return (0, _takumi_rs_helpers_html.fromHtml)(element);
107
91
  return (0, _takumi_rs_helpers_jsx.fromJsx)(element, options?.jsx);
108
92
  }
93
+ /** Resolves the renderer to use: a caller-supplied one, or the shared global. */
94
+ async function resolveRenderer(options) {
95
+ if (options && "renderer" in options && options.renderer) return options.renderer;
96
+ const imports = await getImports(options?.module);
97
+ return globalRenderer ??= new imports.Renderer();
98
+ }
99
+ /** Transforms an input into a node tree and extracts its emojis. */
100
+ async function resolveContent(element, options) {
101
+ const { node: originalNode, stylesheets } = await transformElement(element, options);
102
+ const emojiType = options?.emoji ?? "twemoji";
103
+ return {
104
+ node: emojiType !== "from-font" ? (0, _takumi_rs_helpers_emoji.extractEmojis)(originalNode, emojiType) : originalNode,
105
+ stylesheets
106
+ };
107
+ }
108
+ /** Merges caller-supplied images with the resources fetched from the nodes. */
109
+ async function collectImages(nodes, options) {
110
+ const providedImages = /* @__PURE__ */ new Map();
111
+ for (const image of options?.images ?? []) providedImages.set(image.src, image);
112
+ const fetched = await (0, _takumi_rs_helpers.fetchResources)([...new Set(nodes.flatMap((node) => (0, _takumi_rs_helpers.extractResourceUrls)(node)))].filter((url) => !providedImages.has(url)), options?.resourcesOptions);
113
+ return [...providedImages.values(), ...fetched];
114
+ }
115
+ function mergeStylesheets(options, extra) {
116
+ return [...options?.stylesheets ?? [], ...extra];
117
+ }
109
118
  /**
110
119
  * Renders a React element, HTML string, or Takumi node tree into an image.
111
120
  *
@@ -128,21 +137,95 @@ async function transformElement(element, options) {
128
137
  */
129
138
  async function render(element, options) {
130
139
  options?.signal?.throwIfAborted();
131
- const imports = await getImports(options && "module" in options ? options.module : void 0);
132
- const isExternalRenderer = options && "renderer" in options;
133
- const renderer = isExternalRenderer ? options.renderer : globalRenderer ??= new imports.Renderer({ loadDefaultFonts: shouldLoadDefaultFonts(options) });
134
- if (!isExternalRenderer) await loadRendererResources(renderer, options);
135
- const { node: originalNode, stylesheets } = await transformElement(element, options);
136
- const emojiType = options?.emoji ?? "twemoji";
137
- const node = emojiType !== "from-font" ? (0, _takumi_rs_helpers_emoji.extractEmojis)(originalNode, emojiType) : originalNode;
138
- const fetchedResources = options?.fetchedResources ?? await (0, _takumi_rs_helpers.fetchResources)((0, _takumi_rs_helpers.extractResourceUrls)(node), options?.resourcesOptions);
139
- const renderOptions = {
140
+ const renderer = await resolveRenderer(options);
141
+ const { node, stylesheets } = await resolveContent(element, options);
142
+ const images = await collectImages([node], options);
143
+ options?.signal?.throwIfAborted();
144
+ return renderer.render(node, {
140
145
  ...options,
141
- fetchedResources,
142
- stylesheets: [...options?.stylesheets ?? [], ...stylesheets]
143
- };
146
+ images,
147
+ stylesheets: mergeStylesheets(options, stylesheets)
148
+ });
149
+ }
150
+ /**
151
+ * Renders a React element, HTML string, or Takumi node tree into a vector SVG
152
+ * document string.
153
+ *
154
+ * Same input handling and resource pipeline as {@link render}, but emits real SVG
155
+ * (`<rect>`, `<path>`, gradients, glyph outlines, embedded images) instead of a
156
+ * raster bitmap.
157
+ *
158
+ * @example
159
+ * ```tsx
160
+ * import { renderSvg } from "takumi-js";
161
+ *
162
+ * const svg = await renderSvg(
163
+ * <div tw="bg-blue-500 text-white p-4">Hello World</div>,
164
+ * { width: 1200, height: 630 }
165
+ * );
166
+ * ```
167
+ *
168
+ * @returns A promise that resolves to the SVG document string.
169
+ */
170
+ async function renderSvg(element, options) {
144
171
  options?.signal?.throwIfAborted();
145
- return renderer.render(node, renderOptions, options?.signal);
172
+ const renderer = await resolveRenderer(options);
173
+ const { node, stylesheets } = await resolveContent(element, options);
174
+ const images = await collectImages([node], options);
175
+ options?.signal?.throwIfAborted();
176
+ return renderer.renderSvg(node, {
177
+ ...options,
178
+ images,
179
+ stylesheets: mergeStylesheets(options, stylesheets)
180
+ });
181
+ }
182
+ /**
183
+ * Renders a sequence of scenes into an animated image (WebP / APNG / GIF).
184
+ *
185
+ * Each scene's content goes through the same input handling and resource pipeline
186
+ * as {@link render}; resources are fetched once across all scenes.
187
+ *
188
+ * @example
189
+ * ```tsx
190
+ * import { renderAnimation } from "takumi-js";
191
+ *
192
+ * const webp = await renderAnimation({
193
+ * width: 600,
194
+ * height: 400,
195
+ * fps: 30,
196
+ * format: "webp",
197
+ * scenes: [
198
+ * { node: <div tw="bg-red-500 w-full h-full" />, durationMs: 500 },
199
+ * { node: <div tw="bg-blue-500 w-full h-full" />, durationMs: 500 },
200
+ * ],
201
+ * });
202
+ * ```
203
+ *
204
+ * @returns A promise that resolves to the encoded animation (Buffer/Uint8Array).
205
+ */
206
+ async function renderAnimation(options) {
207
+ options.signal?.throwIfAborted();
208
+ const renderer = await resolveRenderer(options);
209
+ const scenes = await Promise.all(options.scenes.map(async (scene) => {
210
+ const { node, stylesheets } = await resolveContent(scene.node, options);
211
+ return {
212
+ node,
213
+ durationMs: scene.durationMs,
214
+ stylesheets
215
+ };
216
+ }));
217
+ const images = await collectImages(scenes.map((scene) => scene.node), options);
218
+ const stylesheets = mergeStylesheets(options, scenes.flatMap((scene) => scene.stylesheets));
219
+ options.signal?.throwIfAborted();
220
+ return renderer.renderAnimation({
221
+ ...options,
222
+ scenes: scenes.map(({ node, durationMs }) => ({
223
+ node,
224
+ durationMs
225
+ })),
226
+ images,
227
+ stylesheets
228
+ });
146
229
  }
147
230
  //#endregion
148
231
  Object.defineProperty(exports, "render", {
@@ -151,3 +234,15 @@ Object.defineProperty(exports, "render", {
151
234
  return render;
152
235
  }
153
236
  });
237
+ Object.defineProperty(exports, "renderAnimation", {
238
+ enumerable: true,
239
+ get: function() {
240
+ return renderAnimation;
241
+ }
242
+ });
243
+ Object.defineProperty(exports, "renderSvg", {
244
+ enumerable: true,
245
+ get: function() {
246
+ return renderSvg;
247
+ }
248
+ });
@@ -0,0 +1,117 @@
1
+ import { EmojiType } from "@takumi-rs/helpers/emoji";
2
+ import { FetchResourcesOptions, Node, ReactElementLike } from "@takumi-rs/helpers";
3
+ import { FromJsxOptions } from "@takumi-rs/helpers/jsx";
4
+ import * as napi from "@takumi-rs/core";
5
+ import * as wasm from "@takumi-rs/wasm";
6
+ import { ReactNode } from "react";
7
+
8
+ //#region src/render.d.ts
9
+ type Renderer = napi.Renderer | wasm.Renderer;
10
+ /** The managed-renderer plumbing shared by every entry point. */
11
+ type SharedRenderExtras = {
12
+ renderer: Renderer;
13
+ signal?: AbortSignal;
14
+ jsx?: FromJsxOptions;
15
+ resourcesOptions?: FetchResourcesOptions;
16
+ /**
17
+ * @description The emoji provider to use when rendering emojis. If set to `"from-font"`, the renderer will attempt to source emoji glyphs from the loaded fonts.
18
+ * @default "twemoji"
19
+ */
20
+ emoji?: EmojiType | "from-font";
21
+ };
22
+ type ManagedRendererOptions = {
23
+ /**
24
+ * @description The WebAssembly module to use for the renderer. If not provided, the default resolving strategy will be used.
25
+ */
26
+ module?: wasm.InitInput | Promise<wasm.InitInput> | {
27
+ default: wasm.InitInput;
28
+ };
29
+ };
30
+ /**
31
+ * Adds the managed-renderer plumbing to a set of inner options. Either bring your
32
+ * own `renderer`, or let Takumi resolve one (optionally pointing at a WASM
33
+ * `module`).
34
+ */
35
+ type Managed<TInner> = (TInner & SharedRenderExtras) | (TInner & Omit<SharedRenderExtras, "renderer"> & ManagedRendererOptions);
36
+ type InnerRenderOptions = napi.RenderOptions | wasm.RenderOptions;
37
+ type InnerSvgRenderOptions = napi.SvgRenderOptions | wasm.SvgRenderOptions;
38
+ type InnerRenderAnimationOptions = napi.RenderAnimationOptions | wasm.RenderAnimationOptions;
39
+ type RenderOptions = Managed<InnerRenderOptions>;
40
+ type RenderSvgOptions = Managed<InnerSvgRenderOptions>;
41
+ /** A single animation scene whose content is any renderable input. */
42
+ type RenderAnimationScene = Omit<napi.AnimationSceneSource, "node"> & {
43
+ /** The content to render for this scene: JSX, an HTML string, or a node tree. */node: RenderInput;
44
+ };
45
+ type RenderAnimationOptions = Managed<Omit<InnerRenderAnimationOptions, "scenes"> & {
46
+ /** The scenes to render sequentially. */scenes: RenderAnimationScene[];
47
+ }>;
48
+ type RenderInput = ReactNode | ReactElementLike | Node | string;
49
+ /**
50
+ * Renders a React element, HTML string, or Takumi node tree into an image.
51
+ *
52
+ * This function automatically detects the best renderer for your environment (native Rust on Node.js,
53
+ * WASM on Edge/Workers) and handles resource fetching (fonts, images) and emoji extraction.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * import { render } from "takumi-js";
58
+ *
59
+ * const buffer = await render(
60
+ * <div tw="bg-blue-500 text-white p-4">Hello World</div>,
61
+ * { width: 1200, height: 630 }
62
+ * );
63
+ * ```
64
+ *
65
+ * @param element - The content to render. Can be a JSX element (React-like), an HTML string, or a pre-constructed node tree.
66
+ * @param options - Configuration for rendering, including dimensions, format, fonts, and more.
67
+ * @returns A promise that resolves to the rendered image data (Buffer/Uint8Array).
68
+ */
69
+ declare function render(element: RenderInput, options?: RenderOptions): Promise<Uint8Array<ArrayBufferLike> | Buffer<ArrayBufferLike>>;
70
+ /**
71
+ * Renders a React element, HTML string, or Takumi node tree into a vector SVG
72
+ * document string.
73
+ *
74
+ * Same input handling and resource pipeline as {@link render}, but emits real SVG
75
+ * (`<rect>`, `<path>`, gradients, glyph outlines, embedded images) instead of a
76
+ * raster bitmap.
77
+ *
78
+ * @example
79
+ * ```tsx
80
+ * import { renderSvg } from "takumi-js";
81
+ *
82
+ * const svg = await renderSvg(
83
+ * <div tw="bg-blue-500 text-white p-4">Hello World</div>,
84
+ * { width: 1200, height: 630 }
85
+ * );
86
+ * ```
87
+ *
88
+ * @returns A promise that resolves to the SVG document string.
89
+ */
90
+ declare function renderSvg(element: RenderInput, options?: RenderSvgOptions): Promise<string>;
91
+ /**
92
+ * Renders a sequence of scenes into an animated image (WebP / APNG / GIF).
93
+ *
94
+ * Each scene's content goes through the same input handling and resource pipeline
95
+ * as {@link render}; resources are fetched once across all scenes.
96
+ *
97
+ * @example
98
+ * ```tsx
99
+ * import { renderAnimation } from "takumi-js";
100
+ *
101
+ * const webp = await renderAnimation({
102
+ * width: 600,
103
+ * height: 400,
104
+ * fps: 30,
105
+ * format: "webp",
106
+ * scenes: [
107
+ * { node: <div tw="bg-red-500 w-full h-full" />, durationMs: 500 },
108
+ * { node: <div tw="bg-blue-500 w-full h-full" />, durationMs: 500 },
109
+ * ],
110
+ * });
111
+ * ```
112
+ *
113
+ * @returns A promise that resolves to the encoded animation (Buffer/Uint8Array).
114
+ */
115
+ declare function renderAnimation(options: RenderAnimationOptions): Promise<Uint8Array<ArrayBufferLike> | Buffer<ArrayBufferLike>>;
116
+ //#endregion
117
+ export { RenderSvgOptions as a, renderSvg as c, RenderOptions as i, RenderAnimationScene as n, render as o, RenderInput as r, renderAnimation as s, RenderAnimationOptions as t };
@@ -0,0 +1,117 @@
1
+ import { EmojiType } from "@takumi-rs/helpers/emoji";
2
+ import { FetchResourcesOptions, Node, ReactElementLike } from "@takumi-rs/helpers";
3
+ import { FromJsxOptions } from "@takumi-rs/helpers/jsx";
4
+ import * as napi from "@takumi-rs/core";
5
+ import * as wasm from "@takumi-rs/wasm";
6
+ import { ReactNode } from "react";
7
+
8
+ //#region src/render.d.ts
9
+ type Renderer = napi.Renderer | wasm.Renderer;
10
+ /** The managed-renderer plumbing shared by every entry point. */
11
+ type SharedRenderExtras = {
12
+ renderer: Renderer;
13
+ signal?: AbortSignal;
14
+ jsx?: FromJsxOptions;
15
+ resourcesOptions?: FetchResourcesOptions;
16
+ /**
17
+ * @description The emoji provider to use when rendering emojis. If set to `"from-font"`, the renderer will attempt to source emoji glyphs from the loaded fonts.
18
+ * @default "twemoji"
19
+ */
20
+ emoji?: EmojiType | "from-font";
21
+ };
22
+ type ManagedRendererOptions = {
23
+ /**
24
+ * @description The WebAssembly module to use for the renderer. If not provided, the default resolving strategy will be used.
25
+ */
26
+ module?: wasm.InitInput | Promise<wasm.InitInput> | {
27
+ default: wasm.InitInput;
28
+ };
29
+ };
30
+ /**
31
+ * Adds the managed-renderer plumbing to a set of inner options. Either bring your
32
+ * own `renderer`, or let Takumi resolve one (optionally pointing at a WASM
33
+ * `module`).
34
+ */
35
+ type Managed<TInner> = (TInner & SharedRenderExtras) | (TInner & Omit<SharedRenderExtras, "renderer"> & ManagedRendererOptions);
36
+ type InnerRenderOptions = napi.RenderOptions | wasm.RenderOptions;
37
+ type InnerSvgRenderOptions = napi.SvgRenderOptions | wasm.SvgRenderOptions;
38
+ type InnerRenderAnimationOptions = napi.RenderAnimationOptions | wasm.RenderAnimationOptions;
39
+ type RenderOptions = Managed<InnerRenderOptions>;
40
+ type RenderSvgOptions = Managed<InnerSvgRenderOptions>;
41
+ /** A single animation scene whose content is any renderable input. */
42
+ type RenderAnimationScene = Omit<napi.AnimationSceneSource, "node"> & {
43
+ /** The content to render for this scene: JSX, an HTML string, or a node tree. */node: RenderInput;
44
+ };
45
+ type RenderAnimationOptions = Managed<Omit<InnerRenderAnimationOptions, "scenes"> & {
46
+ /** The scenes to render sequentially. */scenes: RenderAnimationScene[];
47
+ }>;
48
+ type RenderInput = ReactNode | ReactElementLike | Node | string;
49
+ /**
50
+ * Renders a React element, HTML string, or Takumi node tree into an image.
51
+ *
52
+ * This function automatically detects the best renderer for your environment (native Rust on Node.js,
53
+ * WASM on Edge/Workers) and handles resource fetching (fonts, images) and emoji extraction.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * import { render } from "takumi-js";
58
+ *
59
+ * const buffer = await render(
60
+ * <div tw="bg-blue-500 text-white p-4">Hello World</div>,
61
+ * { width: 1200, height: 630 }
62
+ * );
63
+ * ```
64
+ *
65
+ * @param element - The content to render. Can be a JSX element (React-like), an HTML string, or a pre-constructed node tree.
66
+ * @param options - Configuration for rendering, including dimensions, format, fonts, and more.
67
+ * @returns A promise that resolves to the rendered image data (Buffer/Uint8Array).
68
+ */
69
+ declare function render(element: RenderInput, options?: RenderOptions): Promise<Uint8Array<ArrayBufferLike> | Buffer<ArrayBufferLike>>;
70
+ /**
71
+ * Renders a React element, HTML string, or Takumi node tree into a vector SVG
72
+ * document string.
73
+ *
74
+ * Same input handling and resource pipeline as {@link render}, but emits real SVG
75
+ * (`<rect>`, `<path>`, gradients, glyph outlines, embedded images) instead of a
76
+ * raster bitmap.
77
+ *
78
+ * @example
79
+ * ```tsx
80
+ * import { renderSvg } from "takumi-js";
81
+ *
82
+ * const svg = await renderSvg(
83
+ * <div tw="bg-blue-500 text-white p-4">Hello World</div>,
84
+ * { width: 1200, height: 630 }
85
+ * );
86
+ * ```
87
+ *
88
+ * @returns A promise that resolves to the SVG document string.
89
+ */
90
+ declare function renderSvg(element: RenderInput, options?: RenderSvgOptions): Promise<string>;
91
+ /**
92
+ * Renders a sequence of scenes into an animated image (WebP / APNG / GIF).
93
+ *
94
+ * Each scene's content goes through the same input handling and resource pipeline
95
+ * as {@link render}; resources are fetched once across all scenes.
96
+ *
97
+ * @example
98
+ * ```tsx
99
+ * import { renderAnimation } from "takumi-js";
100
+ *
101
+ * const webp = await renderAnimation({
102
+ * width: 600,
103
+ * height: 400,
104
+ * fps: 30,
105
+ * format: "webp",
106
+ * scenes: [
107
+ * { node: <div tw="bg-red-500 w-full h-full" />, durationMs: 500 },
108
+ * { node: <div tw="bg-blue-500 w-full h-full" />, durationMs: 500 },
109
+ * ],
110
+ * });
111
+ * ```
112
+ *
113
+ * @returns A promise that resolves to the encoded animation (Buffer/Uint8Array).
114
+ */
115
+ declare function renderAnimation(options: RenderAnimationOptions): Promise<Uint8Array<ArrayBufferLike> | Buffer<ArrayBufferLike>>;
116
+ //#endregion
117
+ export { RenderSvgOptions as a, renderSvg as c, RenderOptions as i, RenderAnimationScene as n, render as o, RenderInput as r, renderAnimation as s, RenderAnimationOptions as t };
package/dist/response.cjs CHANGED
@@ -2,22 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_render = require("./render-BkAfi_5a.cjs");
5
+ const require_render = require("./render-BWrJI7_9.cjs");
6
6
  //#region src/response/index.ts
7
- function mergeOptions(defaultOptions, options) {
8
- if (!defaultOptions) return options;
9
- if (!options) return defaultOptions;
10
- const headers = new Headers(defaultOptions?.headers);
11
- if (options?.headers) new Headers(options.headers).forEach((value, key) => {
12
- headers.set(key, value);
13
- });
14
- return {
15
- ...defaultOptions,
16
- ...options,
17
- headers,
18
- stylesheets: [...defaultOptions?.stylesheets ?? [], ...options?.stylesheets ?? []]
19
- };
20
- }
21
7
  const contentTypeMap = {
22
8
  png: "image/png",
23
9
  jpeg: "image/jpeg",
@@ -29,62 +15,38 @@ function defaultErrorHandler(error) {
29
15
  console.error("Failed to render image.");
30
16
  console.error(error);
31
17
  }
32
- /**
33
- * Creates a reusable ImageResponse factory with shared configuration.
34
- *
35
- * Use this to avoid repeating configuration like fonts, stylesheets, or cache headers
36
- * across multiple API routes.
37
- *
38
- * @example
39
- * ```tsx
40
- * const myImageResponse = createImageResponse({
41
- * fonts: [{ name: "Inter", data: fontBuffer }],
42
- * headers: { "Cache-Control": "public, max-age=31536000" }
43
- * });
44
- *
45
- * export function GET() {
46
- * return myImageResponse(<div>Custom Og Image</div>);
47
- * }
48
- * ```
49
- *
50
- * @param defaultOptions - Options that will be applied to every response created by this factory.
51
- */
52
- function createImageResponse(defaultOptions) {
53
- return function imageResponse(element, options) {
54
- const mergedOptions = mergeOptions(defaultOptions, options);
55
- let resolveReady;
56
- let rejectReady;
57
- const ready = new Promise((resolve, reject) => {
58
- resolveReady = resolve;
59
- rejectReady = reject;
60
- });
61
- const stream = new ReadableStream({ async start(controller) {
62
- try {
63
- const image = await require_render.render(element, mergedOptions);
64
- controller.enqueue(image);
65
- controller.close();
66
- resolveReady();
67
- } catch (error) {
68
- controller.error(error);
69
- rejectReady(error);
70
- await (mergedOptions?.onError ?? defaultErrorHandler)(error);
71
- }
72
- } });
73
- const headers = new Headers(mergedOptions?.headers);
74
- if (!headers.get("content-type")) headers.set("content-type", contentTypeMap[mergedOptions?.format ?? "png"]);
75
- const response = new Response(stream, {
76
- headers,
77
- status: mergedOptions?.status,
78
- statusText: mergedOptions?.statusText
79
- });
80
- return Object.defineProperty(response, "ready", {
81
- enumerable: false,
82
- value: ready,
83
- writable: false
84
- });
85
- };
18
+ function buildImageResponse(element, options) {
19
+ let resolveReady;
20
+ let rejectReady;
21
+ const ready = new Promise((resolve, reject) => {
22
+ resolveReady = resolve;
23
+ rejectReady = reject;
24
+ });
25
+ const stream = new ReadableStream({ async start(controller) {
26
+ try {
27
+ const image = await require_render.render(element, options);
28
+ controller.enqueue(image);
29
+ controller.close();
30
+ resolveReady();
31
+ } catch (error) {
32
+ controller.error(error);
33
+ rejectReady(error);
34
+ await (options?.onError ?? defaultErrorHandler)(error);
35
+ }
36
+ } });
37
+ const headers = new Headers(options?.headers);
38
+ if (!headers.get("content-type")) headers.set("content-type", contentTypeMap[options?.format ?? "png"]);
39
+ const response = new Response(stream, {
40
+ headers,
41
+ status: options?.status,
42
+ statusText: options?.statusText
43
+ });
44
+ return Object.defineProperty(response, "ready", {
45
+ enumerable: false,
46
+ value: ready,
47
+ writable: false
48
+ });
86
49
  }
87
- let defaultImageResponse;
88
50
  /**
89
51
  * A universal ImageResponse class for generating images in API routes.
90
52
  *
@@ -111,8 +73,7 @@ let defaultImageResponse;
111
73
  var ImageResponse = class extends Response {
112
74
  ready;
113
75
  constructor(component, options) {
114
- defaultImageResponse ??= createImageResponse();
115
- const response = defaultImageResponse(component, options);
76
+ const response = buildImageResponse(component, options);
116
77
  super(response.body, response);
117
78
  this.ready = response.ready;
118
79
  }
@@ -120,4 +81,3 @@ var ImageResponse = class extends Response {
120
81
  //#endregion
121
82
  exports.ImageResponse = ImageResponse;
122
83
  exports.default = ImageResponse;
123
- exports.createImageResponse = createImageResponse;
@@ -1,4 +1,4 @@
1
- import { n as RenderOptions, t as RenderInput } from "./render-lU4_qVw3.cjs";
1
+ import { i as RenderOptions, r as RenderInput } from "./render-DJjKHz2l.cjs";
2
2
 
3
3
  //#region src/response/index.d.ts
4
4
  type ImageResponseResult = Response & {
@@ -7,28 +7,6 @@ type ImageResponseResult = Response & {
7
7
  type ImageResponseOptions = RenderOptions & ResponseInit & {
8
8
  onError?: (error: unknown) => void | Promise<void>;
9
9
  };
10
- type ImageResponseFactory = (component: RenderInput, options?: ImageResponseOptions) => ImageResponseResult;
11
- /**
12
- * Creates a reusable ImageResponse factory with shared configuration.
13
- *
14
- * Use this to avoid repeating configuration like fonts, stylesheets, or cache headers
15
- * across multiple API routes.
16
- *
17
- * @example
18
- * ```tsx
19
- * const myImageResponse = createImageResponse({
20
- * fonts: [{ name: "Inter", data: fontBuffer }],
21
- * headers: { "Cache-Control": "public, max-age=31536000" }
22
- * });
23
- *
24
- * export function GET() {
25
- * return myImageResponse(<div>Custom Og Image</div>);
26
- * }
27
- * ```
28
- *
29
- * @param defaultOptions - Options that will be applied to every response created by this factory.
30
- */
31
- declare function createImageResponse(defaultOptions?: ImageResponseOptions): ImageResponseFactory;
32
10
  /**
33
11
  * A universal ImageResponse class for generating images in API routes.
34
12
  *
@@ -57,4 +35,4 @@ declare class ImageResponse extends Response {
57
35
  constructor(component: RenderInput, options?: ImageResponseOptions);
58
36
  }
59
37
  //#endregion
60
- export { ImageResponse, ImageResponse as default, ImageResponseFactory, ImageResponseOptions, ImageResponseResult, createImageResponse };
38
+ export { ImageResponse, ImageResponse as default, ImageResponseOptions, ImageResponseResult };
@@ -1,4 +1,4 @@
1
- import { n as RenderOptions, t as RenderInput } from "./render-lU4_qVw3.mjs";
1
+ import { i as RenderOptions, r as RenderInput } from "./render-DJjKHz2l.mjs";
2
2
 
3
3
  //#region src/response/index.d.ts
4
4
  type ImageResponseResult = Response & {
@@ -7,28 +7,6 @@ type ImageResponseResult = Response & {
7
7
  type ImageResponseOptions = RenderOptions & ResponseInit & {
8
8
  onError?: (error: unknown) => void | Promise<void>;
9
9
  };
10
- type ImageResponseFactory = (component: RenderInput, options?: ImageResponseOptions) => ImageResponseResult;
11
- /**
12
- * Creates a reusable ImageResponse factory with shared configuration.
13
- *
14
- * Use this to avoid repeating configuration like fonts, stylesheets, or cache headers
15
- * across multiple API routes.
16
- *
17
- * @example
18
- * ```tsx
19
- * const myImageResponse = createImageResponse({
20
- * fonts: [{ name: "Inter", data: fontBuffer }],
21
- * headers: { "Cache-Control": "public, max-age=31536000" }
22
- * });
23
- *
24
- * export function GET() {
25
- * return myImageResponse(<div>Custom Og Image</div>);
26
- * }
27
- * ```
28
- *
29
- * @param defaultOptions - Options that will be applied to every response created by this factory.
30
- */
31
- declare function createImageResponse(defaultOptions?: ImageResponseOptions): ImageResponseFactory;
32
10
  /**
33
11
  * A universal ImageResponse class for generating images in API routes.
34
12
  *
@@ -57,4 +35,4 @@ declare class ImageResponse extends Response {
57
35
  constructor(component: RenderInput, options?: ImageResponseOptions);
58
36
  }
59
37
  //#endregion
60
- export { ImageResponse, ImageResponse as default, ImageResponseFactory, ImageResponseOptions, ImageResponseResult, createImageResponse };
38
+ export { ImageResponse, ImageResponse as default, ImageResponseOptions, ImageResponseResult };
package/dist/response.mjs CHANGED
@@ -1,19 +1,5 @@
1
- import { t as render } from "./render-BKqYuN_7.mjs";
1
+ import { t as render } from "./render-1w0Pei0G.mjs";
2
2
  //#region src/response/index.ts
3
- function mergeOptions(defaultOptions, options) {
4
- if (!defaultOptions) return options;
5
- if (!options) return defaultOptions;
6
- const headers = new Headers(defaultOptions?.headers);
7
- if (options?.headers) new Headers(options.headers).forEach((value, key) => {
8
- headers.set(key, value);
9
- });
10
- return {
11
- ...defaultOptions,
12
- ...options,
13
- headers,
14
- stylesheets: [...defaultOptions?.stylesheets ?? [], ...options?.stylesheets ?? []]
15
- };
16
- }
17
3
  const contentTypeMap = {
18
4
  png: "image/png",
19
5
  jpeg: "image/jpeg",
@@ -25,62 +11,38 @@ function defaultErrorHandler(error) {
25
11
  console.error("Failed to render image.");
26
12
  console.error(error);
27
13
  }
28
- /**
29
- * Creates a reusable ImageResponse factory with shared configuration.
30
- *
31
- * Use this to avoid repeating configuration like fonts, stylesheets, or cache headers
32
- * across multiple API routes.
33
- *
34
- * @example
35
- * ```tsx
36
- * const myImageResponse = createImageResponse({
37
- * fonts: [{ name: "Inter", data: fontBuffer }],
38
- * headers: { "Cache-Control": "public, max-age=31536000" }
39
- * });
40
- *
41
- * export function GET() {
42
- * return myImageResponse(<div>Custom Og Image</div>);
43
- * }
44
- * ```
45
- *
46
- * @param defaultOptions - Options that will be applied to every response created by this factory.
47
- */
48
- function createImageResponse(defaultOptions) {
49
- return function imageResponse(element, options) {
50
- const mergedOptions = mergeOptions(defaultOptions, options);
51
- let resolveReady;
52
- let rejectReady;
53
- const ready = new Promise((resolve, reject) => {
54
- resolveReady = resolve;
55
- rejectReady = reject;
56
- });
57
- const stream = new ReadableStream({ async start(controller) {
58
- try {
59
- const image = await render(element, mergedOptions);
60
- controller.enqueue(image);
61
- controller.close();
62
- resolveReady();
63
- } catch (error) {
64
- controller.error(error);
65
- rejectReady(error);
66
- await (mergedOptions?.onError ?? defaultErrorHandler)(error);
67
- }
68
- } });
69
- const headers = new Headers(mergedOptions?.headers);
70
- if (!headers.get("content-type")) headers.set("content-type", contentTypeMap[mergedOptions?.format ?? "png"]);
71
- const response = new Response(stream, {
72
- headers,
73
- status: mergedOptions?.status,
74
- statusText: mergedOptions?.statusText
75
- });
76
- return Object.defineProperty(response, "ready", {
77
- enumerable: false,
78
- value: ready,
79
- writable: false
80
- });
81
- };
14
+ function buildImageResponse(element, options) {
15
+ let resolveReady;
16
+ let rejectReady;
17
+ const ready = new Promise((resolve, reject) => {
18
+ resolveReady = resolve;
19
+ rejectReady = reject;
20
+ });
21
+ const stream = new ReadableStream({ async start(controller) {
22
+ try {
23
+ const image = await render(element, options);
24
+ controller.enqueue(image);
25
+ controller.close();
26
+ resolveReady();
27
+ } catch (error) {
28
+ controller.error(error);
29
+ rejectReady(error);
30
+ await (options?.onError ?? defaultErrorHandler)(error);
31
+ }
32
+ } });
33
+ const headers = new Headers(options?.headers);
34
+ if (!headers.get("content-type")) headers.set("content-type", contentTypeMap[options?.format ?? "png"]);
35
+ const response = new Response(stream, {
36
+ headers,
37
+ status: options?.status,
38
+ statusText: options?.statusText
39
+ });
40
+ return Object.defineProperty(response, "ready", {
41
+ enumerable: false,
42
+ value: ready,
43
+ writable: false
44
+ });
82
45
  }
83
- let defaultImageResponse;
84
46
  /**
85
47
  * A universal ImageResponse class for generating images in API routes.
86
48
  *
@@ -107,11 +69,10 @@ let defaultImageResponse;
107
69
  var ImageResponse = class extends Response {
108
70
  ready;
109
71
  constructor(component, options) {
110
- defaultImageResponse ??= createImageResponse();
111
- const response = defaultImageResponse(component, options);
72
+ const response = buildImageResponse(component, options);
112
73
  super(response.body, response);
113
74
  this.ready = response.ready;
114
75
  }
115
76
  };
116
77
  //#endregion
117
- export { ImageResponse, ImageResponse as default, createImageResponse };
78
+ export { ImageResponse, ImageResponse as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "takumi-js",
3
- "version": "1.8.7",
3
+ "version": "2.0.0-beta.1",
4
4
  "description": "All-in-one Takumi package for Node.js and WebAssembly runtimes.",
5
5
  "keywords": [
6
6
  "css",
@@ -129,9 +129,9 @@
129
129
  "publish-lint": "attw --pack . && publint --strict ."
130
130
  },
131
131
  "dependencies": {
132
- "@takumi-rs/core": "1.8.7",
133
- "@takumi-rs/helpers": "1.8.7",
134
- "@takumi-rs/wasm": "1.8.7"
132
+ "@takumi-rs/core": "2.0.0-beta.1",
133
+ "@takumi-rs/helpers": "2.0.0-beta.1",
134
+ "@takumi-rs/wasm": "2.0.0-beta.1"
135
135
  },
136
136
  "devDependencies": {
137
137
  "@types/bun": "catalog:",
@@ -1,63 +0,0 @@
1
- import { EmojiType } from "@takumi-rs/helpers/emoji";
2
- import { FetchResourcesOptions, Node, ReactElementLike } from "@takumi-rs/helpers";
3
- import { FromJsxOptions } from "@takumi-rs/helpers/jsx";
4
- import * as napi from "@takumi-rs/core";
5
- import * as wasm from "@takumi-rs/wasm";
6
- import { ReactNode } from "react";
7
-
8
- //#region src/renderer.d.ts
9
- type ManagedRendererOptions = {
10
- fonts?: napi.FontLoader[];
11
- /**
12
- * Whether to load the embedded default fonts.
13
- * Defaults to `false` when `fonts` are provided.
14
- */
15
- loadDefaultFonts?: boolean;
16
- persistentImages?: napi.ImageSourceLoader[];
17
- /**
18
- * @description The WebAssembly module to use for the renderer. If not provided, the default resolving strategy will be used.
19
- */
20
- module?: wasm.InitInput | Promise<wasm.InitInput> | {
21
- default: wasm.InitInput;
22
- };
23
- };
24
- //#endregion
25
- //#region src/render.d.ts
26
- type InnerRenderOptions = napi.RenderOptions | wasm.RenderOptions;
27
- type RenderOptionsWithRenderer = InnerRenderOptions & {
28
- renderer: napi.Renderer | wasm.Renderer;
29
- signal?: AbortSignal;
30
- jsx?: FromJsxOptions;
31
- resourcesOptions?: FetchResourcesOptions;
32
- /**
33
- * @description The emoji provider to use when rendering emojis. If set to `"from-font"`, the renderer will attempt to source emoji glyphs from the loaded fonts.
34
- * @default "twemoji"
35
- */
36
- emoji?: EmojiType | "from-font";
37
- };
38
- type RenderOptionsWithoutRenderer = Omit<RenderOptionsWithRenderer, "renderer"> & ManagedRendererOptions;
39
- type RenderOptions = RenderOptionsWithRenderer | RenderOptionsWithoutRenderer;
40
- type RenderInput = ReactNode | ReactElementLike | Node | string;
41
- /**
42
- * Renders a React element, HTML string, or Takumi node tree into an image.
43
- *
44
- * This function automatically detects the best renderer for your environment (native Rust on Node.js,
45
- * WASM on Edge/Workers) and handles resource fetching (fonts, images) and emoji extraction.
46
- *
47
- * @example
48
- * ```tsx
49
- * import { render } from "takumi-js";
50
- *
51
- * const buffer = await render(
52
- * <div tw="bg-blue-500 text-white p-4">Hello World</div>,
53
- * { width: 1200, height: 630 }
54
- * );
55
- * ```
56
- *
57
- * @param element - The content to render. Can be a JSX element (React-like), an HTML string, or a pre-constructed node tree.
58
- * @param options - Configuration for rendering, including dimensions, format, fonts, and more.
59
- * @returns A promise that resolves to the rendered image data (Buffer/Uint8Array).
60
- */
61
- declare function render(element: RenderInput, options?: RenderOptions): Promise<Uint8Array<ArrayBufferLike> | Buffer<ArrayBufferLike>>;
62
- //#endregion
63
- export { RenderOptions as n, render as r, RenderInput as t };
@@ -1,63 +0,0 @@
1
- import { EmojiType } from "@takumi-rs/helpers/emoji";
2
- import { FetchResourcesOptions, Node, ReactElementLike } from "@takumi-rs/helpers";
3
- import { FromJsxOptions } from "@takumi-rs/helpers/jsx";
4
- import * as napi from "@takumi-rs/core";
5
- import * as wasm from "@takumi-rs/wasm";
6
- import { ReactNode } from "react";
7
-
8
- //#region src/renderer.d.ts
9
- type ManagedRendererOptions = {
10
- fonts?: napi.FontLoader[];
11
- /**
12
- * Whether to load the embedded default fonts.
13
- * Defaults to `false` when `fonts` are provided.
14
- */
15
- loadDefaultFonts?: boolean;
16
- persistentImages?: napi.ImageSourceLoader[];
17
- /**
18
- * @description The WebAssembly module to use for the renderer. If not provided, the default resolving strategy will be used.
19
- */
20
- module?: wasm.InitInput | Promise<wasm.InitInput> | {
21
- default: wasm.InitInput;
22
- };
23
- };
24
- //#endregion
25
- //#region src/render.d.ts
26
- type InnerRenderOptions = napi.RenderOptions | wasm.RenderOptions;
27
- type RenderOptionsWithRenderer = InnerRenderOptions & {
28
- renderer: napi.Renderer | wasm.Renderer;
29
- signal?: AbortSignal;
30
- jsx?: FromJsxOptions;
31
- resourcesOptions?: FetchResourcesOptions;
32
- /**
33
- * @description The emoji provider to use when rendering emojis. If set to `"from-font"`, the renderer will attempt to source emoji glyphs from the loaded fonts.
34
- * @default "twemoji"
35
- */
36
- emoji?: EmojiType | "from-font";
37
- };
38
- type RenderOptionsWithoutRenderer = Omit<RenderOptionsWithRenderer, "renderer"> & ManagedRendererOptions;
39
- type RenderOptions = RenderOptionsWithRenderer | RenderOptionsWithoutRenderer;
40
- type RenderInput = ReactNode | ReactElementLike | Node | string;
41
- /**
42
- * Renders a React element, HTML string, or Takumi node tree into an image.
43
- *
44
- * This function automatically detects the best renderer for your environment (native Rust on Node.js,
45
- * WASM on Edge/Workers) and handles resource fetching (fonts, images) and emoji extraction.
46
- *
47
- * @example
48
- * ```tsx
49
- * import { render } from "takumi-js";
50
- *
51
- * const buffer = await render(
52
- * <div tw="bg-blue-500 text-white p-4">Hello World</div>,
53
- * { width: 1200, height: 630 }
54
- * );
55
- * ```
56
- *
57
- * @param element - The content to render. Can be a JSX element (React-like), an HTML string, or a pre-constructed node tree.
58
- * @param options - Configuration for rendering, including dimensions, format, fonts, and more.
59
- * @returns A promise that resolves to the rendered image data (Buffer/Uint8Array).
60
- */
61
- declare function render(element: RenderInput, options?: RenderOptions): Promise<Uint8Array<ArrayBufferLike> | Buffer<ArrayBufferLike>>;
62
- //#endregion
63
- export { RenderOptions as n, render as r, RenderInput as t };