Skip to content

Commit 0124340

Browse files
author
Bob Fanger
committed
feat: Added support for react elements
Fixes #13
1 parent 13137d5 commit 0124340

File tree

9 files changed

+39
-12
lines changed

9 files changed

+39
-12
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"type": "git",
1111
"url": "https://github.com/bfanger/svelte-preprocess-react.git"
1212
},
13-
"version": "0.10.0",
13+
"version": "0.11.0",
1414
"license": "MIT",
1515
"type": "module",
1616
"scripts": {

playwright/tests/hooks.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { test, expect } from "@playwright/test";
33
test.use({ viewport: { width: 480, height: 360 } });
44
test.describe("hooks", () => {
55
test("counter", async ({ page }) => {
6-
await page.goto("/hooks");
6+
await page.goto("/hooks", { waitUntil: "networkidle" });
77
await expect(page.locator('[data-testid="count"]')).toHaveText("0");
88
await page.locator('[data-testid="add"]').click();
99
await expect(page.locator('[data-testid="count"]')).toHaveText("1");

src/lib/internal/types.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ import type React from "react";
22
import type { ComponentClass, FunctionComponent } from "react";
33
import type { Readable, Writable } from "svelte/store";
44

5-
export type ConstructorOf<T> = {
6-
new (): T;
7-
};
8-
95
export type HandlerName<T extends string> = `on${Capitalize<T>}`;
106
export type EventName<T extends string> = T extends `on${infer N}`
117
? Uncapitalize<N>

src/lib/preprocessReact.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ function transform(content: string, options: TransformOptions) {
125125
.join(";");
126126

127127
if (!script) {
128-
s.prepend(`<script>\n${imports}\n\n${wrappers}\n</script>\n\n`);
128+
s.prepend(`<script>\n${imports.join("; ")}\n\n${wrappers}\n</script>\n\n`);
129129
} else {
130130
s.appendRight(script.content.end, wrappers);
131131
s.appendRight(script.content.start, `${imports.join("; ")}; `);
@@ -160,7 +160,11 @@ function replaceReactTags(
160160
);
161161
}
162162
if (!components[alias]) {
163-
components[alias] = componentExpression;
163+
if (componentExpression.match(/^[a-z-]+$/)) {
164+
components[alias] = `"${componentExpression}"`;
165+
} else {
166+
components[alias] = componentExpression;
167+
}
164168
}
165169
tag.attributes.forEach((attr) => {
166170
if (attr.type === "EventHandler") {

src/lib/sveltify.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { ComponentClass, FunctionComponent } from "react";
33
import type { SvelteComponentTyped } from "svelte/internal";
44
import type ReactDOMServer from "react-dom/server";
55
import { writable, type Readable } from "svelte/store";
6-
import type { ConstructorOf, SvelteInit, TreeNode } from "./internal/types";
6+
import type { SvelteInit, TreeNode } from "./internal/types";
77
import ReactWrapper from "./internal/ReactWrapper.svelte";
88
import Slot from "./internal/Slot.svelte";
99
import Bridge, { type BridgeProps } from "./internal/Bridge.js";
@@ -23,7 +23,11 @@ const tree: TreeNode = {
2323
hooks: writable([]),
2424
};
2525

26-
type Sveltified<P> = ConstructorOf<SvelteComponentTyped<Omit<P, "children">>>;
26+
declare type Sveltified<P extends Record<string, any>> = new (args: {
27+
target: any;
28+
props?: P;
29+
}) => SvelteComponentTyped<P>;
30+
2731
/**
2832
* Convert a React component into a Svelte component.
2933
*/
@@ -32,7 +36,7 @@ export default function sveltify<P>(
3236
createPortal: BridgeProps["createPortal"],
3337
ReactDOMClient: any,
3438
renderToString?: typeof ReactDOMServer.renderToString
35-
): Sveltified<P> {
39+
): Sveltified<Omit<P, "children">> {
3640
const Wrapper = ReactWrapper as any;
3741
const ssr = typeof Wrapper.$$render === "function";
3842
if (ssr) {

src/routes/preprocessor/+page.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
"Multiline content". {10 ** 4} Lorem ipsum dolor sit amet consectetur adipisicing
1818
elit. Suscipit nisi atque asperiores.</react:Alert
1919
>
20+
<react:div>a div</react:div>

src/tests/__snapshots__/preprocess.spec.ts.snap

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const React$Clicker = React$$sveltify(Clicker, React$$createPortal, React$$React
3232

3333
exports[`svelte-preprocess-react > should inject a script tag 1`] = `
3434
"<script>
35-
import React$$sveltify from \\"svelte-preprocess-react/sveltify\\",import React$$ReactDOM from \\"react-dom/client\\",import { createPortal as React$$createPortal} from \\"react-dom\\",import { renderToString as React$$renderToString } from \\"react-dom/server\\"
35+
import React$$sveltify from \\"svelte-preprocess-react/sveltify\\"; import React$$ReactDOM from \\"react-dom/client\\"; import { createPortal as React$$createPortal} from \\"react-dom\\"; import { renderToString as React$$renderToString } from \\"react-dom/server\\"
3636
3737
const React$Counter = React$$sveltify(Counter, React$$createPortal, React$$ReactDOM, React$$renderToString);
3838
</script>
@@ -132,6 +132,19 @@ const React$Clicker = React$$sveltify(Clicker, React$$createPortal, React$$React
132132
"
133133
`;
134134

135+
exports[`svelte-preprocess-react > should process <react:element> (lowercase) tags 1`] = `
136+
"<script>
137+
import React$$sveltify from \\"svelte-preprocess-react/sveltify\\"; import React$$ReactDOM from \\"react-dom/client\\"; import { createPortal as React$$createPortal} from \\"react-dom\\"; import { renderToString as React$$renderToString } from \\"react-dom/server\\"
138+
139+
const React$button = React$$sveltify(\\"button\\", React$$createPortal, React$$ReactDOM, React$$renderToString);
140+
</script>
141+
142+
<React$button onClick={() => console.info(\\"clicked\\")}>
143+
<slot />
144+
</React$button>
145+
"
146+
`;
147+
135148
exports[`svelte-preprocess-react > should support typescript when using preprocess 1`] = `
136149
"<script lang=\\"ts\\">export let title;
137150
</script>

src/tests/fixtures/Element.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<react:button on:click={() => console.info("clicked")}>
2+
<slot />
3+
</react:button>

src/tests/preprocess.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ describe("svelte-preprocess-react", () => {
103103
);
104104
expect(output.code).toMatchSnapshot();
105105
});
106+
it("should process <react:element> (lowercase) tags", async () => {
107+
const filename = resolveFilename("./fixtures/Element.svelte");
108+
const src = await readFile(filename, "utf8");
109+
const output = await preprocess(src, preprocessReact(), { filename });
110+
expect(output.code).toMatchSnapshot();
111+
});
106112
});
107113

108114
const base = dirname(import.meta.url).replace("file://", "");

0 commit comments

Comments
 (0)