@fraqjs/plugin-takumi 0.1.1 → 0.1.3

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.d.mts CHANGED
@@ -7,6 +7,7 @@ import { ReactNode } from "react";
7
7
  //#region src/service.d.ts
8
8
  interface TakumiServiceOptions {
9
9
  renderer?: ConstructRendererOptions;
10
+ renderDefaults?: RenderOptions;
10
11
  onFontRegisterConflict?: 'error' | 'warn-and-ignore' | 'warn-and-replace';
11
12
  }
12
13
  interface PathBasedFontDetails {
@@ -16,17 +17,19 @@ interface PathBasedFontDetails {
16
17
  style?: 'normal' | 'italic' | 'oblique' | `oblique ${number}deg` | (string & {});
17
18
  }
18
19
  declare class TakumiService implements Disposable {
19
- private readonly ctx;
20
+ private readonly options?;
21
+ private readonly ctx?;
20
22
  readonly renderer: Renderer;
21
23
  private readonly abortController;
22
24
  private readonly registeredFontFamilies;
23
25
  private onFontRegisterConflict;
24
- constructor(ctx: Context, options: TakumiServiceOptions);
26
+ constructor(options?: TakumiServiceOptions | undefined, ctx?: Context | undefined);
25
27
  registerFontFamily(family: string, fonts: (string | PathBasedFontDetails | Font)[], signal?: AbortSignal): Promise<void>;
26
28
  renderJsx(jsx: ReactNode | ReactElementLike, renderOptions?: RenderOptions, signal?: AbortSignal): Promise<Buffer>;
27
29
  renderJsxWithEmoji(jsx: ReactNode | ReactElementLike, renderOptions?: RenderOptions, signal?: AbortSignal, emojiType?: EmojiType): Promise<Buffer>;
28
30
  renderHtml(html: string, renderOptions?: RenderOptions, signal?: AbortSignal): Promise<Buffer>;
29
31
  renderHtmlWithEmoji(html: string, renderOptions?: RenderOptions, signal?: AbortSignal, emojiType?: EmojiType): Promise<Buffer>;
32
+ private mergeRenderOptions;
30
33
  private processEmoji;
31
34
  dispose(): void;
32
35
  }
@@ -35,6 +38,7 @@ declare class TakumiService implements Disposable {
35
38
  interface TakumiPluginOptions extends TakumiServiceOptions {
36
39
  loadBuiltinFonts?: boolean;
37
40
  }
41
+ declare function loadBuiltinFontsForService(service: TakumiService): Promise<void>;
38
42
  declare const TakumiPlugin: import("@fraqjs/fraq").Plugin<[options?: TakumiPluginOptions | undefined], import("@fraqjs/fraq").Injection | undefined, import("@fraqjs/fraq").Injection | undefined>;
39
43
  //#endregion
40
- export { PathBasedFontDetails, TakumiPlugin, TakumiPlugin as default, TakumiPluginOptions, TakumiService, TakumiServiceOptions };
44
+ export { PathBasedFontDetails, TakumiPlugin, TakumiPlugin as default, TakumiPluginOptions, TakumiService, TakumiServiceOptions, loadBuiltinFontsForService };
package/dist/index.mjs CHANGED
@@ -7,35 +7,32 @@ import { fromHtml } from "@takumi-rs/helpers/html";
7
7
  import { fromJsx } from "@takumi-rs/helpers/jsx";
8
8
  import fs from "node:fs/promises";
9
9
  //#region src/service.ts
10
- function withMergedStylesheets(stylesheets, renderOptions) {
11
- const extraStylesheets = renderOptions?.stylesheets ?? [];
12
- return {
13
- ...renderOptions,
14
- stylesheets: [...stylesheets, ...extraStylesheets]
15
- };
16
- }
17
10
  function combineAbortSignals(...signals) {
18
11
  return AbortSignal.any(signals.filter((signal) => signal !== void 0));
19
12
  }
20
13
  var TakumiService = class {
14
+ options;
21
15
  ctx;
22
16
  renderer;
23
17
  abortController = new AbortController();
24
18
  registeredFontFamilies = /* @__PURE__ */ new Set();
25
19
  onFontRegisterConflict;
26
- constructor(ctx, options) {
20
+ constructor(options, ctx) {
21
+ this.options = options;
27
22
  this.ctx = ctx;
28
- this.renderer = new Renderer(options.renderer);
29
- this.onFontRegisterConflict = options.onFontRegisterConflict ?? "warn-and-ignore";
23
+ this.renderer = new Renderer(options?.renderer);
24
+ this.onFontRegisterConflict = options?.onFontRegisterConflict ?? "warn-and-ignore";
30
25
  }
31
26
  async registerFontFamily(family, fonts, signal) {
32
27
  if (this.registeredFontFamilies.has(family)) {
33
28
  const message = `Font family "${family}" has already been registered.`;
34
29
  if (this.onFontRegisterConflict === "error") throw new Error(message);
35
30
  else if (this.onFontRegisterConflict === "warn-and-ignore") {
36
- this.ctx.logger.warn(`${message} Ignoring new registration.`);
31
+ if (this.ctx) this.ctx.logger.warn(`${message} Ignoring new registration.`);
32
+ else console.warn(`${message} Ignoring new registration.`);
37
33
  return;
38
- } else if (this.onFontRegisterConflict === "warn-and-replace") this.ctx.logger.warn(`${message} Replacing previous registration.`);
34
+ } else if (this.onFontRegisterConflict === "warn-and-replace") if (this.ctx) this.ctx.logger.warn(`${message} Replacing previous registration.`);
35
+ else console.warn(`${message} Replacing previous registration.`);
39
36
  }
40
37
  await this.renderer.loadFonts(await Promise.all(fonts.map(async (font) => {
41
38
  if (typeof font === "string") return {
@@ -56,28 +53,52 @@ var TakumiService = class {
56
53
  }
57
54
  async renderJsx(jsx, renderOptions, signal) {
58
55
  const { node, stylesheets } = await fromJsx(jsx);
59
- return this.renderer.render(node, withMergedStylesheets(stylesheets, renderOptions), combineAbortSignals(signal, this.abortController.signal));
56
+ return this.renderer.render(node, this.mergeRenderOptions({
57
+ stylesheets,
58
+ userOptions: renderOptions
59
+ }), combineAbortSignals(signal, this.abortController.signal));
60
60
  }
61
61
  async renderJsxWithEmoji(jsx, renderOptions, signal, emojiType = "noto") {
62
62
  const { node, stylesheets } = await fromJsx(jsx);
63
63
  const { node: processedNode, fetchedResources } = await this.processEmoji(node, emojiType);
64
- return this.renderer.render(processedNode, withMergedStylesheets(stylesheets, {
65
- ...renderOptions,
66
- fetchedResources: [...fetchedResources, ...renderOptions?.fetchedResources ?? []]
64
+ return this.renderer.render(processedNode, this.mergeRenderOptions({
65
+ stylesheets,
66
+ fetchedResources,
67
+ userOptions: renderOptions
67
68
  }), combineAbortSignals(signal, this.abortController.signal));
68
69
  }
69
70
  async renderHtml(html, renderOptions, signal) {
70
71
  const { node, stylesheets } = fromHtml(html);
71
- return this.renderer.render(node, withMergedStylesheets(stylesheets, renderOptions), combineAbortSignals(signal, this.abortController.signal));
72
+ return this.renderer.render(node, this.mergeRenderOptions({
73
+ stylesheets,
74
+ userOptions: renderOptions
75
+ }), combineAbortSignals(signal, this.abortController.signal));
72
76
  }
73
77
  async renderHtmlWithEmoji(html, renderOptions, signal, emojiType = "noto") {
74
78
  const { node, stylesheets } = fromHtml(html);
75
79
  const { node: processedNode, fetchedResources } = await this.processEmoji(node, emojiType);
76
- return this.renderer.render(processedNode, withMergedStylesheets(stylesheets, {
77
- ...renderOptions,
78
- fetchedResources: [...fetchedResources, ...renderOptions?.fetchedResources ?? []]
80
+ return this.renderer.render(processedNode, this.mergeRenderOptions({
81
+ stylesheets,
82
+ fetchedResources,
83
+ userOptions: renderOptions
79
84
  }), combineAbortSignals(signal, this.abortController.signal));
80
85
  }
86
+ mergeRenderOptions(components) {
87
+ return {
88
+ ...this.options?.renderDefaults,
89
+ ...components.userOptions,
90
+ stylesheets: [
91
+ ...this.options?.renderDefaults?.stylesheets ?? [],
92
+ ...components.stylesheets ?? [],
93
+ ...components.userOptions?.stylesheets ?? []
94
+ ],
95
+ fetchedResources: [
96
+ ...this.options?.renderDefaults?.fetchedResources ?? [],
97
+ ...components.fetchedResources ?? [],
98
+ ...components.userOptions?.fetchedResources ?? []
99
+ ]
100
+ };
101
+ }
81
102
  async processEmoji(node, emojiType = "twemoji") {
82
103
  const processedNode = extractEmojis(node, emojiType);
83
104
  return {
@@ -91,20 +112,23 @@ var TakumiService = class {
91
112
  };
92
113
  //#endregion
93
114
  //#region src/index.ts
115
+ async function loadBuiltinFontsForService(service) {
116
+ const require = createRequire(import.meta.url);
117
+ await service.registerFontFamily("Inter", [require.resolve("../fonts/Inter-VariableFont_opsz,wght.ttf"), require.resolve("../fonts/Inter-Italic-VariableFont_opsz,wght.ttf")]);
118
+ await service.registerFontFamily("Roboto Mono", [require.resolve("../fonts/RobotoMono-VariableFont_wght.ttf"), require.resolve("../fonts/RobotoMono-Italic-VariableFont_wght.ttf")]);
119
+ await service.registerFontFamily("Noto Sans SC", [require.resolve("../fonts/NotoSansSC-VariableFont_wght.ttf")]);
120
+ }
94
121
  const TakumiPlugin = definePlugin({
95
122
  name: "takumi",
96
123
  provides: [TakumiService],
97
124
  async apply(ctx, options) {
98
- const service = new TakumiService(ctx, options ?? {});
125
+ const service = new TakumiService(options, ctx);
99
126
  if (options?.loadBuiltinFonts ?? true) {
100
127
  ctx.logger.debug("Loading built-in fonts...");
101
- const require = createRequire(import.meta.url);
102
- await service.registerFontFamily("Inter", [require.resolve("../fonts/Inter-VariableFont_opsz,wght.ttf"), require.resolve("../fonts/Inter-Italic-VariableFont_opsz,wght.ttf")]);
103
- await service.registerFontFamily("Roboto Mono", [require.resolve("../fonts/RobotoMono-VariableFont_wght.ttf"), require.resolve("../fonts/RobotoMono-Italic-VariableFont_wght.ttf")]);
104
- await service.registerFontFamily("Noto Sans SC", [require.resolve("../fonts/NotoSansSC-VariableFont_wght.ttf")]);
128
+ await loadBuiltinFontsForService(service);
105
129
  }
106
130
  ctx.provide(TakumiService, service);
107
131
  }
108
132
  });
109
133
  //#endregion
110
- export { TakumiPlugin, TakumiPlugin as default, TakumiService };
134
+ export { TakumiPlugin, TakumiPlugin as default, TakumiService, loadBuiltinFontsForService };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fraqjs/plugin-takumi",
3
3
  "type": "module",
4
- "version": "0.1.1",
4
+ "version": "0.1.3",
5
5
  "description": "Takumi integration plugin for Fraq",
6
6
  "files": [
7
7
  "dist",
@@ -19,7 +19,7 @@
19
19
  "license": "MIT",
20
20
  "peerDependencies": {
21
21
  "react": "^19.0.0",
22
- "@fraqjs/fraq": "^0.8.2"
22
+ "@fraqjs/fraq": "^0.10.1"
23
23
  },
24
24
  "dependencies": {
25
25
  "@takumi-rs/core": "^1.7.0",