@toonstrip/astro 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.
@@ -0,0 +1,3 @@
1
+ export { ComicStrip } from "./tag-name.js";
2
+ export { default as toonstrip } from "./integration.js";
3
+ export type { ToonstripOptions } from "./integration.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { ComicStrip } from "./tag-name.js";
2
+ export { default as toonstrip } from "./integration.js";
@@ -0,0 +1,13 @@
1
+ import type { AstroIntegration } from "astro";
2
+ export interface ToonstripOptions {
3
+ /**
4
+ * Module specifiers of `@toonstrip/pack-*` packages to serve to the browser.
5
+ * Each pack's `pack.json` + `characters/` + `backdrops/` are copied into the
6
+ * site's public dir under `_toonstrip/<pack.json name>/` at config-setup
7
+ * time, so `<ComicStrip packs={['comic-chat']} />` can resolve the name to
8
+ * a URL `@toonstrip/element`'s fetch-based loader can reach. No
9
+ * auto-discovery — packs used by a page must be listed explicitly here.
10
+ */
11
+ packs?: string[];
12
+ }
13
+ export default function toonstrip(options?: ToonstripOptions): AstroIntegration;
@@ -0,0 +1,47 @@
1
+ // Node built-ins are imported dynamically, inside the hook body, rather than
2
+ // at module scope: this same module is also re-imported client-side (Astro's
3
+ // hydration re-fetches the astro-island's `component-url`, and `ComicStrip`
4
+ // lives in this package's index alongside `toonstrip`) — a static top-level
5
+ // `node:fs`/`node:module` import breaks there ("externalized for browser
6
+ // compatibility"), even though the function body itself never runs in a
7
+ // browser. Dynamic imports keep this module's top level browser-safe.
8
+ async function copyPackAssets(specifier, publicDir) {
9
+ const { createRequire } = await import("node:module");
10
+ const { cpSync, existsSync, mkdirSync, readFileSync } = await import("node:fs");
11
+ const { dirname, join } = await import("node:path");
12
+ const require = createRequire(import.meta.url);
13
+ const packDir = dirname(require.resolve(`${specifier}/package.json`));
14
+ const packJsonPath = join(packDir, "pack.json");
15
+ const packJson = JSON.parse(readFileSync(packJsonPath, "utf-8"));
16
+ const dest = join(publicDir, "_toonstrip", packJson.name);
17
+ mkdirSync(dest, { recursive: true });
18
+ cpSync(packJsonPath, join(dest, "pack.json"));
19
+ for (const dir of ["characters", "backdrops"]) {
20
+ const src = join(packDir, dir);
21
+ if (existsSync(src))
22
+ cpSync(src, join(dest, dir), { recursive: true });
23
+ }
24
+ }
25
+ export default function toonstrip(options = {}) {
26
+ return {
27
+ name: "@toonstrip/astro",
28
+ hooks: {
29
+ "astro:config:setup": async ({ addRenderer, config }) => {
30
+ addRenderer({
31
+ name: "@toonstrip/astro",
32
+ // Bare specifiers (not `new URL(...).href`) so Vite can place these
33
+ // in its normal module graph — a raw file:// URL renders fine in
34
+ // dev but breaks `astro build`'s static-output "built path" lookup,
35
+ // which only resolves entrypoints it can trace through that graph.
36
+ serverEntrypoint: "@toonstrip/astro/dist/renderer/server.js",
37
+ clientEntrypoint: "@toonstrip/astro/dist/renderer/client.js",
38
+ });
39
+ const { fileURLToPath } = await import("node:url");
40
+ const publicDir = fileURLToPath(config.publicDir);
41
+ for (const specifier of options.packs ?? []) {
42
+ await copyPackAssets(specifier, publicDir);
43
+ }
44
+ },
45
+ },
46
+ };
47
+ }
@@ -0,0 +1,6 @@
1
+ interface ComicStripProps {
2
+ document?: unknown;
3
+ packs?: string[];
4
+ }
5
+ declare const _default: (element: HTMLElement) => (_component: string, props: ComicStripProps) => Promise<void>;
6
+ export default _default;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Maps a pack *name* (e.g. "comic-chat", per the dev plan's documented
3
+ * `packs={['comic-chat']}` usage) to the URL the `toonstrip()` integration
4
+ * copies that pack's assets to. See integration.ts's `astro:config:setup`.
5
+ */
6
+ function packUrl(name) {
7
+ return `/_toonstrip/${name}/`;
8
+ }
9
+ export default (element) => async (_component, props) => {
10
+ // Deferred until the client directive's condition (e.g. `client:visible`)
11
+ // fires — `@toonstrip/element` defines `<comic-strip>` at module scope via
12
+ // `extends HTMLElement`, which would crash under Astro's SSR if imported
13
+ // from anywhere reachable at render time. This dynamic import is the only
14
+ // place in `@toonstrip/astro` that ever loads it.
15
+ await import("@toonstrip/element");
16
+ const target = element.children[0];
17
+ if (!target)
18
+ return;
19
+ if (props.document !== undefined)
20
+ target.document = props.document;
21
+ if (props.packs)
22
+ target.packs = props.packs.map(packUrl);
23
+ };
@@ -0,0 +1,9 @@
1
+ declare function check(Component: unknown): boolean;
2
+ declare function renderToStaticMarkup(Component: string): {
3
+ html: string;
4
+ };
5
+ declare const _default: {
6
+ check: typeof check;
7
+ renderToStaticMarkup: typeof renderToStaticMarkup;
8
+ };
9
+ export default _default;
@@ -0,0 +1,12 @@
1
+ import { ComicStrip } from "../tag-name.js";
2
+ function check(Component) {
3
+ return Component === ComicStrip;
4
+ }
5
+ function renderToStaticMarkup(Component) {
6
+ // Real content only ever exists client-side (canvas rendering needs a real
7
+ // browser canvas context) — the server placeholder is intentionally inert.
8
+ // Props travel via Astro's own astro-island `props` attribute, not through
9
+ // this markup, so nothing needs serializing into it.
10
+ return { html: `<${Component}></${Component}>` };
11
+ }
12
+ export default { check, renderToStaticMarkup };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Zero-dependency, SSR-safe tag-name constant. Imported directly by consumers'
3
+ * `.astro` frontmatter (which runs on the server), so this module must never
4
+ * import anything that touches `HTMLElement`/`window` — `@toonstrip/element`
5
+ * does exactly that at module scope, which is why it is imported only inside
6
+ * `renderer/client.ts`, never from here.
7
+ */
8
+ export declare const ComicStrip = "comic-strip";
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Zero-dependency, SSR-safe tag-name constant. Imported directly by consumers'
3
+ * `.astro` frontmatter (which runs on the server), so this module must never
4
+ * import anything that touches `HTMLElement`/`window` — `@toonstrip/element`
5
+ * does exactly that at module scope, which is why it is imported only inside
6
+ * `renderer/client.ts`, never from here.
7
+ */
8
+ export const ComicStrip = "comic-strip";
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@toonstrip/astro",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc -p tsconfig.json",
13
+ "test": "vitest run",
14
+ "lint": "tsc -p tsconfig.json --noEmit"
15
+ },
16
+ "peerDependencies": {
17
+ "astro": "^7.0.0"
18
+ },
19
+ "dependencies": {
20
+ "@toonstrip/element": "workspace:*",
21
+ "@toonstrip/schema": "workspace:*"
22
+ },
23
+ "devDependencies": {
24
+ "astro": "^7.2.9",
25
+ "typescript": "^5.6.3",
26
+ "vitest": "^2.1.4"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ }
31
+ }