@toonstrip/next 0.1.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 ADDED
@@ -0,0 +1,56 @@
1
+ # @toonstrip/next
2
+
3
+ `@toonstrip/react`'s `<ComicStrip>` behind an App-Router-safe `'use client'` boundary,
4
+ plus `@toonstrip/next/server`'s `renderPlaceholder` for a real SSR PNG placeholder — no
5
+ layout shift on hydration, and content visible with JavaScript disabled.
6
+
7
+ Part of [toonstrip](https://github.com/dkdev24/toonstrip), a
8
+ framework-embeddable comic-strip renderer. Docs, playground, and
9
+ changelog: [toonstrip.danielkimdev.com](https://toonstrip.danielkimdev.com).
10
+
11
+ ## Install
12
+
13
+ ```
14
+ npm install @toonstrip/next @toonstrip/cli @toonstrip/pack-comic-chat
15
+ ```
16
+
17
+ `@toonstrip/cli` must be your app's own direct dependency, not only reachable
18
+ transitively through `@toonstrip/next` — see
19
+ [`docs/next.md`](https://github.com/dkdev24/toonstrip/blob/main/docs/next.md#native-dependency)
20
+ for why, and for the `next.config.mjs` `serverExternalPackages` setting it also needs.
21
+
22
+ ## Use
23
+
24
+ ```tsx
25
+ // app/page.tsx — a Server Component; no "use client" needed here
26
+ import { ComicStrip } from "@toonstrip/next";
27
+ import { renderPlaceholder } from "@toonstrip/next/server";
28
+ import doc from "./my-strip.json";
29
+
30
+ export default async function Page() {
31
+ const placeholder = await renderPlaceholder(doc, { width: 640 });
32
+ return (
33
+ <ComicStrip
34
+ document={doc}
35
+ packs={["/packs/comic-chat/"]}
36
+ placeholder={placeholder}
37
+ />
38
+ );
39
+ }
40
+ ```
41
+
42
+ Same props as `@toonstrip/react`'s `<ComicStrip>`. `renderPlaceholder` is a separate
43
+ `@toonstrip/next/server` entry point (not the package root) because it pulls in
44
+ `@toonstrip/cli`'s native canvas dependency — call it only from a Server Component or
45
+ other server-only code.
46
+
47
+ ## Worked example
48
+
49
+ See `examples/next-app` in the
50
+ [repo](https://github.com/dkdev24/toonstrip/tree/main/examples/next-app) for a complete,
51
+ runnable App Router app. Full field reference:
52
+ [`docs/next.md`](https://github.com/dkdev24/toonstrip/blob/main/docs/next.md).
53
+
54
+ ## License
55
+
56
+ MIT
@@ -0,0 +1,2 @@
1
+ export { ComicStrip } from "@toonstrip/react";
2
+ export type { ComicStripProps, ComicStripPlaceholder } from "@toonstrip/react";
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ // The client-side, App-Router-safe boundary (dev plan §13.4): `@toonstrip/react`'s
3
+ // `<ComicStrip>` uses `useRef`/`useEffect`, so it must be marked a Client
4
+ // Component wherever a Server Component imports it. `packages/element`'s own
5
+ // SSR guards (customElements/HTMLElement) are what keep the *module* safe to
6
+ // import during the server render pass that still happens for a "use client"
7
+ // tree; this directive is the separate, RSC-protocol half of that story.
8
+ export { ComicStrip } from "@toonstrip/react";
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Server-only SSR placeholder helper (dev plan §13.4). Reuses §8's existing
3
+ * headless-canvas render path (`packages/cli`, already published) to produce
4
+ * a real PNG of the strip at request/build time, ready to hand to
5
+ * `<ComicStrip placeholder>` as the light-DOM image it shows until client JS
6
+ * hydrates and paints the live canvas.
7
+ *
8
+ * A separate entry point ("@toonstrip/next/server", not the package root):
9
+ * `@toonstrip/cli` pulls in `@napi-rs/canvas`, a native Node addon that must
10
+ * never end up in a client bundle. Only import this from a Server Component
11
+ * or other server-only code.
12
+ *
13
+ * `@toonstrip/cli` is imported dynamically with `webpackIgnore` rather than
14
+ * statically: Next's `serverExternalPackages` opt-out is meant to stop it
15
+ * being bundled, but a workspace package reached through a symlinked,
16
+ * non-`node_modules` local package (`@toonstrip/cli`, here) doesn't reliably
17
+ * hit that path, and webpack then tries to statically bundle
18
+ * `@napi-rs/canvas`'s platform-detection `require()`s for every OS/arch and
19
+ * fails on the binary `.node` files. `webpackIgnore` leaves this import
20
+ * completely alone, so Node resolves and loads it normally at request time —
21
+ * from the *bundled output file's* location, though, so the consuming app
22
+ * must list `@toonstrip/cli` as its own direct dependency (not only reachable
23
+ * transitively through `@toonstrip/next`) for that resolution to succeed
24
+ * under pnpm's default strict `node_modules` layout.
25
+ */
26
+ import type { ComicStripPlaceholder } from "@toonstrip/react";
27
+ import type { ComicStripDocument } from "@toonstrip/schema";
28
+ import type { RenderOptions } from "@toonstrip/cli";
29
+ export declare function renderPlaceholder(doc: ComicStripDocument, options?: RenderOptions): Promise<ComicStripPlaceholder>;
package/dist/server.js ADDED
@@ -0,0 +1,10 @@
1
+ export async function renderPlaceholder(doc, options = {}) {
2
+ const { renderDocument } = await import(/* webpackIgnore: true */ "@toonstrip/cli");
3
+ const { png, cssWidth, cssHeight } = await renderDocument(doc, options);
4
+ // The <img>'s width/height are CSS pixels (RenderResult.cssWidth/cssHeight),
5
+ // not the (possibly `scale`d-up) PNG's own pixel size — an `<img>` displays
6
+ // at its width/height attributes regardless of the file's actual pixel
7
+ // density, so using the PNG's raw pixel size here would render it 2x too
8
+ // large (the default `scale`) and shift layout on hydration.
9
+ return { src: `data:image/png;base64,${png.toString("base64")}`, width: cssWidth, height: cssHeight };
10
+ }
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@toonstrip/next",
3
+ "version": "0.1.0",
4
+ "description": "@toonstrip/react behind an App-Router-safe 'use client' boundary, plus a server-only SSR placeholder helper.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./server": {
15
+ "types": "./dist/server.d.ts",
16
+ "default": "./dist/server.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc -p tsconfig.json",
24
+ "test": "vitest run",
25
+ "lint": "tsc -p tsconfig.json --noEmit"
26
+ },
27
+ "peerDependencies": {
28
+ "react": "^18.0.0 || ^19.0.0",
29
+ "react-dom": "^18.0.0 || ^19.0.0"
30
+ },
31
+ "dependencies": {
32
+ "@toonstrip/cli": "workspace:*",
33
+ "@toonstrip/react": "workspace:*",
34
+ "@toonstrip/schema": "workspace:*"
35
+ },
36
+ "devDependencies": {
37
+ "@types/react": "^18.3.12",
38
+ "@types/react-dom": "^18.3.1",
39
+ "react": "^18.3.1",
40
+ "react-dom": "^18.3.1",
41
+ "typescript": "^5.6.3",
42
+ "vitest": "^2.1.4"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "keywords": [
48
+ "toonstrip",
49
+ "comic",
50
+ "next",
51
+ "nextjs",
52
+ "ssr"
53
+ ],
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "git+https://github.com/dkdev24/toonstrip.git",
57
+ "directory": "packages/next"
58
+ },
59
+ "homepage": "https://github.com/dkdev24/toonstrip#readme",
60
+ "bugs": "https://github.com/dkdev24/toonstrip/issues"
61
+ }